glimmer-dsl-libui 0.1.2 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +1127 -65
  4. data/VERSION +1 -1
  5. data/examples/area_gallery.rb +50 -0
  6. data/examples/area_gallery2.rb +111 -0
  7. data/examples/area_gallery3.rb +52 -0
  8. data/examples/area_gallery4.rb +113 -0
  9. data/examples/basic_area2.rb +1 -1
  10. data/examples/basic_button.rb +2 -2
  11. data/examples/basic_entry.rb +2 -2
  12. data/examples/basic_table_progress_bar.rb +13 -3
  13. data/examples/basic_transform.rb +27 -0
  14. data/examples/control_gallery.rb +3 -3
  15. data/examples/dynamic_area.rb +1 -1
  16. data/examples/form.rb +2 -2
  17. data/examples/histogram.rb +118 -0
  18. data/examples/meta_example.rb +71 -20
  19. data/examples/midi_player.rb +8 -10
  20. data/glimmer-dsl-libui.gemspec +0 -0
  21. data/lib/glimmer/dsl/libui/control_expression.rb +1 -3
  22. data/lib/glimmer/dsl/libui/dsl.rb +1 -0
  23. data/lib/glimmer/dsl/libui/file_expression.rb +5 -1
  24. data/lib/glimmer/dsl/libui/property_expression.rb +5 -1
  25. data/lib/glimmer/{libui/box.rb → dsl/libui/shape_expression.rb} +26 -29
  26. data/lib/glimmer/dsl/libui/tab_item_expression.rb +2 -2
  27. data/lib/glimmer/libui/control_proxy/area_proxy.rb +117 -0
  28. data/lib/glimmer/libui/{menu_item_proxy.rb → control_proxy/box/horizontal_box_proxy.rb} +9 -12
  29. data/lib/glimmer/libui/{vertical_box_proxy.rb → control_proxy/box/vertical_box_proxy.rb} +10 -6
  30. data/lib/glimmer/libui/control_proxy/box.rb +61 -0
  31. data/lib/glimmer/libui/{button_proxy.rb → control_proxy/button_proxy.rb} +14 -12
  32. data/lib/glimmer/libui/{checkbox_proxy.rb → control_proxy/checkbox_proxy.rb} +14 -12
  33. data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +118 -0
  34. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +76 -0
  35. data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +46 -0
  36. data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +80 -0
  37. data/lib/glimmer/libui/{radio_buttons_proxy.rb → control_proxy/column/image_column_proxy.rb} +14 -13
  38. data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +48 -0
  39. data/lib/glimmer/libui/{progress_bar_column_proxy.rb → control_proxy/column/progress_bar_column_proxy.rb} +14 -10
  40. data/lib/glimmer/libui/control_proxy/column/text_column_proxy.rb +46 -0
  41. data/lib/glimmer/libui/control_proxy/column.rb +55 -0
  42. data/lib/glimmer/libui/{checkbox_column_proxy.rb → control_proxy/combobox_proxy.rb} +16 -13
  43. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/date_picker_proxy.rb +43 -0
  44. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/time_picker_proxy.rb +43 -0
  45. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +72 -0
  46. data/lib/glimmer/libui/control_proxy/dual_column.rb +40 -0
  47. data/lib/glimmer/libui/control_proxy/editable_column.rb +46 -0
  48. data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +45 -0
  49. data/lib/glimmer/libui/{dual_column.rb → control_proxy/enableable_column.rb} +18 -10
  50. data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +70 -0
  51. data/lib/glimmer/libui/{form_proxy.rb → control_proxy/form_proxy.rb} +26 -24
  52. data/lib/glimmer/libui/{grid_proxy.rb → control_proxy/grid_proxy.rb} +29 -27
  53. data/lib/glimmer/libui/{group_proxy.rb → control_proxy/group_proxy.rb} +24 -22
  54. data/lib/glimmer/libui/{image_part_proxy.rb → control_proxy/image_part_proxy.rb} +20 -18
  55. data/lib/glimmer/libui/{image_proxy.rb → control_proxy/image_proxy.rb} +32 -30
  56. data/lib/glimmer/libui/{combobox_proxy.rb → control_proxy/label_proxy.rb} +13 -13
  57. data/lib/glimmer/libui/control_proxy/matrix_proxy.rb +147 -0
  58. data/lib/glimmer/libui/{editable_column.rb → control_proxy/menu_item_proxy/about_menu_item_proxy.rb} +13 -16
  59. data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +41 -0
  60. data/lib/glimmer/libui/{preferences_menu_item_proxy.rb → control_proxy/menu_item_proxy/preferences_menu_item_proxy.rb} +11 -9
  61. data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +66 -0
  62. data/lib/glimmer/libui/control_proxy/menu_item_proxy/separator_menu_item_proxy.rb +41 -0
  63. data/lib/glimmer/libui/control_proxy/menu_item_proxy.rb +45 -0
  64. data/lib/glimmer/libui/{editable_combobox_proxy.rb → control_proxy/menu_proxy.rb} +13 -13
  65. data/lib/glimmer/libui/{horizontal_box_proxy.rb → control_proxy/message_box/msg_box_error_proxy.rb} +9 -6
  66. data/lib/glimmer/libui/{multiline_entry_proxy.rb → control_proxy/message_box/msg_box_proxy.rb} +8 -6
  67. data/lib/glimmer/libui/{check_menu_item_proxy.rb → control_proxy/message_box.rb} +11 -10
  68. data/lib/glimmer/libui/control_proxy/multiline_entry_proxy/non_wrapping_multiline_entry_proxy.rb +34 -0
  69. data/lib/glimmer/libui/{image_column_proxy.rb → control_proxy/multiline_entry_proxy.rb} +10 -11
  70. data/lib/glimmer/libui/control_proxy/path_proxy.rb +169 -0
  71. data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +45 -0
  72. data/lib/glimmer/libui/{button_column_proxy.rb → control_proxy/tab_item_proxy.rb} +37 -40
  73. data/lib/glimmer/libui/control_proxy/table_proxy.rb +182 -0
  74. data/lib/glimmer/libui/control_proxy/transformable.rb +74 -0
  75. data/lib/glimmer/libui/control_proxy/window_proxy.rb +128 -0
  76. data/lib/glimmer/libui/control_proxy.rb +41 -22
  77. data/lib/glimmer/libui/{enableable_column.rb → parent.rb} +7 -15
  78. data/lib/glimmer/libui/shape/arc.rb +43 -0
  79. data/lib/glimmer/libui/{date_picker_proxy.rb → shape/bezier.rb} +8 -9
  80. data/lib/glimmer/libui/{quit_menu_item_proxy.rb → shape/figure.rb} +24 -32
  81. data/lib/glimmer/libui/{non_wrapping_multiline_entry_proxy.rb → shape/line.rb} +11 -5
  82. data/lib/glimmer/libui/{time_picker_proxy.rb → shape/rectangle.rb} +8 -9
  83. data/lib/glimmer/libui/{about_menu_item_proxy.rb → shape/square.rb} +9 -8
  84. data/lib/glimmer/libui/shape.rb +145 -0
  85. data/lib/glimmer/libui.rb +92 -0
  86. data/lib/glimmer-dsl-libui.rb +2 -0
  87. metadata +82 -48
  88. data/lib/glimmer/libui/area_proxy.rb +0 -105
  89. data/lib/glimmer/libui/checkbox_text_column_proxy.rb +0 -76
  90. data/lib/glimmer/libui/color_button_proxy.rb +0 -64
  91. data/lib/glimmer/libui/column.rb +0 -51
  92. data/lib/glimmer/libui/date_time_picker_proxy.rb +0 -68
  93. data/lib/glimmer/libui/font_button_proxy.rb +0 -68
  94. data/lib/glimmer/libui/image_text_column_proxy.rb +0 -44
  95. data/lib/glimmer/libui/label_proxy.rb +0 -41
  96. data/lib/glimmer/libui/menu_proxy.rb +0 -41
  97. data/lib/glimmer/libui/path_proxy.rb +0 -167
  98. data/lib/glimmer/libui/rectangle_proxy.rb +0 -100
  99. data/lib/glimmer/libui/separator_menu_item_proxy.rb +0 -37
  100. data/lib/glimmer/libui/tab_item_proxy.rb +0 -67
  101. data/lib/glimmer/libui/table_proxy.rb +0 -180
  102. data/lib/glimmer/libui/text_column_proxy.rb +0 -42
  103. data/lib/glimmer/libui/window_proxy.rb +0 -119
data/README.md CHANGED
@@ -1,4 +1,4 @@
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.1.2
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.1.6
2
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)
@@ -19,7 +19,7 @@ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/gl
19
19
  - Scaffolding for new custom controls, apps, and gems
20
20
  - Native-Executable packaging on Mac, Windows, and Linux.
21
21
 
22
- Example:
22
+ Hello, World!
23
23
 
24
24
  ```ruby
25
25
  require 'glimmer-dsl-libui'
@@ -32,6 +32,106 @@ window('hello world').show
32
32
  ![glimmer-dsl-libui-mac-basic-window.png](images/glimmer-dsl-libui-mac-basic-window.png)
33
33
  ![glimmer-dsl-libui-linux-basic-window.png](images/glimmer-dsl-libui-linux-basic-window.png)
34
34
 
35
+ Basic Table Progress Bar
36
+
37
+ ```ruby
38
+ require 'glimmer-dsl-libui'
39
+
40
+ include Glimmer
41
+
42
+ data = [
43
+ ['task 1', 0],
44
+ ['task 2', 15],
45
+ ['task 3', 100],
46
+ ['task 4', 75],
47
+ ['task 5', -1],
48
+ ]
49
+
50
+ window('Task Progress', 300, 200) {
51
+ vertical_box {
52
+ table {
53
+ text_column('Task')
54
+ progress_bar_column('Progress')
55
+
56
+ cell_rows data # implicit data-binding
57
+ }
58
+
59
+ button('Mark All As Done') {
60
+ stretchy false
61
+
62
+ on_clicked do
63
+ data.each_with_index do |row_data, row|
64
+ data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
65
+ end
66
+ end
67
+ }
68
+ }
69
+ }.show
70
+ ```
71
+
72
+ ![glimmer-dsl-libui-mac-basic-table-progress-bar.png](images/glimmer-dsl-libui-mac-basic-table-progress-bar.png)
73
+ ![glimmer-dsl-libui-linux-basic-table-progress-bar.png](images/glimmer-dsl-libui-linux-basic-table-progress-bar.png)
74
+
75
+ Area Gallery
76
+
77
+ ```ruby
78
+ require 'glimmer-dsl-libui'
79
+
80
+ include Glimmer
81
+
82
+ window('Area Gallery', 400, 400) {
83
+ area {
84
+ path { # declarative stable path
85
+ square(0, 0, 100)
86
+ square(100, 100, 400)
87
+
88
+ fill r: 102, g: 102, b: 204
89
+ }
90
+ path { # declarative stable path
91
+ rectangle(0, 100, 100, 400)
92
+ rectangle(100, 0, 400, 100)
93
+
94
+ fill r: 204, g: 102, b: 204
95
+ }
96
+ path { # declarative stable path
97
+ figure(100, 100) {
98
+ line(100, 400)
99
+ line(400, 100)
100
+ line(400, 400)
101
+
102
+ closed true
103
+ }
104
+
105
+ fill r: 202, g: 102, b: 104, a: 0.5
106
+ stroke r: 0, g: 0, b: 0
107
+ }
108
+ path { # declarative stable path
109
+ figure(0, 0) {
110
+ bezier(200, 100, 100, 200, 400, 100)
111
+ bezier(300, 100, 100, 300, 100, 400)
112
+ bezier(100, 300, 300, 100, 400, 400)
113
+
114
+ closed true
115
+ }
116
+
117
+ fill r: 202, g: 102, b: 204, a: 0.5
118
+ stroke thickness: 2, r: 0, g: 0, b: 0
119
+ }
120
+ path { # declarative stable path
121
+ arc(200, 200, 90, 0, 360, false)
122
+
123
+ fill r: 202, g: 102, b: 204, a: 0.5
124
+ stroke thickness: 2, r: 0, g: 0, b: 0
125
+ }
126
+ }
127
+ }.show
128
+ ```
129
+
130
+ ![glimmer-dsl-libui-mac-area-gallery.png](images/glimmer-dsl-libui-mac-area-gallery.png)
131
+ ![glimmer-dsl-libui-linux-area-gallery.png](images/glimmer-dsl-libui-linux-area-gallery.png)
132
+
133
+ [Check Out Many More Examples Over Here!](#examples)
134
+
35
135
  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.
36
136
 
37
137
  Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
@@ -43,9 +143,10 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
43
143
 
44
144
  ## Table of Contents
45
145
 
46
- - [Glimmer DSL for LibUI 0.1.2](#-glimmer-dsl-for-libui-012)
146
+ - [Glimmer DSL for LibUI 0.1.6](#-glimmer-dsl-for-libui-016)
47
147
  - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
48
148
  - [Usage](#usage)
149
+ - [Girb (Glimmer IRB)](#girb-glimmer-irb)
49
150
  - [API](#api)
50
151
  - [Supported Controls](#supported-controls)
51
152
  - [Common Control Properties](#common-control-properties)
@@ -58,7 +159,6 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
58
159
  - [API Gotchas](#api-gotchas)
59
160
  - [Original API](#original-api)
60
161
  - [Glimmer Style Guide](#glimmer-style-guide)
61
- - [Girb (Glimmer IRB)](#girb-glimmer-irb)
62
162
  - [Examples](#examples)
63
163
  - [Basic Window](#basic-window)
64
164
  - [Basic Button](#basic-button)
@@ -83,6 +183,9 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
83
183
  - [Form Table](#form-table)
84
184
  - [Basic Area](#basic-area)
85
185
  - [Dynamic Area](#dynamic-area)
186
+ - [Area Gallery](#area-gallery)
187
+ - [Histogram](#histogram)
188
+ - [Basic Transform](#basic-transform)
86
189
  - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
87
190
  - [Help](#help)
88
191
  - [Issues](#issues)
@@ -146,10 +249,10 @@ require 'glimmer-dsl-libui'
146
249
 
147
250
  include Glimmer
148
251
 
149
- window('hello world', 300, 200) { |w|
252
+ window('hello world', 300, 200) {
150
253
  button('Button') {
151
254
  on_clicked do
152
- msg_box(w, 'Information', 'You clicked the button')
255
+ msg_box('Information', 'You clicked the button')
153
256
  end
154
257
  }
155
258
 
@@ -170,7 +273,7 @@ gem install glimmer-dsl-libui
170
273
  Or install via Bundler `Gemfile`:
171
274
 
172
275
  ```ruby
173
- gem 'glimmer-dsl-libui', '~> 0.1.2'
276
+ gem 'glimmer-dsl-libui', '~> 0.1.6'
174
277
  ```
175
278
 
176
279
  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.
@@ -197,6 +300,24 @@ end
197
300
  Application.new.launch
198
301
  ```
199
302
 
303
+ If you are new to [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), check out [Girb](#girb-glimmer-irb) and [Examples](#examples) to quickly learn through copy/paste. You may refer to the [API](#api) later on once you have gotten your feet wet with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) and need more detailed reference information.
304
+
305
+ ## Girb (Glimmer IRB)
306
+
307
+ You can run the `girb` command (`bin/girb` if you cloned the project locally) to do some quick and dirty experimentation and learning:
308
+
309
+ ```
310
+ girb
311
+ ```
312
+
313
+ This gives you `irb` with the `glimmer-dsl-libui` gem loaded and the `Glimmer` module mixed into the main object for easy experimentation with GUI.
314
+
315
+ ![glimmer-dsl-libui-girb.png](images/glimmer-dsl-libui-girb.png)
316
+
317
+ For a more advanced code editing tool, check out the [Meta-Example (The Example of Examples)](#examples).
318
+
319
+ Gotcha: On the Mac, when you close a window opened in `girb`, it remains open until you enter `exit` or open another GUI window.
320
+
200
321
  ## API
201
322
 
202
323
  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`).
@@ -227,6 +348,8 @@ Control(Args) | Properties | Listeners
227
348
  ------------- | ---------- | ---------
228
349
  `about_menu_item` | None | `on_clicked`
229
350
  `area` | None | `on_draw`
351
+ `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)` | `x_center` (`Numeric`), `y_center` (`Numeric`), `radius` (`Numeric`), `start_angle` (`Numeric`), `sweep` (`Numeric`), `is_negative` (Boolean) | None
352
+ `bezier(c1_x as Numeric, c1_y as Numeric, c2_x as Numeric, c2_y as Numeric, end_x as Numeric, end_y as Numeric)` | `c1_x` (`Numeric`), `c1_y` (`Numeric`), `c2_x` (`Numeric`), `c2_y` (`Numeric`), `end_x` (`Numeric`), `end_y` (`Numeric`) | None
230
353
  `button(text as String)` | `text` (`String`) | `on_clicked`
231
354
  `button_column(name as String)` | `enabled` (Boolean) | None
232
355
  `checkbox(text as String)` | `checked` (Boolean), `text` (`String`) | `on_toggled`
@@ -238,6 +361,7 @@ Control(Args) | Properties | Listeners
238
361
  `date_time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
239
362
  `editable_combobox` | `items` (`Array` of `String`), `text` (`String`) | `on_changed`
240
363
  `entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
364
+ `figure(x=nil as Numeric, y=nil as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `closed` (Boolean) | None
241
365
  `font_button` | `font` [read-only] (`Hash` of keys: `:family`, `:size`, `:weight`, `:italic`, `:stretch`), `family` as `String`, `size` as `Float`, `weight` as `Integer`, `italic` as `Integer`, `stretch` as `Integer` | `on_changed`
242
366
  `form` | `padded` (Boolean) | None
243
367
  `grid` | `padded` (Boolean) | None
@@ -249,11 +373,13 @@ Control(Args) | Properties | Listeners
249
373
  `image_column(name as String)` | None | None
250
374
  `image_text_column(name as String)` | None | None
251
375
  `label(text as String)` | `text` (`String`) | None
376
+ `line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
377
+ `matrix(m11 = nil as Numeric, m12 = nil as Numeric, m21 = nil as Numeric, m22 = nil as Numeric, m31 = nil as Numeric, m32 = nil as Numeric)` | `m11` (`Numeric`), `m12` (`Numeric`), `m21` (`Numeric`), `m22` (`Numeric`), `m31` (`Numeric`), `m32` (`Numeric`) | None
252
378
  `menu(text as String)` | None | None
253
379
  `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
254
380
  `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
255
- `msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
256
- `msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
381
+ `msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
382
+ `msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
257
383
  `non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
258
384
  `path` | `fill` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`), `stroke` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, `:cap` as `Numeric`, `:join` as `Numeric`, `:thickness` as `Numeric`, `:miter_limit` as `Numeric` ) | None
259
385
  `preferences_menu_item` | None | `on_clicked`
@@ -261,14 +387,15 @@ Control(Args) | Properties | Listeners
261
387
  `progress_bar_column(name as String)` | None | None
262
388
  `quit_menu_item` | None | `on_clicked`
263
389
  `radio_buttons` | `selected` (`Integer`) | `on_selected`
264
- `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | None | None
390
+ `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `width` (`Numeric`), `height` (`Numeric`) | None
265
391
  `slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
266
392
  `spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
393
+ `square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
267
394
  `tab` | `margined` (Boolean), `num_pages` (`Integer`) | None
268
395
  `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
269
396
  `table` | `cell_rows` (`Array` (rows) of `Arrays` (row columns) of cell values (e.g. `String` values for `text_column` cells or `Array` of `image`/`String` for `image_text_column`)), `editable` as Boolean | None
270
397
  `text_column(name as String)` | `editable` (Boolean) | None
271
- `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
398
+ `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
272
399
  `vertical_box` | `padded` (Boolean) | None
273
400
  `window(title as String, width as Integer, height as Integer, has_menubar as Boolean)` | `borderless` (Boolean), `content_size` (width `Numeric`, height `Numeric`), `fullscreen` (Boolean), `margined` (Boolean), `title` (`String`) | `on_closing`, `on_content_size_changed`, `on_destroy`
274
401
 
@@ -328,11 +455,85 @@ Note that the `cell_rows` property declaration results in "implicit data-binding
328
455
  - Inserting cell rows: Calling `Array#<<`, `Array#push`, `Array#prepend`, or any insertion/addition `Array` method automatically inserts rows in actual `table` control
329
456
  - Changing cell rows: Calling `Array#[]=`, `Array#map!`, or any update `Array` method automatically updates rows in actual `table` control
330
457
 
458
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
459
+
460
+ ```ruby
461
+ require 'glimmer-dsl-libui'
462
+
463
+ include Glimmer
464
+
465
+ data = [
466
+ ['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
467
+ ['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
468
+ ['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
469
+ ['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
470
+ ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
471
+ ]
472
+
473
+ window('Contacts', 600, 600) { |w|
474
+ margined true
475
+
476
+ vertical_box {
477
+ form {
478
+ stretchy false
479
+
480
+ @name_entry = entry {
481
+ label 'Name'
482
+ }
483
+ @email_entry = entry {
484
+ label 'Email'
485
+ }
486
+ @phone_entry = entry {
487
+ label 'Phone'
488
+ }
489
+ @city_entry = entry {
490
+ label 'City'
491
+ }
492
+ @state_entry = entry {
493
+ label 'State'
494
+ }
495
+ }
496
+
497
+ button('Save Contact') {
498
+ stretchy false
499
+
500
+ on_clicked do
501
+ new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
502
+ if new_row.include?('')
503
+ msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
504
+ else
505
+ data << new_row # automatically inserts a row into the table due to implicit data-binding
506
+ @name_entry.text = ''
507
+ @email_entry.text = ''
508
+ @phone_entry.text = ''
509
+ @city_entry.text = ''
510
+ @state_entry.text = ''
511
+ end
512
+ end
513
+ }
514
+
515
+ table {
516
+ text_column('Name')
517
+ text_column('Email')
518
+ text_column('Phone')
519
+ text_column('City')
520
+ text_column('State')
521
+
522
+ cell_rows data # implicit data-binding
523
+ }
524
+ }
525
+ }.show
526
+ ```
527
+
528
+ ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
529
+
530
+ Learn more by checking out [examples](#examples).
531
+
331
532
  ### Area API
332
533
 
333
- The `area` control can be used in one of two ways:
334
- - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Paths proxy objects are preserved across redraws assuming there would be few stable paths (mostly for decorative reasons).
335
- - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block and nest `path(area_draw_params)` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
534
+ The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
535
+ - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be few stable paths (mostly for decorative reasons).
536
+ - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block that receives a `area_draw_params` argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
336
537
 
337
538
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
338
539
 
@@ -358,7 +559,7 @@ window('Basic Area', 400, 400) {
358
559
 
359
560
  ![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
360
561
 
361
- Here is the same example using a semi-declarative `area` with `on_draw` listener and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
562
+ Here is the same example using a semi-declarative `area` with `on_draw` listener that receives a `area_draw_params` argument and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
362
563
 
363
564
  ```ruby
364
565
  require 'glimmer-dsl-libui'
@@ -371,7 +572,7 @@ window('Basic Area', 400, 400) {
371
572
  vertical_box {
372
573
  area {
373
574
  on_draw do |area_draw_params|
374
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
575
+ path { # a dynamic path is added semi-declaratively inside on_draw block
375
576
  rectangle(0, 0, 400, 400)
376
577
 
377
578
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -384,16 +585,108 @@ window('Basic Area', 400, 400) {
384
585
 
385
586
  Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
386
587
 
387
- In general, it is recommended to use declarative stable paths whenever feasible since they require less code and simpler maintenance. But, in more advanced cases, semi-declarative dynamic paths could be used instead, especially if there are thousands of paths.
588
+ Available nested `path` shapes:
589
+ - `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)`
590
+ - `square(x as Numeric, y as Numeric, length as Numeric)`
591
+ - `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
592
+ - `line(x as Numeric, y as Numeric)`
593
+ - `bezier(c1_x as Numeric, c1_y as Numeric, c2_x as Numeric, c2_y as Numeric, end_x as Numeric, end_y as Numeric)`
594
+ - `figure(x=nil as Numeric, y=nil as Numeric)` (composite that can contain other shapes) (can set `closed true` to connect last point to first point automatically)
595
+
596
+ Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
597
+
598
+ The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
599
+ - `:context`: the drawing context object
600
+ - `:area_width`: area width
601
+ - `:area_height`: area height
602
+ - `:clip_x`: clip region top-left x coordinate
603
+ - `:clip_y`: clip region top-left y coordinate
604
+ - `:clip_width`: clip region width
605
+ - `:clip_height`: clip region height
606
+
607
+ In general, it is recommended to use declarative stable paths whenever feasible since they require less code and simpler maintenance. But, in more advanced cases, semi-declarative dynamic paths could be used instead, especially if there are thousands of dynamic paths that need maximum performance and low memory footprint.
608
+
609
+ Note that when nesting an `area` directly underneath `window` (without a layout control like `vertical_box`), it is automatically reparented with `vertical_box` in between the `window` and `area` since it would not show up on Linux otherwise.
610
+
611
+ To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
612
+
613
+ A transform `matrix` can be set on a path by building a `matrix(m11 = nil, m12 = nil, m21 = nil, m22 = nil, m31 = nil, m32 = nil) {operations}` proxy object and then setting via `transform` property, or alternatively by building and setting the matrix in one call to `transform(m11 = nil, m12 = nil, m21 = nil, m22 = nil, m31 = nil, m32 = nil) {operations}` passing it the matrix arguments and/or content operations.
614
+
615
+ When instantiating a `matrix` object, it always starts with identity matrix.
616
+
617
+ Here are the following operations that can be performed in a `matrix` body:
618
+ - `identity` [alias: `set_identity`]: resets matrix to identity matrix
619
+ - `translate(x as Numeric, y as Numeric)`
620
+ - `scale(x_center = 0 as Numeric, y_center = 0 as Numeric, x as Numeric, y as Numeric)`
621
+ - `skew(x = 0 as Numeric, y = 0 as Numeric, x_amount as Numeric, y_amount as Numeric)`
622
+ - `rotate(x = 0 as Numeric, y = 0 as Numeric, degrees as Numeric)`
623
+
624
+ Example of using transform matrix (you may copy/paste in [`girb`](#girb-glimmer-irb)):
388
625
 
389
- To redraw an `area`, you may call `#queue_redraw_all` method.
626
+ ```ruby
627
+ require 'glimmer-dsl-libui'
628
+
629
+ include Glimmer
630
+
631
+ window('Basic Transform', 350, 350) {
632
+ area {
633
+ path {
634
+ square(0, 0, 350)
635
+
636
+ fill r: 255, g: 255, b: 0
637
+ }
638
+ 40.times do |n|
639
+ path {
640
+ square(0, 0, 100)
641
+
642
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
643
+ stroke :black, thickness: 2
644
+ transform {
645
+ skew 0.15, 0.15
646
+ translate 50, 50
647
+ rotate 100, 100, -9 * n
648
+ scale 1.1, 1.1
649
+ }
650
+ }
651
+ end
652
+ }
653
+ }.show
654
+ ```
655
+
656
+ Keep in mind that this part could be written differently when there is a need to reuse the matrix:
657
+
658
+ ```ruby
659
+ transform {
660
+ translate 100, 100
661
+ rotate 100, 100, -9 * n
662
+ }
663
+ ```
664
+
665
+ Alternatively:
666
+
667
+ ```ruby
668
+ m1 = matrix {
669
+ translate 100, 100
670
+ rotate 100, 100, -9 * n
671
+ }
672
+ transform m1
673
+ # and then reuse m1 elsewhere too
674
+ ```
675
+
676
+ Note that `area`, `path`, and nested shapes are all truly declarative, meaning they do not care about the ordering of calls to `fill`, `stroke`, and `transform`. Furthermore, any transform that is applied is reversed at the end of the block, so you never have to worry about the ordering of `transform` calls among different paths. You simply set a transform on the `path`s that need it and it is guaranteed to be called before all its content is drawn, and then undone afterwards to avoid affecting later paths. Matrix `transform` can be set on an entire `area` too, applying to all nested `path`s.
677
+
678
+ `fill` and `stroke` accept [X11](https://en.wikipedia.org/wiki/X11_color_names) color `Symbol`s/`String`s like `:skyblue` and `'sandybrown'` or 6-number hex or 3-number hex-shorthand (as `Integer` or `String` with or without `0x` prefix)
679
+
680
+ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
681
+
682
+ Check [Histogram](#histogram) example for use of hex colors.
390
683
 
391
684
  ### Smart Defaults and Conventions
392
685
 
393
686
  - `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
394
687
  - `group` controls have `margined` as `true` upon instantiation to ensure more user-friendly GUI by default
395
688
  - All controls nested under a `horizontal_box`, `vertical_box`, and `form` have `stretchy` property (fill maximum space) as `true` by default (passed to `box_append`/`form_append` method)
396
- - `window` instatiation args can be left off, having the following defaults when unspecified: `title` as `''`, `width` as `150`, `height` as `150`, and `has_menubar` as `true`)
689
+ - `window` instatiation args can be left off, having the following defaults when unspecified: `title` as `''`, `width` as `190`, `height` as `150`, and `has_menubar` as `true`)
397
690
  - `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)
398
691
  - `group` has `title` property default to `''` if not specified in instantiation args, so it can be instantiated without args with `title` property specified in nested block (e.g. `group {title 'Address'; ...}`)
399
692
  - `button`, `checkbox`, and `label` have `text` default to `''` if not specified in instantiation args, so they can be instantiated without args with `text` property specified in nested block (e.g. `button {text 'Greet'; on_clicked {puts 'Hello'}}`)
@@ -419,11 +712,17 @@ To redraw an `area`, you may call `#queue_redraw_all` method.
419
712
  - `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
420
713
  - Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
421
714
  - Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
715
+ - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
716
+ - All resources are freed automatically once no longer needed or left to garbage collection.
717
+ - When nesting an `area` directly underneath `window` (without a layout control like `vertical_box`), it is automatically reparented with `vertical_box` in between the `window` and `area` since it would not show up on Linux otherwise.
718
+ - Colors may be passed in as a hash of `:r`, `:g`, `:b`, `:a`, or `:red`, `:green`, `:blue`, `:alpha`, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color like `:skyblue`, or 6-number hex or 3-number hex (as `Integer` or `String` with or without `0x` prefix)
719
+ - Color alpha value defaults to `1.0` when not specified.
422
720
 
423
721
  ### API Gotchas
424
722
 
425
723
  - There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`).
426
724
  - `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on Windows and Linux (not Mac) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
725
+ - It seems that `arc` `start_angle` and `sweep` properties are ignored by [libui](https://github.com/andlabs/libui) and always set to `0` and `360` respectively, producing a full circle.
427
726
 
428
727
  ### Original API
429
728
 
@@ -439,21 +738,9 @@ check out the [libui C headers](https://github.com/andlabs/libui/blob/master/ui.
439
738
  - Control listeners are always declared starting with on_ prefix and affixing listener event method name afterwards in underscored lowercase form. Their multi-line blocks have a `do; end` style.
440
739
  - Pure logic multi-line blocks that do not constitute GUI DSL view elements have `do; end` style to clearly separate logic code from view code.
441
740
 
442
- ## Girb (Glimmer IRB)
443
-
444
- You can run the `girb` command (`bin/girb` if you cloned the project locally):
445
-
446
- ```
447
- girb
448
- ```
449
-
450
- This gives you `irb` with the `glimmer-dsl-libui` gem loaded and the `Glimmer` module mixed into the main object for easy experimentation with GUI.
451
-
452
- Gotcha: On the Mac, when you close a window opened in `girb`, it remains open until you enter `exit` or open another GUI window.
453
-
454
741
  ## Examples
455
742
 
456
- These examples include reimplementions of the examples in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) as well as brand new examples.
743
+ The following examples include reimplementions of the examples in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) as well as brand new examples.
457
744
 
458
745
  To browse all examples, simply launch the [Meta-Example](examples/meta_example.rb), which lists all examples and displays each example's code when selected. It also enables code editing to facilitate experimentation and learning.
459
746
 
@@ -507,7 +794,7 @@ class MetaExample
507
794
  end
508
795
 
509
796
  def launch
510
- window('Meta-Example', 700, 500) { |w|
797
+ window('Meta-Example', 700, 500) {
511
798
  margined true
512
799
 
513
800
  horizontal_box {
@@ -529,7 +816,7 @@ class MetaExample
529
816
  meta_example_file = File.join(Dir.home, '.meta_example.rb')
530
817
  File.write(meta_example_file, @nwme.text)
531
818
  result = `ruby -r #{glimmer_dsl_libui_file} #{meta_example_file} 2>&1`
532
- msg_box(w, 'Error Running Example', result) if result.include?('error')
819
+ msg_box('Error Running Example', result) if result.include?('error')
533
820
  rescue => e
534
821
  puts 'Unable to write code changes! Running original example...'
535
822
  system "ruby -r #{glimmer_dsl_libui_file} #{file_path_for(@examples[@rbs.selected])}"
@@ -613,7 +900,7 @@ window('hello world', 300, 200, true) {
613
900
  }.show
614
901
  ```
615
902
 
616
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
903
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting `window` properties instead of arguments):
617
904
 
618
905
  ```ruby
619
906
  require 'glimmer-dsl-libui'
@@ -694,10 +981,10 @@ require 'glimmer-dsl-libui'
694
981
 
695
982
  include Glimmer
696
983
 
697
- window('hello world', 300, 200) { |w|
984
+ window('hello world', 300, 200) {
698
985
  button('Button') {
699
986
  on_clicked do
700
- msg_box(w, 'Information', 'You clicked the button')
987
+ msg_box('Information', 'You clicked the button')
701
988
  end
702
989
  }
703
990
 
@@ -781,7 +1068,7 @@ require 'glimmer-dsl-libui'
781
1068
 
782
1069
  include Glimmer
783
1070
 
784
- window('Basic Entry', 300, 50) { |w|
1071
+ window('Basic Entry', 300, 50) {
785
1072
  horizontal_box {
786
1073
  e = entry {
787
1074
  # stretchy true # Smart default option for appending to horizontal_box
@@ -797,7 +1084,7 @@ window('Basic Entry', 300, 50) { |w|
797
1084
 
798
1085
  on_clicked do
799
1086
  text = e.text
800
- msg_box(w, 'You entered', text)
1087
+ msg_box('You entered', text)
801
1088
  end
802
1089
  }
803
1090
  }
@@ -901,12 +1188,12 @@ ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"
901
1188
  Mac
902
1189
 
903
1190
  ![glimmer-dsl-libui-mac-midi-player.png](images/glimmer-dsl-libui-mac-midi-player.png)
904
- ![glimmer-dsl-libui-mac-midi-player-version-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-version-msg-box.png)
1191
+ ![glimmer-dsl-libui-mac-midi-player-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-msg-box.png)
905
1192
 
906
1193
  Linux
907
1194
 
908
1195
  ![glimmer-dsl-libui-linux-midi-player.png](images/glimmer-dsl-libui-linux-midi-player.png)
909
- ![glimmer-dsl-libui-linux-midi-player-version-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-version-msg-box.png)
1196
+ ![glimmer-dsl-libui-linux-midi-player-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-msg-box.png)
910
1197
 
911
1198
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
912
1199
 
@@ -1052,23 +1339,22 @@ class TinyMidiPlayer
1052
1339
  end
1053
1340
  end
1054
1341
 
1055
- def show_version(main_window)
1056
- msg_box(main_window,
1057
- 'Tiny Midi Player',
1058
- "Written in Ruby\n" \
1059
- "https://github.com/kojix2/libui\n" \
1060
- "Version #{VERSION}")
1342
+ def show_version
1343
+ msg_box('Tiny Midi Player',
1344
+ "Written in Ruby\n" \
1345
+ "https://github.com/kojix2/libui\n" \
1346
+ "Version #{VERSION}")
1061
1347
  end
1062
1348
 
1063
1349
  def create_gui
1064
1350
  menu('Help') { |m|
1065
1351
  menu_item('Version') {
1066
1352
  on_clicked do
1067
- show_version(@main_window)
1353
+ show_version
1068
1354
  end
1069
1355
  }
1070
1356
  }
1071
- @main_window = window('Tiny Midi Player', 200, 50) {
1357
+ window('Tiny Midi Player', 200, 50) {
1072
1358
  horizontal_box {
1073
1359
  vertical_box {
1074
1360
  stretchy false
@@ -1084,7 +1370,7 @@ class TinyMidiPlayer
1084
1370
  end
1085
1371
  }
1086
1372
  }
1087
-
1373
+
1088
1374
  combobox { |c|
1089
1375
  items @midi_files.map { |path| File.basename(path) }
1090
1376
 
@@ -1094,8 +1380,7 @@ class TinyMidiPlayer
1094
1380
  end
1095
1381
  }
1096
1382
  }
1097
- }
1098
- @main_window.show
1383
+ }.show
1099
1384
  end
1100
1385
  end
1101
1386
 
@@ -1331,14 +1616,14 @@ include Glimmer
1331
1616
  menu('File') {
1332
1617
  menu_item('Open') {
1333
1618
  on_clicked do
1334
- file = open_file(MAIN_WINDOW)
1619
+ file = open_file
1335
1620
  puts file unless file.nil?
1336
1621
  end
1337
1622
  }
1338
1623
 
1339
1624
  menu_item('Save') {
1340
1625
  on_clicked do
1341
- file = save_file(MAIN_WINDOW)
1626
+ file = save_file
1342
1627
  puts file unless file.nil?
1343
1628
  end
1344
1629
  }
@@ -1381,7 +1666,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1381
1666
  stretchy false
1382
1667
 
1383
1668
  on_clicked do
1384
- msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1669
+ msg_box('Information', 'You clicked the button')
1385
1670
  end
1386
1671
  }
1387
1672
 
@@ -1389,7 +1674,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1389
1674
  stretchy false
1390
1675
 
1391
1676
  on_toggled do |c|
1392
- checked = c.checked == 1
1677
+ checked = c.checked?
1393
1678
  MAIN_WINDOW.title = "Checkbox is #{checked}"
1394
1679
  c.text = "I am the checkbox (#{checked})"
1395
1680
  end
@@ -1843,7 +2128,7 @@ require 'glimmer-dsl-libui'
1843
2128
 
1844
2129
  include Glimmer
1845
2130
 
1846
- window('Form') { |w|
2131
+ window('Form') {
1847
2132
  margined true
1848
2133
 
1849
2134
  vertical_box {
@@ -1859,7 +2144,7 @@ window('Form') { |w|
1859
2144
 
1860
2145
  button('Display Name') {
1861
2146
  on_clicked do
1862
- msg_box(w, 'Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
2147
+ msg_box('Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
1863
2148
  end
1864
2149
  }
1865
2150
  }
@@ -2543,13 +2828,23 @@ data = [
2543
2828
  ['task 5', -1],
2544
2829
  ]
2545
2830
 
2546
- window('Task progress', 300, 200) {
2547
- horizontal_box {
2831
+ window('Task Progress', 300, 200) {
2832
+ vertical_box {
2548
2833
  table {
2549
2834
  text_column('Task')
2550
2835
  progress_bar_column('Progress')
2551
2836
 
2552
- cell_rows data
2837
+ cell_rows data # implicit data-binding
2838
+ }
2839
+
2840
+ button('Mark All As Done') {
2841
+ stretchy false
2842
+
2843
+ on_clicked do
2844
+ data.each_with_index do |row_data, row|
2845
+ data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
2846
+ end
2847
+ end
2553
2848
  }
2554
2849
  }
2555
2850
  }.show
@@ -2749,7 +3044,7 @@ window('Basic Area', 400, 400) {
2749
3044
  }.show
2750
3045
  ```
2751
3046
 
2752
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3047
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (semi-declarative `on_draw` dynamic `path` approach):
2753
3048
 
2754
3049
  ```ruby
2755
3050
  require 'glimmer-dsl-libui'
@@ -2762,7 +3057,7 @@ window('Basic Area', 400, 400) {
2762
3057
  vertical_box {
2763
3058
  area {
2764
3059
  on_draw do |area_draw_params|
2765
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3060
+ path { # a dynamic path is added semi-declaratively inside on_draw block
2766
3061
  rectangle(0, 0, 400, 400)
2767
3062
 
2768
3063
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -2892,7 +3187,7 @@ window('Dynamic Area', 240, 500) {
2892
3187
 
2893
3188
  @area = area {
2894
3189
  on_draw do |area_draw_params|
2895
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3190
+ path { # a dynamic path is added semi-declaratively inside on_draw block
2896
3191
  rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
2897
3192
 
2898
3193
  fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
@@ -2903,7 +3198,7 @@ window('Dynamic Area', 240, 500) {
2903
3198
  }.show
2904
3199
  ```
2905
3200
 
2906
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3201
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (declarative stable `path` approach):
2907
3202
 
2908
3203
  ```ruby
2909
3204
  require 'glimmer-dsl-libui'
@@ -3005,6 +3300,773 @@ window('Dynamic Area', 240, 600) {
3005
3300
  }.show
3006
3301
  ```
3007
3302
 
3303
+ ### Area Gallery
3304
+
3305
+ [examples/area_gallery.rb](examples/area_gallery.rb)
3306
+
3307
+ Run with this command from the root of the project if you cloned the project:
3308
+
3309
+ ```
3310
+ ruby -r './lib/glimmer-dsl-libui' examples/area_gallery.rb
3311
+ ```
3312
+
3313
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
3314
+
3315
+ ```
3316
+ ruby -r glimmer-dsl-libui -e "require 'examples/area_gallery'"
3317
+ ```
3318
+
3319
+ Mac
3320
+
3321
+ ![glimmer-dsl-libui-mac-area-gallery.png](images/glimmer-dsl-libui-mac-area-gallery.png)
3322
+
3323
+ Linux
3324
+
3325
+ ![glimmer-dsl-libui-linux-area-gallery.png](images/glimmer-dsl-libui-linux-area-gallery.png)
3326
+
3327
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3328
+
3329
+ ```ruby
3330
+ require 'glimmer-dsl-libui'
3331
+
3332
+ include Glimmer
3333
+
3334
+ window('Area Gallery', 400, 400) {
3335
+ area {
3336
+ path { # declarative stable path
3337
+ square(0, 0, 100)
3338
+ square(100, 100, 400)
3339
+
3340
+ fill r: 102, g: 102, b: 204
3341
+ }
3342
+ path { # declarative stable path
3343
+ rectangle(0, 100, 100, 400)
3344
+ rectangle(100, 0, 400, 100)
3345
+
3346
+ fill r: 204, g: 102, b: 204
3347
+ }
3348
+ path { # declarative stable path
3349
+ figure(100, 100) {
3350
+ line(100, 400)
3351
+ line(400, 100)
3352
+ line(400, 400)
3353
+
3354
+ closed true
3355
+ }
3356
+
3357
+ fill r: 202, g: 102, b: 104, a: 0.5
3358
+ stroke r: 0, g: 0, b: 0
3359
+ }
3360
+ path { # declarative stable path
3361
+ figure(0, 0) {
3362
+ bezier(200, 100, 100, 200, 400, 100)
3363
+ bezier(300, 100, 100, 300, 100, 400)
3364
+ bezier(100, 300, 300, 100, 400, 400)
3365
+
3366
+ closed true
3367
+ }
3368
+
3369
+ fill r: 202, g: 102, b: 204, a: 0.5
3370
+ stroke thickness: 2, r: 0, g: 0, b: 0
3371
+ }
3372
+ path { # declarative stable path
3373
+ arc(200, 200, 90, 0, 360, false)
3374
+
3375
+ fill r: 202, g: 102, b: 204, a: 0.5
3376
+ stroke thickness: 2, r: 0, g: 0, b: 0
3377
+ }
3378
+ }
3379
+ }.show
3380
+ ```
3381
+
3382
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting shape properties instead of arguments):
3383
+
3384
+ ```ruby
3385
+ require 'glimmer-dsl-libui'
3386
+
3387
+ include Glimmer
3388
+
3389
+ window('Area Gallery', 400, 400) {
3390
+ area {
3391
+ path { # declarative stable path
3392
+ square {
3393
+ x 0
3394
+ y 0
3395
+ length 100
3396
+ }
3397
+ square {
3398
+ x 100
3399
+ y 100
3400
+ length 400
3401
+ }
3402
+
3403
+ fill r: 102, g: 102, b: 204
3404
+ }
3405
+ path { # declarative stable path
3406
+ rectangle {
3407
+ x 0
3408
+ y 100
3409
+ width 100
3410
+ height 400
3411
+ }
3412
+ rectangle {
3413
+ x 100
3414
+ y 0
3415
+ width 400
3416
+ height 100
3417
+ }
3418
+
3419
+ fill r: 204, g: 102, b: 204
3420
+ }
3421
+ path { # declarative stable path
3422
+ figure {
3423
+ x 100
3424
+ y 100
3425
+
3426
+ line {
3427
+ x 100
3428
+ y 400
3429
+ }
3430
+ line {
3431
+ x 400
3432
+ y 100
3433
+ }
3434
+ line {
3435
+ x 400
3436
+ y 400
3437
+ }
3438
+
3439
+ closed true
3440
+ }
3441
+
3442
+ fill r: 202, g: 102, b: 104, a: 0.5
3443
+ stroke r: 0, g: 0, b: 0
3444
+ }
3445
+ path { # declarative stable path
3446
+ figure {
3447
+ x 0
3448
+ y 0
3449
+
3450
+ bezier {
3451
+ c1_x 200
3452
+ c1_y 100
3453
+ c2_x 100
3454
+ c2_y 200
3455
+ end_x 400
3456
+ end_y 100
3457
+ }
3458
+ bezier {
3459
+ c1_x 300
3460
+ c1_y 100
3461
+ c2_x 100
3462
+ c2_y 300
3463
+ end_x 100
3464
+ end_y 400
3465
+ }
3466
+ bezier {
3467
+ c1_x 100
3468
+ c1_y 300
3469
+ c2_x 300
3470
+ c2_y 100
3471
+ end_x 400
3472
+ end_y 400
3473
+ }
3474
+
3475
+ closed true
3476
+ }
3477
+
3478
+ fill r: 202, g: 102, b: 204, a: 0.5
3479
+ stroke thickness: 2, r: 0, g: 0, b: 0
3480
+ }
3481
+ path { # declarative stable path
3482
+ arc {
3483
+ x_center 200
3484
+ y_center 200
3485
+ radius 90
3486
+ start_angle 0
3487
+ sweep 360
3488
+ is_negative false
3489
+ }
3490
+
3491
+ fill r: 202, g: 102, b: 204, a: 0.5
3492
+ stroke thickness: 2, r: 0, g: 0, b: 0
3493
+ }
3494
+ }
3495
+ }.show
3496
+ ```
3497
+
3498
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (semi-declarative `on_draw` dynamic `path` approach):
3499
+
3500
+ ```ruby
3501
+ require 'glimmer-dsl-libui'
3502
+
3503
+ include Glimmer
3504
+
3505
+ window('Area Gallery', 400, 400) {
3506
+ area {
3507
+ on_draw do |area_draw_params|
3508
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3509
+ square(0, 0, 100)
3510
+ square(100, 100, 400)
3511
+
3512
+ fill r: 102, g: 102, b: 204
3513
+ }
3514
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3515
+ rectangle(0, 100, 100, 400)
3516
+ rectangle(100, 0, 400, 100)
3517
+
3518
+ fill r: 204, g: 102, b: 204
3519
+ }
3520
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3521
+ figure(100, 100) {
3522
+ line(100, 400)
3523
+ line(400, 100)
3524
+ line(400, 400)
3525
+
3526
+ closed true
3527
+ }
3528
+
3529
+ fill r: 202, g: 102, b: 104, a: 0.5
3530
+ stroke r: 0, g: 0, b: 0
3531
+ }
3532
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3533
+ figure(0, 0) {
3534
+ bezier(200, 100, 100, 200, 400, 100)
3535
+ bezier(300, 100, 100, 300, 100, 400)
3536
+ bezier(100, 300, 300, 100, 400, 400)
3537
+
3538
+ closed true
3539
+ }
3540
+
3541
+ fill r: 202, g: 102, b: 204, a: 0.5
3542
+ stroke thickness: 2, r: 0, g: 0, b: 0
3543
+ }
3544
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3545
+ arc(200, 200, 90, 0, 360, false)
3546
+
3547
+ fill r: 202, g: 102, b: 204, a: 0.5
3548
+ stroke thickness: 2, r: 0, g: 0, b: 0
3549
+ }
3550
+ end
3551
+ }
3552
+ }.show
3553
+ ```
3554
+
3555
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (setting shape properties instead of arguments with semi-declarative `on_draw` dynamic `path` approach):
3556
+
3557
+ ```ruby
3558
+ require 'glimmer-dsl-libui'
3559
+
3560
+ include Glimmer
3561
+
3562
+ window('Area Gallery', 400, 400) {
3563
+ area {
3564
+ on_draw do |area_draw_params|
3565
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3566
+ square {
3567
+ x 0
3568
+ y 0
3569
+ length 100
3570
+ }
3571
+ square {
3572
+ x 100
3573
+ y 100
3574
+ length 400
3575
+ }
3576
+
3577
+ fill r: 102, g: 102, b: 204
3578
+ }
3579
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3580
+ rectangle {
3581
+ x 0
3582
+ y 100
3583
+ width 100
3584
+ height 400
3585
+ }
3586
+ rectangle {
3587
+ x 100
3588
+ y 0
3589
+ width 400
3590
+ height 100
3591
+ }
3592
+
3593
+ fill r: 204, g: 102, b: 204
3594
+ }
3595
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3596
+ figure {
3597
+ x 100
3598
+ y 100
3599
+
3600
+ line {
3601
+ x 100
3602
+ y 400
3603
+ }
3604
+ line {
3605
+ x 400
3606
+ y 100
3607
+ }
3608
+ line {
3609
+ x 400
3610
+ y 400
3611
+ }
3612
+
3613
+ closed true
3614
+ }
3615
+
3616
+ fill r: 202, g: 102, b: 104, a: 0.5
3617
+ stroke r: 0, g: 0, b: 0
3618
+ }
3619
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3620
+ figure {
3621
+ x 0
3622
+ y 0
3623
+
3624
+ bezier {
3625
+ c1_x 200
3626
+ c1_y 100
3627
+ c2_x 100
3628
+ c2_y 200
3629
+ end_x 400
3630
+ end_y 100
3631
+ }
3632
+ bezier {
3633
+ c1_x 300
3634
+ c1_y 100
3635
+ c2_x 100
3636
+ c2_y 300
3637
+ end_x 100
3638
+ end_y 400
3639
+ }
3640
+ bezier {
3641
+ c1_x 100
3642
+ c1_y 300
3643
+ c2_x 300
3644
+ c2_y 100
3645
+ end_x 400
3646
+ end_y 400
3647
+ }
3648
+
3649
+ closed true
3650
+ }
3651
+
3652
+ fill r: 202, g: 102, b: 204, a: 0.5
3653
+ stroke thickness: 2, r: 0, g: 0, b: 0
3654
+ }
3655
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3656
+ arc {
3657
+ x_center 200
3658
+ y_center 200
3659
+ radius 90
3660
+ start_angle 0
3661
+ sweep 360
3662
+ is_negative false
3663
+ }
3664
+
3665
+ fill r: 202, g: 102, b: 204, a: 0.5
3666
+ stroke thickness: 2, r: 0, g: 0, b: 0
3667
+ }
3668
+ end
3669
+ }
3670
+ }.show
3671
+ ```
3672
+
3673
+ ### Histogram
3674
+
3675
+ [examples/histogram.rb](examples/histogram.rb)
3676
+
3677
+ Run with this command from the root of the project if you cloned the project:
3678
+
3679
+ ```
3680
+ ruby -r './lib/glimmer-dsl-libui' examples/histogram.rb
3681
+ ```
3682
+
3683
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
3684
+
3685
+ ```
3686
+ ruby -r glimmer-dsl-libui -e "require 'examples/histogram'"
3687
+ ```
3688
+
3689
+ Mac
3690
+
3691
+ ![glimmer-dsl-libui-mac-histogram.png](images/glimmer-dsl-libui-mac-histogram.png)
3692
+
3693
+ Linux
3694
+
3695
+ ![glimmer-dsl-libui-linux-histogram.png](images/glimmer-dsl-libui-linux-histogram.png)
3696
+
3697
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
3698
+
3699
+ ```ruby
3700
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
3701
+
3702
+ require 'libui'
3703
+
3704
+ UI = LibUI
3705
+
3706
+ X_OFF_LEFT = 20
3707
+ Y_OFF_TOP = 20
3708
+ X_OFF_RIGHT = 20
3709
+ Y_OFF_BOTTOM = 20
3710
+ POINT_RADIUS = 5
3711
+
3712
+ init = UI.init
3713
+ handler = UI::FFI::AreaHandler.malloc
3714
+ histogram = UI.new_area(handler)
3715
+ brush = UI::FFI::DrawBrush.malloc
3716
+ color_button = UI.new_color_button
3717
+ blue = 0x1E90FF
3718
+ datapoints = []
3719
+
3720
+ def graph_size(area_width, area_height)
3721
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
3722
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
3723
+ [graph_width, graph_height]
3724
+ end
3725
+
3726
+ matrix = UI::FFI::DrawMatrix.malloc
3727
+
3728
+ def point_locations(datapoints, width, height)
3729
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
3730
+ yincr = height / 100.0
3731
+
3732
+ data = []
3733
+ datapoints.each_with_index do |dp, i|
3734
+ val = 100 - UI.spinbox_value(dp)
3735
+ data << [xincr * i, yincr * val]
3736
+ i += 1
3737
+ end
3738
+
3739
+ data
3740
+ end
3741
+
3742
+ def construct_graph(datapoints, width, height, should_extend)
3743
+ locations = point_locations(datapoints, width, height)
3744
+ path = UI.draw_new_path(0) # winding
3745
+ first_location = locations[0] # x and y
3746
+ UI.draw_path_new_figure(path, first_location[0], first_location[1])
3747
+ locations.each do |loc|
3748
+ UI.draw_path_line_to(path, loc[0], loc[1])
3749
+ end
3750
+
3751
+ if should_extend
3752
+ UI.draw_path_line_to(path, width, height)
3753
+ UI.draw_path_line_to(path, 0, height)
3754
+ UI.draw_path_close_figure(path)
3755
+ end
3756
+
3757
+ UI.draw_path_end(path)
3758
+
3759
+ path
3760
+ end
3761
+
3762
+ handler_draw_event = Fiddle::Closure::BlockCaller.new(
3763
+ 0, [1, 1, 1]
3764
+ ) do |_area_handler, _area, area_draw_params|
3765
+ area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
3766
+ path = UI.draw_new_path(0) # winding
3767
+ UI.draw_path_add_rectangle(path, 0, 0, area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3768
+ UI.draw_path_end(path)
3769
+ set_solid_brush(brush, 0xFFFFFF, 1.0) # white
3770
+ UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
3771
+ UI.draw_free_path(path)
3772
+ dsp = UI::FFI::DrawStrokeParams.malloc
3773
+ dsp.Cap = 0 # flat
3774
+ dsp.Join = 0 # miter
3775
+ dsp.Thickness = 2
3776
+ dsp.MiterLimit = 10 # DEFAULT_MITER_LIMIT
3777
+ dashes = Fiddle::Pointer.malloc(8)
3778
+ dsp.Dashes = dashes
3779
+ dsp.NumDashes = 0
3780
+ dsp.DashPhase = 0
3781
+
3782
+ # draw axes
3783
+ set_solid_brush(brush, 0x000000, 1.0) # black
3784
+ graph_width, graph_height = *graph_size(area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3785
+
3786
+ path = UI.draw_new_path(0) # winding
3787
+ UI.draw_path_new_figure(path, X_OFF_LEFT, Y_OFF_TOP)
3788
+ UI.draw_path_line_to(path, X_OFF_LEFT, Y_OFF_TOP + graph_height)
3789
+ UI.draw_path_line_to(path, X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3790
+ UI.draw_path_end(path)
3791
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
3792
+ UI.draw_free_path(path)
3793
+
3794
+ # now transform the coordinate space so (0, 0) is the top-left corner of the graph
3795
+ UI.draw_matrix_set_identity(matrix)
3796
+ UI.draw_matrix_translate(matrix, X_OFF_LEFT, Y_OFF_TOP)
3797
+ UI.draw_transform(area_draw_params.Context, matrix)
3798
+
3799
+ # now get the color for the graph itself and set up the brush
3800
+ # uiColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA)
3801
+ graph_r = Fiddle::Pointer.malloc(8) # double
3802
+ graph_g = Fiddle::Pointer.malloc(8) # double
3803
+ graph_b = Fiddle::Pointer.malloc(8) # double
3804
+ graph_a = Fiddle::Pointer.malloc(8) # double
3805
+
3806
+ UI.color_button_color(color_button, graph_r, graph_g, graph_b, graph_a)
3807
+ brush.Type = 0 # solid
3808
+ brush.R = graph_r[0, 8].unpack1('d')
3809
+ brush.G = graph_g[0, 8].unpack1('d')
3810
+ brush.B = graph_b[0, 8].unpack1('d')
3811
+
3812
+ # now create the fill for the graph below the graph line
3813
+ path = construct_graph(datapoints, graph_width, graph_height, true)
3814
+ brush.A = graph_a[0, 8].unpack1('d') / 2.0
3815
+ UI.draw_fill(area_draw_params.Context, path, brush)
3816
+ UI.draw_free_path(path)
3817
+
3818
+ # now draw the histogram line
3819
+ path = construct_graph(datapoints, graph_width, graph_height, false)
3820
+ brush.A = graph_a[0, 8].unpack1('d')
3821
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
3822
+ UI.draw_free_path(path)
3823
+ end
3824
+
3825
+ handler.Draw = handler_draw_event
3826
+
3827
+ # Assigning to local variables
3828
+ # This is intended to protect Fiddle::Closure from garbage collection.
3829
+ # See https://github.com/kojix2/LibUI/issues/8
3830
+ handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3831
+ handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3832
+ handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3833
+ handler.KeyEvent = (c4 = Fiddle::Closure::BlockCaller.new(1, [0]) { 0 })
3834
+
3835
+ UI.freeInitError(init) unless init.nil?
3836
+
3837
+ hbox = UI.new_horizontal_box
3838
+ UI.box_set_padded(hbox, 1)
3839
+
3840
+ vbox = UI.new_vertical_box
3841
+ UI.box_set_padded(vbox, 1)
3842
+ UI.box_append(hbox, vbox, 0)
3843
+ UI.box_append(hbox, histogram, 1)
3844
+
3845
+ datapoints = Array.new(10) do
3846
+ UI.new_spinbox(0, 100).tap do |datapoint|
3847
+ UI.spinbox_set_value(datapoint, Random.new.rand(90))
3848
+ UI.spinbox_on_changed(datapoint) do
3849
+ UI.area_queue_redraw_all(histogram)
3850
+ end
3851
+ UI.box_append(vbox, datapoint, 0)
3852
+ end
3853
+ end
3854
+
3855
+ def set_solid_brush(brush, color, alpha)
3856
+ brush.Type = 0 # solid
3857
+ brush.R = ((color >> 16) & 0xFF) / 255.0
3858
+ brush.G = ((color >> 8) & 0xFF) / 255.0
3859
+ brush.B = (color & 0xFF) / 255.0
3860
+ brush.A = alpha
3861
+ brush
3862
+ end
3863
+
3864
+ set_solid_brush(brush, blue, 1.0)
3865
+ UI.color_button_set_color(color_button, brush.R, brush.G, brush.B, brush.A)
3866
+
3867
+ UI.color_button_on_changed(color_button) do
3868
+ UI.area_queue_redraw_all(histogram)
3869
+ end
3870
+
3871
+ UI.box_append(vbox, color_button, 0)
3872
+
3873
+ MAIN_WINDOW = UI.new_window('histogram example', 640, 480, 1)
3874
+ UI.window_set_margined(MAIN_WINDOW, 1)
3875
+ UI.window_set_child(MAIN_WINDOW, hbox)
3876
+
3877
+ should_quit = proc do |_ptr|
3878
+ UI.control_destroy(MAIN_WINDOW)
3879
+ UI.quit
3880
+ 0
3881
+ end
3882
+
3883
+ UI.window_on_closing(MAIN_WINDOW, should_quit)
3884
+ UI.on_should_quit(should_quit)
3885
+ UI.control_show(MAIN_WINDOW)
3886
+
3887
+ UI.main
3888
+ UI.quit
3889
+ ```
3890
+
3891
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3892
+
3893
+ ```ruby
3894
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
3895
+
3896
+ require 'glimmer-dsl-libui'
3897
+
3898
+ include Glimmer
3899
+
3900
+ X_OFF_LEFT = 20
3901
+ Y_OFF_TOP = 20
3902
+ X_OFF_RIGHT = 20
3903
+ Y_OFF_BOTTOM = 20
3904
+ POINT_RADIUS = 5
3905
+ COLOR_BLUE = 0x1E90FF
3906
+
3907
+ @datapoints = 10.times.map {Random.new.rand(90)}
3908
+
3909
+ def graph_size(area_width, area_height)
3910
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
3911
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
3912
+ [graph_width, graph_height]
3913
+ end
3914
+
3915
+ def point_locations(width, height)
3916
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
3917
+ yincr = height / 100.0
3918
+
3919
+ @datapoints.each_with_index.map do |value, i|
3920
+ val = 100 - value
3921
+ [xincr * i, yincr * val]
3922
+ end
3923
+ end
3924
+
3925
+ # method-based custom control representing a graph path
3926
+ def graph_path(width, height, should_extend, &block)
3927
+ locations = point_locations(width, height)
3928
+ path {
3929
+ first_location = locations[0] # x and y
3930
+ figure(first_location[0], first_location[1]) {
3931
+ locations.each do |loc|
3932
+ line(loc[0], loc[1])
3933
+ end
3934
+ if should_extend
3935
+ line(width, height)
3936
+ line(0, height)
3937
+
3938
+ closed true
3939
+ end
3940
+ }
3941
+
3942
+ # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
3943
+ transform {
3944
+ translate X_OFF_LEFT, Y_OFF_TOP
3945
+ }
3946
+
3947
+ block.call
3948
+ }
3949
+ end
3950
+
3951
+ window('histogram example', 640, 480) {
3952
+ margined true
3953
+
3954
+ horizontal_box {
3955
+ vertical_box {
3956
+ stretchy false
3957
+
3958
+ 10.times do |i|
3959
+ spinbox(0, 100) { |sb|
3960
+ stretchy false
3961
+ value @datapoints[i]
3962
+
3963
+ on_changed do
3964
+ @datapoints[i] = sb.value
3965
+ @area.queue_redraw_all
3966
+ end
3967
+ }
3968
+ end
3969
+
3970
+ @color_button = color_button {
3971
+ stretchy false
3972
+ color COLOR_BLUE
3973
+
3974
+ on_changed do
3975
+ @area.queue_redraw_all
3976
+ end
3977
+ }
3978
+ }
3979
+
3980
+ @area = area {
3981
+ on_draw do |area_draw_params|
3982
+ path {
3983
+ rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height])
3984
+
3985
+ fill 0xFFFFFF
3986
+ }
3987
+
3988
+ graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
3989
+
3990
+ path {
3991
+ figure(X_OFF_LEFT, Y_OFF_TOP) {
3992
+ line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
3993
+ line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3994
+ }
3995
+
3996
+ stroke 0x000000, thickness: 2, miter_limit: 10
3997
+ }
3998
+
3999
+ # now create the fill for the graph below the graph line
4000
+ graph_path(graph_width, graph_height, true) {
4001
+ fill @color_button.color.merge(a: 0.5)
4002
+ }
4003
+
4004
+ # now draw the histogram line
4005
+ graph_path(graph_width, graph_height, false) {
4006
+ stroke @color_button.color.merge(thickness: 2, miter_limit: 10)
4007
+ }
4008
+ end
4009
+ }
4010
+ }
4011
+ }.show
4012
+ ```
4013
+
4014
+ ### Basic Transform
4015
+
4016
+ [examples/basic_transform.rb](examples/basic_transform.rb)
4017
+
4018
+ Run with this command from the root of the project if you cloned the project:
4019
+
4020
+ ```
4021
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_transform.rb
4022
+ ```
4023
+
4024
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
4025
+
4026
+ ```
4027
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_transform'"
4028
+ ```
4029
+
4030
+ Mac
4031
+
4032
+ ![glimmer-dsl-libui-mac-basic-transform.png](images/glimmer-dsl-libui-mac-basic-transform.png)
4033
+
4034
+ Linux
4035
+
4036
+ ![glimmer-dsl-libui-linux-basic-transform.png](images/glimmer-dsl-libui-linux-basic-transform.png)
4037
+
4038
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
4039
+
4040
+ ```ruby
4041
+ require 'glimmer-dsl-libui'
4042
+
4043
+ include Glimmer
4044
+
4045
+ window('Basic Transform', 350, 350) {
4046
+ area {
4047
+ path {
4048
+ square(0, 0, 350)
4049
+
4050
+ fill r: 255, g: 255, b: 0
4051
+ }
4052
+ 40.times do |n|
4053
+ path {
4054
+ square(0, 0, 100)
4055
+
4056
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
4057
+ stroke :black, thickness: 2
4058
+ transform {
4059
+ skew 0.15, 0.15
4060
+ translate 50, 50
4061
+ rotate 100, 100, -9 * n
4062
+ scale 1.1, 1.1
4063
+ }
4064
+ }
4065
+ end
4066
+ }
4067
+ }.show
4068
+ ```
4069
+
3008
4070
  ## Contributing to glimmer-dsl-libui
3009
4071
 
3010
4072
  - Check out the latest master to make sure the feature hasn't been