1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Portable UI controls for mobiles apps
23 # var layout = new ListLayout(parent=self)
24 # var lbl = new Label(parent=layout, text="Hello world", align=0.5)
25 # var but = new Button(parent=layout, text="Press here")
27 # redef fun on_event(event) do lbl.text = "Pressed!"
30 # redef fun root_window do return new MyWindow
37 import linux
::ui
is conditional
(linux
)
38 import android
::ui
is conditional
(android
)
39 import ios
::ui
is conditional
(ios
)
44 # The current `Window` of this activity
46 # This attribute is set by `push_window`.
47 var window
: Window is noinit
49 # Make `window` visible and push it on the top of the `window_stack`
51 # This method can be called at any times while the app is active.
52 fun push_window
(window
: Window)
54 window_stack
.add window
59 # Pop the current `window` from the stack and show the previous one
61 # Require: `window_stack.not_empty`
64 assert window_stack
.not_empty
66 window
= window_stack
.last
70 # Stack of active windows
71 var window_stack
= new Array[Window]
75 var window
= root_window
79 redef fun on_resume
do window
.on_resume
81 redef fun on_pause
do window
.on_pause
83 redef fun on_stop
do window
.on_stop
85 redef fun on_restore_state
do window
.on_restore_state
87 redef fun on_save_state
do window
.on_save_state
90 # Hook to create the first window shown to the user
92 # By default, a `Window` is created, which can be refined to customize it.
93 # However, most apps should refine this method to return a different window,
94 # this way the app can have more than one window.
95 fun root_window
: Window do return new Window
97 # An event created by an `AppComponent` and sent to `AppObserver`s
101 # Observer of `AppEvent`s raised by `AppComponent`s
102 interface AppObserver
103 # Notification of `event` raised by `sender`
105 # To be implemented in subclasses as needed.
106 fun on_event
(event
: AppEvent) do end
109 redef class AppComponent
112 # All `AppObserver` notified of events raised by `self`
114 # By default, only `self` is an observer.
115 # Any other `AppObserver` can be added to this collection.
116 var observers
= new HashSet[AppObserver].from
([self: AppObserver])
118 # Propagate `event` to all `observers` by calling `AppObserver::on_event`
119 fun notify_observers
(event
: AppEvent)
121 for observer
in observers
do
122 observer
.on_event
(event
)
127 # A control implementing the UI
131 # Direct parent `Control` in the control tree
133 # The parents (direct and indirect) receive all events from `self`,
134 # like the `observers`.
136 # If `null` then `self` is at the root of the tree, or not yet attached.
137 var parent
: nullable CompositeControl = null is private writable(set_parent
)
139 # Direct parent `Control` in the control tree
141 # The parents (direct and indirect) receive all events from `self`,
142 # like the `observers`.
144 # Setting `parent` calls `remove` on the old parent and `add` on the new one.
145 fun parent
=(parent
: nullable CompositeControl)
147 var old_parent
= self.parent
148 if old_parent
!= null and old_parent
!= parent
then
149 old_parent
.remove
self
152 if parent
!= null then parent
.add
self
157 # Also notify the parents (both direct and indirect)
158 redef fun notify_observers
(event
)
170 # A `Control` grouping other controls
171 class CompositeControl
174 # Child controls composing this control
175 protected var items
= new Array[Control]
177 # Add `item` as a child of `self`
178 protected fun add
(item
: Control) do items
.add item
180 # Remove `item` from `self`
181 fun remove
(item
: Control) do if has
(item
) then items
.remove item
183 # Is `item` in `self`?
184 fun has
(item
: Control): Bool do return items
.has
(item
)
186 # Remove all items from `self`
187 fun clear
do for item
in items
.to_a
do remove item
189 redef fun on_create
do for i
in items
do i
.on_create
191 redef fun on_resume
do for i
in items
do i
.on_resume
193 redef fun on_pause
do for i
in items
do i
.on_pause
195 redef fun on_stop
do for i
in items
do i
.on_stop
197 redef fun on_restore_state
do for i
in items
do i
.on_restore_state
199 redef fun on_save_state
do for i
in items
do i
.on_save_state
202 # A window, root of the `Control` tree
204 # Each window should hold a single control, usually a `CompositeControl`,
205 # which in turn holds all the displayed controls.
207 super CompositeControl
209 # Should the back button be shown and used to go back to a previous window?
210 fun enable_back_button
: Bool do return app
.window_stack
.length
> 1
212 # The back button has been pressed, usually to open the previous window
213 fun on_back_button
do app
.pop_window
216 # A visible `Control`
220 # Is this control enabled so the user can interact with it?
222 # By default, or if set to `null`, the control is enabled.
223 var enabled
: nullable Bool is writable, abstract, autoinit
226 # A control displaying some `text`
228 # For a text-only control, see `Label`.
229 abstract class TextView
232 # Main `Text` of this control
234 # By default, or if set to `null`, no text is shown.
235 var text
: nullable Text is writable, abstract, autoinit
237 # Set the relative size of the text
239 # A value of 1.0, the default, use the platform default text size.
240 # Values under 1.0 set a smaller text size, and over 1.0 a larger size.
242 # Implementation varies per platform, and some controls may be unaffected
243 # depending on the customization options of each platform.
244 # For consistent results, it is recommended to use only on instances
245 # of `Label` and `size` should be either 0.5, 1.0 or 1.5.
246 fun size
=(size
: nullable Float) is autoinit
do end
248 # Align the text horizontally
250 # Use 0.0 to align left (the default), 0.5 to align in the center and
251 # 1.0 to align on the right.
253 # Implementation varies per platform, and some controls may be unaffected
254 # depending on the customization options of each platform.
255 # For consistent results, it is recommended to use only on instances
256 # of `Label` and `size` should be either 0.0, 0.5 or 1.0.
257 fun align
=(align
: nullable Float) is autoinit
do end
260 # A control for the user to enter custom `text`
264 # Hide password or any content entered in this view?
265 var is_password
: nullable Bool is writable
268 # A pressable button, raises `ButtonPressEvent`
273 # A simple text label
278 # Toggle control between two states, also displays a label
282 # Is this control in the checked/on state?
283 var is_checked
= false is writable
286 # Event sent from a `VIEW`
290 # The `VIEW` that raised this event
293 # Type of the `sender`
297 # A `Button` press event
298 class ButtonPressEvent
301 redef type VIEW: Button
304 # The `CheckBox` `sender` has been toggled
308 redef type VIEW: CheckBox
311 # A layout to visually organize `Control`s
312 abstract class Layout
314 super CompositeControl
317 # An horizontal linear organization
318 class HorizontalLayout
322 # A vertical linear organization
327 # Scrollable list of views in a simple list
330 super CompositeControl
334 # Open the URL `self` with the default browser
335 fun open_in_browser
do print_error
"Text::open_in_browser not implemented on this platform."