glimmer-dsl-libui 0.1.3 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +901 -104
  4. data/VERSION +1 -1
  5. data/examples/area_gallery.rb +36 -38
  6. data/examples/area_gallery2.rb +111 -0
  7. data/examples/area_gallery3.rb +52 -0
  8. data/examples/area_gallery4.rb +113 -0
  9. data/examples/basic_area2.rb +1 -1
  10. data/examples/basic_button.rb +2 -2
  11. data/examples/basic_entry.rb +2 -2
  12. data/examples/basic_table_progress_bar.rb +13 -3
  13. data/examples/basic_transform.rb +27 -0
  14. data/examples/control_gallery.rb +3 -3
  15. data/examples/dynamic_area.rb +1 -1
  16. data/examples/form.rb +2 -2
  17. data/examples/histogram.rb +118 -0
  18. data/examples/meta_example.rb +71 -20
  19. data/examples/midi_player.rb +8 -10
  20. data/glimmer-dsl-libui.gemspec +0 -0
  21. data/lib/glimmer/dsl/libui/control_expression.rb +0 -2
  22. data/lib/glimmer/dsl/libui/file_expression.rb +5 -1
  23. data/lib/glimmer/dsl/libui/shape_expression.rb +2 -4
  24. data/lib/glimmer/dsl/libui/tab_item_expression.rb +2 -2
  25. data/lib/glimmer/libui/control_proxy/area_proxy.rb +117 -0
  26. data/lib/glimmer/libui/{menu_item_proxy.rb → control_proxy/box/horizontal_box_proxy.rb} +9 -12
  27. data/lib/glimmer/libui/{horizontal_box_proxy.rb → control_proxy/box/vertical_box_proxy.rb} +10 -6
  28. data/lib/glimmer/libui/{box.rb → control_proxy/box.rb} +31 -27
  29. data/lib/glimmer/libui/{button_proxy.rb → control_proxy/button_proxy.rb} +14 -12
  30. data/lib/glimmer/libui/{checkbox_proxy.rb → control_proxy/checkbox_proxy.rb} +14 -12
  31. data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +118 -0
  32. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +76 -0
  33. data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +46 -0
  34. data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +80 -0
  35. data/lib/glimmer/libui/{radio_buttons_proxy.rb → control_proxy/column/image_column_proxy.rb} +14 -13
  36. data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +48 -0
  37. data/lib/glimmer/libui/control_proxy/column/progress_bar_column_proxy.rb +44 -0
  38. data/lib/glimmer/libui/{checkbox_column_proxy.rb → control_proxy/column/text_column_proxy.rb} +17 -13
  39. data/lib/glimmer/libui/control_proxy/column.rb +55 -0
  40. data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +45 -0
  41. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/date_picker_proxy.rb +43 -0
  42. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/time_picker_proxy.rb +43 -0
  43. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +72 -0
  44. data/lib/glimmer/libui/control_proxy/dual_column.rb +40 -0
  45. data/lib/glimmer/libui/control_proxy/editable_column.rb +46 -0
  46. data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +45 -0
  47. data/lib/glimmer/libui/{dual_column.rb → control_proxy/enableable_column.rb} +18 -10
  48. data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +70 -0
  49. data/lib/glimmer/libui/{form_proxy.rb → control_proxy/form_proxy.rb} +26 -24
  50. data/lib/glimmer/libui/{grid_proxy.rb → control_proxy/grid_proxy.rb} +29 -27
  51. data/lib/glimmer/libui/{group_proxy.rb → control_proxy/group_proxy.rb} +24 -22
  52. data/lib/glimmer/libui/{image_part_proxy.rb → control_proxy/image_part_proxy.rb} +20 -18
  53. data/lib/glimmer/libui/{image_proxy.rb → control_proxy/image_proxy.rb} +32 -30
  54. data/lib/glimmer/libui/{combobox_proxy.rb → control_proxy/label_proxy.rb} +13 -13
  55. data/lib/glimmer/libui/control_proxy/matrix_proxy.rb +147 -0
  56. data/lib/glimmer/libui/{editable_column.rb → control_proxy/menu_item_proxy/about_menu_item_proxy.rb} +13 -16
  57. data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +41 -0
  58. data/lib/glimmer/libui/{date_picker_proxy.rb → control_proxy/menu_item_proxy/preferences_menu_item_proxy.rb} +10 -10
  59. data/lib/glimmer/libui/{quit_menu_item_proxy.rb → control_proxy/menu_item_proxy/quit_menu_item_proxy.rb} +33 -29
  60. data/lib/glimmer/libui/control_proxy/menu_item_proxy/separator_menu_item_proxy.rb +41 -0
  61. data/lib/glimmer/libui/control_proxy/menu_item_proxy.rb +45 -0
  62. data/lib/glimmer/libui/{editable_combobox_proxy.rb → control_proxy/menu_proxy.rb} +13 -13
  63. data/lib/glimmer/libui/{vertical_box_proxy.rb → control_proxy/message_box/msg_box_error_proxy.rb} +9 -6
  64. data/lib/glimmer/libui/{multiline_entry_proxy.rb → control_proxy/message_box/msg_box_proxy.rb} +8 -6
  65. data/lib/glimmer/libui/{time_picker_proxy.rb → control_proxy/message_box.rb} +9 -10
  66. data/lib/glimmer/libui/{rectangle.rb → control_proxy/multiline_entry_proxy/non_wrapping_multiline_entry_proxy.rb} +6 -7
  67. data/lib/glimmer/libui/{progress_bar_column_proxy.rb → control_proxy/multiline_entry_proxy.rb} +10 -11
  68. data/lib/glimmer/libui/control_proxy/path_proxy.rb +190 -0
  69. data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +45 -0
  70. data/lib/glimmer/libui/{button_column_proxy.rb → control_proxy/tab_item_proxy.rb} +37 -40
  71. data/lib/glimmer/libui/control_proxy/table_proxy.rb +182 -0
  72. data/lib/glimmer/libui/control_proxy/transformable.rb +74 -0
  73. data/lib/glimmer/libui/control_proxy/window_proxy.rb +128 -0
  74. data/lib/glimmer/libui/control_proxy.rb +39 -20
  75. data/lib/glimmer/libui/{enableable_column.rb → parent.rb} +7 -15
  76. data/lib/glimmer/libui/{arc.rb → shape/arc.rb} +13 -10
  77. data/lib/glimmer/libui/shape/bezier.rb +38 -0
  78. data/lib/glimmer/libui/{figure.rb → shape/figure.rb} +23 -20
  79. data/lib/glimmer/libui/{line.rb → shape/line.rb} +9 -6
  80. data/lib/glimmer/libui/{bezier.rb → shape/rectangle.rb} +9 -6
  81. data/lib/glimmer/libui/{square.rb → shape/square.rb} +9 -6
  82. data/lib/glimmer/libui/shape.rb +30 -14
  83. data/lib/glimmer/libui.rb +92 -0
  84. data/lib/glimmer-dsl-libui.rb +2 -0
  85. metadata +79 -53
  86. data/lib/glimmer/libui/about_menu_item_proxy.rb +0 -37
  87. data/lib/glimmer/libui/area_proxy.rb +0 -105
  88. data/lib/glimmer/libui/check_menu_item_proxy.rb +0 -37
  89. data/lib/glimmer/libui/checkbox_text_column_proxy.rb +0 -76
  90. data/lib/glimmer/libui/color_button_proxy.rb +0 -64
  91. data/lib/glimmer/libui/column.rb +0 -51
  92. data/lib/glimmer/libui/date_time_picker_proxy.rb +0 -68
  93. data/lib/glimmer/libui/font_button_proxy.rb +0 -68
  94. data/lib/glimmer/libui/image_column_proxy.rb +0 -40
  95. data/lib/glimmer/libui/image_text_column_proxy.rb +0 -44
  96. data/lib/glimmer/libui/label_proxy.rb +0 -41
  97. data/lib/glimmer/libui/menu_proxy.rb +0 -41
  98. data/lib/glimmer/libui/non_wrapping_multiline_entry_proxy.rb +0 -32
  99. data/lib/glimmer/libui/path_proxy.rb +0 -169
  100. data/lib/glimmer/libui/preferences_menu_item_proxy.rb +0 -37
  101. data/lib/glimmer/libui/separator_menu_item_proxy.rb +0 -37
  102. data/lib/glimmer/libui/tab_item_proxy.rb +0 -67
  103. data/lib/glimmer/libui/table_proxy.rb +0 -180
  104. data/lib/glimmer/libui/text_column_proxy.rb +0 -42
  105. 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.3
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.7
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)
@@ -47,13 +47,23 @@ data = [
47
47
  ['task 5', -1],
48
48
  ]
49
49
 
50
- window('Task progress', 300, 200) {
51
- horizontal_box {
50
+ window('Task Progress', 300, 200) {
51
+ vertical_box {
52
52
  table {
53
53
  text_column('Task')
54
54
  progress_bar_column('Progress')
55
55
 
56
- cell_rows data
56
+ cell_rows data # implicit data-binding
57
+ }
58
+
59
+ button('Mark All As Done') {
60
+ stretchy false
61
+
62
+ on_clicked do
63
+ data.each_with_index do |row_data, row|
64
+ data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
65
+ end
66
+ end
57
67
  }
58
68
  }
59
69
  }.show
@@ -70,50 +80,48 @@ require 'glimmer-dsl-libui'
70
80
  include Glimmer
71
81
 
72
82
  window('Area Gallery', 400, 400) {
73
- vertical_box {
74
- area {
75
- path { # declarative stable path
76
- square(0, 0, 100)
77
- square(100, 100, 400)
78
-
79
- fill r: 102, g: 102, b: 204
80
- }
81
- path { # declarative stable path
82
- rectangle(0, 100, 100, 400)
83
- rectangle(100, 0, 400, 100)
84
-
85
- fill r: 204, g: 102, b: 204
86
- }
87
- path { # declarative stable path
88
- figure(100, 100) {
89
- line(100, 400)
90
- line(400, 100)
91
- line(400, 400)
92
-
93
- closed true
94
- }
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)
95
101
 
96
- fill r: 202, g: 102, b: 104, a: 0.5
97
- stroke thickness: 1, r: 0, g: 0, b: 0
102
+ closed true
98
103
  }
99
- path { # declarative stable path
100
- figure(0, 0) {
101
- bezier(200, 100, 100, 200, 400, 100)
102
- bezier(300, 100, 100, 300, 100, 400)
103
- bezier(100, 300, 300, 100, 400, 400)
104
104
 
105
- closed true
106
- }
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)
107
113
 
108
- fill r: 202, g: 102, b: 204, a: 0.5
109
- stroke thickness: 2, r: 0, g: 0, b: 0
114
+ closed true
110
115
  }
111
- path { # declarative stable path
112
- arc(200, 200, 90, 0, 360, false)
113
116
 
114
- fill r: 202, g: 102, b: 204, a: 0.5
115
- stroke thickness: 2, r: 0, g: 0, b: 0
116
- }
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
117
125
  }
118
126
  }
119
127
  }.show
@@ -135,7 +143,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
135
143
 
136
144
  ## Table of Contents
137
145
 
138
- - [Glimmer DSL for LibUI 0.1.3](#-glimmer-dsl-for-libui-013)
146
+ - [Glimmer DSL for LibUI 0.1.7](#-glimmer-dsl-for-libui-017)
139
147
  - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
140
148
  - [Usage](#usage)
141
149
  - [Girb (Glimmer IRB)](#girb-glimmer-irb)
@@ -176,6 +184,8 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
176
184
  - [Basic Area](#basic-area)
177
185
  - [Dynamic Area](#dynamic-area)
178
186
  - [Area Gallery](#area-gallery)
187
+ - [Histogram](#histogram)
188
+ - [Basic Transform](#basic-transform)
179
189
  - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
180
190
  - [Help](#help)
181
191
  - [Issues](#issues)
@@ -239,10 +249,10 @@ require 'glimmer-dsl-libui'
239
249
 
240
250
  include Glimmer
241
251
 
242
- window('hello world', 300, 200) { |w|
252
+ window('hello world', 300, 200) {
243
253
  button('Button') {
244
254
  on_clicked do
245
- msg_box(w, 'Information', 'You clicked the button')
255
+ msg_box('Information', 'You clicked the button')
246
256
  end
247
257
  }
248
258
 
@@ -263,7 +273,7 @@ gem install glimmer-dsl-libui
263
273
  Or install via Bundler `Gemfile`:
264
274
 
265
275
  ```ruby
266
- gem 'glimmer-dsl-libui', '~> 0.1.3'
276
+ gem 'glimmer-dsl-libui', '~> 0.1.7'
267
277
  ```
268
278
 
269
279
  Add `require 'glimmer-dsl-libui'` at the top, and then `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
@@ -351,7 +361,7 @@ Control(Args) | Properties | Listeners
351
361
  `date_time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
352
362
  `editable_combobox` | `items` (`Array` of `String`), `text` (`String`) | `on_changed`
353
363
  `entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
354
- `figure(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `closed` (Boolean) | None
364
+ `figure(x=nil as Numeric, y=nil as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `closed` (Boolean) | None
355
365
  `font_button` | `font` [read-only] (`Hash` of keys: `:family`, `:size`, `:weight`, `:italic`, `:stretch`), `family` as `String`, `size` as `Float`, `weight` as `Integer`, `italic` as `Integer`, `stretch` as `Integer` | `on_changed`
356
366
  `form` | `padded` (Boolean) | None
357
367
  `grid` | `padded` (Boolean) | None
@@ -364,13 +374,14 @@ Control(Args) | Properties | Listeners
364
374
  `image_text_column(name as String)` | None | None
365
375
  `label(text as String)` | `text` (`String`) | None
366
376
  `line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
377
+ `matrix(m11 = nil as Numeric, m12 = nil as Numeric, m21 = nil as Numeric, m22 = nil as Numeric, m31 = nil as Numeric, m32 = nil as Numeric)` | `m11` (`Numeric`), `m12` (`Numeric`), `m21` (`Numeric`), `m22` (`Numeric`), `m31` (`Numeric`), `m32` (`Numeric`) | None
367
378
  `menu(text as String)` | None | None
368
379
  `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
369
380
  `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
370
- `msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
371
- `msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
381
+ `msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
382
+ `msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
372
383
  `non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
373
- `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
384
+ `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
374
385
  `preferences_menu_item` | None | `on_clicked`
375
386
  `progress_bar` | `value` (`Numeric`) | None
376
387
  `progress_bar_column(name as String)` | None | None
@@ -384,7 +395,7 @@ Control(Args) | Properties | Listeners
384
395
  `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
385
396
  `table` | `cell_rows` (`Array` (rows) of `Arrays` (row columns) of cell values (e.g. `String` values for `text_column` cells or `Array` of `image`/`String` for `image_text_column`)), `editable` as Boolean | None
386
397
  `text_column(name as String)` | `editable` (Boolean) | None
387
- `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
398
+ `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
388
399
  `vertical_box` | `padded` (Boolean) | None
389
400
  `window(title as String, width as Integer, height as Integer, has_menubar as Boolean)` | `borderless` (Boolean), `content_size` (width `Numeric`, height `Numeric`), `fullscreen` (Boolean), `margined` (Boolean), `title` (`String`) | `on_closing`, `on_content_size_changed`, `on_destroy`
390
401
 
@@ -520,9 +531,9 @@ Learn more by checking out [examples](#examples).
520
531
 
521
532
  ### Area API
522
533
 
523
- The `area` control can be used in one of two ways:
524
- - 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).
525
- - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block and nest `path(area_draw_params)` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
534
+ The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
535
+ - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be few stable paths (mostly for decorative reasons).
536
+ - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block that receives a `area_draw_params` argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
526
537
 
527
538
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
528
539
 
@@ -548,7 +559,7 @@ window('Basic Area', 400, 400) {
548
559
 
549
560
  ![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
550
561
 
551
- Here is the same example using a semi-declarative `area` with `on_draw` listener and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
562
+ Here is the same example using a semi-declarative `area` with `on_draw` listener that receives a `area_draw_params` argument and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
552
563
 
553
564
  ```ruby
554
565
  require 'glimmer-dsl-libui'
@@ -561,7 +572,7 @@ window('Basic Area', 400, 400) {
561
572
  vertical_box {
562
573
  area {
563
574
  on_draw do |area_draw_params|
564
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
575
+ path { # a dynamic path is added semi-declaratively inside on_draw block
565
576
  rectangle(0, 0, 400, 400)
566
577
 
567
578
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -574,24 +585,110 @@ window('Basic Area', 400, 400) {
574
585
 
575
586
  Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
576
587
 
588
+ `path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
589
+
577
590
  Available nested `path` shapes:
578
591
  - `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)`
579
592
  - `square(x as Numeric, y as Numeric, length as Numeric)`
580
593
  - `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
581
594
  - `line(x as Numeric, y as Numeric)`
582
595
  - `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)`
583
- - `figure(x as Numeric, y as Numeric)` (composite that can contain other shapes) (can set `closed true` to connect last point to first point automatically)
596
+ - `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)
597
+
598
+ Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
584
599
 
585
- 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.
600
+ The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
601
+ - `:context`: the drawing context object
602
+ - `:area_width`: area width
603
+ - `:area_height`: area height
604
+ - `:clip_x`: clip region top-left x coordinate
605
+ - `:clip_y`: clip region top-left y coordinate
606
+ - `:clip_width`: clip region width
607
+ - `:clip_height`: clip region height
586
608
 
587
- To redraw an `area`, you may call `#queue_redraw_all` method.
609
+ 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.
610
+
611
+ 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.
612
+
613
+ To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
614
+
615
+ 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.
616
+
617
+ When instantiating a `matrix` object, it always starts with identity matrix.
618
+
619
+ Here are the following operations that can be performed in a `matrix` body:
620
+ - `identity` [alias: `set_identity`]: resets matrix to identity matrix
621
+ - `translate(x as Numeric, y as Numeric)`
622
+ - `scale(x_center = 0 as Numeric, y_center = 0 as Numeric, x as Numeric, y as Numeric)`
623
+ - `skew(x = 0 as Numeric, y = 0 as Numeric, x_amount as Numeric, y_amount as Numeric)`
624
+ - `rotate(x = 0 as Numeric, y = 0 as Numeric, degrees as Numeric)`
625
+
626
+ Example of using transform matrix (you may copy/paste in [`girb`](#girb-glimmer-irb)):
627
+
628
+ ```ruby
629
+ require 'glimmer-dsl-libui'
630
+
631
+ include Glimmer
632
+
633
+ window('Basic Transform', 350, 350) {
634
+ area {
635
+ path {
636
+ square(0, 0, 350)
637
+
638
+ fill r: 255, g: 255, b: 0
639
+ }
640
+ 40.times do |n|
641
+ path {
642
+ square(0, 0, 100)
643
+
644
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
645
+ stroke :black, thickness: 2
646
+ transform {
647
+ skew 0.15, 0.15
648
+ translate 50, 50
649
+ rotate 100, 100, -9 * n
650
+ scale 1.1, 1.1
651
+ }
652
+ }
653
+ end
654
+ }
655
+ }.show
656
+ ```
657
+
658
+ Keep in mind that this part could be written differently when there is a need to reuse the matrix:
659
+
660
+ ```ruby
661
+ transform {
662
+ translate 100, 100
663
+ rotate 100, 100, -9 * n
664
+ }
665
+ ```
666
+
667
+ Alternatively:
668
+
669
+ ```ruby
670
+ m1 = matrix {
671
+ translate 100, 100
672
+ rotate 100, 100, -9 * n
673
+ }
674
+ transform m1
675
+ # and then reuse m1 elsewhere too
676
+ ```
677
+
678
+ 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.
679
+
680
+ `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)
681
+
682
+ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
683
+
684
+ Check [Histogram](#histogram) example for use of hex colors.
588
685
 
589
686
  ### Smart Defaults and Conventions
590
687
 
591
688
  - `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
592
689
  - `group` controls have `margined` as `true` upon instantiation to ensure more user-friendly GUI by default
593
690
  - 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)
594
- - `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`)
691
+ - `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`)
595
692
  - `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)
596
693
  - `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'; ...}`)
597
694
  - `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'}}`)
@@ -617,11 +714,17 @@ To redraw an `area`, you may call `#queue_redraw_all` method.
617
714
  - `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
618
715
  - Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
619
716
  - Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
717
+ - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
718
+ - All resources are freed automatically once no longer needed or left to garbage collection.
719
+ - 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.
720
+ - 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)
721
+ - Color alpha value defaults to `1.0` when not specified.
620
722
 
621
723
  ### API Gotchas
622
724
 
623
725
  - There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`).
624
726
  - `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on Windows and Linux (not Mac) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
727
+ - It seems that `arc` `start_angle` and `sweep` properties are ignored by [libui](https://github.com/andlabs/libui) and always set to `0` and `360` respectively, producing a full circle.
625
728
 
626
729
  ### Original API
627
730
 
@@ -693,7 +796,7 @@ class MetaExample
693
796
  end
694
797
 
695
798
  def launch
696
- window('Meta-Example', 700, 500) { |w|
799
+ window('Meta-Example', 700, 500) {
697
800
  margined true
698
801
 
699
802
  horizontal_box {
@@ -715,7 +818,7 @@ class MetaExample
715
818
  meta_example_file = File.join(Dir.home, '.meta_example.rb')
716
819
  File.write(meta_example_file, @nwme.text)
717
820
  result = `ruby -r #{glimmer_dsl_libui_file} #{meta_example_file} 2>&1`
718
- msg_box(w, 'Error Running Example', result) if result.include?('error')
821
+ msg_box('Error Running Example', result) if result.include?('error')
719
822
  rescue => e
720
823
  puts 'Unable to write code changes! Running original example...'
721
824
  system "ruby -r #{glimmer_dsl_libui_file} #{file_path_for(@examples[@rbs.selected])}"
@@ -799,7 +902,7 @@ window('hello world', 300, 200, true) {
799
902
  }.show
800
903
  ```
801
904
 
802
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
905
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting `window` properties instead of arguments):
803
906
 
804
907
  ```ruby
805
908
  require 'glimmer-dsl-libui'
@@ -880,10 +983,10 @@ require 'glimmer-dsl-libui'
880
983
 
881
984
  include Glimmer
882
985
 
883
- window('hello world', 300, 200) { |w|
986
+ window('hello world', 300, 200) {
884
987
  button('Button') {
885
988
  on_clicked do
886
- msg_box(w, 'Information', 'You clicked the button')
989
+ msg_box('Information', 'You clicked the button')
887
990
  end
888
991
  }
889
992
 
@@ -967,7 +1070,7 @@ require 'glimmer-dsl-libui'
967
1070
 
968
1071
  include Glimmer
969
1072
 
970
- window('Basic Entry', 300, 50) { |w|
1073
+ window('Basic Entry', 300, 50) {
971
1074
  horizontal_box {
972
1075
  e = entry {
973
1076
  # stretchy true # Smart default option for appending to horizontal_box
@@ -983,7 +1086,7 @@ window('Basic Entry', 300, 50) { |w|
983
1086
 
984
1087
  on_clicked do
985
1088
  text = e.text
986
- msg_box(w, 'You entered', text)
1089
+ msg_box('You entered', text)
987
1090
  end
988
1091
  }
989
1092
  }
@@ -1087,12 +1190,12 @@ ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"
1087
1190
  Mac
1088
1191
 
1089
1192
  ![glimmer-dsl-libui-mac-midi-player.png](images/glimmer-dsl-libui-mac-midi-player.png)
1090
- ![glimmer-dsl-libui-mac-midi-player-version-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-version-msg-box.png)
1193
+ ![glimmer-dsl-libui-mac-midi-player-msg-box.png](images/glimmer-dsl-libui-mac-midi-player-msg-box.png)
1091
1194
 
1092
1195
  Linux
1093
1196
 
1094
1197
  ![glimmer-dsl-libui-linux-midi-player.png](images/glimmer-dsl-libui-linux-midi-player.png)
1095
- ![glimmer-dsl-libui-linux-midi-player-version-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-version-msg-box.png)
1198
+ ![glimmer-dsl-libui-linux-midi-player-msg-box.png](images/glimmer-dsl-libui-linux-midi-player-msg-box.png)
1096
1199
 
1097
1200
  [LibUI](https://github.com/kojix2/LibUI) Original Version:
1098
1201
 
@@ -1238,23 +1341,22 @@ class TinyMidiPlayer
1238
1341
  end
1239
1342
  end
1240
1343
 
1241
- def show_version(main_window)
1242
- msg_box(main_window,
1243
- 'Tiny Midi Player',
1244
- "Written in Ruby\n" \
1245
- "https://github.com/kojix2/libui\n" \
1246
- "Version #{VERSION}")
1344
+ def show_version
1345
+ msg_box('Tiny Midi Player',
1346
+ "Written in Ruby\n" \
1347
+ "https://github.com/kojix2/libui\n" \
1348
+ "Version #{VERSION}")
1247
1349
  end
1248
1350
 
1249
1351
  def create_gui
1250
1352
  menu('Help') { |m|
1251
1353
  menu_item('Version') {
1252
1354
  on_clicked do
1253
- show_version(@main_window)
1355
+ show_version
1254
1356
  end
1255
1357
  }
1256
1358
  }
1257
- @main_window = window('Tiny Midi Player', 200, 50) {
1359
+ window('Tiny Midi Player', 200, 50) {
1258
1360
  horizontal_box {
1259
1361
  vertical_box {
1260
1362
  stretchy false
@@ -1270,7 +1372,7 @@ class TinyMidiPlayer
1270
1372
  end
1271
1373
  }
1272
1374
  }
1273
-
1375
+
1274
1376
  combobox { |c|
1275
1377
  items @midi_files.map { |path| File.basename(path) }
1276
1378
 
@@ -1280,8 +1382,7 @@ class TinyMidiPlayer
1280
1382
  end
1281
1383
  }
1282
1384
  }
1283
- }
1284
- @main_window.show
1385
+ }.show
1285
1386
  end
1286
1387
  end
1287
1388
 
@@ -1517,14 +1618,14 @@ include Glimmer
1517
1618
  menu('File') {
1518
1619
  menu_item('Open') {
1519
1620
  on_clicked do
1520
- file = open_file(MAIN_WINDOW)
1621
+ file = open_file
1521
1622
  puts file unless file.nil?
1522
1623
  end
1523
1624
  }
1524
1625
 
1525
1626
  menu_item('Save') {
1526
1627
  on_clicked do
1527
- file = save_file(MAIN_WINDOW)
1628
+ file = save_file
1528
1629
  puts file unless file.nil?
1529
1630
  end
1530
1631
  }
@@ -1567,7 +1668,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1567
1668
  stretchy false
1568
1669
 
1569
1670
  on_clicked do
1570
- msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
1671
+ msg_box('Information', 'You clicked the button')
1571
1672
  end
1572
1673
  }
1573
1674
 
@@ -1575,7 +1676,7 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
1575
1676
  stretchy false
1576
1677
 
1577
1678
  on_toggled do |c|
1578
- checked = c.checked == 1
1679
+ checked = c.checked?
1579
1680
  MAIN_WINDOW.title = "Checkbox is #{checked}"
1580
1681
  c.text = "I am the checkbox (#{checked})"
1581
1682
  end
@@ -2029,7 +2130,7 @@ require 'glimmer-dsl-libui'
2029
2130
 
2030
2131
  include Glimmer
2031
2132
 
2032
- window('Form') { |w|
2133
+ window('Form') {
2033
2134
  margined true
2034
2135
 
2035
2136
  vertical_box {
@@ -2045,7 +2146,7 @@ window('Form') { |w|
2045
2146
 
2046
2147
  button('Display Name') {
2047
2148
  on_clicked do
2048
- msg_box(w, 'Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
2149
+ msg_box('Name', "#{@first_name_entry.text} #{@last_name_entry.text}")
2049
2150
  end
2050
2151
  }
2051
2152
  }
@@ -2729,13 +2830,23 @@ data = [
2729
2830
  ['task 5', -1],
2730
2831
  ]
2731
2832
 
2732
- window('Task progress', 300, 200) {
2733
- horizontal_box {
2833
+ window('Task Progress', 300, 200) {
2834
+ vertical_box {
2734
2835
  table {
2735
2836
  text_column('Task')
2736
2837
  progress_bar_column('Progress')
2737
2838
 
2738
- cell_rows data
2839
+ cell_rows data # implicit data-binding
2840
+ }
2841
+
2842
+ button('Mark All As Done') {
2843
+ stretchy false
2844
+
2845
+ on_clicked do
2846
+ data.each_with_index do |row_data, row|
2847
+ data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
2848
+ end
2849
+ end
2739
2850
  }
2740
2851
  }
2741
2852
  }.show
@@ -2935,7 +3046,7 @@ window('Basic Area', 400, 400) {
2935
3046
  }.show
2936
3047
  ```
2937
3048
 
2938
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3049
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (semi-declarative `on_draw` dynamic `path` approach):
2939
3050
 
2940
3051
  ```ruby
2941
3052
  require 'glimmer-dsl-libui'
@@ -2948,7 +3059,7 @@ window('Basic Area', 400, 400) {
2948
3059
  vertical_box {
2949
3060
  area {
2950
3061
  on_draw do |area_draw_params|
2951
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3062
+ path { # a dynamic path is added semi-declaratively inside on_draw block
2952
3063
  rectangle(0, 0, 400, 400)
2953
3064
 
2954
3065
  fill r: 102, g: 102, b: 204, a: 1.0
@@ -3078,7 +3189,7 @@ window('Dynamic Area', 240, 500) {
3078
3189
 
3079
3190
  @area = area {
3080
3191
  on_draw do |area_draw_params|
3081
- path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
3192
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3082
3193
  rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
3083
3194
 
3084
3195
  fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
@@ -3089,7 +3200,7 @@ window('Dynamic Area', 240, 500) {
3089
3200
  }.show
3090
3201
  ```
3091
3202
 
3092
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
3203
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (declarative stable `path` approach):
3093
3204
 
3094
3205
  ```ruby
3095
3206
  require 'glimmer-dsl-libui'
@@ -3223,21 +3334,192 @@ require 'glimmer-dsl-libui'
3223
3334
  include Glimmer
3224
3335
 
3225
3336
  window('Area Gallery', 400, 400) {
3226
- vertical_box {
3227
- area {
3228
- path { # declarative stable path
3337
+ area {
3338
+ path { # declarative stable path
3339
+ square(0, 0, 100)
3340
+ square(100, 100, 400)
3341
+
3342
+ fill r: 102, g: 102, b: 204
3343
+ }
3344
+ path { # declarative stable path
3345
+ rectangle(0, 100, 100, 400)
3346
+ rectangle(100, 0, 400, 100)
3347
+
3348
+ fill r: 204, g: 102, b: 204
3349
+ }
3350
+ path { # declarative stable path
3351
+ figure(100, 100) {
3352
+ line(100, 400)
3353
+ line(400, 100)
3354
+ line(400, 400)
3355
+
3356
+ closed true
3357
+ }
3358
+
3359
+ fill r: 202, g: 102, b: 104, a: 0.5
3360
+ stroke r: 0, g: 0, b: 0
3361
+ }
3362
+ path { # declarative stable path
3363
+ figure(0, 0) {
3364
+ bezier(200, 100, 100, 200, 400, 100)
3365
+ bezier(300, 100, 100, 300, 100, 400)
3366
+ bezier(100, 300, 300, 100, 400, 400)
3367
+
3368
+ closed true
3369
+ }
3370
+
3371
+ fill r: 202, g: 102, b: 204, a: 0.5
3372
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3373
+ }
3374
+ path { # declarative stable path
3375
+ arc(200, 200, 90, 0, 360, false)
3376
+
3377
+ fill r: 202, g: 102, b: 204, a: 0.5
3378
+ stroke r: 0, g: 0, b: 0, thickness: 2
3379
+ }
3380
+ }
3381
+ }.show
3382
+ ```
3383
+
3384
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting shape properties instead of arguments):
3385
+
3386
+ ```ruby
3387
+ require 'glimmer-dsl-libui'
3388
+
3389
+ include Glimmer
3390
+
3391
+ window('Area Gallery', 400, 400) {
3392
+ area {
3393
+ path { # declarative stable path
3394
+ square {
3395
+ x 0
3396
+ y 0
3397
+ length 100
3398
+ }
3399
+ square {
3400
+ x 100
3401
+ y 100
3402
+ length 400
3403
+ }
3404
+
3405
+ fill r: 102, g: 102, b: 204
3406
+ }
3407
+ path { # declarative stable path
3408
+ rectangle {
3409
+ x 0
3410
+ y 100
3411
+ width 100
3412
+ height 400
3413
+ }
3414
+ rectangle {
3415
+ x 100
3416
+ y 0
3417
+ width 400
3418
+ height 100
3419
+ }
3420
+
3421
+ fill r: 204, g: 102, b: 204
3422
+ }
3423
+ path { # declarative stable path
3424
+ figure {
3425
+ x 100
3426
+ y 100
3427
+
3428
+ line {
3429
+ x 100
3430
+ y 400
3431
+ }
3432
+ line {
3433
+ x 400
3434
+ y 100
3435
+ }
3436
+ line {
3437
+ x 400
3438
+ y 400
3439
+ }
3440
+
3441
+ closed true
3442
+ }
3443
+
3444
+ fill r: 202, g: 102, b: 104, a: 0.5
3445
+ stroke r: 0, g: 0, b: 0
3446
+ }
3447
+ path { # declarative stable path
3448
+ figure {
3449
+ x 0
3450
+ y 0
3451
+
3452
+ bezier {
3453
+ c1_x 200
3454
+ c1_y 100
3455
+ c2_x 100
3456
+ c2_y 200
3457
+ end_x 400
3458
+ end_y 100
3459
+ }
3460
+ bezier {
3461
+ c1_x 300
3462
+ c1_y 100
3463
+ c2_x 100
3464
+ c2_y 300
3465
+ end_x 100
3466
+ end_y 400
3467
+ }
3468
+ bezier {
3469
+ c1_x 100
3470
+ c1_y 300
3471
+ c2_x 300
3472
+ c2_y 100
3473
+ end_x 400
3474
+ end_y 400
3475
+ }
3476
+
3477
+ closed true
3478
+ }
3479
+
3480
+ fill r: 202, g: 102, b: 204, a: 0.5
3481
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3482
+ }
3483
+ path { # declarative stable path
3484
+ arc {
3485
+ x_center 200
3486
+ y_center 200
3487
+ radius 90
3488
+ start_angle 0
3489
+ sweep 360
3490
+ is_negative false
3491
+ }
3492
+
3493
+ fill r: 202, g: 102, b: 204, a: 0.5
3494
+ stroke r: 0, g: 0, b: 0, thickness: 2
3495
+ }
3496
+ }
3497
+ }.show
3498
+ ```
3499
+
3500
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (semi-declarative `on_draw` dynamic `path` approach):
3501
+
3502
+ ```ruby
3503
+ require 'glimmer-dsl-libui'
3504
+
3505
+ include Glimmer
3506
+
3507
+ window('Area Gallery', 400, 400) {
3508
+ area {
3509
+ on_draw do |area_draw_params|
3510
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3229
3511
  square(0, 0, 100)
3230
3512
  square(100, 100, 400)
3231
3513
 
3232
3514
  fill r: 102, g: 102, b: 204
3233
3515
  }
3234
- path { # declarative stable path
3516
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3235
3517
  rectangle(0, 100, 100, 400)
3236
3518
  rectangle(100, 0, 400, 100)
3237
-
3519
+
3238
3520
  fill r: 204, g: 102, b: 204
3239
3521
  }
3240
- path { # declarative stable path
3522
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3241
3523
  figure(100, 100) {
3242
3524
  line(100, 400)
3243
3525
  line(400, 100)
@@ -3247,9 +3529,9 @@ window('Area Gallery', 400, 400) {
3247
3529
  }
3248
3530
 
3249
3531
  fill r: 202, g: 102, b: 104, a: 0.5
3250
- stroke thickness: 1, r: 0, g: 0, b: 0
3532
+ stroke r: 0, g: 0, b: 0
3251
3533
  }
3252
- path { # declarative stable path
3534
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3253
3535
  figure(0, 0) {
3254
3536
  bezier(200, 100, 100, 200, 400, 100)
3255
3537
  bezier(300, 100, 100, 300, 100, 400)
@@ -3259,15 +3541,530 @@ window('Area Gallery', 400, 400) {
3259
3541
  }
3260
3542
 
3261
3543
  fill r: 202, g: 102, b: 204, a: 0.5
3262
- stroke thickness: 2, r: 0, g: 0, b: 0
3544
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3263
3545
  }
3264
- path { # declarative stable path
3546
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3265
3547
  arc(200, 200, 90, 0, 360, false)
3266
3548
 
3267
3549
  fill r: 202, g: 102, b: 204, a: 0.5
3268
- stroke thickness: 2, r: 0, g: 0, b: 0
3550
+ stroke r: 0, g: 0, b: 0, thickness: 2
3551
+ }
3552
+ end
3553
+ }
3554
+ }.show
3555
+ ```
3556
+
3557
+ 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):
3558
+
3559
+ ```ruby
3560
+ require 'glimmer-dsl-libui'
3561
+
3562
+ include Glimmer
3563
+
3564
+ window('Area Gallery', 400, 400) {
3565
+ area {
3566
+ on_draw do |area_draw_params|
3567
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3568
+ square {
3569
+ x 0
3570
+ y 0
3571
+ length 100
3572
+ }
3573
+ square {
3574
+ x 100
3575
+ y 100
3576
+ length 400
3577
+ }
3578
+
3579
+ fill r: 102, g: 102, b: 204
3580
+ }
3581
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3582
+ rectangle {
3583
+ x 0
3584
+ y 100
3585
+ width 100
3586
+ height 400
3587
+ }
3588
+ rectangle {
3589
+ x 100
3590
+ y 0
3591
+ width 400
3592
+ height 100
3593
+ }
3594
+
3595
+ fill r: 204, g: 102, b: 204
3596
+ }
3597
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3598
+ figure {
3599
+ x 100
3600
+ y 100
3601
+
3602
+ line {
3603
+ x 100
3604
+ y 400
3605
+ }
3606
+ line {
3607
+ x 400
3608
+ y 100
3609
+ }
3610
+ line {
3611
+ x 400
3612
+ y 400
3613
+ }
3614
+
3615
+ closed true
3616
+ }
3617
+
3618
+ fill r: 202, g: 102, b: 104, a: 0.5
3619
+ stroke r: 0, g: 0, b: 0
3620
+ }
3621
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3622
+ figure {
3623
+ x 0
3624
+ y 0
3625
+
3626
+ bezier {
3627
+ c1_x 200
3628
+ c1_y 100
3629
+ c2_x 100
3630
+ c2_y 200
3631
+ end_x 400
3632
+ end_y 100
3633
+ }
3634
+ bezier {
3635
+ c1_x 300
3636
+ c1_y 100
3637
+ c2_x 100
3638
+ c2_y 300
3639
+ end_x 100
3640
+ end_y 400
3641
+ }
3642
+ bezier {
3643
+ c1_x 100
3644
+ c1_y 300
3645
+ c2_x 300
3646
+ c2_y 100
3647
+ end_x 400
3648
+ end_y 400
3649
+ }
3650
+
3651
+ closed true
3652
+ }
3653
+
3654
+ fill r: 202, g: 102, b: 204, a: 0.5
3655
+ stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3656
+ }
3657
+ path { # a dynamic path is added semi-declaratively inside on_draw block
3658
+ arc {
3659
+ x_center 200
3660
+ y_center 200
3661
+ radius 90
3662
+ start_angle 0
3663
+ sweep 360
3664
+ is_negative false
3665
+ }
3666
+
3667
+ fill r: 202, g: 102, b: 204, a: 0.5
3668
+ stroke r: 0, g: 0, b: 0, thickness: 2
3669
+ }
3670
+ end
3671
+ }
3672
+ }.show
3673
+ ```
3674
+
3675
+ ### Histogram
3676
+
3677
+ [examples/histogram.rb](examples/histogram.rb)
3678
+
3679
+ Run with this command from the root of the project if you cloned the project:
3680
+
3681
+ ```
3682
+ ruby -r './lib/glimmer-dsl-libui' examples/histogram.rb
3683
+ ```
3684
+
3685
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
3686
+
3687
+ ```
3688
+ ruby -r glimmer-dsl-libui -e "require 'examples/histogram'"
3689
+ ```
3690
+
3691
+ Mac
3692
+
3693
+ ![glimmer-dsl-libui-mac-histogram.png](images/glimmer-dsl-libui-mac-histogram.png)
3694
+
3695
+ Linux
3696
+
3697
+ ![glimmer-dsl-libui-linux-histogram.png](images/glimmer-dsl-libui-linux-histogram.png)
3698
+
3699
+ [LibUI](https://github.com/kojix2/LibUI) Original Version:
3700
+
3701
+ ```ruby
3702
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
3703
+
3704
+ require 'libui'
3705
+
3706
+ UI = LibUI
3707
+
3708
+ X_OFF_LEFT = 20
3709
+ Y_OFF_TOP = 20
3710
+ X_OFF_RIGHT = 20
3711
+ Y_OFF_BOTTOM = 20
3712
+ POINT_RADIUS = 5
3713
+
3714
+ init = UI.init
3715
+ handler = UI::FFI::AreaHandler.malloc
3716
+ histogram = UI.new_area(handler)
3717
+ brush = UI::FFI::DrawBrush.malloc
3718
+ color_button = UI.new_color_button
3719
+ blue = 0x1E90FF
3720
+ datapoints = []
3721
+
3722
+ def graph_size(area_width, area_height)
3723
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
3724
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
3725
+ [graph_width, graph_height]
3726
+ end
3727
+
3728
+ matrix = UI::FFI::DrawMatrix.malloc
3729
+
3730
+ def point_locations(datapoints, width, height)
3731
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
3732
+ yincr = height / 100.0
3733
+
3734
+ data = []
3735
+ datapoints.each_with_index do |dp, i|
3736
+ val = 100 - UI.spinbox_value(dp)
3737
+ data << [xincr * i, yincr * val]
3738
+ i += 1
3739
+ end
3740
+
3741
+ data
3742
+ end
3743
+
3744
+ def construct_graph(datapoints, width, height, should_extend)
3745
+ locations = point_locations(datapoints, width, height)
3746
+ path = UI.draw_new_path(0) # winding
3747
+ first_location = locations[0] # x and y
3748
+ UI.draw_path_new_figure(path, first_location[0], first_location[1])
3749
+ locations.each do |loc|
3750
+ UI.draw_path_line_to(path, loc[0], loc[1])
3751
+ end
3752
+
3753
+ if should_extend
3754
+ UI.draw_path_line_to(path, width, height)
3755
+ UI.draw_path_line_to(path, 0, height)
3756
+ UI.draw_path_close_figure(path)
3757
+ end
3758
+
3759
+ UI.draw_path_end(path)
3760
+
3761
+ path
3762
+ end
3763
+
3764
+ handler_draw_event = Fiddle::Closure::BlockCaller.new(
3765
+ 0, [1, 1, 1]
3766
+ ) do |_area_handler, _area, area_draw_params|
3767
+ area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
3768
+ path = UI.draw_new_path(0) # winding
3769
+ UI.draw_path_add_rectangle(path, 0, 0, area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3770
+ UI.draw_path_end(path)
3771
+ set_solid_brush(brush, 0xFFFFFF, 1.0) # white
3772
+ UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
3773
+ UI.draw_free_path(path)
3774
+ dsp = UI::FFI::DrawStrokeParams.malloc
3775
+ dsp.Cap = 0 # flat
3776
+ dsp.Join = 0 # miter
3777
+ dsp.Thickness = 2
3778
+ dsp.MiterLimit = 10 # DEFAULT_MITER_LIMIT
3779
+ dashes = Fiddle::Pointer.malloc(8)
3780
+ dsp.Dashes = dashes
3781
+ dsp.NumDashes = 0
3782
+ dsp.DashPhase = 0
3783
+
3784
+ # draw axes
3785
+ set_solid_brush(brush, 0x000000, 1.0) # black
3786
+ graph_width, graph_height = *graph_size(area_draw_params.AreaWidth, area_draw_params.AreaHeight)
3787
+
3788
+ path = UI.draw_new_path(0) # winding
3789
+ UI.draw_path_new_figure(path, X_OFF_LEFT, Y_OFF_TOP)
3790
+ UI.draw_path_line_to(path, X_OFF_LEFT, Y_OFF_TOP + graph_height)
3791
+ UI.draw_path_line_to(path, X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3792
+ UI.draw_path_end(path)
3793
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
3794
+ UI.draw_free_path(path)
3795
+
3796
+ # now transform the coordinate space so (0, 0) is the top-left corner of the graph
3797
+ UI.draw_matrix_set_identity(matrix)
3798
+ UI.draw_matrix_translate(matrix, X_OFF_LEFT, Y_OFF_TOP)
3799
+ UI.draw_transform(area_draw_params.Context, matrix)
3800
+
3801
+ # now get the color for the graph itself and set up the brush
3802
+ # uiColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA)
3803
+ graph_r = Fiddle::Pointer.malloc(8) # double
3804
+ graph_g = Fiddle::Pointer.malloc(8) # double
3805
+ graph_b = Fiddle::Pointer.malloc(8) # double
3806
+ graph_a = Fiddle::Pointer.malloc(8) # double
3807
+
3808
+ UI.color_button_color(color_button, graph_r, graph_g, graph_b, graph_a)
3809
+ brush.Type = 0 # solid
3810
+ brush.R = graph_r[0, 8].unpack1('d')
3811
+ brush.G = graph_g[0, 8].unpack1('d')
3812
+ brush.B = graph_b[0, 8].unpack1('d')
3813
+
3814
+ # now create the fill for the graph below the graph line
3815
+ path = construct_graph(datapoints, graph_width, graph_height, true)
3816
+ brush.A = graph_a[0, 8].unpack1('d') / 2.0
3817
+ UI.draw_fill(area_draw_params.Context, path, brush)
3818
+ UI.draw_free_path(path)
3819
+
3820
+ # now draw the histogram line
3821
+ path = construct_graph(datapoints, graph_width, graph_height, false)
3822
+ brush.A = graph_a[0, 8].unpack1('d')
3823
+ UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
3824
+ UI.draw_free_path(path)
3825
+ end
3826
+
3827
+ handler.Draw = handler_draw_event
3828
+
3829
+ # Assigning to local variables
3830
+ # This is intended to protect Fiddle::Closure from garbage collection.
3831
+ # See https://github.com/kojix2/LibUI/issues/8
3832
+ handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3833
+ handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3834
+ handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
3835
+ handler.KeyEvent = (c4 = Fiddle::Closure::BlockCaller.new(1, [0]) { 0 })
3836
+
3837
+ UI.freeInitError(init) unless init.nil?
3838
+
3839
+ hbox = UI.new_horizontal_box
3840
+ UI.box_set_padded(hbox, 1)
3841
+
3842
+ vbox = UI.new_vertical_box
3843
+ UI.box_set_padded(vbox, 1)
3844
+ UI.box_append(hbox, vbox, 0)
3845
+ UI.box_append(hbox, histogram, 1)
3846
+
3847
+ datapoints = Array.new(10) do
3848
+ UI.new_spinbox(0, 100).tap do |datapoint|
3849
+ UI.spinbox_set_value(datapoint, Random.new.rand(90))
3850
+ UI.spinbox_on_changed(datapoint) do
3851
+ UI.area_queue_redraw_all(histogram)
3852
+ end
3853
+ UI.box_append(vbox, datapoint, 0)
3854
+ end
3855
+ end
3856
+
3857
+ def set_solid_brush(brush, color, alpha)
3858
+ brush.Type = 0 # solid
3859
+ brush.R = ((color >> 16) & 0xFF) / 255.0
3860
+ brush.G = ((color >> 8) & 0xFF) / 255.0
3861
+ brush.B = (color & 0xFF) / 255.0
3862
+ brush.A = alpha
3863
+ brush
3864
+ end
3865
+
3866
+ set_solid_brush(brush, blue, 1.0)
3867
+ UI.color_button_set_color(color_button, brush.R, brush.G, brush.B, brush.A)
3868
+
3869
+ UI.color_button_on_changed(color_button) do
3870
+ UI.area_queue_redraw_all(histogram)
3871
+ end
3872
+
3873
+ UI.box_append(vbox, color_button, 0)
3874
+
3875
+ MAIN_WINDOW = UI.new_window('histogram example', 640, 480, 1)
3876
+ UI.window_set_margined(MAIN_WINDOW, 1)
3877
+ UI.window_set_child(MAIN_WINDOW, hbox)
3878
+
3879
+ should_quit = proc do |_ptr|
3880
+ UI.control_destroy(MAIN_WINDOW)
3881
+ UI.quit
3882
+ 0
3883
+ end
3884
+
3885
+ UI.window_on_closing(MAIN_WINDOW, should_quit)
3886
+ UI.on_should_quit(should_quit)
3887
+ UI.control_show(MAIN_WINDOW)
3888
+
3889
+ UI.main
3890
+ UI.quit
3891
+ ```
3892
+
3893
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3894
+
3895
+ ```ruby
3896
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
3897
+
3898
+ require 'glimmer-dsl-libui'
3899
+
3900
+ include Glimmer
3901
+
3902
+ X_OFF_LEFT = 20
3903
+ Y_OFF_TOP = 20
3904
+ X_OFF_RIGHT = 20
3905
+ Y_OFF_BOTTOM = 20
3906
+ POINT_RADIUS = 5
3907
+ COLOR_BLUE = 0x1E90FF
3908
+
3909
+ @datapoints = 10.times.map {Random.new.rand(90)}
3910
+
3911
+ def graph_size(area_width, area_height)
3912
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
3913
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
3914
+ [graph_width, graph_height]
3915
+ end
3916
+
3917
+ def point_locations(width, height)
3918
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
3919
+ yincr = height / 100.0
3920
+
3921
+ @datapoints.each_with_index.map do |value, i|
3922
+ val = 100 - value
3923
+ [xincr * i, yincr * val]
3924
+ end
3925
+ end
3926
+
3927
+ # method-based custom control representing a graph path
3928
+ def graph_path(width, height, should_extend, &block)
3929
+ locations = point_locations(width, height)
3930
+ path {
3931
+ first_location = locations[0] # x and y
3932
+ figure(first_location[0], first_location[1]) {
3933
+ locations.each do |loc|
3934
+ line(loc[0], loc[1])
3935
+ end
3936
+ if should_extend
3937
+ line(width, height)
3938
+ line(0, height)
3939
+
3940
+ closed true
3941
+ end
3942
+ }
3943
+
3944
+ # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
3945
+ transform {
3946
+ translate X_OFF_LEFT, Y_OFF_TOP
3947
+ }
3948
+
3949
+ block.call
3950
+ }
3951
+ end
3952
+
3953
+ window('histogram example', 640, 480) {
3954
+ margined true
3955
+
3956
+ horizontal_box {
3957
+ vertical_box {
3958
+ stretchy false
3959
+
3960
+ 10.times do |i|
3961
+ spinbox(0, 100) { |sb|
3962
+ stretchy false
3963
+ value @datapoints[i]
3964
+
3965
+ on_changed do
3966
+ @datapoints[i] = sb.value
3967
+ @area.queue_redraw_all
3968
+ end
3969
+ }
3970
+ end
3971
+
3972
+ @color_button = color_button {
3973
+ stretchy false
3974
+ color COLOR_BLUE
3975
+
3976
+ on_changed do
3977
+ @area.queue_redraw_all
3978
+ end
3269
3979
  }
3270
3980
  }
3981
+
3982
+ @area = area {
3983
+ on_draw do |area_draw_params|
3984
+ path {
3985
+ rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height])
3986
+
3987
+ fill 0xFFFFFF
3988
+ }
3989
+
3990
+ graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
3991
+
3992
+ path {
3993
+ figure(X_OFF_LEFT, Y_OFF_TOP) {
3994
+ line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
3995
+ line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
3996
+ }
3997
+
3998
+ stroke 0x000000, thickness: 2, miter_limit: 10
3999
+ }
4000
+
4001
+ # now create the fill for the graph below the graph line
4002
+ graph_path(graph_width, graph_height, true) {
4003
+ fill @color_button.color.merge(a: 0.5)
4004
+ }
4005
+
4006
+ # now draw the histogram line
4007
+ graph_path(graph_width, graph_height, false) {
4008
+ stroke @color_button.color.merge(thickness: 2, miter_limit: 10)
4009
+ }
4010
+ end
4011
+ }
4012
+ }
4013
+ }.show
4014
+ ```
4015
+
4016
+ ### Basic Transform
4017
+
4018
+ [examples/basic_transform.rb](examples/basic_transform.rb)
4019
+
4020
+ Run with this command from the root of the project if you cloned the project:
4021
+
4022
+ ```
4023
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_transform.rb
4024
+ ```
4025
+
4026
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
4027
+
4028
+ ```
4029
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_transform'"
4030
+ ```
4031
+
4032
+ Mac
4033
+
4034
+ ![glimmer-dsl-libui-mac-basic-transform.png](images/glimmer-dsl-libui-mac-basic-transform.png)
4035
+
4036
+ Linux
4037
+
4038
+ ![glimmer-dsl-libui-linux-basic-transform.png](images/glimmer-dsl-libui-linux-basic-transform.png)
4039
+
4040
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
4041
+
4042
+ ```ruby
4043
+ require 'glimmer-dsl-libui'
4044
+
4045
+ include Glimmer
4046
+
4047
+ window('Basic Transform', 350, 350) {
4048
+ area {
4049
+ path {
4050
+ square(0, 0, 350)
4051
+
4052
+ fill r: 255, g: 255, b: 0
4053
+ }
4054
+ 40.times do |n|
4055
+ path {
4056
+ square(0, 0, 100)
4057
+
4058
+ fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
4059
+ stroke :black, thickness: 2
4060
+ transform {
4061
+ skew 0.15, 0.15
4062
+ translate 50, 50
4063
+ rotate 100, 100, -9 * n
4064
+ scale 1.1, 1.1
4065
+ }
4066
+ }
4067
+ end
3271
4068
  }
3272
4069
  }.show
3273
4070
  ```