lib/core/stream: LineIterator use CachedIterator
[nit.git] / lib / app / ui.nit
index 1b2b7ae..42e36ce 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Portable UI API for the _app.nit_ framework
+# Portable UI controls for mobiles apps
+#
+# ~~~
+# import app::ui
+#
+# class MyWindow
+#     super Window
+#
+#     var layout = new ListLayout(parent=self)
+#     var lbl = new Label(parent=layout, text="Hello world", align=0.5)
+#     var but = new Button(parent=layout, text="Press here")
+#
+#     redef fun on_event(event) do lbl.text = "Pressed!"
+# end
+#
+# redef fun root_window do return new MyWindow
+# ~~~
 module ui
 
 import app_base
@@ -27,12 +43,38 @@ redef class App
 
        # The current `Window` of this activity
        #
-       # This attribute must be set by refinements of `App`.
-       var window: Window is writable
+       # This attribute is set by `push_window`.
+       var window: Window is noinit
 
-       redef fun on_create do window.on_create
+       # Make `window` visible and push it on the top of the `window_stack`
+       #
+       # This method can be called at any times while the app is active.
+       fun push_window(window: Window)
+       do
+               window_stack.add window
+               self.window = window
+               window.on_create
+       end
 
-       redef fun on_start do window.on_start
+       # Pop the current `window` from the stack and show the previous one
+       #
+       # Require: `window_stack.not_empty`
+       fun pop_window
+       do
+               assert window_stack.not_empty
+               window_stack.pop
+               window = window_stack.last
+               window.on_resume
+       end
+
+       # Stack of active windows
+       var window_stack = new Array[Window]
+
+       redef fun on_create
+       do
+               var window = root_window
+               push_window window
+       end
 
        redef fun on_resume do window.on_resume
 
@@ -40,13 +82,18 @@ redef class App
 
        redef fun on_stop do window.on_stop
 
-       redef fun on_destroy do window.on_destroy
-
        redef fun on_restore_state do window.on_restore_state
 
        redef fun on_save_state do window.on_save_state
 end
 
+# Hook to create the first window shown to the user
+#
+# By default, a `Window` is created, which can be refined to customize it.
+# However, most apps should refine this method to return a different window,
+# this way the app can have more than one window.
+fun root_window: Window do return new Window
+
 # An event created by an `AppComponent` and sent to `AppObserver`s
 interface AppEvent
 end
@@ -83,11 +130,17 @@ class Control
 
        # Direct parent `Control` in the control tree
        #
+       # The parents (direct and indirect) receive all events from `self`,
+       # like the `observers`.
+       #
        # If `null` then `self` is at the root of the tree, or not yet attached.
        var parent: nullable CompositeControl = null is private writable(set_parent)
 
        # Direct parent `Control` in the control tree
        #
+       # The parents (direct and indirect) receive all events from `self`,
+       # like the `observers`.
+       #
        # Setting `parent` calls `remove` on the old parent and `add` on the new one.
        fun parent=(parent: nullable CompositeControl)
        is autoinit     do
@@ -100,12 +153,25 @@ class Control
 
                set_parent parent
        end
+
+       # Also notify the parents (both direct and indirect)
+       redef fun notify_observers(event)
+       do
+               super
+
+               var p = parent
+               while p != null do
+                       p.on_event event
+                       p = p.parent
+               end
+       end
 end
 
 # A `Control` grouping other controls
 class CompositeControl
        super Control
 
+       # Child controls composing this control
        protected var items = new Array[Control]
 
        # Add `item` as a child of `self`
@@ -122,27 +188,32 @@ class CompositeControl
 
        redef fun on_create do for i in items do i.on_create
 
-       redef fun on_start do for i in items do i.on_start
-
        redef fun on_resume do for i in items do i.on_resume
 
        redef fun on_pause do for i in items do i.on_pause
 
        redef fun on_stop do for i in items do i.on_stop
 
-       redef fun on_destroy do for i in items do i.on_destroy
-
        redef fun on_restore_state do for i in items do i.on_restore_state
 
        redef fun on_save_state do for i in items do i.on_save_state
 end
 
 # A window, root of the `Control` tree
+#
+# Each window should hold a single control, usually a `CompositeControl`,
+# which in turn holds all the displayed controls.
 class Window
        super CompositeControl
+
+       # Should the back button be shown and used to go back to a previous window?
+       fun enable_back_button: Bool do return app.window_stack.length > 1
+
+       # The back button has been pressed, usually to open the previous window
+       fun on_back_button do app.pop_window
 end
 
-# A viewable `Control`
+# A visible `Control`
 abstract class View
        super Control
 
@@ -152,7 +223,9 @@ abstract class View
        var enabled: nullable Bool is writable, abstract, autoinit
 end
 
-# A control with some `text`
+# A control displaying some `text`
+#
+# For a text-only control, see `Label`.
 abstract class TextView
        super View
 
@@ -181,7 +254,7 @@ abstract class TextView
        # depending on the customization options of each platform.
        # For consistent results, it is recommended to use only on instances
        # of `Label` and `size` should be either 0.0, 0.5 or 1.0.
-       fun align=(center: nullable Float) is autoinit do end
+       fun align=(align: nullable Float) is autoinit do end
 end
 
 # A control for the user to enter custom `text`
@@ -192,17 +265,17 @@ class TextInput
        var is_password: nullable Bool is writable
 end
 
-# A pushable button, raises `ButtonPressEvent`
+# A pressable button, raises `ButtonPressEvent`
 class Button
        super TextView
 end
 
-# A text label
+# A simple text label
 class Label
        super TextView
 end
 
-# Toggle control with two states and a label
+# Toggle control between two states, also displays a label
 class CheckBox
        super TextView
 
@@ -256,3 +329,8 @@ class ListLayout
        super View
        super CompositeControl
 end
+
+redef class Text
+       # Open the URL `self` with the default browser
+       fun open_in_browser do print_error "Text::open_in_browser not implemented on this platform."
+end