lib/ios: implement ToggleEvent
[nit.git] / lib / ios / ui / ui.nit
index bac7c94..ad4aaac 100644 (file)
@@ -25,16 +25,16 @@ in "ObjC" `{
 @interface NitCallbackReference: NSObject
 
        // Nit object target of the callbacks from UI events
-       @property (nonatomic) Button nit_button;
+       @property (nonatomic) View nit_view;
 
        // Actual callback method
-       -(void) nitOnEvent: (UIButton*) sender;
+       -(void) nitOnEvent: (UIView*) sender;
 @end
 
 @implementation NitCallbackReference
 
-       -(void) nitOnEvent: (UIButton*) sender {
-               Button_on_click(self.nit_button);
+       -(void) nitOnEvent: (UIView*) sender {
+               View_on_ios_event(self.nit_view);
        }
 @end
 
@@ -78,14 +78,38 @@ in "ObjC" `{
 redef class App
        redef fun did_finish_launching_with_options
        do
+               app_delegate.window = new UIWindow
+               app_delegate.window.background_color = new UIColor.white_color
                super
-               window.native.make_key_and_visible
+               app_delegate.window.make_key_and_visible
                return true
        end
 
+       private fun set_view_controller(window: UIWindow, native: UIViewController)
+       in "ObjC" `{
+               // Set the required root view controller
+               UINavigationController *navController = (UINavigationController*)window.rootViewController;
+
+               if (navController == NULL) {
+                       navController = [[UINavigationController alloc]initWithRootViewController:native];
+                       navController.edgesForExtendedLayout = UIRectEdgeNone;
+
+                       // Must be non-translucent for the controls to be placed under
+                       // (as in Y axis) of the navigation bar.
+                       navController.navigationBar.translucent = NO;
+
+                       window.rootViewController = navController;
+               }
+               else {
+                       [navController pushViewController:native animated:YES];
+               }
+
+               native.edgesForExtendedLayout = UIRectEdgeNone;
+       `}
+
        redef fun window=(window)
        do
-               app_delegate.window = window.native
+               set_view_controller(app_delegate.window, window.native)
                super
        end
 end
@@ -112,6 +136,8 @@ redef class View
        redef type NATIVE: UIView
 
        redef var enabled = null is lazy
+
+       private fun on_ios_event do end
 end
 
 redef class CompositeControl
@@ -128,10 +154,14 @@ end
 
 redef class Window
 
-       redef type NATIVE: UIWindow
-       redef var native = new UIWindow
+       redef type NATIVE: UIViewController
+       redef var native = new UIViewController
 
-       init do native.background_color = new UIColor.white_color
+       # Title of this window
+       fun title: String do return native.title.to_s
+
+       # Set the title of this window
+       fun title=(title: String) do native.title = title.to_nsstring
 
        redef fun add(view)
        do
@@ -139,26 +169,9 @@ redef class Window
 
                var native_view = view.native
                assert native_view isa UIView
-               native.add_subview native_view
 
-               fill_whole_window_with(native_view, native)
+               native.view = native_view
        end
-
-       private fun fill_whole_window_with(native: UIView, window: UIWindow)
-       in "ObjC" `{
-               // Hard coded borders including the top bar
-               // FIXME this may cause problems with retina devices
-               [window addConstraints:[NSLayoutConstraint
-                       constraintsWithVisualFormat: @"V:|-24-[view]-8-|"
-                       options: 0 metrics: nil views: @{@"view": native}]];
-               [window addConstraints:[NSLayoutConstraint
-                       constraintsWithVisualFormat: @"H:|-8-[view]-8-|"
-                       options: 0 metrics: nil views: @{@"view": native}]];
-
-               // Set the required root view controller
-               window.rootViewController = [[UIViewController alloc]initWithNibName:nil bundle:nil];
-               window.rootViewController.view = native;
-       `}
 end
 
 redef class Layout
@@ -170,7 +183,6 @@ redef class Layout
        do
                native.alignment = new UIStackViewAlignment.fill
                native.distribution = new UIStackViewDistribution.fill_equally
-               native.translates_autoresizing_mask_into_constraits = false
 
                # TODO make customizable
                native.spacing = 4.0
@@ -201,6 +213,31 @@ redef class Label
 
        redef fun text=(text) do native.text = (text or else "").to_nsstring
        redef fun text do return native.text.to_s
+
+       redef fun size=(size)
+       do
+               size = size or else 1.0
+               var points = 8.0 + size * 8.0
+               set_size_native(native, points)
+       end
+
+       private fun set_size_native(native: UILabel, points: Float)
+       in "ObjC" `{
+               native.font = [UIFont systemFontOfSize: points];
+       `}
+
+       redef fun align=(align) do set_align_native(native, align or else 0.0)
+
+       private fun set_align_native(native: UILabel, align: Float)
+       in "ObjC" `{
+
+               if (align == 0.5)
+                       native.textAlignment = NSTextAlignmentCenter;
+               else if (align < 0.5)
+                       native.textAlignment = NSTextAlignmentLeft;
+               else//if (align > 0.5)
+                       native.textAlignment = NSTextAlignmentRight;
+       `}
 end
 
 # On iOS, check boxes are a layout composed of a label and an `UISwitch`
@@ -218,7 +255,10 @@ redef class CheckBox
        # `UISwitch` acting as the real check box
        var ui_switch: UISwitch is noautoinit
 
-       init do
+       redef fun on_ios_event do notify_observers new ToggleEvent(self)
+
+       init
+       do
                # Tweak the layout so it is centered
                layout.native.distribution = new UIStackViewDistribution.fill_proportionally
                layout.native.alignment = new UIStackViewAlignment.center
@@ -227,6 +267,8 @@ redef class CheckBox
                var s = new UISwitch
                native.add_arranged_subview s
                ui_switch = s
+
+               ui_switch.set_callback self
        end
 
        redef fun text=(text) do lbl.text = text
@@ -236,6 +278,23 @@ redef class CheckBox
        redef fun is_checked=(value) do ui_switch.set_on_animated(value, true)
 end
 
+redef class UISwitch
+       # Register callbacks on this switch to be relayed to `sender`
+       private fun set_callback(sender: View)
+       import View.on_ios_event in "ObjC" `{
+
+               NitCallbackReference *ncr = [[NitCallbackReference alloc] init];
+               ncr.nit_view = sender;
+
+               // Pin the objects in both Objective-C and Nit GC
+               View_incr_ref(sender);
+               ncr = (__bridge NitCallbackReference*)CFBridgingRetain(ncr);
+
+               [self addTarget:ncr action:@selector(nitOnEvent:)
+                       forControlEvents:UIControlEventValueChanged];
+       `}
+end
+
 redef class TextInput
 
        redef type NATIVE: UITextField
@@ -258,25 +317,25 @@ redef class Button
 
        init do native.set_callback self
 
+       redef fun on_ios_event do notify_observers new ButtonPressEvent(self)
+
        redef fun text=(text) do if text != null then native.title = text.to_nsstring
        redef fun text do return native.current_title.to_s
 
-       private fun on_click do notify_observers new ButtonPressEvent(self)
-
        redef fun enabled=(enabled) do native.enabled = enabled or else true
        redef fun enabled do return native.enabled
 end
 
 redef class UIButton
        # Register callbacks on this button to be relayed to `sender`
-       private fun set_callback(sender: Button)
-       import Button.on_click in "ObjC" `{
+       private fun set_callback(sender: View)
+       import View.on_ios_event in "ObjC" `{
 
                NitCallbackReference *ncr = [[NitCallbackReference alloc] init];
-               ncr.nit_button = sender;
+               ncr.nit_view = sender;
 
                // Pin the objects in both Objective-C and Nit GC
-               Button_incr_ref(sender);
+               View_incr_ref(sender);
                ncr = (__bridge NitCallbackReference*)CFBridgingRetain(ncr);
 
                [self addTarget:ncr action:@selector(nitOnEvent:)