glimmer-dsl-libui 0.0.3 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +758 -24
  4. data/VERSION +1 -1
  5. data/examples/control_gallery.rb +168 -0
  6. data/examples/midi_player.rb +90 -0
  7. data/glimmer-dsl-libui.gemspec +0 -0
  8. data/lib/glimmer/dsl/libui/control_expression.rb +1 -3
  9. data/lib/glimmer/dsl/libui/dsl.rb +1 -1
  10. data/lib/glimmer/dsl/libui/file_expression.rb +33 -0
  11. data/lib/glimmer/dsl/libui/open_file_expression.rb +33 -0
  12. data/lib/glimmer/dsl/libui/save_file_expression.rb +33 -0
  13. data/lib/glimmer/dsl/libui/tab_item_expression.rb +35 -0
  14. data/lib/glimmer/libui/about_menu_item_proxy.rb +37 -0
  15. data/lib/glimmer/libui/box.rb +12 -0
  16. data/lib/glimmer/libui/check_menu_item_proxy.rb +37 -0
  17. data/lib/glimmer/libui/combobox_proxy.rb +43 -0
  18. data/lib/glimmer/libui/control_proxy.rb +87 -22
  19. data/lib/glimmer/libui/editable_combobox_proxy.rb +43 -0
  20. data/lib/glimmer/libui/group_proxy.rb +43 -0
  21. data/lib/glimmer/libui/horizontal_box_proxy.rb +1 -1
  22. data/lib/glimmer/libui/menu_item_proxy.rb +41 -0
  23. data/lib/glimmer/libui/multiline_entry_proxy.rb +35 -0
  24. data/lib/glimmer/libui/non_wrapping_multiline_entry_proxy.rb +32 -0
  25. data/lib/glimmer/libui/preferences_menu_item_proxy.rb +37 -0
  26. data/lib/glimmer/libui/quit_menu_item_proxy.rb +62 -0
  27. data/lib/glimmer/libui/radio_buttons_proxy.rb +43 -0
  28. data/lib/glimmer/libui/separator_menu_item_proxy.rb +37 -0
  29. data/lib/glimmer/libui/tab_item_proxy.rb +66 -0
  30. data/lib/glimmer/libui/vertical_box_proxy.rb +1 -1
  31. data/lib/glimmer/libui/window_proxy.rb +3 -3
  32. data/lib/glimmer-dsl-libui.rb +2 -0
  33. metadata +24 -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.3
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.7
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](#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,40 @@ 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.7](#-glimmer-dsl-for-libui-007)
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 Dialogs](#extra-dialogs)
54
+ - [Extra Operations](#extra-operations)
55
+ - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
56
+ - [Original API](#original-api)
57
+ - [Girb (Glimmer IRB)](#girb-glimmer-irb)
58
+ - [Examples](#examples)
59
+ - [Basic Window](#basic-window)
60
+ - [Basic Button](#basic-button)
61
+ - [Basic Entry](#basic-entry)
62
+ - [Simple Notepad](#simple-notepad)
63
+ - [Midi Player](#midi-player)
64
+ - [Control Gallery](#control-gallery)
65
+ - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
66
+ - [Help](#help)
67
+ - [Issues](#issues)
68
+ - [Chat](#chat)
69
+ - [Process](#process)
70
+ - [Planned Features and Feature Suggestions](#planned-features-and-feature-suggestions)
71
+ - [Change Log](#change-log)
72
+ - [Contributors](#contributors)
73
+ - [License](#license)
74
+
42
75
  ## Glimmer GUI DSL Concepts
43
76
 
44
- The Glimmer GUI DSL provides a declarative syntax for [LibUI](https://github.com/kojix2/LibUI) that:
77
+ The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for [LibUI](https://github.com/kojix2/LibUI) that:
45
78
  - Supports smart defaults (e.g. automatic `on_closing` listener that quits `window`)
46
79
  - Automates wiring of widgets (e.g. `button` is automatically set as child of `window`)
47
80
  - Hides lower-level details (e.g. `LibUI.main` loop is started automatically when triggering `show` on `window`)
@@ -116,7 +149,7 @@ gem install glimmer-dsl-libui
116
149
  Or install via Bundler `Gemfile`:
117
150
 
118
151
  ```ruby
119
- gem 'glimmer-dsl-libui', '~> 0.0.3'
152
+ gem 'glimmer-dsl-libui', '~> 0.0.7'
120
153
  ```
121
154
 
122
155
  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.
@@ -145,7 +178,7 @@ Application.new.launch
145
178
 
146
179
  ## API
147
180
 
148
- 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`).
181
+ 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`).
149
182
 
150
183
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
151
184
 
@@ -158,6 +191,93 @@ w.set_title 'aloha'
158
191
  puts w.title # => aloha
159
192
  ```
160
193
 
194
+ 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.
195
+
196
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
197
+
198
+ ```ruby
199
+ w = window('hello world', 300, 200, 1) # => #<Glimmer::LibUI::WindowProxy:0x00007fde4ea39fb0
200
+ w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0 free=0x0000000000000000>
201
+ ```
202
+
203
+ ### Supported Controls
204
+
205
+ Control(Args) | Properties | Listeners
206
+ ------------- | ---------- | ---------
207
+ `about_menu_item` | None | `on_clicked`
208
+ `button(text as String)` | `text` (`String`) | `on_clicked`
209
+ `checkbox(text as String)` | `checked` (`1` or `0`), `text` (`String`) | `on_toggled`
210
+ `combobox` | `items` (`Array` of `String`), `selected` (`1` or `0`) | `on_selected`
211
+ `color_button` | `color` (r `Numeric`, g `Numeric`, b `Numeric`, a `Numeric`), `selected` (`1` or `0`) | `on_selected`
212
+ `date_picker` | None | None
213
+ `date_time_picker` | `time` (`LibUI::FFI::TM`) | `on_changed`
214
+ `editable_combobox` | `items` (`Array` of `String`), `text` (`String`) | `on_changed`
215
+ `entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
216
+ `font_button` | `font` (`LibUI::FFI::FontDescriptor`) | `on_changed`
217
+ `group(text as String)` | `margined` (`1` or `0`), `title` (`String`) | None
218
+ `horizontal_box` | `padded` (`1` or `0`) | None
219
+ `horizontal_separator` | None | None
220
+ `label(text as String)` | `text` (`String`) | None
221
+ `menu(text as String)` | None | None
222
+ `menu_item(text as String)` | `checked` (`1` or `0`) | `on_clicked`
223
+ `multiline_entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
224
+ `msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
225
+ `msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
226
+ `non_wrapping_multiline_entry` | `read_only` (`1` or `0`), `text` (`String`) | `on_changed`
227
+ `preferences_menu_item` | None | `on_clicked`
228
+ `progress_bar` | `value` (`Numeric`) | None
229
+ `quit_menu_item` | None | `on_clicked`
230
+ `radio_buttons` | `selected` (`1` or `0`) | `on_selected`
231
+ `slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
232
+ `spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
233
+ `tab` | `margined` (`1` or `0`), `num_pages` (`Integer`) | None
234
+ `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (`1` or `0`), `name` [read-only] (`String`) | None
235
+ `time_picker` | None | None
236
+ `vertical_box` | `padded` (`1` or `0`) | None
237
+ `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`
238
+
239
+ ### Common Control Properties
240
+ - `enabled` (`1` or `0`)
241
+ - `libui` (`Fiddle::Pointer`): returns wrapped [LibUI](https://github.com/kojix2/LibUI) object
242
+ - `parent_proxy` (`Glimmer::LibUI::ControlProxy` or subclass)
243
+ - `parent` (`Fiddle::Pointer`)
244
+ - `toplevel` [read-only] (`1` or `0`)
245
+ - `visible` (`1` or `0`)
246
+ - `stretchy` [dsl-only] (`1` or `0`): available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `horizontal_box` or `vertical_box`
247
+
248
+ ### Common Control Operations
249
+ - `destroy`
250
+ - `disable`
251
+ - `enable`
252
+ - `hide`
253
+ - `show`
254
+
255
+ ### Extra Dialogs
256
+
257
+ - `open_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
258
+ - `save_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
259
+
260
+ ### Extra Operations
261
+
262
+ - `ControlProxy::all_control_proxies`: returns all instantiated control proxies in the application
263
+ - `ControlProxy::main_window_proxy`: returns the first window proxy instantiated in the application
264
+ - `ControlProxy#window_proxy`: returns the window proxy parent for a control
265
+
266
+ ### Smart Defaults and Conventions
267
+
268
+ - `horizontal_box` and `vertical_box` controls have `padded` as `1` upon instantiation to ensure more user-friendly GUI by default
269
+ - `group` controls have `margined` as `1` upon instantiation to ensure more user-friendly GUI by default
270
+ - All controls nested under a `horizontal_box` or `vertical_box` have `stretchy` property (passed to `box_append` method) as `1` by default (filling maximum space)
271
+ - `window` has an `on_closing` listener by default that quits application upon hitting the close button (can be overridden with a manual `on_closing` implementation that returns integer `0` for success)
272
+ - `quit_menu_item` has an `on_clicked` listener by default that quits application upon selecting the quit menu item (can be overridden with a manual `on_clicked` implementation that returns integer `0` for success)
273
+ - If an `on_closing` listener was defined on `window` and it does not return an integer, default exit behavior is assumed (`window.destroy` is called followed by `LibUI.quit`, returning `0`).
274
+ - If an `on_clicked` listener was defined on `quit_menu_item` and it does not return an integer, default exit behavior is assumed (`main_window.destroy` is called followed by `LibUI.quit`, returning `0`).
275
+
276
+ ### Original API
277
+
278
+ 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),
279
+ check out the [libui C headers](https://github.com/andlabs/libui/blob/master/ui.h)
280
+
161
281
  ## Girb (Glimmer IRB)
162
282
 
163
283
  You can run the `girb` command (`bin/girb` if you cloned the project locally):
@@ -172,7 +292,7 @@ Gotcha: On the Mac, when you close a window opened in `girb`, it remains open un
172
292
 
173
293
  ## Examples
174
294
 
175
- These examples reimplement the ones in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the Glimmer GUI DSL.
295
+ These examples reimplement the ones in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts).
176
296
 
177
297
  ### Basic Window
178
298
 
@@ -192,11 +312,11 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_window'"
192
312
 
193
313
  Mac
194
314
 
195
- ![glimmer-dsl-libui-basic-window-mac.png](images/glimmer-dsl-libui-basic-window-mac.png)
315
+ ![glimmer-dsl-libui-mac-basic-window.png](images/glimmer-dsl-libui-mac-basic-window.png)
196
316
 
197
317
  Linux
198
318
 
199
- ![glimmer-dsl-libui-basic-window-linux.png](images/glimmer-dsl-libui-basic-window-linux.png)
319
+ ![glimmer-dsl-libui-linux-basic-window.png](images/glimmer-dsl-libui-linux-basic-window.png)
200
320
 
201
321
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
202
322
 
@@ -254,13 +374,13 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_button'"
254
374
 
255
375
  Mac
256
376
 
257
- ![glimmer-dsl-libui-basic-button-mac.png](images/glimmer-dsl-libui-basic-button-mac.png)
258
- ![glimmer-dsl-libui-basic-button-msg-box-mac.png](images/glimmer-dsl-libui-basic-button-msg-box-mac.png)
377
+ ![glimmer-dsl-libui-mac-basic-button.png](images/glimmer-dsl-libui-mac-basic-button.png)
378
+ ![glimmer-dsl-libui-mac-basic-button-msg-box.png](images/glimmer-dsl-libui-basic-button-msg-box.png)
259
379
 
260
380
  Linux
261
381
 
262
- ![glimmer-dsl-libui-basic-button-linux.png](images/glimmer-dsl-libui-basic-button-linux.png)
263
- ![glimmer-dsl-libui-basic-button-msg-box-linux.png](images/glimmer-dsl-libui-basic-button-msg-box-linux.png)
382
+ ![glimmer-dsl-libui-linux-basic-button.png](images/glimmer-dsl-libui-linux-basic-button.png)
383
+ ![glimmer-dsl-libui-linux-basic-button-msg-box.png](images/glimmer-dsl-libui-linux-basic-button-msg-box.png)
264
384
 
265
385
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
266
386
 
@@ -331,13 +451,13 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_entry'"
331
451
 
332
452
  Mac
333
453
 
334
- ![glimmer-dsl-libui-basic-entry-mac.png](images/glimmer-dsl-libui-basic-entry-mac.png)
335
- ![glimmer-dsl-libui-basic-entry-msg-box-mac.png](images/glimmer-dsl-libui-basic-entry-msg-box-mac.png)
454
+ ![glimmer-dsl-libui-mac-basic-entry.png](images/glimmer-dsl-libui-mac-basic-entry.png)
455
+ ![glimmer-dsl-libui-mac-basic-entry-msg-box.png](images/glimmer-dsl-libui-mac-basic-entry-msg-box.png)
336
456
 
337
457
  Linux
338
458
 
339
- ![glimmer-dsl-libui-basic-entry-linux.png](images/glimmer-dsl-libui-basic-entry-linux.png)
340
- ![glimmer-dsl-libui-basic-entry-msg-box-linux.png](images/glimmer-dsl-libui-basic-entry-msg-box-linux.png)
459
+ ![glimmer-dsl-libui-linux-basic-entry.png](images/glimmer-dsl-libui-linux-basic-entry.png)
460
+ ![glimmer-dsl-libui-linux-basic-entry-msg-box.png](images/glimmer-dsl-libui-linux-basic-entry-msg-box.png)
341
461
 
342
462
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
343
463
 
@@ -432,11 +552,11 @@ ruby -r glimmer-dsl-libui -e "require 'examples/simple_notepad'"
432
552
 
433
553
  Mac
434
554
 
435
- ![glimmer-dsl-libui-simple-notepad-mac.png](images/glimmer-dsl-libui-simple-notepad-mac.png)
555
+ ![glimmer-dsl-libui-mac-simple-notepad.png](images/glimmer-dsl-libui-mac-simple-notepad.png)
436
556
 
437
557
  Linux
438
558
 
439
- ![glimmer-dsl-libui-simple-notepad-linux.png](images/glimmer-dsl-libui-simple-notepad-linux.png)
559
+ ![glimmer-dsl-libui-linux-simple-notepad.png](images/glimmer-dsl-libui-linux-simple-notepad.png)
440
560
 
441
561
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
442
562
 
@@ -484,6 +604,620 @@ window('Notepad', 500, 300, 1) {
484
604
  }.show
485
605
  ```
486
606
 
607
+ ### Midi Player
608
+
609
+ This example has prerequisites:
610
+ - 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).
611
+ - Add `*.mid` files to `~/Music` directory (you may copy the ones included in [sounds](sounds) directory)
612
+
613
+ [examples/midi_player.rb](examples/midi_player.rb)
614
+
615
+ Run with this command from the root of the project if you cloned the project:
616
+
617
+ ```
618
+ ruby -r './lib/glimmer-dsl-libui' examples/midi_player.rb
619
+ ```
620
+
621
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
622
+
623
+ ```
624
+ ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"
625
+ ```
626
+
627
+ Mac
628
+
629
+ ![glimmer-dsl-libui-mac-midi-player.png](images/glimmer-dsl-libui-mac-midi-player.png)
630
+ ![glimmer-dsl-libui-mac-midi-player-version-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-version-msg-box.png)
631
+
632
+ Linux
633
+
634
+ ![glimmer-dsl-libui-linux-midi-player.png](images/glimmer-dsl-libui-linux-midi-player.png)
635
+ ![glimmer-dsl-libui-linux-midi-player-version-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-version-msg-box.png)
636
+
637
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
638
+
639
+ ```ruby
640
+ require 'libui'
641
+ UI = LibUI
642
+
643
+ class TinyMidiPlayer
644
+ VERSION = '0.0.1'
645
+
646
+ def initialize
647
+ UI.init
648
+ @pid = nil
649
+ @music_directory = File.expand_path(ARGV[0] || '~/Music/')
650
+ @midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
651
+ .sort_by { |path| File.basename(path) }
652
+ at_exit { stop_midi }
653
+ create_gui
654
+ end
655
+
656
+ def stop_midi
657
+ if @pid
658
+ if @th.alive?
659
+ Process.kill(:SIGKILL, @pid)
660
+ @pid = nil
661
+ else
662
+ @pid = nil
663
+ end
664
+ end
665
+ end
666
+
667
+ def play_midi
668
+ stop_midi
669
+ if @pid.nil? && @selected_file
670
+ begin
671
+ @pid = spawn "timidity #{@selected_file}"
672
+ @th = Process.detach @pid
673
+ rescue Errno::ENOENT
674
+ warn 'Timidty++ not found. Please install Timidity++.'
675
+ warn 'https://sourceforge.net/projects/timidity/'
676
+ end
677
+ end
678
+ end
679
+
680
+ def show_version(main_window)
681
+ UI.msg_box(main_window,
682
+ 'Tiny Midi Player',
683
+ "Written in Ruby\n" \
684
+ "https://github.com/kojix2/libui\n" \
685
+ "Version #{VERSION}")
686
+ end
687
+
688
+ def create_gui
689
+ help_menu = UI.new_menu('Help')
690
+ version_item = UI.menu_append_item(help_menu, 'Version')
691
+
692
+ UI.new_window('Tiny Midi Player', 200, 50, 1).tap do |main_window|
693
+ UI.menu_item_on_clicked(version_item) { show_version(main_window) }
694
+
695
+ UI.window_on_closing(main_window) do
696
+ UI.control_destroy(main_window)
697
+ UI.quit
698
+ 0
699
+ end
700
+
701
+ UI.new_horizontal_box.tap do |hbox|
702
+ UI.new_vertical_box.tap do |vbox|
703
+ UI.new_button('▶').tap do |button1|
704
+ UI.button_on_clicked(button1) { play_midi }
705
+ UI.box_append(vbox, button1, 1)
706
+ end
707
+ UI.new_button('■').tap do |button2|
708
+ UI.button_on_clicked(button2) { stop_midi }
709
+ UI.box_append(vbox, button2, 1)
710
+ end
711
+ UI.box_append(hbox, vbox, 0)
712
+ end
713
+ UI.window_set_child(main_window, hbox)
714
+
715
+ UI.new_combobox.tap do |cbox|
716
+ @midi_files.each do |path|
717
+ name = File.basename(path)
718
+ UI.combobox_append(cbox, name)
719
+ end
720
+ UI.combobox_on_selected(cbox) do |ptr|
721
+ @selected_file = @midi_files[UI.combobox_selected(ptr)]
722
+ play_midi if @th&.alive?
723
+ 0
724
+ end
725
+ UI.box_append(hbox, cbox, 1)
726
+ end
727
+ end
728
+ UI.control_show(main_window)
729
+ end
730
+ UI.main
731
+ UI.quit
732
+ end
733
+ end
734
+
735
+ TinyMidiPlayer.new
736
+ ```
737
+
738
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
739
+
740
+ ```ruby
741
+ require 'glimmer-dsl-libui'
742
+
743
+ class TinyMidiPlayer
744
+ include Glimmer
745
+
746
+ VERSION = '0.0.1'
747
+
748
+ def initialize
749
+ @pid = nil
750
+ @music_directory = File.expand_path(ARGV[0] || '~/Music/')
751
+ @midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
752
+ .sort_by { |path| File.basename(path) }
753
+ at_exit { stop_midi }
754
+ create_gui
755
+ end
756
+
757
+ def stop_midi
758
+ if @pid
759
+ if @th.alive?
760
+ Process.kill(:SIGKILL, @pid)
761
+ @pid = nil
762
+ else
763
+ @pid = nil
764
+ end
765
+ end
766
+ end
767
+
768
+ def play_midi
769
+ stop_midi
770
+ if @pid.nil? && @selected_file
771
+ begin
772
+ @pid = spawn "timidity #{@selected_file}"
773
+ @th = Process.detach @pid
774
+ rescue Errno::ENOENT
775
+ warn 'Timidty++ not found. Please install Timidity++.'
776
+ warn 'https://sourceforge.net/projects/timidity/'
777
+ end
778
+ end
779
+ end
780
+
781
+ def show_version(main_window)
782
+ msg_box(main_window,
783
+ 'Tiny Midi Player',
784
+ "Written in Ruby\n" \
785
+ "https://github.com/kojix2/libui\n" \
786
+ "Version #{VERSION}")
787
+ end
788
+
789
+ def create_gui
790
+ menu('Help') { |m|
791
+ menu_item('Version') {
792
+ on_clicked do
793
+ show_version(@main_window)
794
+ end
795
+ }
796
+ }
797
+ @main_window = window('Tiny Midi Player', 200, 50, 1) {
798
+ horizontal_box {
799
+ vertical_box {
800
+ stretchy 0
801
+
802
+ button('▶') {
803
+ on_clicked do
804
+ play_midi
805
+ end
806
+ }
807
+ button('■') {
808
+ on_clicked do
809
+ stop_midi
810
+ end
811
+ }
812
+ }
813
+
814
+ combobox { |c|
815
+ items @midi_files.map { |path| File.basename(path) }
816
+
817
+ on_selected do
818
+ @selected_file = @midi_files[c.selected]
819
+ play_midi if @th&.alive?
820
+ end
821
+ }
822
+ }
823
+ }
824
+ @main_window.show
825
+ end
826
+ end
827
+
828
+ TinyMidiPlayer.new
829
+ ```
830
+
831
+ ### Control Gallery
832
+
833
+ [examples/control_gallery.rb](examples/control_gallery.rb)
834
+
835
+ Run with this command from the root of the project if you cloned the project:
836
+
837
+ ```
838
+ ruby -r './lib/glimmer-dsl-libui' examples/control_gallery.rb
839
+ ```
840
+
841
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
842
+
843
+ ```
844
+ ruby -r glimmer-dsl-libui -e "require 'examples/control_gallery'"
845
+ ```
846
+
847
+ Mac
848
+
849
+ ![glimmer-dsl-libui-mac-control-gallery.png](images/glimmer-dsl-libui-mac-control-gallery.png)
850
+
851
+ Linux
852
+
853
+ ![glimmer-dsl-libui-linux-control-gallery.png](images/glimmer-dsl-libui-linux-control-gallery.png)
854
+
855
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
856
+
857
+ ```ruby
858
+ require 'libui'
859
+ UI = LibUI
860
+
861
+ UI.init
862
+
863
+ should_quit = proc do
864
+ puts 'Bye Bye'
865
+ UI.control_destroy(MAIN_WINDOW)
866
+ UI.quit
867
+ 0
868
+ end
869
+
870
+ # File menu
871
+ menu = UI.new_menu('File')
872
+ open_menu_item = UI.menu_append_item(menu, 'Open')
873
+ UI.menu_item_on_clicked(open_menu_item) do
874
+ pt = UI.open_file(MAIN_WINDOW)
875
+ puts pt unless pt.null?
876
+ end
877
+ save_menu_item = UI.menu_append_item(menu, 'Save')
878
+ UI.menu_item_on_clicked(save_menu_item) do
879
+ pt = UI.save_file(MAIN_WINDOW)
880
+ puts pt unless pt.null?
881
+ end
882
+
883
+ UI.menu_append_quit_item(menu)
884
+ UI.on_should_quit(should_quit)
885
+
886
+ # Edit menu
887
+ edit_menu = UI.new_menu('Edit')
888
+ UI.menu_append_check_item(edit_menu, 'Checkable Item_')
889
+ UI.menu_append_separator(edit_menu)
890
+ disabled_item = UI.menu_append_item(edit_menu, 'Disabled Item_')
891
+ UI.menu_item_disable(disabled_item)
892
+
893
+ preferences = UI.menu_append_preferences_item(menu)
894
+
895
+ # Help menu
896
+ help_menu = UI.new_menu('Help')
897
+ UI.menu_append_item(help_menu, 'Help')
898
+ UI.menu_append_about_item(help_menu)
899
+
900
+ # Main Window
901
+ MAIN_WINDOW = UI.new_window('Control Gallery', 600, 500, 1)
902
+ UI.window_set_margined(MAIN_WINDOW, 1)
903
+ UI.window_on_closing(MAIN_WINDOW, should_quit)
904
+
905
+ vbox = UI.new_vertical_box
906
+ UI.window_set_child(MAIN_WINDOW, vbox)
907
+ hbox = UI.new_horizontal_box
908
+ UI.box_set_padded(vbox, 1)
909
+ UI.box_set_padded(hbox, 1)
910
+
911
+ UI.box_append(vbox, hbox, 1)
912
+
913
+ # Group - Basic Controls
914
+ group = UI.new_group('Basic Controls')
915
+ UI.group_set_margined(group, 1)
916
+ UI.box_append(hbox, group, 1) # OSX bug?
917
+
918
+ inner = UI.new_vertical_box
919
+ UI.box_set_padded(inner, 1)
920
+ UI.group_set_child(group, inner)
921
+
922
+ # Button
923
+ button = UI.new_button('Button')
924
+ UI.button_on_clicked(button) do
925
+ UI.msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
926
+ end
927
+ UI.box_append(inner, button, 0)
928
+
929
+ # Checkbox
930
+ checkbox = UI.new_checkbox('Checkbox')
931
+ UI.checkbox_on_toggled(checkbox) do |ptr|
932
+ checked = UI.checkbox_checked(ptr) == 1
933
+ UI.window_set_title(MAIN_WINDOW, "Checkbox is #{checked}")
934
+ UI.checkbox_set_text(ptr, "I am the checkbox (#{checked})")
935
+ end
936
+ UI.box_append(inner, checkbox, 0)
937
+
938
+ # Label
939
+ UI.box_append(inner, UI.new_label('Label'), 0)
940
+
941
+ # Separator
942
+ UI.box_append(inner, UI.new_horizontal_separator, 0)
943
+
944
+ # Date Picker
945
+ UI.box_append(inner, UI.new_date_picker, 0)
946
+
947
+ # Time Picker
948
+ UI.box_append(inner, UI.new_time_picker, 0)
949
+
950
+ # Date Time Picker
951
+ UI.box_append(inner, UI.new_date_time_picker, 0)
952
+
953
+ # Font Button
954
+ UI.box_append(inner, UI.new_font_button, 0)
955
+
956
+ # Color Button
957
+ UI.box_append(inner, UI.new_color_button, 0)
958
+
959
+ inner2 = UI.new_vertical_box
960
+ UI.box_set_padded(inner2, 1)
961
+ UI.box_append(hbox, inner2, 1)
962
+
963
+ # Group - Numbers
964
+ group = UI.new_group('Numbers')
965
+ UI.group_set_margined(group, 1)
966
+ UI.box_append(inner2, group, 0)
967
+
968
+ inner = UI.new_vertical_box
969
+ UI.box_set_padded(inner, 1)
970
+ UI.group_set_child(group, inner)
971
+
972
+ # Spinbox
973
+ spinbox = UI.new_spinbox(0, 100)
974
+ UI.spinbox_set_value(spinbox, 42)
975
+ UI.spinbox_on_changed(spinbox) do |ptr|
976
+ puts "New Spinbox value: #{UI.spinbox_value(ptr)}"
977
+ end
978
+ UI.box_append(inner, spinbox, 0)
979
+
980
+ # Slider
981
+ slider = UI.new_slider(0, 100)
982
+ UI.box_append(inner, slider, 0)
983
+
984
+ # Progressbar
985
+ progressbar = UI.new_progress_bar
986
+ UI.box_append(inner, progressbar, 0)
987
+
988
+ UI.slider_on_changed(slider) do |ptr|
989
+ v = UI.slider_value(ptr)
990
+ puts "New Slider value: #{v}"
991
+ UI.progress_bar_set_value(progressbar, v)
992
+ end
993
+
994
+ # Group - Lists
995
+ group = UI.new_group('Lists')
996
+ UI.group_set_margined(group, 1)
997
+ UI.box_append(inner2, group, 0)
998
+
999
+ inner = UI.new_vertical_box
1000
+ UI.box_set_padded(inner, 1)
1001
+ UI.group_set_child(group, inner)
1002
+
1003
+ # Combobox
1004
+ cbox = UI.new_combobox
1005
+ UI.combobox_append(cbox, 'combobox Item 1')
1006
+ UI.combobox_append(cbox, 'combobox Item 2')
1007
+ UI.combobox_append(cbox, 'combobox Item 3')
1008
+ UI.box_append(inner, cbox, 0)
1009
+ UI.combobox_on_selected(cbox) do |ptr|
1010
+ puts "New combobox selection: #{UI.combobox_selected(ptr)}"
1011
+ end
1012
+
1013
+ # Editable Combobox
1014
+ ebox = UI.new_editable_combobox
1015
+ UI.editable_combobox_append(ebox, 'Editable Item 1')
1016
+ UI.editable_combobox_append(ebox, 'Editable Item 2')
1017
+ UI.editable_combobox_append(ebox, 'Editable Item 3')
1018
+ UI.box_append(inner, ebox, 0)
1019
+
1020
+ # Radio Buttons
1021
+ rb = UI.new_radio_buttons
1022
+ UI.radio_buttons_append(rb, 'Radio Button 1')
1023
+ UI.radio_buttons_append(rb, 'Radio Button 2')
1024
+ UI.radio_buttons_append(rb, 'Radio Button 3')
1025
+ UI.box_append(inner, rb, 1)
1026
+
1027
+ # Tab
1028
+ tab = UI.new_tab
1029
+ hbox1 = UI.new_horizontal_box
1030
+ hbox2 = UI.new_horizontal_box
1031
+ UI.tab_append(tab, 'Page 1', hbox1)
1032
+ UI.tab_append(tab, 'Page 2', hbox2)
1033
+ UI.tab_append(tab, 'Page 3', UI.new_horizontal_box)
1034
+ UI.box_append(inner2, tab, 1)
1035
+
1036
+ # Text Entry
1037
+ text_entry = UI.new_entry
1038
+ UI.entry_set_text text_entry, 'Please enter your feelings'
1039
+ UI.entry_on_changed(text_entry) do |ptr|
1040
+ puts "Current textbox data: '#{UI.entry_text(ptr)}'"
1041
+ end
1042
+ UI.box_append(hbox1, text_entry, 1)
1043
+
1044
+ UI.control_show(MAIN_WINDOW)
1045
+
1046
+ UI.main
1047
+ UI.quit
1048
+ ```
1049
+
1050
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
1051
+
1052
+ ```ruby
1053
+ require 'glimmer-dsl-libui'
1054
+
1055
+ include Glimmer
1056
+
1057
+ menu('File') {
1058
+ menu_item('Open') {
1059
+ on_clicked do
1060
+ file = open_file(MAIN_WINDOW)
1061
+ puts file unless file.nil?
1062
+ end
1063
+ }
1064
+
1065
+ menu_item('Save') {
1066
+ on_clicked do
1067
+ file = save_file(MAIN_WINDOW)
1068
+ puts file unless file.nil?
1069
+ end
1070
+ }
1071
+
1072
+ quit_menu_item {
1073
+ on_clicked do
1074
+ puts 'Bye Bye'
1075
+ end
1076
+ }
1077
+
1078
+ preferences_menu_item # Can optionally contain an on_clicked listener
1079
+ }
1080
+
1081
+ menu('Edit') {
1082
+ check_menu_item('Checkable Item_')
1083
+ separator_menu_item
1084
+ menu_item('Disabled Item_') {
1085
+ enabled 0
1086
+ }
1087
+ }
1088
+
1089
+ menu('Help') {
1090
+ menu_item('Help')
1091
+
1092
+ about_menu_item # Can optionally contain an on_clicked listener
1093
+ }
1094
+
1095
+ MAIN_WINDOW = window('Control Gallery', 600, 500, 1) {
1096
+ margined 1
1097
+
1098
+ on_closing do
1099
+ puts 'Bye Bye'
1100
+ end
1101
+
1102
+ vertical_box {
1103
+ horizontal_box {
1104
+ group('Basic Controls') {
1105
+ vertical_box {
1106
+ button('Button') {
1107
+ stretchy 0
1108
+
1109
+ on_clicked do
1110
+ msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1111
+ end
1112
+ }
1113
+
1114
+ checkbox('Checkbox') {
1115
+ stretchy 0
1116
+
1117
+ on_toggled do |c|
1118
+ checked = c.checked == 1
1119
+ MAIN_WINDOW.title = "Checkbox is #{checked}"
1120
+ c.text = "I am the checkbox (#{checked})"
1121
+ end
1122
+ }
1123
+
1124
+ label('Label') { stretchy 0 }
1125
+
1126
+ horizontal_separator { stretchy 0 }
1127
+
1128
+ date_picker { stretchy 0 }
1129
+
1130
+ time_picker { stretchy 0 }
1131
+
1132
+ date_time_picker { stretchy 0 }
1133
+
1134
+ font_button { stretchy 0 }
1135
+
1136
+ color_button { stretchy 0 }
1137
+ }
1138
+ }
1139
+
1140
+ vertical_box {
1141
+ group('Numbers') {
1142
+ stretchy 0
1143
+
1144
+ vertical_box {
1145
+ spinbox(0, 100) {
1146
+ stretchy 0
1147
+ value 42
1148
+
1149
+ on_changed do |s|
1150
+ puts "New Spinbox value: #{s.value}"
1151
+ end
1152
+ }
1153
+
1154
+ slider(0, 100) {
1155
+ stretchy 0
1156
+
1157
+ on_changed do |s|
1158
+ v = s.value
1159
+ puts "New Slider value: #{v}"
1160
+ @progress_bar.value = v
1161
+ end
1162
+ }
1163
+
1164
+ @progress_bar = progress_bar { stretchy 0 }
1165
+ }
1166
+ }
1167
+
1168
+ group('Lists') {
1169
+ stretchy 0
1170
+
1171
+ vertical_box {
1172
+ combobox {
1173
+ stretchy 0
1174
+ items 'combobox Item 1', 'combobox Item 2', 'combobox Item 3' # also accepts a single array argument
1175
+
1176
+ on_selected do |c|
1177
+ puts "New combobox selection: #{c.selected}"
1178
+ end
1179
+ }
1180
+
1181
+ editable_combobox {
1182
+ stretchy 0
1183
+ items 'Editable Item 1', 'Editable Item 2', 'Editable Item 3' # also accepts a single array argument
1184
+ }
1185
+
1186
+ radio_buttons {
1187
+ items 'Radio Button 1', 'Radio Button 2', 'Radio Button 3' # also accepts a single array argument
1188
+ }
1189
+ }
1190
+ }
1191
+
1192
+ tab {
1193
+ tab_item('Page 1') {
1194
+ horizontal_box {
1195
+ entry {
1196
+ text 'Please enter your feelings'
1197
+
1198
+ on_changed do |e|
1199
+ puts "Current textbox data: '#{e.text}'"
1200
+ end
1201
+ }
1202
+ }
1203
+ }
1204
+
1205
+ tab_item('Page 2') {
1206
+ horizontal_box
1207
+ }
1208
+
1209
+ tab_item('Page 3') {
1210
+ horizontal_box
1211
+ }
1212
+ }
1213
+ }
1214
+ }
1215
+ }
1216
+ }
1217
+
1218
+ MAIN_WINDOW.show
1219
+ ```
1220
+
487
1221
  ## Contributing to glimmer-dsl-libui
488
1222
 
489
1223
  - Check out the latest master to make sure the feature hasn't been