glimmer-dsl-libui 0.0.2 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +837 -27
  4. data/VERSION +1 -1
  5. data/examples/basic_entry.rb +1 -1
  6. data/examples/control_gallery.rb +184 -0
  7. data/examples/midi_player.rb +90 -0
  8. data/examples/simple_notepad.rb +15 -0
  9. data/glimmer-dsl-libui.gemspec +0 -0
  10. data/lib/glimmer/dsl/libui/control_expression.rb +1 -3
  11. data/lib/glimmer/dsl/libui/dsl.rb +1 -1
  12. data/lib/glimmer/dsl/libui/file_expression.rb +33 -0
  13. data/lib/glimmer/dsl/libui/open_file_expression.rb +33 -0
  14. data/lib/glimmer/dsl/libui/save_file_expression.rb +33 -0
  15. data/lib/glimmer/dsl/libui/tab_item_expression.rb +35 -0
  16. data/lib/glimmer/libui/about_menu_item_proxy.rb +37 -0
  17. data/lib/glimmer/libui/box.rb +4 -0
  18. data/lib/glimmer/libui/check_menu_item_proxy.rb +37 -0
  19. data/lib/glimmer/libui/combobox_proxy.rb +43 -0
  20. data/lib/glimmer/libui/control_proxy.rb +75 -22
  21. data/lib/glimmer/libui/editable_combobox_proxy.rb +43 -0
  22. data/lib/glimmer/libui/group_proxy.rb +35 -0
  23. data/lib/glimmer/libui/horizontal_box_proxy.rb +1 -1
  24. data/lib/glimmer/libui/menu_item_proxy.rb +41 -0
  25. data/lib/glimmer/libui/multiline_entry_proxy.rb +35 -0
  26. data/lib/glimmer/libui/non_wrapping_multiline_entry_proxy.rb +32 -0
  27. data/lib/glimmer/libui/preferences_menu_item_proxy.rb +37 -0
  28. data/lib/glimmer/libui/quit_menu_item_proxy.rb +62 -0
  29. data/lib/glimmer/libui/radio_buttons_proxy.rb +43 -0
  30. data/lib/glimmer/libui/separator_menu_item_proxy.rb +37 -0
  31. data/lib/glimmer/libui/tab_item_proxy.rb +66 -0
  32. data/lib/glimmer/libui/vertical_box_proxy.rb +1 -1
  33. data/lib/glimmer/libui/window_proxy.rb +3 -3
  34. data/lib/glimmer-dsl-libui.rb +2 -0
  35. metadata +25 -5
data/README.md CHANGED
@@ -1,14 +1,16 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.0.2
2
- ## Dependency-Free Ruby Desktop Development GUI Library
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.0.6
2
+ ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
5
5
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
6
 
7
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is a dependency-free Ruby desktop development GUI library. No need to pre-install any pre-requisites. Just install the gem and have platform-independent GUI that just works!
7
+ [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/kojix2/LibUI) is a prerequisite-free Ruby desktop development GUI library. No need to pre-install any prerequisites. Just install the gem and have platform-independent native GUI that just works!
8
8
 
9
- The main trade-off against [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) and [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than [LibUI](https://github.com/kojix2/LibUI) as GUI toolkits. Still, if there is only a need to build a small simple application, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) could be a pretty good choice due to having zero external dependencies beyond what is included in the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui).
9
+ [LibUI](https://github.com/kojix2/LibUI) is a thin [Ruby](https://www.ruby-lang.org/en/) wrapper around [libui](https://github.com/andlabs/libui), a relatively new C GUI library that renders native widgets on every platform (similar to [SWT](https://www.eclipse.org/swt/), but without the heavy weight of the [Java Virtual Machine](https://www.java.com/en/)).
10
10
 
11
- [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
11
+ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) as opposed to [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) or [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than mid-alpha [libui](https://github.com/andlabs/libui) as GUI toolkits. Still, if there is only a need to build a small simple application, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) could be a good convenient choice due to having zero prerequisites beyond the dependencies included in the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui). Also, just like [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk), its apps start instantly and have a small memory footprint. [LibUI](https://github.com/kojix2/LibUI) is a promising new GUI toolkit that might prove quite worthy in the future.
12
+
13
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
12
14
  - Declarative DSL syntax that visually maps to the GUI widget hierarchy
13
15
  - Convention over configuration via smart defaults and automation of low-level details
14
16
  - Requiring the least amount of syntax possible to build GUI
@@ -27,10 +29,10 @@ include Glimmer
27
29
  window('hello world', 300, 200, 1).show
28
30
  ```
29
31
 
30
- ![glimmer-dsl-libui-basic-window-mac.png](images/glimmer-dsl-libui-basic-window-mac.png)
31
- ![glimmer-dsl-libui-basic-window-linux.png](images/glimmer-dsl-libui-basic-window-linux.png)
32
+ ![glimmer-dsl-libui-mac-basic-window.png](images/glimmer-dsl-libui-mac-basic-window.png)
33
+ ![glimmer-dsl-libui-linux-basic-window.png](images/glimmer-dsl-libui-linux-basic-window.png)
32
34
 
33
- NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is in early alpha mode. Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
35
+ NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is in early alpha mode (only supports included examples). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
34
36
 
35
37
  Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
36
38
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
@@ -39,9 +41,37 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
39
41
  - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
40
42
  - [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
41
43
 
44
+ ## Table of Contents
45
+
46
+ - [Glimmer DSL for LibUI 0.0.6](#-glimmer-dsl-for-libui-006)
47
+ - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
48
+ - [Usage](#usage)
49
+ - [API](#api)
50
+ - [Supported Controls](#supported-controls)
51
+ - [Common Control Properties](#common-control-properties)
52
+ - [Common Control Operations](#common-control-operations)
53
+ - [Extra Operations](#extra-operations)
54
+ - [Girb (Glimmer IRB)](#girb-glimmer-irb)
55
+ - [Examples](#examples)
56
+ - [Basic Window](#basic-window)
57
+ - [Basic Button](#basic-button)
58
+ - [Basic Entry](#basic-entry)
59
+ - [Simple Notepad](#simple-notepad)
60
+ - [Midi Player](#midi-player)
61
+ - [Control Gallery](#control-gallery)
62
+ - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
63
+ - [Help](#help)
64
+ - [Issues](#issues)
65
+ - [Chat](#chat)
66
+ - [Process](#process)
67
+ - [Planned Features and Feature Suggestions](#planned-features-and-feature-suggestions)
68
+ - [Change Log](#change-log)
69
+ - [Contributors](#contributors)
70
+ - [License](#license)
71
+
42
72
  ## Glimmer GUI DSL Concepts
43
73
 
44
- The Glimmer GUI DSL provides a declarative syntax for [LibUI](https://github.com/kojix2/LibUI) that:
74
+ The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for [LibUI](https://github.com/kojix2/LibUI) that:
45
75
  - Supports smart defaults (e.g. automatic `on_closing` listener that quits `window`)
46
76
  - Automates wiring of widgets (e.g. `button` is automatically set as child of `window`)
47
77
  - Hides lower-level details (e.g. `LibUI.main` loop is started automatically when triggering `show` on `window`)
@@ -51,8 +81,8 @@ The Glimmer GUI DSL provides a declarative syntax for [LibUI](https://github.com
51
81
  The Glimmer GUI DSL follows these simple concepts in mapping from [LibUI](https://github.com/kojix2/LibUI) syntax:
52
82
  - **Control**: [LibUI](https://github.com/kojix2/LibUI) controls may be declared by lower-case underscored name (aka keyword) (e.g. `window` or `button`). Behind the scenes, they are represented by keyword methods that map to corresponding `LibUI.new_keyword` methods receiving args (e.g. `window('hello world', 300, 200, 1)`).
53
83
  - **Content/Properties/Listeners Block**: Any keyword may be optionally followed by a Ruby curly-brace multi-line-block containing nested controls (content) and/or properties (attributes) (e.g. `window('hello world', 300, 200, 1) {button('greet')}`). It optionally recives one arg representing the control (e.g. `button('greet') {|b| on_clicked { puts b.text}}`)
54
- - **Property**: Control properties may be declared inside keyword blocks with lower-case underscored name followed by property value args (e.g. `title "hello world"` inside `group`). Behind the scenes, they properties correspond to `control_set_property` methods.
55
- - **Listener**: Control listeners may be declared inside keyword blocks with listener lower-case underscored name beginning with `on_` and receiving required block handler (e.g. `on_clicked {puts 'clicked'}` inside `button`). Behind the scenes, they listeners correspond to `control_on_event` methods.
84
+ - **Property**: Control properties may be declared inside keyword blocks with lower-case underscored name followed by property value args (e.g. `title "hello world"` inside `group`). Behind the scenes, properties correspond to `control_set_property` methods.
85
+ - **Listener**: Control listeners may be declared inside keyword blocks with listener lower-case underscored name beginning with `on_` and receiving required block handler (e.g. `on_clicked {puts 'clicked'}` inside `button`). Behind the scenes, listeners correspond to `control_on_event` methods.
56
86
 
57
87
  Example of an app written in [LibUI](https://github.com/kojix2/LibUI)'s procedural imperative syntax:
58
88
 
@@ -65,7 +95,11 @@ UI.init
65
95
 
66
96
  main_window = UI.new_window('hello world', 300, 200, 1)
67
97
 
68
- UI.control_show(main_window)
98
+ button = UI.new_button('Button')
99
+
100
+ UI.button_on_clicked(button) do
101
+ UI.msg_box(main_window, 'Information', 'You clicked the button')
102
+ end
69
103
 
70
104
  UI.window_on_closing(main_window) do
71
105
  puts 'Bye Bye'
@@ -74,6 +108,9 @@ UI.window_on_closing(main_window) do
74
108
  0
75
109
  end
76
110
 
111
+ UI.window_set_child(main_window, button)
112
+ UI.control_show(main_window)
113
+
77
114
  UI.main
78
115
  UI.quit
79
116
  ```
@@ -85,7 +122,13 @@ require 'glimmer-dsl-libui'
85
122
 
86
123
  include Glimmer
87
124
 
88
- window('hello world', 300, 200, 1) {
125
+ window('hello world', 300, 200, 1) { |w|
126
+ button('Button') {
127
+ on_clicked do
128
+ msg_box(w, 'Information', 'You clicked the button')
129
+ end
130
+ }
131
+
89
132
  on_closing do
90
133
  puts 'Bye Bye'
91
134
  end
@@ -103,7 +146,7 @@ gem install glimmer-dsl-libui
103
146
  Or install via Bundler `Gemfile`:
104
147
 
105
148
  ```ruby
106
- gem 'glimmer-dsl-libui', '~> 0.0.2'
149
+ gem 'glimmer-dsl-libui', '~> 0.0.6'
107
150
  ```
108
151
 
109
152
  Add `require 'glimmer-dsl-libui'` at the top, and then `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
@@ -132,7 +175,7 @@ Application.new.launch
132
175
 
133
176
  ## API
134
177
 
135
- Any control returned by a Glimmer GUI DSL keyword declaration can be introspected for its properties and updated via object-oriented attributes (standard Ruby `attr`/`attr=` or `set_attr`).
178
+ Any control returned by a [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) keyword declaration can be introspected for its properties and updated via object-oriented attributes (standard Ruby `attr`/`attr=` or `set_attr`).
136
179
 
137
180
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
138
181
 
@@ -145,6 +188,73 @@ w.set_title 'aloha'
145
188
  puts w.title # => aloha
146
189
  ```
147
190
 
191
+ Controls are wrapped as Ruby proxy objects, having a `#libui` method to obtain the wrapped Fiddle pointer object. Ruby proxy objects rely on composition (via [Proxy Design Pattern](https://en.wikipedia.org/wiki/Proxy_pattern)) instead of inheritance to shield consumers from having to deal with lower-level details unless absolutely needed.
192
+
193
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
194
+
195
+ ```ruby
196
+ w = window('hello world', 300, 200, 1) # => #<Glimmer::LibUI::WindowProxy:0x00007fde4ea39fb0
197
+ w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0 free=0x0000000000000000>
198
+ ```
199
+
200
+ ### Supported Controls
201
+
202
+ Control(Args) | Properties | Listeners
203
+ ------------- | ---------- | ---------
204
+ `about_menu_item` | None | `on_clicked`
205
+ `button(text as String)` | `text` (`String`) | `on_clicked`
206
+ `checkbox(text as String)` | `checked` (`1` or `0`), `text` (`String`) | `on_toggled`
207
+ `combobox` | `items` (`Array` of `String`), `selected` (`1` or `0`) | `on_selected`
208
+ `color_button` | `color` (r `Numeric`, g `Numeric`, b `Numeric`, a `Numeric`), `selected` (`1` or `0`) | `on_selected`
209
+ `date_picker` | None | None
210
+ `date_time_picker` | `time` (`UI::FFI::TM`) | `on_changed`
211
+ `editable_combobox` | `items` (`Array` of `String`), `text` (`String`) | `on_changed`
212
+ `entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
213
+ `font_button` | `font` (`UI::FFI::FontDescriptor`) | `on_changed`
214
+ `group(text as String)` | `margined` (`1` or `0`), `title` (`String`) | None
215
+ `horizontal_box` | `padded` (`1` or `0`) | None
216
+ `horizontal_separator` | None | None
217
+ `label(text as String)` | `text` (`String`) | None
218
+ `menu(text as String)` | None | None
219
+ `menu_item(text as String)` | `checked` (`1` or `0`) | `on_clicked`
220
+ `multiline_entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
221
+ `msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
222
+ `msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
223
+ `non_wrapping_multiline_entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
224
+ `preferences_menu_item` | None | `on_clicked`
225
+ `progress_bar` | `value` (`Numeric`) | None
226
+ `quit_menu_item` | None | `on_clicked`
227
+ `radio_buttons` | `selected` (`1` or `0`) | `on_selected`
228
+ `slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
229
+ `spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
230
+ `tab` | `margined` (`1` or `0`), `num_pages` (`Integer`) | None
231
+ `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (`1` or `0`), `name` [read-only] (`String`) | None
232
+ `time_picker` | None | None
233
+ `vertical_box` | `padded` (`1` or `0`) | None
234
+ `window(title as String, width as Integer, height as Integer, has_menubar as 1 or 0)` | `borderless` (`1` or `0`), `content_size` (width `Numeric`, height `Numeric`), `fullscreen` (`1` or `0`), `margined` (`1` or `0`), `title` (`String`) | `on_closing`, `on_content_size_changed`
235
+
236
+ ### Common Control Properties
237
+ - `enabled` (`1` or `0`)
238
+ - `libui` (`Fiddle::Pointer`): returns wrapped [LibUI](https://github.com/kojix2/LibUI) object
239
+ - `parent_proxy` (`Glimmer::LibUI::ControlProxy` or subclass)
240
+ - `parent` (`Fiddle::Pointer`)
241
+ - `toplevel` [read-only] (`1` or `0`)
242
+ - `visible` (`1` or `0`)
243
+ - `stretchy` [dsl-only] (`1` or `0`): available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `horizontal_box` or `vertical_box`
244
+
245
+ ### Common Control Operations
246
+ - `destroy`
247
+ - `disable`
248
+ - `enable`
249
+ - `hide`
250
+ - `show`
251
+
252
+ ### Extra Operations
253
+ - `open_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
254
+ - `save_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
255
+
256
+ To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed through [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), check out the [libui C headers](https://github.com/andlabs/libui/blob/master/ui.h)
257
+
148
258
  ## Girb (Glimmer IRB)
149
259
 
150
260
  You can run the `girb` command (`bin/girb` if you cloned the project locally):
@@ -159,7 +269,7 @@ Gotcha: On the Mac, when you close a window opened in `girb`, it remains open un
159
269
 
160
270
  ## Examples
161
271
 
162
- These examples reimplement the ones in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the Glimmer GUI DSL.
272
+ These examples reimplement the ones in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts).
163
273
 
164
274
  ### Basic Window
165
275
 
@@ -179,11 +289,11 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_window'"
179
289
 
180
290
  Mac
181
291
 
182
- ![glimmer-dsl-libui-basic-window-mac.png](images/glimmer-dsl-libui-basic-window-mac.png)
292
+ ![glimmer-dsl-libui-mac-basic-window.png](images/glimmer-dsl-libui-mac-basic-window.png)
183
293
 
184
294
  Linux
185
295
 
186
- ![glimmer-dsl-libui-basic-window-linux.png](images/glimmer-dsl-libui-basic-window-linux.png)
296
+ ![glimmer-dsl-libui-linux-basic-window.png](images/glimmer-dsl-libui-linux-basic-window.png)
187
297
 
188
298
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
189
299
 
@@ -241,13 +351,13 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_button'"
241
351
 
242
352
  Mac
243
353
 
244
- ![glimmer-dsl-libui-basic-button-mac.png](images/glimmer-dsl-libui-basic-button-mac.png)
245
- ![glimmer-dsl-libui-basic-button-msg-box-mac.png](images/glimmer-dsl-libui-basic-button-msg-box-mac.png)
354
+ ![glimmer-dsl-libui-mac-basic-button.png](images/glimmer-dsl-libui-mac-basic-button.png)
355
+ ![glimmer-dsl-libui-mac-basic-button-msg-box.png](images/glimmer-dsl-libui-basic-button-msg-box.png)
246
356
 
247
357
  Linux
248
358
 
249
- ![glimmer-dsl-libui-basic-button-linux.png](images/glimmer-dsl-libui-basic-button-linux.png)
250
- ![glimmer-dsl-libui-basic-button-msg-box-linux.png](images/glimmer-dsl-libui-basic-button-msg-box-linux.png)
359
+ ![glimmer-dsl-libui-linux-basic-button.png](images/glimmer-dsl-libui-linux-basic-button.png)
360
+ ![glimmer-dsl-libui-linux-basic-button-msg-box.png](images/glimmer-dsl-libui-linux-basic-button-msg-box.png)
251
361
 
252
362
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
253
363
 
@@ -318,13 +428,13 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_entry'"
318
428
 
319
429
  Mac
320
430
 
321
- ![glimmer-dsl-libui-basic-entry-mac.png](images/glimmer-dsl-libui-basic-entry-mac.png)
322
- ![glimmer-dsl-libui-basic-entry-msg-box-mac.png](images/glimmer-dsl-libui-basic-entry-msg-box-mac.png)
431
+ ![glimmer-dsl-libui-mac-basic-entry.png](images/glimmer-dsl-libui-mac-basic-entry.png)
432
+ ![glimmer-dsl-libui-mac-basic-entry-msg-box.png](images/glimmer-dsl-libui-mac-basic-entry-msg-box.png)
323
433
 
324
434
  Linux
325
435
 
326
- ![glimmer-dsl-libui-basic-entry-linux.png](images/glimmer-dsl-libui-basic-entry-linux.png)
327
- ![glimmer-dsl-libui-basic-entry-msg-box-linux.png](images/glimmer-dsl-libui-basic-entry-msg-box-linux.png)
436
+ ![glimmer-dsl-libui-linux-basic-entry.png](images/glimmer-dsl-libui-linux-basic-entry.png)
437
+ ![glimmer-dsl-libui-linux-basic-entry-msg-box.png](images/glimmer-dsl-libui-linux-basic-entry-msg-box.png)
328
438
 
329
439
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
330
440
 
@@ -377,7 +487,7 @@ include Glimmer
377
487
  window('Basic Entry', 300, 50, 1) { |w|
378
488
  horizontal_box {
379
489
  e = entry {
380
- stretchy 1
490
+ # stretchy 1 # Smart default option for appending to horizontal_box
381
491
 
382
492
  on_changed do
383
493
  puts e.text
@@ -401,6 +511,706 @@ window('Basic Entry', 300, 50, 1) { |w|
401
511
  }.show
402
512
  ```
403
513
 
514
+ ### Simple Notepad
515
+
516
+ [examples/simple_notepad.rb](examples/simple_notepad.rb)
517
+
518
+ Run with this command from the root of the project if you cloned the project:
519
+
520
+ ```
521
+ ruby -r './lib/glimmer-dsl-libui' examples/simple_notepad.rb
522
+ ```
523
+
524
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
525
+
526
+ ```
527
+ ruby -r glimmer-dsl-libui -e "require 'examples/simple_notepad'"
528
+ ```
529
+
530
+ Mac
531
+
532
+ ![glimmer-dsl-libui-mac-simple-notepad.png](images/glimmer-dsl-libui-mac-simple-notepad.png)
533
+
534
+ Linux
535
+
536
+ ![glimmer-dsl-libui-linux-simple-notepad.png](images/glimmer-dsl-libui-linux-simple-notepad.png)
537
+
538
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
539
+
540
+ ```ruby
541
+ require 'libui'
542
+
543
+ UI = LibUI
544
+
545
+ UI.init
546
+
547
+ main_window = UI.new_window('Notepad', 500, 300, 1)
548
+ UI.window_on_closing(main_window) do
549
+ puts 'Bye Bye'
550
+ UI.control_destroy(main_window)
551
+ UI.quit
552
+ 0
553
+ end
554
+
555
+ vbox = UI.new_vertical_box
556
+ UI.window_set_child(main_window, vbox)
557
+
558
+ entry = UI.new_non_wrapping_multiline_entry
559
+ UI.box_append(vbox, entry, 1)
560
+
561
+ UI.control_show(main_window)
562
+ UI.main
563
+ UI.quit
564
+ ```
565
+
566
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
567
+
568
+ ```ruby
569
+ require 'glimmer-dsl-libui'
570
+
571
+ include Glimmer
572
+
573
+ window('Notepad', 500, 300, 1) {
574
+ on_closing do
575
+ puts 'Bye Bye'
576
+ end
577
+
578
+ vertical_box {
579
+ non_wrapping_multiline_entry
580
+ }
581
+ }.show
582
+ ```
583
+
584
+ ### Midi Player
585
+
586
+ This example has prerequisites:
587
+ - Install [TiMidity](http://timidity.sourceforge.net) and ensure `timidity` command is in `PATH` (can be installed via [Homebrew](https://brew.sh) on Mac or [apt-get](https://help.ubuntu.com/community/AptGet/Howto) on Linux).
588
+ - Add `*.mid` files to `~/Music` directory (you may copy the ones included in [sounds](sounds) directory)
589
+
590
+ [examples/midi_player.rb](examples/midi_player.rb)
591
+
592
+ Run with this command from the root of the project if you cloned the project:
593
+
594
+ ```
595
+ ruby -r './lib/glimmer-dsl-libui' examples/midi_player.rb
596
+ ```
597
+
598
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
599
+
600
+ ```
601
+ ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"
602
+ ```
603
+
604
+ Mac
605
+
606
+ ![glimmer-dsl-libui-mac-midi-player.png](images/glimmer-dsl-libui-mac-midi-player.png)
607
+ ![glimmer-dsl-libui-mac-midi-player-version-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-version-msg-box.png)
608
+
609
+ Linux
610
+
611
+ ![glimmer-dsl-libui-linux-midi-player.png](images/glimmer-dsl-libui-linux-midi-player.png)
612
+ ![glimmer-dsl-libui-linux-midi-player-version-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-version-msg-box.png)
613
+
614
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
615
+
616
+ ```ruby
617
+ require 'libui'
618
+ UI = LibUI
619
+
620
+ class TinyMidiPlayer
621
+ VERSION = '0.0.1'
622
+
623
+ def initialize
624
+ UI.init
625
+ @pid = nil
626
+ @music_directory = File.expand_path(ARGV[0] || '~/Music/')
627
+ @midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
628
+ .sort_by { |path| File.basename(path) }
629
+ at_exit { stop_midi }
630
+ create_gui
631
+ end
632
+
633
+ def stop_midi
634
+ if @pid
635
+ if @th.alive?
636
+ Process.kill(:SIGKILL, @pid)
637
+ @pid = nil
638
+ else
639
+ @pid = nil
640
+ end
641
+ end
642
+ end
643
+
644
+ def play_midi
645
+ stop_midi
646
+ if @pid.nil? && @selected_file
647
+ begin
648
+ @pid = spawn "timidity #{@selected_file}"
649
+ @th = Process.detach @pid
650
+ rescue Errno::ENOENT
651
+ warn 'Timidty++ not found. Please install Timidity++.'
652
+ warn 'https://sourceforge.net/projects/timidity/'
653
+ end
654
+ end
655
+ end
656
+
657
+ def show_version(main_window)
658
+ UI.msg_box(main_window,
659
+ 'Tiny Midi Player',
660
+ "Written in Ruby\n" \
661
+ "https://github.com/kojix2/libui\n" \
662
+ "Version #{VERSION}")
663
+ end
664
+
665
+ def create_gui
666
+ help_menu = UI.new_menu('Help')
667
+ version_item = UI.menu_append_item(help_menu, 'Version')
668
+
669
+ UI.new_window('Tiny Midi Player', 200, 50, 1).tap do |main_window|
670
+ UI.menu_item_on_clicked(version_item) { show_version(main_window) }
671
+
672
+ UI.window_on_closing(main_window) do
673
+ UI.control_destroy(main_window)
674
+ UI.quit
675
+ 0
676
+ end
677
+
678
+ UI.new_horizontal_box.tap do |hbox|
679
+ UI.new_vertical_box.tap do |vbox|
680
+ UI.new_button('▶').tap do |button1|
681
+ UI.button_on_clicked(button1) { play_midi }
682
+ UI.box_append(vbox, button1, 1)
683
+ end
684
+ UI.new_button('■').tap do |button2|
685
+ UI.button_on_clicked(button2) { stop_midi }
686
+ UI.box_append(vbox, button2, 1)
687
+ end
688
+ UI.box_append(hbox, vbox, 0)
689
+ end
690
+ UI.window_set_child(main_window, hbox)
691
+
692
+ UI.new_combobox.tap do |cbox|
693
+ @midi_files.each do |path|
694
+ name = File.basename(path)
695
+ UI.combobox_append(cbox, name)
696
+ end
697
+ UI.combobox_on_selected(cbox) do |ptr|
698
+ @selected_file = @midi_files[UI.combobox_selected(ptr)]
699
+ play_midi if @th&.alive?
700
+ 0
701
+ end
702
+ UI.box_append(hbox, cbox, 1)
703
+ end
704
+ end
705
+ UI.control_show(main_window)
706
+ end
707
+ UI.main
708
+ UI.quit
709
+ end
710
+ end
711
+
712
+ TinyMidiPlayer.new
713
+ ```
714
+
715
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
716
+
717
+ ```ruby
718
+ require 'glimmer-dsl-libui'
719
+
720
+ class TinyMidiPlayer
721
+ include Glimmer
722
+
723
+ VERSION = '0.0.1'
724
+
725
+ def initialize
726
+ @pid = nil
727
+ @music_directory = File.expand_path(ARGV[0] || '~/Music/')
728
+ @midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
729
+ .sort_by { |path| File.basename(path) }
730
+ at_exit { stop_midi }
731
+ create_gui
732
+ end
733
+
734
+ def stop_midi
735
+ if @pid
736
+ if @th.alive?
737
+ Process.kill(:SIGKILL, @pid)
738
+ @pid = nil
739
+ else
740
+ @pid = nil
741
+ end
742
+ end
743
+ end
744
+
745
+ def play_midi
746
+ stop_midi
747
+ if @pid.nil? && @selected_file
748
+ begin
749
+ @pid = spawn "timidity #{@selected_file}"
750
+ @th = Process.detach @pid
751
+ rescue Errno::ENOENT
752
+ warn 'Timidty++ not found. Please install Timidity++.'
753
+ warn 'https://sourceforge.net/projects/timidity/'
754
+ end
755
+ end
756
+ end
757
+
758
+ def show_version(main_window)
759
+ msg_box(main_window,
760
+ 'Tiny Midi Player',
761
+ "Written in Ruby\n" \
762
+ "https://github.com/kojix2/libui\n" \
763
+ "Version #{VERSION}")
764
+ end
765
+
766
+ def create_gui
767
+ menu('Help') { |m|
768
+ menu_item('Version') {
769
+ on_clicked do
770
+ show_version(@main_window)
771
+ end
772
+ }
773
+ }
774
+ @main_window = window('Tiny Midi Player', 200, 50, 1) {
775
+ horizontal_box {
776
+ vertical_box {
777
+ stretchy 0
778
+
779
+ button('▶') {
780
+ on_clicked do
781
+ play_midi
782
+ end
783
+ }
784
+ button('■') {
785
+ on_clicked do
786
+ stop_midi
787
+ end
788
+ }
789
+ }
790
+
791
+ combobox { |c|
792
+ items @midi_files.map { |path| File.basename(path) }
793
+
794
+ on_selected do
795
+ @selected_file = @midi_files[c.selected]
796
+ play_midi if @th&.alive?
797
+ end
798
+ }
799
+ }
800
+ }
801
+ @main_window.show
802
+ end
803
+ end
804
+
805
+ TinyMidiPlayer.new
806
+ ```
807
+
808
+ ### Control Gallery
809
+
810
+ [examples/control_gallery.rb](examples/control_gallery.rb)
811
+
812
+ Run with this command from the root of the project if you cloned the project:
813
+
814
+ ```
815
+ ruby -r './lib/glimmer-dsl-libui' examples/control_gallery.rb
816
+ ```
817
+
818
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
819
+
820
+ ```
821
+ ruby -r glimmer-dsl-libui -e "require 'examples/control_gallery'"
822
+ ```
823
+
824
+ Mac
825
+
826
+ ![glimmer-dsl-libui-mac-control-gallery.png](images/glimmer-dsl-libui-mac-control-gallery.png)
827
+
828
+ Linux
829
+
830
+ ![glimmer-dsl-libui-linux-control-gallery.png](images/glimmer-dsl-libui-linux-control-gallery.png)
831
+
832
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
833
+
834
+ ```ruby
835
+ require 'libui'
836
+ UI = LibUI
837
+
838
+ UI.init
839
+
840
+ should_quit = proc do
841
+ puts 'Bye Bye'
842
+ UI.control_destroy(MAIN_WINDOW)
843
+ UI.quit
844
+ 0
845
+ end
846
+
847
+ # File menu
848
+ menu = UI.new_menu('File')
849
+ open_menu_item = UI.menu_append_item(menu, 'Open')
850
+ UI.menu_item_on_clicked(open_menu_item) do
851
+ pt = UI.open_file(MAIN_WINDOW)
852
+ puts pt unless pt.null?
853
+ end
854
+ save_menu_item = UI.menu_append_item(menu, 'Save')
855
+ UI.menu_item_on_clicked(save_menu_item) do
856
+ pt = UI.save_file(MAIN_WINDOW)
857
+ puts pt unless pt.null?
858
+ end
859
+
860
+ UI.menu_append_quit_item(menu)
861
+ UI.on_should_quit(should_quit)
862
+
863
+ # Edit menu
864
+ edit_menu = UI.new_menu('Edit')
865
+ UI.menu_append_check_item(edit_menu, 'Checkable Item_')
866
+ UI.menu_append_separator(edit_menu)
867
+ disabled_item = UI.menu_append_item(edit_menu, 'Disabled Item_')
868
+ UI.menu_item_disable(disabled_item)
869
+
870
+ preferences = UI.menu_append_preferences_item(menu)
871
+
872
+ # Help menu
873
+ help_menu = UI.new_menu('Help')
874
+ UI.menu_append_item(help_menu, 'Help')
875
+ UI.menu_append_about_item(help_menu)
876
+
877
+ # Main Window
878
+ MAIN_WINDOW = UI.new_window('Control Gallery', 600, 500, 1)
879
+ UI.window_set_margined(MAIN_WINDOW, 1)
880
+ UI.window_on_closing(MAIN_WINDOW, should_quit)
881
+
882
+ vbox = UI.new_vertical_box
883
+ UI.window_set_child(MAIN_WINDOW, vbox)
884
+ hbox = UI.new_horizontal_box
885
+ UI.box_set_padded(vbox, 1)
886
+ UI.box_set_padded(hbox, 1)
887
+
888
+ UI.box_append(vbox, hbox, 1)
889
+
890
+ # Group - Basic Controls
891
+ group = UI.new_group('Basic Controls')
892
+ UI.group_set_margined(group, 1)
893
+ UI.box_append(hbox, group, 1) # OSX bug?
894
+
895
+ inner = UI.new_vertical_box
896
+ UI.box_set_padded(inner, 1)
897
+ UI.group_set_child(group, inner)
898
+
899
+ # Button
900
+ button = UI.new_button('Button')
901
+ UI.button_on_clicked(button) do
902
+ UI.msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
903
+ end
904
+ UI.box_append(inner, button, 0)
905
+
906
+ # Checkbox
907
+ checkbox = UI.new_checkbox('Checkbox')
908
+ UI.checkbox_on_toggled(checkbox) do |ptr|
909
+ checked = UI.checkbox_checked(ptr) == 1
910
+ UI.window_set_title(MAIN_WINDOW, "Checkbox is #{checked}")
911
+ UI.checkbox_set_text(ptr, "I am the checkbox (#{checked})")
912
+ end
913
+ UI.box_append(inner, checkbox, 0)
914
+
915
+ # Label
916
+ UI.box_append(inner, UI.new_label('Label'), 0)
917
+
918
+ # Separator
919
+ UI.box_append(inner, UI.new_horizontal_separator, 0)
920
+
921
+ # Date Picker
922
+ UI.box_append(inner, UI.new_date_picker, 0)
923
+
924
+ # Time Picker
925
+ UI.box_append(inner, UI.new_time_picker, 0)
926
+
927
+ # Date Time Picker
928
+ UI.box_append(inner, UI.new_date_time_picker, 0)
929
+
930
+ # Font Button
931
+ UI.box_append(inner, UI.new_font_button, 0)
932
+
933
+ # Color Button
934
+ UI.box_append(inner, UI.new_color_button, 0)
935
+
936
+ inner2 = UI.new_vertical_box
937
+ UI.box_set_padded(inner2, 1)
938
+ UI.box_append(hbox, inner2, 1)
939
+
940
+ # Group - Numbers
941
+ group = UI.new_group('Numbers')
942
+ UI.group_set_margined(group, 1)
943
+ UI.box_append(inner2, group, 0)
944
+
945
+ inner = UI.new_vertical_box
946
+ UI.box_set_padded(inner, 1)
947
+ UI.group_set_child(group, inner)
948
+
949
+ # Spinbox
950
+ spinbox = UI.new_spinbox(0, 100)
951
+ UI.spinbox_set_value(spinbox, 42)
952
+ UI.spinbox_on_changed(spinbox) do |ptr|
953
+ puts "New Spinbox value: #{UI.spinbox_value(ptr)}"
954
+ end
955
+ UI.box_append(inner, spinbox, 0)
956
+
957
+ # Slider
958
+ slider = UI.new_slider(0, 100)
959
+ UI.box_append(inner, slider, 0)
960
+
961
+ # Progressbar
962
+ progressbar = UI.new_progress_bar
963
+ UI.box_append(inner, progressbar, 0)
964
+
965
+ UI.slider_on_changed(slider) do |ptr|
966
+ v = UI.slider_value(ptr)
967
+ puts "New Slider value: #{v}"
968
+ UI.progress_bar_set_value(progressbar, v)
969
+ end
970
+
971
+ # Group - Lists
972
+ group = UI.new_group('Lists')
973
+ UI.group_set_margined(group, 1)
974
+ UI.box_append(inner2, group, 0)
975
+
976
+ inner = UI.new_vertical_box
977
+ UI.box_set_padded(inner, 1)
978
+ UI.group_set_child(group, inner)
979
+
980
+ # Combobox
981
+ cbox = UI.new_combobox
982
+ UI.combobox_append(cbox, 'combobox Item 1')
983
+ UI.combobox_append(cbox, 'combobox Item 2')
984
+ UI.combobox_append(cbox, 'combobox Item 3')
985
+ UI.box_append(inner, cbox, 0)
986
+ UI.combobox_on_selected(cbox) do |ptr|
987
+ puts "New combobox selection: #{UI.combobox_selected(ptr)}"
988
+ end
989
+
990
+ # Editable Combobox
991
+ ebox = UI.new_editable_combobox
992
+ UI.editable_combobox_append(ebox, 'Editable Item 1')
993
+ UI.editable_combobox_append(ebox, 'Editable Item 2')
994
+ UI.editable_combobox_append(ebox, 'Editable Item 3')
995
+ UI.box_append(inner, ebox, 0)
996
+
997
+ # Radio Buttons
998
+ rb = UI.new_radio_buttons
999
+ UI.radio_buttons_append(rb, 'Radio Button 1')
1000
+ UI.radio_buttons_append(rb, 'Radio Button 2')
1001
+ UI.radio_buttons_append(rb, 'Radio Button 3')
1002
+ UI.box_append(inner, rb, 1)
1003
+
1004
+ # Tab
1005
+ tab = UI.new_tab
1006
+ hbox1 = UI.new_horizontal_box
1007
+ hbox2 = UI.new_horizontal_box
1008
+ UI.tab_append(tab, 'Page 1', hbox1)
1009
+ UI.tab_append(tab, 'Page 2', hbox2)
1010
+ UI.tab_append(tab, 'Page 3', UI.new_horizontal_box)
1011
+ UI.box_append(inner2, tab, 1)
1012
+
1013
+ # Text Entry
1014
+ text_entry = UI.new_entry
1015
+ UI.entry_set_text text_entry, 'Please enter your feelings'
1016
+ UI.entry_on_changed(text_entry) do |ptr|
1017
+ puts "Current textbox data: '#{UI.entry_text(ptr)}'"
1018
+ end
1019
+ UI.box_append(hbox1, text_entry, 1)
1020
+
1021
+ UI.control_show(MAIN_WINDOW)
1022
+
1023
+ UI.main
1024
+ UI.quit
1025
+ ```
1026
+
1027
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
1028
+
1029
+ ```ruby
1030
+ require 'glimmer-dsl-libui'
1031
+
1032
+ include Glimmer
1033
+
1034
+ menu('File') {
1035
+ menu_item('Open') {
1036
+ on_clicked do
1037
+ file = open_file(MAIN_WINDOW)
1038
+ puts file unless file.nil?
1039
+ end
1040
+ }
1041
+
1042
+ menu_item('Save') {
1043
+ on_clicked do
1044
+ file = save_file(MAIN_WINDOW)
1045
+ puts file unless file.nil?
1046
+ end
1047
+ }
1048
+
1049
+ quit_menu_item {
1050
+ on_clicked do
1051
+ puts 'Bye Bye'
1052
+ end
1053
+ }
1054
+
1055
+ preferences_menu_item # Can optionally contain an on_clicked listener
1056
+ }
1057
+
1058
+ menu('Edit') {
1059
+ check_menu_item('Checkable Item_')
1060
+ separator_menu_item
1061
+ menu_item('Disabled Item_') {
1062
+ enabled 0
1063
+ }
1064
+ }
1065
+
1066
+ menu('Help') {
1067
+ menu_item('Help')
1068
+
1069
+ about_menu_item # Can optionally contain an on_clicked listener
1070
+ }
1071
+
1072
+ MAIN_WINDOW = window('Control Gallery', 600, 500, 1) {
1073
+ margined 1
1074
+
1075
+ on_closing do
1076
+ puts 'Bye Bye'
1077
+ end
1078
+
1079
+ vertical_box {
1080
+ padded 1
1081
+
1082
+ horizontal_box {
1083
+ padded 1
1084
+
1085
+ group('Basic Controls') {
1086
+ margined 1
1087
+
1088
+ vertical_box {
1089
+ padded 1
1090
+
1091
+ button('Button') {
1092
+ stretchy 0
1093
+
1094
+ on_clicked do
1095
+ msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1096
+ end
1097
+ }
1098
+
1099
+ checkbox('Checkbox') {
1100
+ stretchy 0
1101
+
1102
+ on_toggled do |c|
1103
+ checked = c.checked == 1
1104
+ MAIN_WINDOW.title = "Checkbox is #{checked}"
1105
+ c.text = "I am the checkbox (#{checked})"
1106
+ end
1107
+ }
1108
+
1109
+ label('Label') { stretchy 0 }
1110
+
1111
+ horizontal_separator { stretchy 0 }
1112
+
1113
+ date_picker { stretchy 0 }
1114
+
1115
+ time_picker { stretchy 0 }
1116
+
1117
+ date_time_picker { stretchy 0 }
1118
+
1119
+ font_button { stretchy 0 }
1120
+
1121
+ color_button { stretchy 0 }
1122
+ }
1123
+ }
1124
+
1125
+ vertical_box {
1126
+ padded 1
1127
+
1128
+ group('Numbers') {
1129
+ stretchy 0
1130
+ margined 1
1131
+
1132
+ vertical_box {
1133
+ padded 1
1134
+
1135
+ spinbox(0, 100) {
1136
+ stretchy 0
1137
+ value 42
1138
+
1139
+ on_changed do |s|
1140
+ puts "New Spinbox value: #{s.value}"
1141
+ end
1142
+ }
1143
+
1144
+ slider(0, 100) {
1145
+ stretchy 0
1146
+
1147
+ on_changed do |s|
1148
+ v = s.value
1149
+ puts "New Slider value: #{v}"
1150
+ @progress_bar.value = v
1151
+ end
1152
+ }
1153
+
1154
+ @progress_bar = progress_bar { stretchy 0 }
1155
+ }
1156
+ }
1157
+
1158
+ group('Lists') {
1159
+ stretchy 0
1160
+ margined 1
1161
+
1162
+ vertical_box {
1163
+ padded 1
1164
+
1165
+ combobox {
1166
+ stretchy 0
1167
+ items 'combobox Item 1', 'combobox Item 2', 'combobox Item 3' # also accepts a single array argument
1168
+
1169
+ on_selected do |c|
1170
+ puts "New combobox selection: #{c.selected}"
1171
+ end
1172
+ }
1173
+
1174
+ editable_combobox {
1175
+ stretchy 0
1176
+ items 'Editable Item 1', 'Editable Item 2', 'Editable Item 3' # also accepts a single array argument
1177
+ }
1178
+
1179
+ radio_buttons {
1180
+ items 'Radio Button 1', 'Radio Button 2', 'Radio Button 3' # also accepts a single array argument
1181
+ }
1182
+ }
1183
+ }
1184
+
1185
+ tab {
1186
+ tab_item('Page 1') {
1187
+ horizontal_box {
1188
+ entry {
1189
+ text 'Please enter your feelings'
1190
+
1191
+ on_changed do |e|
1192
+ puts "Current textbox data: '#{e.text}'"
1193
+ end
1194
+ }
1195
+ }
1196
+ }
1197
+
1198
+ tab_item('Page 2') {
1199
+ horizontal_box
1200
+ }
1201
+
1202
+ tab_item('Page 3') {
1203
+ horizontal_box
1204
+ }
1205
+ }
1206
+ }
1207
+ }
1208
+ }
1209
+ }
1210
+
1211
+ MAIN_WINDOW.show
1212
+ ```
1213
+
404
1214
  ## Contributing to glimmer-dsl-libui
405
1215
 
406
1216
  - Check out the latest master to make sure the feature hasn't been