glimmer-dsl-libui 0.1.4 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
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