tests: add some runtime error in nitin.input
[nit.git] / lib / app / ui.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Portable UI API for the _app.nit_ framework
16 module ui
17
18 import app_base
19
20 # Platform variations
21 import linux::ui is conditional(linux)
22 import android::ui is conditional(android)
23 import ios::ui is conditional(ios)
24
25 redef class App
26 super AppComponent
27
28 # The current `Window` of this activity
29 #
30 # This attribute is set by `push_window`.
31 var window: Window is noinit
32
33 # Make visible and push `window` on the top of `pop_window`
34 #
35 # This method must be called at least once within `App::on_create`.
36 # It can be called at any times while the app is active.
37 fun push_window(window: Window)
38 do
39 window_stack.add window
40 self.window = window
41 end
42
43 # Pop the current `window` from the stack and show the previous one
44 #
45 # Require: `window_stack.not_empty`
46 fun pop_window
47 do
48 assert window_stack.not_empty
49 window_stack.pop
50 window = window_stack.last
51 window.on_resume
52 end
53
54 # Stack of active windows
55 var window_stack = new Array[Window]
56
57 redef fun on_create do window.on_create
58
59 redef fun on_resume do window.on_resume
60
61 redef fun on_pause do window.on_pause
62
63 redef fun on_stop do window.on_stop
64
65 redef fun on_restore_state do window.on_restore_state
66
67 redef fun on_save_state do window.on_save_state
68 end
69
70 # An event created by an `AppComponent` and sent to `AppObserver`s
71 interface AppEvent
72 end
73
74 # Observer of `AppEvent`s raised by `AppComponent`s
75 interface AppObserver
76 # Notification of `event` raised by `sender`
77 #
78 # To be implemented in subclasses as needed.
79 fun on_event(event: AppEvent) do end
80 end
81
82 redef class AppComponent
83 super AppObserver
84
85 # All `AppObserver` notified of events raised by `self`
86 #
87 # By default, only `self` is an observer.
88 # Any other `AppObserver` can be added to this collection.
89 var observers = new HashSet[AppObserver].from([self: AppObserver])
90
91 # Propagate `event` to all `observers` by calling `AppObserver::on_event`
92 fun notify_observers(event: AppEvent)
93 do
94 for observer in observers do
95 observer.on_event(event)
96 end
97 end
98 end
99
100 # A control implementing the UI
101 class Control
102 super AppComponent
103
104 # Direct parent `Control` in the control tree
105 #
106 # The parents (direct and indirect) receive all events from `self`,
107 # like the `observers`.
108 #
109 # If `null` then `self` is at the root of the tree, or not yet attached.
110 var parent: nullable CompositeControl = null is private writable(set_parent)
111
112 # Direct parent `Control` in the control tree
113 #
114 # The parents (direct and indirect) receive all events from `self`,
115 # like the `observers`.
116 #
117 # Setting `parent` calls `remove` on the old parent and `add` on the new one.
118 fun parent=(parent: nullable CompositeControl)
119 is autoinit do
120 var old_parent = self.parent
121 if old_parent != null and old_parent != parent then
122 old_parent.remove self
123 end
124
125 if parent != null then parent.add self
126
127 set_parent parent
128 end
129
130 # Also notify the parents (both direct and indirect)
131 redef fun notify_observers(event)
132 do
133 super
134
135 var p = parent
136 while p != null do
137 p.on_event event
138 p = p.parent
139 end
140 end
141 end
142
143 # A `Control` grouping other controls
144 class CompositeControl
145 super Control
146
147 # Child controls composing this control
148 protected var items = new Array[Control]
149
150 # Add `item` as a child of `self`
151 protected fun add(item: Control) do items.add item
152
153 # Remove `item` from `self`
154 fun remove(item: Control) do if has(item) then items.remove item
155
156 # Is `item` in `self`?
157 fun has(item: Control): Bool do return items.has(item)
158
159 # Remove all items from `self`
160 fun clear do for item in items.to_a do remove item
161
162 redef fun on_create do for i in items do i.on_create
163
164 redef fun on_resume do for i in items do i.on_resume
165
166 redef fun on_pause do for i in items do i.on_pause
167
168 redef fun on_stop do for i in items do i.on_stop
169
170 redef fun on_restore_state do for i in items do i.on_restore_state
171
172 redef fun on_save_state do for i in items do i.on_save_state
173 end
174
175 # A window, root of the `Control` tree
176 class Window
177 super CompositeControl
178
179 # Should the back button be shown and used to go back to a previous window?
180 fun enable_back_button: Bool do return app.window_stack.length > 1
181
182 # The back button has been pressed, usually to open the previous window
183 fun on_back_button do app.pop_window
184 end
185
186 # A viewable `Control`
187 abstract class View
188 super Control
189
190 # Is this control enabled so the user can interact with it?
191 #
192 # By default, or if set to `null`, the control is enabled.
193 var enabled: nullable Bool is writable, abstract, autoinit
194 end
195
196 # A control with some `text`
197 abstract class TextView
198 super View
199
200 # Main `Text` of this control
201 #
202 # By default, or if set to `null`, no text is shown.
203 var text: nullable Text is writable, abstract, autoinit
204
205 # Set the relative size of the text
206 #
207 # A value of 1.0, the default, use the platform default text size.
208 # Values under 1.0 set a smaller text size, and over 1.0 a larger size.
209 #
210 # Implementation varies per platform, and some controls may be unaffected
211 # depending on the customization options of each platform.
212 # For consistent results, it is recommended to use only on instances
213 # of `Label` and `size` should be either 0.5, 1.0 or 1.5.
214 fun size=(size: nullable Float) is autoinit do end
215
216 # Align the text horizontally
217 #
218 # Use 0.0 to align left (the default), 0.5 to align in the center and
219 # 1.0 to align on the right.
220 #
221 # Implementation varies per platform, and some controls may be unaffected
222 # depending on the customization options of each platform.
223 # For consistent results, it is recommended to use only on instances
224 # of `Label` and `size` should be either 0.0, 0.5 or 1.0.
225 fun align=(align: nullable Float) is autoinit do end
226 end
227
228 # A control for the user to enter custom `text`
229 class TextInput
230 super TextView
231
232 # Hide password or any content entered in this view?
233 var is_password: nullable Bool is writable
234 end
235
236 # A pushable button, raises `ButtonPressEvent`
237 class Button
238 super TextView
239 end
240
241 # A text label
242 class Label
243 super TextView
244 end
245
246 # Toggle control with two states and a label
247 class CheckBox
248 super TextView
249
250 # Is this control in the checked/on state?
251 var is_checked = false is writable
252 end
253
254 # Event sent from a `VIEW`
255 class ViewEvent
256 super AppEvent
257
258 # The `VIEW` that raised this event
259 var sender: VIEW
260
261 # Type of the `sender`
262 type VIEW: View
263 end
264
265 # A `Button` press event
266 class ButtonPressEvent
267 super ViewEvent
268
269 redef type VIEW: Button
270 end
271
272 # The `CheckBox` `sender` has been toggled
273 class ToggleEvent
274 super ViewEvent
275
276 redef type VIEW: CheckBox
277 end
278
279 # A layout to visually organize `Control`s
280 abstract class Layout
281 super View
282 super CompositeControl
283 end
284
285 # An horizontal linear organization
286 class HorizontalLayout
287 super Layout
288 end
289
290 # A vertical linear organization
291 class VerticalLayout
292 super Layout
293 end
294
295 # Scrollable list of views in a simple list
296 class ListLayout
297 super View
298 super CompositeControl
299 end
300
301 redef class Text
302 # Open the URL `self` with the default browser
303 fun open_in_browser do print_error "Text::open_in_browser not implemented on this platform."
304 end