glimmer-dsl-libui 0.1.4 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +939 -255
  4. data/VERSION +1 -1
  5. data/examples/area_gallery.rb +72 -38
  6. data/examples/area_gallery2.rb +126 -92
  7. data/examples/area_gallery3.rb +74 -40
  8. data/examples/area_gallery4.rb +132 -98
  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_transform.rb +27 -0
  13. data/examples/control_gallery.rb +3 -3
  14. data/examples/dynamic_area.rb +1 -1
  15. data/examples/form.rb +2 -2
  16. data/examples/histogram.rb +118 -0
  17. data/examples/meta_example.rb +71 -20
  18. data/examples/midi_player.rb +8 -10
  19. data/glimmer-dsl-libui.gemspec +0 -0
  20. data/lib/glimmer/dsl/libui/control_expression.rb +0 -2
  21. data/lib/glimmer/dsl/libui/file_expression.rb +5 -1
  22. data/lib/glimmer/dsl/libui/shape_expression.rb +2 -4
  23. data/lib/glimmer/dsl/libui/tab_item_expression.rb +2 -2
  24. data/lib/glimmer/libui/control_proxy/area_proxy.rb +166 -0
  25. data/lib/glimmer/libui/{menu_item_proxy.rb → control_proxy/box/horizontal_box_proxy.rb} +9 -12
  26. data/lib/glimmer/libui/{horizontal_box_proxy.rb → control_proxy/box/vertical_box_proxy.rb} +10 -6
  27. data/lib/glimmer/libui/{box.rb → control_proxy/box.rb} +31 -27
  28. data/lib/glimmer/libui/{button_proxy.rb → control_proxy/button_proxy.rb} +14 -12
  29. data/lib/glimmer/libui/{checkbox_proxy.rb → control_proxy/checkbox_proxy.rb} +14 -12
  30. data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +118 -0
  31. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +76 -0
  32. data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +46 -0
  33. data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +80 -0
  34. data/lib/glimmer/libui/{radio_buttons_proxy.rb → control_proxy/column/image_column_proxy.rb} +14 -13
  35. data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +48 -0
  36. data/lib/glimmer/libui/control_proxy/column/progress_bar_column_proxy.rb +44 -0
  37. data/lib/glimmer/libui/{checkbox_column_proxy.rb → control_proxy/column/text_column_proxy.rb} +17 -13
  38. data/lib/glimmer/libui/control_proxy/column.rb +55 -0
  39. data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +45 -0
  40. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/date_picker_proxy.rb +43 -0
  41. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/time_picker_proxy.rb +43 -0
  42. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +72 -0
  43. data/lib/glimmer/libui/control_proxy/dual_column.rb +40 -0
  44. data/lib/glimmer/libui/control_proxy/editable_column.rb +46 -0
  45. data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +45 -0
  46. data/lib/glimmer/libui/{dual_column.rb → control_proxy/enableable_column.rb} +18 -10
  47. data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +70 -0
  48. data/lib/glimmer/libui/{form_proxy.rb → control_proxy/form_proxy.rb} +26 -24
  49. data/lib/glimmer/libui/{grid_proxy.rb → control_proxy/grid_proxy.rb} +29 -27
  50. data/lib/glimmer/libui/{group_proxy.rb → control_proxy/group_proxy.rb} +24 -22
  51. data/lib/glimmer/libui/{image_part_proxy.rb → control_proxy/image_part_proxy.rb} +20 -18
  52. data/lib/glimmer/libui/{image_proxy.rb → control_proxy/image_proxy.rb} +32 -30
  53. data/lib/glimmer/libui/{combobox_proxy.rb → control_proxy/label_proxy.rb} +13 -13
  54. data/lib/glimmer/libui/control_proxy/matrix_proxy.rb +147 -0
  55. data/lib/glimmer/libui/{editable_column.rb → control_proxy/menu_item_proxy/about_menu_item_proxy.rb} +13 -16
  56. data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +41 -0
  57. data/lib/glimmer/libui/{date_picker_proxy.rb → control_proxy/menu_item_proxy/preferences_menu_item_proxy.rb} +10 -10
  58. data/lib/glimmer/libui/{quit_menu_item_proxy.rb → control_proxy/menu_item_proxy/quit_menu_item_proxy.rb} +33 -29
  59. data/lib/glimmer/libui/control_proxy/menu_item_proxy/separator_menu_item_proxy.rb +41 -0
  60. data/lib/glimmer/libui/control_proxy/menu_item_proxy.rb +45 -0
  61. data/lib/glimmer/libui/{editable_combobox_proxy.rb → control_proxy/menu_proxy.rb} +13 -13
  62. data/lib/glimmer/libui/{vertical_box_proxy.rb → control_proxy/message_box/msg_box_error_proxy.rb} +9 -6
  63. data/lib/glimmer/libui/{multiline_entry_proxy.rb → control_proxy/message_box/msg_box_proxy.rb} +8 -6
  64. data/lib/glimmer/libui/{time_picker_proxy.rb → control_proxy/message_box.rb} +9 -10
  65. data/lib/glimmer/libui/{rectangle.rb → control_proxy/multiline_entry_proxy/non_wrapping_multiline_entry_proxy.rb} +6 -8
  66. data/lib/glimmer/libui/{progress_bar_column_proxy.rb → control_proxy/multiline_entry_proxy.rb} +10 -11
  67. data/lib/glimmer/libui/control_proxy/path_proxy.rb +190 -0
  68. data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +45 -0
  69. data/lib/glimmer/libui/{button_column_proxy.rb → control_proxy/tab_item_proxy.rb} +37 -40
  70. data/lib/glimmer/libui/control_proxy/table_proxy.rb +182 -0
  71. data/lib/glimmer/libui/control_proxy/transformable.rb +74 -0
  72. data/lib/glimmer/libui/control_proxy/window_proxy.rb +128 -0
  73. data/lib/glimmer/libui/control_proxy.rb +72 -21
  74. data/lib/glimmer/libui/{enableable_column.rb → parent.rb} +7 -15
  75. data/lib/glimmer/libui/{arc.rb → shape/arc.rb} +13 -11
  76. data/lib/glimmer/libui/shape/bezier.rb +38 -0
  77. data/lib/glimmer/libui/{figure.rb → shape/figure.rb} +23 -21
  78. data/lib/glimmer/libui/{line.rb → shape/line.rb} +9 -7
  79. data/lib/glimmer/libui/{bezier.rb → shape/rectangle.rb} +9 -7
  80. data/lib/glimmer/libui/{square.rb → shape/square.rb} +9 -7
  81. data/lib/glimmer/libui/shape.rb +16 -15
  82. data/lib/glimmer/libui.rb +92 -0
  83. data/lib/glimmer-dsl-libui.rb +3 -0
  84. metadata +76 -53
  85. data/lib/glimmer/libui/about_menu_item_proxy.rb +0 -37
  86. data/lib/glimmer/libui/area_proxy.rb +0 -105
  87. data/lib/glimmer/libui/check_menu_item_proxy.rb +0 -37
  88. data/lib/glimmer/libui/checkbox_text_column_proxy.rb +0 -76
  89. data/lib/glimmer/libui/color_button_proxy.rb +0 -64
  90. data/lib/glimmer/libui/column.rb +0 -51
  91. data/lib/glimmer/libui/date_time_picker_proxy.rb +0 -68
  92. data/lib/glimmer/libui/font_button_proxy.rb +0 -68
  93. data/lib/glimmer/libui/image_column_proxy.rb +0 -40
  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/non_wrapping_multiline_entry_proxy.rb +0 -32
  98. data/lib/glimmer/libui/path_proxy.rb +0 -169
  99. data/lib/glimmer/libui/preferences_menu_item_proxy.rb +0 -37
  100. data/lib/glimmer/libui/separator_menu_item_proxy.rb +0 -37
  101. data/lib/glimmer/libui/tab_item_proxy.rb +0 -67
  102. data/lib/glimmer/libui/table_proxy.rb +0 -180
  103. data/lib/glimmer/libui/text_column_proxy.rb +0 -42
  104. 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.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.8
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)
@@ -80,51 +80,85 @@ require 'glimmer-dsl-libui'
80
80
  include Glimmer
81
81
 
82
82
  window('Area Gallery', 400, 400) {
83
- vertical_box {
84
- area {
85
- path { # declarative stable path
86
- square(0, 0, 100)
87
- square(100, 100, 400)
88
-
89
- fill r: 102, g: 102, b: 204
90
- }
91
- path { # declarative stable path
92
- rectangle(0, 100, 100, 400)
93
- rectangle(100, 0, 400, 100)
94
-
95
- fill r: 204, g: 102, b: 204
96
- }
97
- path { # declarative stable path
98
- figure(100, 100) {
99
- line(100, 400)
100
- line(400, 100)
101
- line(400, 400)
102
-
103
- closed true
104
- }
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)
105
101
 
106
- fill r: 202, g: 102, b: 104, a: 0.5
107
- stroke r: 0, g: 0, b: 0
102
+ closed true
108
103
  }
109
- path { # declarative stable path
110
- figure(0, 0) {
111
- bezier(200, 100, 100, 200, 400, 100)
112
- bezier(300, 100, 100, 300, 100, 400)
113
- bezier(100, 300, 300, 100, 400, 400)
114
104
 
115
- closed true
116
- }
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)
117
113
 
118
- fill r: 202, g: 102, b: 204, a: 0.5
119
- stroke thickness: 2, r: 0, g: 0, b: 0
114
+ closed true
120
115
  }
121
- path { # declarative stable path
122
- arc(200, 200, 90, 0, 360, false)
123
116
 
124
- fill r: 202, g: 102, b: 204, a: 0.5
125
- stroke thickness: 2, r: 0, g: 0, b: 0
126
- }
117
+ fill r: 202, g: 102, b: 204, a: 0.5
118
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.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 r: 0, g: 0, b: 0, thickness: 2
127
125
  }
126
+
127
+ on_mouse_event do |area_mouse_event|
128
+ p area_mouse_event
129
+ end
130
+
131
+ on_mouse_moved do |area_mouse_event|
132
+ puts 'moved'
133
+ end
134
+
135
+ on_mouse_down do |area_mouse_event|
136
+ puts 'mouse down'
137
+ end
138
+
139
+ on_mouse_up do |area_mouse_event|
140
+ puts 'mouse up'
141
+ end
142
+
143
+ on_mouse_drag_started do |area_mouse_event|
144
+ puts 'drag started'
145
+ end
146
+
147
+ on_mouse_dragged do |area_mouse_event|
148
+ puts 'dragged'
149
+ end
150
+
151
+ on_mouse_dropped do |area_mouse_event|
152
+ puts 'dropped'
153
+ end
154
+
155
+ on_mouse_entered do
156
+ puts 'entered'
157
+ end
158
+
159
+ on_mouse_exited do
160
+ puts 'exited'
161
+ end
128
162
  }
129
163
  }.show
130
164
  ```
@@ -145,7 +179,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
145
179
 
146
180
  ## Table of Contents
147
181
 
148
- - [Glimmer DSL for LibUI 0.1.4](#-glimmer-dsl-for-libui-014)
182
+ - [Glimmer DSL for LibUI 0.1.8](#-glimmer-dsl-for-libui-018)
149
183
  - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
150
184
  - [Usage](#usage)
151
185
  - [Girb (Glimmer IRB)](#girb-glimmer-irb)
@@ -186,6 +220,8 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
186
220
  - [Basic Area](#basic-area)
187
221
  - [Dynamic Area](#dynamic-area)
188
222
  - [Area Gallery](#area-gallery)
223
+ - [Histogram](#histogram)
224
+ - [Basic Transform](#basic-transform)
189
225
  - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
190
226
  - [Help](#help)
191
227
  - [Issues](#issues)
@@ -249,10 +285,10 @@ require 'glimmer-dsl-libui'
249
285
 
250
286
  include Glimmer
251
287
 
252
- window('hello world', 300, 200) { |w|
288
+ window('hello world', 300, 200) {
253
289
  button('Button') {
254
290
  on_clicked do
255
- msg_box(w, 'Information', 'You clicked the button')
291
+ msg_box('Information', 'You clicked the button')
256
292
  end
257
293
  }
258
294
 
@@ -273,7 +309,7 @@ gem install glimmer-dsl-libui
273
309
  Or install via Bundler `Gemfile`:
274
310
 
275
311
  ```ruby
276
- gem 'glimmer-dsl-libui', '~> 0.1.4'
312
+ gem 'glimmer-dsl-libui', '~> 0.1.8'
277
313
  ```
278
314
 
279
315
  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.
@@ -347,7 +383,7 @@ w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0
347
383
  Control(Args) | Properties | Listeners
348
384
  ------------- | ---------- | ---------
349
385
  `about_menu_item` | None | `on_clicked`
350
- `area` | None | `on_draw`
386
+ `area` | None | `on_draw(area_draw_params)`, `on_mouse_event(area_mouse_event)`, `on_mouse_down(area_mouse_event)`, `on_mouse_up(area_mouse_event)`, `on_mouse_drag_started(area_mouse_event)`, `on_mouse_dragged(area_mouse_event)`, `on_mouse_dropped(area_mouse_event)`, `on_mouse_entered`, `on_mouse_exited`
351
387
  `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
388
  `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
353
389
  `button(text as String)` | `text` (`String`) | `on_clicked`
@@ -374,13 +410,14 @@ Control(Args) | Properties | Listeners
374
410
  `image_text_column(name as String)` | None | None
375
411
  `label(text as String)` | `text` (`String`) | None
376
412
  `line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
413
+ `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
377
414
  `menu(text as String)` | None | None
378
415
  `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
379
416
  `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
380
- `msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
381
- `msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
417
+ `msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
418
+ `msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
382
419
  `non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
383
- `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
420
+ `path(draw_fill_mode = :winding)` | `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 (`:round`, `:square`, `:flat`), `:join` as (`:miter`, `:round`, `:bevel`), `:thickness` as `Numeric`, `:miter_limit` as `Numeric`, `:dashes` as `Array` of `Numeric` ) | None
384
421
  `preferences_menu_item` | None | `on_clicked`
385
422
  `progress_bar` | `value` (`Numeric`) | None
386
423
  `progress_bar_column(name as String)` | None | None
@@ -394,7 +431,7 @@ Control(Args) | Properties | Listeners
394
431
  `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
395
432
  `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
396
433
  `text_column(name as String)` | `editable` (Boolean) | None
397
- `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`
434
+ `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
398
435
  `vertical_box` | `padded` (Boolean) | None
399
436
  `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`
400
437
 
@@ -530,9 +567,9 @@ Learn more by checking out [examples](#examples).
530
567
 
531
568
  ### Area API
532
569
 
533
- The `area` control can be used in one of two ways:
534
- - 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).
535
- - 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.
570
+ The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
571
+ - 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).
572
+ - 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.
536
573
 
537
574
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
538
575
 
@@ -558,7 +595,7 @@ window('Basic Area', 400, 400) {
558
595
 
559
596
  ![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
560
597
 
561
- 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)):
598
+ 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)):
562
599
 
563
600
  ```ruby
564
601
  require 'glimmer-dsl-libui'
@@ -571,7 +608,7 @@ window('Basic Area', 400, 400) {
571
608
  vertical_box {
572
609
  area {
573
610
  on_draw do |area_draw_params|
574
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
611
+ path { # a dynamic path is added semi-declaratively inside on_draw block
575
612
  rectangle(0, 0, 400, 400)
576
613
 
577
614
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -584,6 +621,8 @@ window('Basic Area', 400, 400) {
584
621
 
585
622
  Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
586
623
 
624
+ `path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
625
+
587
626
  Available nested `path` shapes:
588
627
  - `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)`
589
628
  - `square(x as Numeric, y as Numeric, length as Numeric)`
@@ -592,16 +631,123 @@ Available nested `path` shapes:
592
631
  - `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)`
593
632
  - `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)
594
633
 
595
- 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.
634
+ Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
635
+
636
+ The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
637
+ - `:context`: the drawing context object
638
+ - `:area_width`: area width
639
+ - `:area_height`: area height
640
+ - `:clip_x`: clip region top-left x coordinate
641
+ - `:clip_y`: clip region top-left y coordinate
642
+ - `:clip_width`: clip region width
643
+ - `:clip_height`: clip region height
644
+
645
+ 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.
646
+
647
+ `area` supported mouse listeners are:
648
+ - `on_mouse_event {|area_mouse_event| ...}`: general catch-all mouse event (recommend use fine-grained event below instead)
649
+ - `on_mouse_down {|area_mouse_event)`
650
+ - `on_mouse_up {|area_mouse_event)`
651
+ - `on_mouse_drag_started {|area_mouse_event)`
652
+ - `on_mouse_dragged {|area_mouse_event)`
653
+ - `on_mouse_dropped {|area_mouse_event)`
654
+ - `on_mouse_entered {...}`
655
+ - `on_mouse_exited {...}`
656
+ - `on_mouse_crossed {|left| ...}` (NOT RECOMMENDED; it does what `on_mouse_entered` and `on_mouse_exited` do by returning a `left` argument indicating if mouse left `area`)
657
+ - `on_drag_broken {...}` (NOT RECOMMENDED; varies per platforms; use `on_mouse_dropped` instead)
658
+
659
+ The `area_mouse_event` argument for mouse events that receive it (e.g. `on_mouse_up`, `on_mouse_dragged`) consist of the following keys:
660
+ - `:x`: mouse x location in relation to area's top-left-corner
661
+ - `:y`: mouse y location in relation to area's top-left-corner
662
+ - `:area_width`: area current width
663
+ - `:area_height`: area current height
664
+ - `:down`: mouse pressed button (e.g. `1` is left button, `3` is right button)
665
+ - `:up`: mouse depressed button (e.g. `1` is left button, `3` is right button)
666
+ - `:count`: count of mouse clicks (e.g. `2` for double-click, `1` for single-click)
667
+ - `:modifers`: `Array` of `Symbol`s from one of the following: `[:command, :shift, :alt, :control]`
668
+ - `:held`: mouse held button during dragging (e.g. `1` is left button, `4` is right button)
669
+
670
+ 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.
671
+
672
+ To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
673
+
674
+ 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.
675
+
676
+ When instantiating a `matrix` object, it always starts with identity matrix.
677
+
678
+ Here are the following operations that can be performed in a `matrix` body:
679
+ - `identity` [alias: `set_identity`]: resets matrix to identity matrix
680
+ - `translate(x as Numeric, y as Numeric)`
681
+ - `scale(x_center = 0 as Numeric, y_center = 0 as Numeric, x as Numeric, y as Numeric)`
682
+ - `skew(x = 0 as Numeric, y = 0 as Numeric, x_amount as Numeric, y_amount as Numeric)`
683
+ - `rotate(x = 0 as Numeric, y = 0 as Numeric, degrees as Numeric)`
684
+
685
+ Example of using transform matrix (you may copy/paste in [`girb`](#girb-glimmer-irb)):
686
+
687
+ ```ruby
688
+ require 'glimmer-dsl-libui'
689
+
690
+ include Glimmer
691
+
692
+ window('Basic Transform', 350, 350) {
693
+ area {
694
+ path {
695
+ square(0, 0, 350)
696
+
697
+ fill r: 255, g: 255, b: 0
698
+ }
699
+ 40.times do |n|
700
+ path {
701
+ square(0, 0, 100)
702
+
703
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
704
+ stroke :black, thickness: 2
705
+ transform {
706
+ skew 0.15, 0.15
707
+ translate 50, 50
708
+ rotate 100, 100, -9 * n
709
+ scale 1.1, 1.1
710
+ }
711
+ }
712
+ end
713
+ }
714
+ }.show
715
+ ```
716
+
717
+ Keep in mind that this part could be written differently when there is a need to reuse the matrix:
718
+
719
+ ```ruby
720
+ transform {
721
+ translate 100, 100
722
+ rotate 100, 100, -9 * n
723
+ }
724
+ ```
725
+
726
+ Alternatively:
727
+
728
+ ```ruby
729
+ m1 = matrix {
730
+ translate 100, 100
731
+ rotate 100, 100, -9 * n
732
+ }
733
+ transform m1
734
+ # and then reuse m1 elsewhere too
735
+ ```
736
+
737
+ 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.
738
+
739
+ `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)
596
740
 
597
- To redraw an `area`, you may call `#queue_redraw_all` method.
741
+ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
742
+
743
+ Check [Histogram](#histogram) example for use of hex colors.
598
744
 
599
745
  ### Smart Defaults and Conventions
600
746
 
601
747
  - `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
602
748
  - `group` controls have `margined` as `true` upon instantiation to ensure more user-friendly GUI by default
603
749
  - 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)
604
- - `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`)
750
+ - `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`)
605
751
  - `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)
606
752
  - `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'; ...}`)
607
753
  - `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'}}`)
@@ -627,6 +773,11 @@ To redraw an `area`, you may call `#queue_redraw_all` method.
627
773
  - `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
628
774
  - Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
629
775
  - Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
776
+ - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
777
+ - All resources are freed automatically once no longer needed or left to garbage collection.
778
+ - 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.
779
+ - 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)
780
+ - Color alpha value defaults to `1.0` when not specified.
630
781
 
631
782
  ### API Gotchas
632
783
 
@@ -654,6 +805,8 @@ The following examples include reimplementions of the examples in the [LibUI](ht
654
805
 
655
806
  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.
656
807
 
808
+ (note that for examples that emit output to terminal/command-line via `p` or `puts`, you must run them directly to see output)
809
+
657
810
  [examples/meta_example.rb](examples/meta_example.rb)
658
811
 
659
812
  Run with this command from the root of the project if you cloned the project:
@@ -704,7 +857,7 @@ class MetaExample
704
857
  end
705
858
 
706
859
  def launch
707
- window('Meta-Example', 700, 500) { |w|
860
+ window('Meta-Example', 700, 500) {
708
861
  margined true
709
862
 
710
863
  horizontal_box {
@@ -726,7 +879,7 @@ class MetaExample
726
879
  meta_example_file = File.join(Dir.home, '.meta_example.rb')
727
880
  File.write(meta_example_file, @nwme.text)
728
881
  result = `ruby -r #{glimmer_dsl_libui_file} #{meta_example_file} 2>&1`
729
- msg_box(w, 'Error Running Example', result) if result.include?('error')
882
+ msg_box('Error Running Example', result) if result.include?('error')
730
883
  rescue => e
731
884
  puts 'Unable to write code changes! Running original example...'
732
885
  system "ruby -r #{glimmer_dsl_libui_file} #{file_path_for(@examples[@rbs.selected])}"
@@ -810,7 +963,7 @@ window('hello world', 300, 200, true) {
810
963
  }.show
811
964
  ```
812
965
 
813
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
966
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting `window` properties instead of arguments):
814
967
 
815
968
  ```ruby
816
969
  require 'glimmer-dsl-libui'
@@ -891,10 +1044,10 @@ require 'glimmer-dsl-libui'
891
1044
 
892
1045
  include Glimmer
893
1046
 
894
- window('hello world', 300, 200) { |w|
1047
+ window('hello world', 300, 200) {
895
1048
  button('Button') {
896
1049
  on_clicked do
897
- msg_box(w, 'Information', 'You clicked the button')
1050
+ msg_box('Information', 'You clicked the button')
898
1051
  end
899
1052
  }
900
1053
 
@@ -978,7 +1131,7 @@ require 'glimmer-dsl-libui'
978
1131
 
979
1132
  include Glimmer
980
1133
 
981
- window('Basic Entry', 300, 50) { |w|
1134
+ window('Basic Entry', 300, 50) {
982
1135
  horizontal_box {
983
1136
  e = entry {
984
1137
  # stretchy true # Smart default option for appending to horizontal_box
@@ -994,7 +1147,7 @@ window('Basic Entry', 300, 50) { |w|
994
1147
 
995
1148
  on_clicked do
996
1149
  text = e.text
997
- msg_box(w, 'You entered', text)
1150
+ msg_box('You entered', text)
998
1151
  end
999
1152
  }
1000
1153
  }
@@ -1098,12 +1251,12 @@ ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"
1098
1251
  Mac
1099
1252
 
1100
1253
  ![glimmer-dsl-libui-mac-midi-player.png](images/glimmer-dsl-libui-mac-midi-player.png)
1101
- ![glimmer-dsl-libui-mac-midi-player-version-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-version-msg-box.png)
1254
+ ![glimmer-dsl-libui-mac-midi-player-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-msg-box.png)
1102
1255
 
1103
1256
  Linux
1104
1257
 
1105
1258
  ![glimmer-dsl-libui-linux-midi-player.png](images/glimmer-dsl-libui-linux-midi-player.png)
1106
- ![glimmer-dsl-libui-linux-midi-player-version-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-version-msg-box.png)
1259
+ ![glimmer-dsl-libui-linux-midi-player-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-msg-box.png)
1107
1260
 
1108
1261
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
1109
1262
 
@@ -1249,23 +1402,22 @@ class TinyMidiPlayer
1249
1402
  end
1250
1403
  end
1251
1404
 
1252
- def show_version(main_window)
1253
- msg_box(main_window,
1254
- 'Tiny Midi Player',
1255
- "Written in Ruby\n" \
1256
- "https://github.com/kojix2/libui\n" \
1257
- "Version #{VERSION}")
1405
+ def show_version
1406
+ msg_box('Tiny Midi Player',
1407
+ "Written in Ruby\n" \
1408
+ "https://github.com/kojix2/libui\n" \
1409
+ "Version #{VERSION}")
1258
1410
  end
1259
1411
 
1260
1412
  def create_gui
1261
1413
  menu('Help') { |m|
1262
1414
  menu_item('Version') {
1263
1415
  on_clicked do
1264
- show_version(@main_window)
1416
+ show_version
1265
1417
  end
1266
1418
  }
1267
1419
  }
1268
- @main_window = window('Tiny Midi Player', 200, 50) {
1420
+ window('Tiny Midi Player', 200, 50) {
1269
1421
  horizontal_box {
1270
1422
  vertical_box {
1271
1423
  stretchy false
@@ -1281,7 +1433,7 @@ class TinyMidiPlayer
1281
1433
  end
1282
1434
  }
1283
1435
  }
1284
-
1436
+
1285
1437
  combobox { |c|
1286
1438
  items @midi_files.map { |path| File.basename(path) }
1287
1439
 
@@ -1291,8 +1443,7 @@ class TinyMidiPlayer
1291
1443
  end
1292
1444
  }
1293
1445
  }
1294
- }
1295
- @main_window.show
1446
+ }.show
1296
1447
  end
1297
1448
  end
1298
1449
 
@@ -1528,14 +1679,14 @@ include Glimmer
1528
1679
  menu('File') {
1529
1680
  menu_item('Open') {
1530
1681
  on_clicked do
1531
- file = open_file(MAIN_WINDOW)
1682
+ file = open_file
1532
1683
  puts file unless file.nil?
1533
1684
  end
1534
1685
  }
1535
1686
 
1536
1687
  menu_item('Save') {
1537
1688
  on_clicked do
1538
- file = save_file(MAIN_WINDOW)
1689
+ file = save_file
1539
1690
  puts file unless file.nil?
1540
1691
  end
1541
1692
  }
@@ -1578,7 +1729,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1578
1729
  stretchy false
1579
1730
 
1580
1731
  on_clicked do
1581
- msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1732
+ msg_box('Information', 'You clicked the button')
1582
1733
  end
1583
1734
  }
1584
1735
 
@@ -1586,7 +1737,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1586
1737
  stretchy false
1587
1738
 
1588
1739
  on_toggled do |c|
1589
- checked = c.checked == 1
1740
+ checked = c.checked?
1590
1741
  MAIN_WINDOW.title = "Checkbox is #{checked}"
1591
1742
  c.text = "I am the checkbox (#{checked})"
1592
1743
  end
@@ -2040,7 +2191,7 @@ require 'glimmer-dsl-libui'
2040
2191
 
2041
2192
  include Glimmer
2042
2193
 
2043
- window('Form') { |w|
2194
+ window('Form') {
2044
2195
  margined true
2045
2196
 
2046
2197
  vertical_box {
@@ -2056,7 +2207,7 @@ window('Form') { |w|
2056
2207
 
2057
2208
  button('Display Name') {
2058
2209
  on_clicked do
2059
- msg_box(w, 'Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
2210
+ msg_box('Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
2060
2211
  end
2061
2212
  }
2062
2213
  }
@@ -2956,7 +3107,7 @@ window('Basic Area', 400, 400) {
2956
3107
  }.show
2957
3108
  ```
2958
3109
 
2959
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3110
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (semi-declarative `on_draw` dynamic `path` approach):
2960
3111
 
2961
3112
  ```ruby
2962
3113
  require 'glimmer-dsl-libui'
@@ -2969,7 +3120,7 @@ window('Basic Area', 400, 400) {
2969
3120
  vertical_box {
2970
3121
  area {
2971
3122
  on_draw do |area_draw_params|
2972
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3123
+ path { # a dynamic path is added semi-declaratively inside on_draw block
2973
3124
  rectangle(0, 0, 400, 400)
2974
3125
 
2975
3126
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -3099,7 +3250,7 @@ window('Dynamic Area', 240, 500) {
3099
3250
 
3100
3251
  @area = area {
3101
3252
  on_draw do |area_draw_params|
3102
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3253
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3103
3254
  rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
3104
3255
 
3105
3256
  fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
@@ -3110,7 +3261,7 @@ window('Dynamic Area', 240, 500) {
3110
3261
  }.show
3111
3262
  ```
3112
3263
 
3113
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3264
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (declarative stable `path` approach):
3114
3265
 
3115
3266
  ```ruby
3116
3267
  require 'glimmer-dsl-libui'
@@ -3244,21 +3395,264 @@ require 'glimmer-dsl-libui'
3244
3395
  include Glimmer
3245
3396
 
3246
3397
  window('Area Gallery', 400, 400) {
3247
- vertical_box {
3248
- area {
3249
- path { # declarative stable path
3398
+ area {
3399
+ path { # declarative stable path
3400
+ square(0, 0, 100)
3401
+ square(100, 100, 400)
3402
+
3403
+ fill r: 102, g: 102, b: 204
3404
+ }
3405
+ path { # declarative stable path
3406
+ rectangle(0, 100, 100, 400)
3407
+ rectangle(100, 0, 400, 100)
3408
+
3409
+ fill r: 204, g: 102, b: 204
3410
+ }
3411
+ path { # declarative stable path
3412
+ figure(100, 100) {
3413
+ line(100, 400)
3414
+ line(400, 100)
3415
+ line(400, 400)
3416
+
3417
+ closed true
3418
+ }
3419
+
3420
+ fill r: 202, g: 102, b: 104, a: 0.5
3421
+ stroke r: 0, g: 0, b: 0
3422
+ }
3423
+ path { # declarative stable path
3424
+ figure(0, 0) {
3425
+ bezier(200, 100, 100, 200, 400, 100)
3426
+ bezier(300, 100, 100, 300, 100, 400)
3427
+ bezier(100, 300, 300, 100, 400, 400)
3428
+
3429
+ closed true
3430
+ }
3431
+
3432
+ fill r: 202, g: 102, b: 204, a: 0.5
3433
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3434
+ }
3435
+ path { # declarative stable path
3436
+ arc(200, 200, 90, 0, 360, false)
3437
+
3438
+ fill r: 202, g: 102, b: 204, a: 0.5
3439
+ stroke r: 0, g: 0, b: 0, thickness: 2
3440
+ }
3441
+
3442
+ on_mouse_event do |area_mouse_event|
3443
+ p area_mouse_event
3444
+ end
3445
+
3446
+ on_mouse_moved do |area_mouse_event|
3447
+ puts 'moved'
3448
+ end
3449
+
3450
+ on_mouse_down do |area_mouse_event|
3451
+ puts 'mouse down'
3452
+ end
3453
+
3454
+ on_mouse_up do |area_mouse_event|
3455
+ puts 'mouse up'
3456
+ end
3457
+
3458
+ on_mouse_drag_started do |area_mouse_event|
3459
+ puts 'drag started'
3460
+ end
3461
+
3462
+ on_mouse_dragged do |area_mouse_event|
3463
+ puts 'dragged'
3464
+ end
3465
+
3466
+ on_mouse_dropped do |area_mouse_event|
3467
+ puts 'dropped'
3468
+ end
3469
+
3470
+ on_mouse_entered do
3471
+ puts 'entered'
3472
+ end
3473
+
3474
+ on_mouse_exited do
3475
+ puts 'exited'
3476
+ end
3477
+ }
3478
+ }.show
3479
+ ```
3480
+
3481
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting shape properties instead of arguments):
3482
+
3483
+ ```ruby
3484
+ require 'glimmer-dsl-libui'
3485
+
3486
+ include Glimmer
3487
+
3488
+ window('Area Gallery', 400, 400) {
3489
+ area {
3490
+ path { # declarative stable path
3491
+ square {
3492
+ x 0
3493
+ y 0
3494
+ length 100
3495
+ }
3496
+ square {
3497
+ x 100
3498
+ y 100
3499
+ length 400
3500
+ }
3501
+
3502
+ fill r: 102, g: 102, b: 204
3503
+ }
3504
+ path { # declarative stable path
3505
+ rectangle {
3506
+ x 0
3507
+ y 100
3508
+ width 100
3509
+ height 400
3510
+ }
3511
+ rectangle {
3512
+ x 100
3513
+ y 0
3514
+ width 400
3515
+ height 100
3516
+ }
3517
+
3518
+ fill r: 204, g: 102, b: 204
3519
+ }
3520
+ path { # declarative stable path
3521
+ figure {
3522
+ x 100
3523
+ y 100
3524
+
3525
+ line {
3526
+ x 100
3527
+ y 400
3528
+ }
3529
+ line {
3530
+ x 400
3531
+ y 100
3532
+ }
3533
+ line {
3534
+ x 400
3535
+ y 400
3536
+ }
3537
+
3538
+ closed true
3539
+ }
3540
+
3541
+ fill r: 202, g: 102, b: 104, a: 0.5
3542
+ stroke r: 0, g: 0, b: 0
3543
+ }
3544
+ path { # declarative stable path
3545
+ figure {
3546
+ x 0
3547
+ y 0
3548
+
3549
+ bezier {
3550
+ c1_x 200
3551
+ c1_y 100
3552
+ c2_x 100
3553
+ c2_y 200
3554
+ end_x 400
3555
+ end_y 100
3556
+ }
3557
+ bezier {
3558
+ c1_x 300
3559
+ c1_y 100
3560
+ c2_x 100
3561
+ c2_y 300
3562
+ end_x 100
3563
+ end_y 400
3564
+ }
3565
+ bezier {
3566
+ c1_x 100
3567
+ c1_y 300
3568
+ c2_x 300
3569
+ c2_y 100
3570
+ end_x 400
3571
+ end_y 400
3572
+ }
3573
+
3574
+ closed true
3575
+ }
3576
+
3577
+ fill r: 202, g: 102, b: 204, a: 0.5
3578
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3579
+ }
3580
+ path { # declarative stable path
3581
+ arc {
3582
+ x_center 200
3583
+ y_center 200
3584
+ radius 90
3585
+ start_angle 0
3586
+ sweep 360
3587
+ is_negative false
3588
+ }
3589
+
3590
+ fill r: 202, g: 102, b: 204, a: 0.5
3591
+ stroke r: 0, g: 0, b: 0, thickness: 2
3592
+ }
3593
+
3594
+ on_mouse_event do |area_mouse_event|
3595
+ p area_mouse_event
3596
+ end
3597
+
3598
+ on_mouse_moved do |area_mouse_event|
3599
+ puts 'moved'
3600
+ end
3601
+
3602
+ on_mouse_down do |area_mouse_event|
3603
+ puts 'mouse down'
3604
+ end
3605
+
3606
+ on_mouse_up do |area_mouse_event|
3607
+ puts 'mouse up'
3608
+ end
3609
+
3610
+ on_mouse_drag_started do |area_mouse_event|
3611
+ puts 'drag started'
3612
+ end
3613
+
3614
+ on_mouse_dragged do |area_mouse_event|
3615
+ puts 'dragged'
3616
+ end
3617
+
3618
+ on_mouse_dropped do |area_mouse_event|
3619
+ puts 'dropped'
3620
+ end
3621
+
3622
+ on_mouse_entered do
3623
+ puts 'entered'
3624
+ end
3625
+
3626
+ on_mouse_exited do
3627
+ puts 'exited'
3628
+ end
3629
+ }
3630
+ }.show
3631
+ ```
3632
+
3633
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (semi-declarative `on_draw` dynamic `path` approach):
3634
+
3635
+ ```ruby
3636
+ require 'glimmer-dsl-libui'
3637
+
3638
+ include Glimmer
3639
+
3640
+ window('Area Gallery', 400, 400) {
3641
+ area {
3642
+ on_draw do |area_draw_params|
3643
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3250
3644
  square(0, 0, 100)
3251
3645
  square(100, 100, 400)
3252
3646
 
3253
3647
  fill r: 102, g: 102, b: 204
3254
3648
  }
3255
- path { # declarative stable path
3649
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3256
3650
  rectangle(0, 100, 100, 400)
3257
3651
  rectangle(100, 0, 400, 100)
3258
-
3652
+
3259
3653
  fill r: 204, g: 102, b: 204
3260
3654
  }
3261
- path { # declarative stable path
3655
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3262
3656
  figure(100, 100) {
3263
3657
  line(100, 400)
3264
3658
  line(400, 100)
@@ -3270,7 +3664,7 @@ window('Area Gallery', 400, 400) {
3270
3664
  fill r: 202, g: 102, b: 104, a: 0.5
3271
3665
  stroke r: 0, g: 0, b: 0
3272
3666
  }
3273
- path { # declarative stable path
3667
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3274
3668
  figure(0, 0) {
3275
3669
  bezier(200, 100, 100, 200, 400, 100)
3276
3670
  bezier(300, 100, 100, 300, 100, 400)
@@ -3280,20 +3674,56 @@ window('Area Gallery', 400, 400) {
3280
3674
  }
3281
3675
 
3282
3676
  fill r: 202, g: 102, b: 204, a: 0.5
3283
- stroke thickness: 2, r: 0, g: 0, b: 0
3677
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3284
3678
  }
3285
- path { # declarative stable path
3679
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3286
3680
  arc(200, 200, 90, 0, 360, false)
3287
3681
 
3288
3682
  fill r: 202, g: 102, b: 204, a: 0.5
3289
- stroke thickness: 2, r: 0, g: 0, b: 0
3683
+ stroke r: 0, g: 0, b: 0, thickness: 2
3290
3684
  }
3291
- }
3685
+ end
3686
+
3687
+ on_mouse_event do |area_mouse_event|
3688
+ p area_mouse_event
3689
+ end
3690
+
3691
+ on_mouse_moved do |area_mouse_event|
3692
+ puts 'moved'
3693
+ end
3694
+
3695
+ on_mouse_down do |area_mouse_event|
3696
+ puts 'mouse down'
3697
+ end
3698
+
3699
+ on_mouse_up do |area_mouse_event|
3700
+ puts 'mouse up'
3701
+ end
3702
+
3703
+ on_mouse_drag_started do |area_mouse_event|
3704
+ puts 'drag started'
3705
+ end
3706
+
3707
+ on_mouse_dragged do |area_mouse_event|
3708
+ puts 'dragged'
3709
+ end
3710
+
3711
+ on_mouse_dropped do |area_mouse_event|
3712
+ puts 'dropped'
3713
+ end
3714
+
3715
+ on_mouse_entered do
3716
+ puts 'entered'
3717
+ end
3718
+
3719
+ on_mouse_exited do
3720
+ puts 'exited'
3721
+ end
3292
3722
  }
3293
3723
  }.show
3294
3724
  ```
3295
3725
 
3296
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3726
+ 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):
3297
3727
 
3298
3728
  ```ruby
3299
3729
  require 'glimmer-dsl-libui'
@@ -3301,9 +3731,9 @@ require 'glimmer-dsl-libui'
3301
3731
  include Glimmer
3302
3732
 
3303
3733
  window('Area Gallery', 400, 400) {
3304
- vertical_box {
3305
- area {
3306
- path { # declarative stable path
3734
+ area {
3735
+ on_draw do |area_draw_params|
3736
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3307
3737
  square {
3308
3738
  x 0
3309
3739
  y 0
@@ -3317,7 +3747,7 @@ window('Area Gallery', 400, 400) {
3317
3747
 
3318
3748
  fill r: 102, g: 102, b: 204
3319
3749
  }
3320
- path { # declarative stable path
3750
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3321
3751
  rectangle {
3322
3752
  x 0
3323
3753
  y 100
@@ -3333,7 +3763,7 @@ window('Area Gallery', 400, 400) {
3333
3763
 
3334
3764
  fill r: 204, g: 102, b: 204
3335
3765
  }
3336
- path { # declarative stable path
3766
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3337
3767
  figure {
3338
3768
  x 100
3339
3769
  y 100
@@ -3357,7 +3787,7 @@ window('Area Gallery', 400, 400) {
3357
3787
  fill r: 202, g: 102, b: 104, a: 0.5
3358
3788
  stroke r: 0, g: 0, b: 0
3359
3789
  }
3360
- path { # declarative stable path
3790
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3361
3791
  figure {
3362
3792
  x 0
3363
3793
  y 0
@@ -3391,9 +3821,9 @@ window('Area Gallery', 400, 400) {
3391
3821
  }
3392
3822
 
3393
3823
  fill r: 202, g: 102, b: 204, a: 0.5
3394
- stroke thickness: 2, r: 0, g: 0, b: 0
3824
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3395
3825
  }
3396
- path { # declarative stable path
3826
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3397
3827
  arc {
3398
3828
  x_center 200
3399
3829
  y_center 200
@@ -3404,185 +3834,383 @@ window('Area Gallery', 400, 400) {
3404
3834
  }
3405
3835
 
3406
3836
  fill r: 202, g: 102, b: 204, a: 0.5
3407
- stroke thickness: 2, r: 0, g: 0, b: 0
3837
+ stroke r: 0, g: 0, b: 0, thickness: 2
3408
3838
  }
3409
- }
3839
+ end
3840
+
3841
+ on_mouse_event do |area_mouse_event|
3842
+ p area_mouse_event
3843
+ end
3844
+
3845
+ on_mouse_moved do |area_mouse_event|
3846
+ puts 'moved'
3847
+ end
3848
+
3849
+ on_mouse_down do |area_mouse_event|
3850
+ puts 'mouse down'
3851
+ end
3852
+
3853
+ on_mouse_up do |area_mouse_event|
3854
+ puts 'mouse up'
3855
+ end
3856
+
3857
+ on_mouse_drag_started do |area_mouse_event|
3858
+ puts 'drag started'
3859
+ end
3860
+
3861
+ on_mouse_dragged do |area_mouse_event|
3862
+ puts 'dragged'
3863
+ end
3864
+
3865
+ on_mouse_dropped do |area_mouse_event|
3866
+ puts 'dropped'
3867
+ end
3868
+
3869
+ on_mouse_entered do
3870
+ puts 'entered'
3871
+ end
3872
+
3873
+ on_mouse_exited do
3874
+ puts 'exited'
3875
+ end
3410
3876
  }
3411
3877
  }.show
3412
3878
  ```
3413
3879
 
3414
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3:
3880
+ ### Histogram
3881
+
3882
+ [examples/histogram.rb](examples/histogram.rb)
3883
+
3884
+ Run with this command from the root of the project if you cloned the project:
3885
+
3886
+ ```
3887
+ ruby -r './lib/glimmer-dsl-libui' examples/histogram.rb
3888
+ ```
3889
+
3890
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
3891
+
3892
+ ```
3893
+ ruby -r glimmer-dsl-libui -e "require 'examples/histogram'"
3894
+ ```
3895
+
3896
+ Mac
3897
+
3898
+ ![glimmer-dsl-libui-mac-histogram.png](images/glimmer-dsl-libui-mac-histogram.png)
3899
+
3900
+ Linux
3901
+
3902
+ ![glimmer-dsl-libui-linux-histogram.png](images/glimmer-dsl-libui-linux-histogram.png)
3903
+
3904
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
3415
3905
 
3416
3906
  ```ruby
3417
- require 'glimmer-dsl-libui'
3907
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
3418
3908
 
3419
- include Glimmer
3909
+ require 'libui'
3420
3910
 
3421
- window('Area Gallery', 400, 400) {
3422
- vertical_box {
3423
- area {
3424
- on_draw do |area_draw_params|
3425
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3426
- square(0, 0, 100)
3427
- square(100, 100, 400)
3428
-
3429
- fill r: 102, g: 102, b: 204
3430
- }
3431
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3432
- rectangle(0, 100, 100, 400)
3433
- rectangle(100, 0, 400, 100)
3911
+ UI = LibUI
3434
3912
 
3435
- fill r: 204, g: 102, b: 204
3436
- }
3437
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3438
- figure(100, 100) {
3439
- line(100, 400)
3440
- line(400, 100)
3441
- line(400, 400)
3913
+ X_OFF_LEFT = 20
3914
+ Y_OFF_TOP = 20
3915
+ X_OFF_RIGHT = 20
3916
+ Y_OFF_BOTTOM = 20
3917
+ POINT_RADIUS = 5
3918
+
3919
+ init = UI.init
3920
+ handler = UI::FFI::AreaHandler.malloc
3921
+ histogram = UI.new_area(handler)
3922
+ brush = UI::FFI::DrawBrush.malloc
3923
+ color_button = UI.new_color_button
3924
+ blue = 0x1E90FF
3925
+ datapoints = []
3926
+
3927
+ def graph_size(area_width, area_height)
3928
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
3929
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
3930
+ [graph_width, graph_height]
3931
+ end
3442
3932
 
3443
- closed true
3444
- }
3933
+ matrix = UI::FFI::DrawMatrix.malloc
3445
3934
 
3446
- fill r: 202, g: 102, b: 104, a: 0.5
3447
- stroke r: 0, g: 0, b: 0
3448
- }
3449
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3450
- figure(0, 0) {
3451
- bezier(200, 100, 100, 200, 400, 100)
3452
- bezier(300, 100, 100, 300, 100, 400)
3453
- bezier(100, 300, 300, 100, 400, 400)
3935
+ def point_locations(datapoints, width, height)
3936
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
3937
+ yincr = height / 100.0
3454
3938
 
3455
- closed true
3456
- }
3939
+ data = []
3940
+ datapoints.each_with_index do |dp, i|
3941
+ val = 100 - UI.spinbox_value(dp)
3942
+ data << [xincr * i, yincr * val]
3943
+ i += 1
3944
+ end
3457
3945
 
3458
- fill r: 202, g: 102, b: 204, a: 0.5
3459
- stroke thickness: 2, r: 0, g: 0, b: 0
3460
- }
3461
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3462
- arc(200, 200, 90, 0, 360, false)
3946
+ data
3947
+ end
3463
3948
 
3464
- fill r: 202, g: 102, b: 204, a: 0.5
3465
- stroke thickness: 2, r: 0, g: 0, b: 0
3466
- }
3467
- end
3468
- }
3469
- }
3470
- }.show
3949
+ def construct_graph(datapoints, width, height, should_extend)
3950
+ locations = point_locations(datapoints, width, height)
3951
+ path = UI.draw_new_path(0) # winding
3952
+ first_location = locations[0] # x and y
3953
+ UI.draw_path_new_figure(path, first_location[0], first_location[1])
3954
+ locations.each do |loc|
3955
+ UI.draw_path_line_to(path, loc[0], loc[1])
3956
+ end
3957
+
3958
+ if should_extend
3959
+ UI.draw_path_line_to(path, width, height)
3960
+ UI.draw_path_line_to(path, 0, height)
3961
+ UI.draw_path_close_figure(path)
3962
+ end
3963
+
3964
+ UI.draw_path_end(path)
3965
+
3966
+ path
3967
+ end
3968
+
3969
+ handler_draw_event = Fiddle::Closure::BlockCaller.new(
3970
+ 0, [1, 1, 1]
3971
+ ) do |_area_handler, _area, area_draw_params|
3972
+ area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
3973
+ path = UI.draw_new_path(0) # winding
3974
+ UI.draw_path_add_rectangle(path, 0, 0, area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3975
+ UI.draw_path_end(path)
3976
+ set_solid_brush(brush, 0xFFFFFF, 1.0) # white
3977
+ UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
3978
+ UI.draw_free_path(path)
3979
+ dsp = UI::FFI::DrawStrokeParams.malloc
3980
+ dsp.Cap = 0 # flat
3981
+ dsp.Join = 0 # miter
3982
+ dsp.Thickness = 2
3983
+ dsp.MiterLimit = 10 # DEFAULT_MITER_LIMIT
3984
+ dashes = Fiddle::Pointer.malloc(8)
3985
+ dsp.Dashes = dashes
3986
+ dsp.NumDashes = 0
3987
+ dsp.DashPhase = 0
3988
+
3989
+ # draw axes
3990
+ set_solid_brush(brush, 0x000000, 1.0) # black
3991
+ graph_width, graph_height = *graph_size(area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3992
+
3993
+ path = UI.draw_new_path(0) # winding
3994
+ UI.draw_path_new_figure(path, X_OFF_LEFT, Y_OFF_TOP)
3995
+ UI.draw_path_line_to(path, X_OFF_LEFT, Y_OFF_TOP + graph_height)
3996
+ UI.draw_path_line_to(path, X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3997
+ UI.draw_path_end(path)
3998
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
3999
+ UI.draw_free_path(path)
4000
+
4001
+ # now transform the coordinate space so (0, 0) is the top-left corner of the graph
4002
+ UI.draw_matrix_set_identity(matrix)
4003
+ UI.draw_matrix_translate(matrix, X_OFF_LEFT, Y_OFF_TOP)
4004
+ UI.draw_transform(area_draw_params.Context, matrix)
4005
+
4006
+ # now get the color for the graph itself and set up the brush
4007
+ # uiColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA)
4008
+ graph_r = Fiddle::Pointer.malloc(8) # double
4009
+ graph_g = Fiddle::Pointer.malloc(8) # double
4010
+ graph_b = Fiddle::Pointer.malloc(8) # double
4011
+ graph_a = Fiddle::Pointer.malloc(8) # double
4012
+
4013
+ UI.color_button_color(color_button, graph_r, graph_g, graph_b, graph_a)
4014
+ brush.Type = 0 # solid
4015
+ brush.R = graph_r[0, 8].unpack1('d')
4016
+ brush.G = graph_g[0, 8].unpack1('d')
4017
+ brush.B = graph_b[0, 8].unpack1('d')
4018
+
4019
+ # now create the fill for the graph below the graph line
4020
+ path = construct_graph(datapoints, graph_width, graph_height, true)
4021
+ brush.A = graph_a[0, 8].unpack1('d') / 2.0
4022
+ UI.draw_fill(area_draw_params.Context, path, brush)
4023
+ UI.draw_free_path(path)
4024
+
4025
+ # now draw the histogram line
4026
+ path = construct_graph(datapoints, graph_width, graph_height, false)
4027
+ brush.A = graph_a[0, 8].unpack1('d')
4028
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
4029
+ UI.draw_free_path(path)
4030
+ end
4031
+
4032
+ handler.Draw = handler_draw_event
4033
+
4034
+ # Assigning to local variables
4035
+ # This is intended to protect Fiddle::Closure from garbage collection.
4036
+ # See https://github.com/kojix2/LibUI/issues/8
4037
+ handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
4038
+ handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
4039
+ handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
4040
+ handler.KeyEvent = (c4 = Fiddle::Closure::BlockCaller.new(1, [0]) { 0 })
4041
+
4042
+ UI.freeInitError(init) unless init.nil?
4043
+
4044
+ hbox = UI.new_horizontal_box
4045
+ UI.box_set_padded(hbox, 1)
4046
+
4047
+ vbox = UI.new_vertical_box
4048
+ UI.box_set_padded(vbox, 1)
4049
+ UI.box_append(hbox, vbox, 0)
4050
+ UI.box_append(hbox, histogram, 1)
4051
+
4052
+ datapoints = Array.new(10) do
4053
+ UI.new_spinbox(0, 100).tap do |datapoint|
4054
+ UI.spinbox_set_value(datapoint, Random.new.rand(90))
4055
+ UI.spinbox_on_changed(datapoint) do
4056
+ UI.area_queue_redraw_all(histogram)
4057
+ end
4058
+ UI.box_append(vbox, datapoint, 0)
4059
+ end
4060
+ end
4061
+
4062
+ def set_solid_brush(brush, color, alpha)
4063
+ brush.Type = 0 # solid
4064
+ brush.R = ((color >> 16) & 0xFF) / 255.0
4065
+ brush.G = ((color >> 8) & 0xFF) / 255.0
4066
+ brush.B = (color & 0xFF) / 255.0
4067
+ brush.A = alpha
4068
+ brush
4069
+ end
4070
+
4071
+ set_solid_brush(brush, blue, 1.0)
4072
+ UI.color_button_set_color(color_button, brush.R, brush.G, brush.B, brush.A)
4073
+
4074
+ UI.color_button_on_changed(color_button) do
4075
+ UI.area_queue_redraw_all(histogram)
4076
+ end
4077
+
4078
+ UI.box_append(vbox, color_button, 0)
4079
+
4080
+ MAIN_WINDOW = UI.new_window('histogram example', 640, 480, 1)
4081
+ UI.window_set_margined(MAIN_WINDOW, 1)
4082
+ UI.window_set_child(MAIN_WINDOW, hbox)
4083
+
4084
+ should_quit = proc do |_ptr|
4085
+ UI.control_destroy(MAIN_WINDOW)
4086
+ UI.quit
4087
+ 0
4088
+ end
4089
+
4090
+ UI.window_on_closing(MAIN_WINDOW, should_quit)
4091
+ UI.on_should_quit(should_quit)
4092
+ UI.control_show(MAIN_WINDOW)
4093
+
4094
+ UI.main
4095
+ UI.quit
3471
4096
  ```
3472
4097
 
3473
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4:
4098
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3474
4099
 
3475
4100
  ```ruby
4101
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
4102
+
3476
4103
  require 'glimmer-dsl-libui'
3477
4104
 
3478
4105
  include Glimmer
3479
4106
 
3480
- window('Area Gallery', 400, 400) {
3481
- vertical_box {
3482
- area {
3483
- on_draw do |area_draw_params|
3484
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3485
- square {
3486
- x 0
3487
- y 0
3488
- length 100
3489
- }
3490
- square {
3491
- x 100
3492
- y 100
3493
- length 400
3494
- }
4107
+ X_OFF_LEFT = 20
4108
+ Y_OFF_TOP = 20
4109
+ X_OFF_RIGHT = 20
4110
+ Y_OFF_BOTTOM = 20
4111
+ POINT_RADIUS = 5
4112
+ COLOR_BLUE = 0x1E90FF
4113
+
4114
+ @datapoints = 10.times.map {Random.new.rand(90)}
4115
+
4116
+ def graph_size(area_width, area_height)
4117
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
4118
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
4119
+ [graph_width, graph_height]
4120
+ end
4121
+
4122
+ def point_locations(width, height)
4123
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
4124
+ yincr = height / 100.0
4125
+
4126
+ @datapoints.each_with_index.map do |value, i|
4127
+ val = 100 - value
4128
+ [xincr * i, yincr * val]
4129
+ end
4130
+ end
4131
+
4132
+ # method-based custom control representing a graph path
4133
+ def graph_path(width, height, should_extend, &block)
4134
+ locations = point_locations(width, height)
4135
+ path {
4136
+ first_location = locations[0] # x and y
4137
+ figure(first_location[0], first_location[1]) {
4138
+ locations.each do |loc|
4139
+ line(loc[0], loc[1])
4140
+ end
4141
+ if should_extend
4142
+ line(width, height)
4143
+ line(0, height)
4144
+
4145
+ closed true
4146
+ end
4147
+ }
4148
+
4149
+ # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
4150
+ transform {
4151
+ translate X_OFF_LEFT, Y_OFF_TOP
4152
+ }
4153
+
4154
+ block.call
4155
+ }
4156
+ end
4157
+
4158
+ window('histogram example', 640, 480) {
4159
+ margined true
4160
+
4161
+ horizontal_box {
4162
+ vertical_box {
4163
+ stretchy false
4164
+
4165
+ 10.times do |i|
4166
+ spinbox(0, 100) { |sb|
4167
+ stretchy false
4168
+ value @datapoints[i]
3495
4169
 
3496
- fill r: 102, g: 102, b: 204
4170
+ on_changed do
4171
+ @datapoints[i] = sb.value
4172
+ @area.queue_redraw_all
4173
+ end
3497
4174
  }
3498
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3499
- rectangle {
3500
- x 0
3501
- y 100
3502
- width 100
3503
- height 400
3504
- }
3505
- rectangle {
3506
- x 100
3507
- y 0
3508
- width 400
3509
- height 100
3510
- }
4175
+ end
4176
+
4177
+ @color_button = color_button {
4178
+ stretchy false
4179
+ color COLOR_BLUE
4180
+
4181
+ on_changed do
4182
+ @area.queue_redraw_all
4183
+ end
4184
+ }
4185
+ }
4186
+
4187
+ @area = area {
4188
+ on_draw do |area_draw_params|
4189
+ path {
4190
+ rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height])
3511
4191
 
3512
- fill r: 204, g: 102, b: 204
4192
+ fill 0xFFFFFF
3513
4193
  }
3514
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3515
- figure {
3516
- x 100
3517
- y 100
3518
-
3519
- line {
3520
- x 100
3521
- y 400
3522
- }
3523
- line {
3524
- x 400
3525
- y 100
3526
- }
3527
- line {
3528
- x 400
3529
- y 400
3530
- }
3531
-
3532
- closed true
4194
+
4195
+ graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
4196
+
4197
+ path {
4198
+ figure(X_OFF_LEFT, Y_OFF_TOP) {
4199
+ line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
4200
+ line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3533
4201
  }
3534
-
3535
- fill r: 202, g: 102, b: 104, a: 0.5
3536
- stroke r: 0, g: 0, b: 0
4202
+
4203
+ stroke 0x000000, thickness: 2, miter_limit: 10
3537
4204
  }
3538
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3539
- figure {
3540
- x 0
3541
- y 0
3542
-
3543
- bezier {
3544
- c1_x 200
3545
- c1_y 100
3546
- c2_x 100
3547
- c2_y 200
3548
- end_x 400
3549
- end_y 100
3550
- }
3551
- bezier {
3552
- c1_x 300
3553
- c1_y 100
3554
- c2_x 100
3555
- c2_y 300
3556
- end_x 100
3557
- end_y 400
3558
- }
3559
- bezier {
3560
- c1_x 100
3561
- c1_y 300
3562
- c2_x 300
3563
- c2_y 100
3564
- end_x 400
3565
- end_y 400
3566
- }
3567
-
3568
- closed true
3569
- }
3570
-
3571
- fill r: 202, g: 102, b: 204, a: 0.5
3572
- stroke thickness: 2, r: 0, g: 0, b: 0
4205
+
4206
+ # now create the fill for the graph below the graph line
4207
+ graph_path(graph_width, graph_height, true) {
4208
+ fill @color_button.color.merge(a: 0.5)
3573
4209
  }
3574
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3575
- arc {
3576
- x_center 200
3577
- y_center 200
3578
- radius 90
3579
- start_angle 0
3580
- sweep 360
3581
- is_negative false
3582
- }
3583
-
3584
- fill r: 202, g: 102, b: 204, a: 0.5
3585
- stroke thickness: 2, r: 0, g: 0, b: 0
4210
+
4211
+ # now draw the histogram line
4212
+ graph_path(graph_width, graph_height, false) {
4213
+ stroke @color_button.color.merge(thickness: 2, miter_limit: 10)
3586
4214
  }
3587
4215
  end
3588
4216
  }
@@ -3590,6 +4218,62 @@ window('Area Gallery', 400, 400) {
3590
4218
  }.show
3591
4219
  ```
3592
4220
 
4221
+ ### Basic Transform
4222
+
4223
+ [examples/basic_transform.rb](examples/basic_transform.rb)
4224
+
4225
+ Run with this command from the root of the project if you cloned the project:
4226
+
4227
+ ```
4228
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_transform.rb
4229
+ ```
4230
+
4231
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
4232
+
4233
+ ```
4234
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_transform'"
4235
+ ```
4236
+
4237
+ Mac
4238
+
4239
+ ![glimmer-dsl-libui-mac-basic-transform.png](images/glimmer-dsl-libui-mac-basic-transform.png)
4240
+
4241
+ Linux
4242
+
4243
+ ![glimmer-dsl-libui-linux-basic-transform.png](images/glimmer-dsl-libui-linux-basic-transform.png)
4244
+
4245
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
4246
+
4247
+ ```ruby
4248
+ require 'glimmer-dsl-libui'
4249
+
4250
+ include Glimmer
4251
+
4252
+ window('Basic Transform', 350, 350) {
4253
+ area {
4254
+ path {
4255
+ square(0, 0, 350)
4256
+
4257
+ fill r: 255, g: 255, b: 0
4258
+ }
4259
+ 40.times do |n|
4260
+ path {
4261
+ square(0, 0, 100)
4262
+
4263
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
4264
+ stroke :black, thickness: 2
4265
+ transform {
4266
+ skew 0.15, 0.15
4267
+ translate 50, 50
4268
+ rotate 100, 100, -9 * n
4269
+ scale 1.1, 1.1
4270
+ }
4271
+ }
4272
+ end
4273
+ }
4274
+ }.show
4275
+ ```
4276
+
3593
4277
  ## Contributing to glimmer-dsl-libui
3594
4278
 
3595
4279
  - Check out the latest master to make sure the feature hasn't been