glimmer-dsl-libui 0.2.16 → 0.2.20

Sign up to get free protection for your applications and to get access to all the features.
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.2.16
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.2.20
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
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -112,31 +112,24 @@ window('Area Gallery', 400, 400) {
112
112
  fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
113
113
  }
114
114
  path { # declarative stable path
115
- figure(100, 100) {
116
- line(100, 400)
117
- line(400, 100)
118
- line(400, 400)
119
-
120
- closed true
121
- }
122
-
115
+ polygon(100, 100, 100, 400, 400, 100, 400, 400)
116
+
123
117
  fill r: 202, g: 102, b: 104, a: 0.5
124
118
  stroke r: 0, g: 0, b: 0
125
119
  }
126
120
  path { # declarative stable path
127
- figure(0, 0) {
128
- bezier(200, 100, 100, 200, 400, 100)
129
- bezier(300, 100, 100, 300, 100, 400)
130
- bezier(100, 300, 300, 100, 400, 400)
131
-
132
- closed true
133
- }
121
+ polybezier(0, 0, 200, 100, 100, 200, 400, 100, 300, 100, 100, 300, 100, 400, 100, 300, 300, 100, 400, 400)
134
122
 
135
123
  fill r: 202, g: 102, b: 204, a: 0.5
136
124
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
137
125
  }
138
126
  path { # declarative stable path
139
- arc(400, 220, 180, 90, 90, false)
127
+ polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
128
+
129
+ stroke r: 0, g: 0, b: 0, thickness: 2
130
+ }
131
+ path { # declarative stable path
132
+ arc(404, 216, 190, 90, 90, false)
140
133
 
141
134
  # radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
142
135
  fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
@@ -148,9 +141,9 @@ window('Area Gallery', 400, 400) {
148
141
  fill r: 202, g: 102, b: 204, a: 0.5
149
142
  stroke r: 0, g: 0, b: 0, thickness: 2
150
143
  }
151
- text(160, 40, 100) { # x, y, width
144
+ text(161, 40, 100) { # x, y, width
152
145
  string('Area Gallery') {
153
- font family: 'Times', size: 14
146
+ font family: 'Arial', size: 14
154
147
  color :black
155
148
  }
156
149
  }
@@ -284,6 +277,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
284
277
  - [Basic Draw Text](#basic-draw-text)
285
278
  - [Custom Draw Text](#custom-draw-text)
286
279
  - [Method-Based Custom Keyword](#method-based-custom-keyword)
280
+ - [Tetris](#tetris)
287
281
  - [Applications](#applications)
288
282
  - [Manga2PDF](#manga2pdf)
289
283
  - [Befunge98 GUI](#befunge98-gui)
@@ -376,7 +370,7 @@ gem install glimmer-dsl-libui
376
370
  Or install via Bundler `Gemfile`:
377
371
 
378
372
  ```ruby
379
- gem 'glimmer-dsl-libui', '~> 0.2.16'
373
+ gem 'glimmer-dsl-libui', '~> 0.2.20'
380
374
  ```
381
375
 
382
376
  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.
@@ -452,7 +446,7 @@ These are all the supported keywords. Note that some keywords do not represent c
452
446
  Keyword(Args) | Properties | Listeners
453
447
  ------------- | ---------- | ---------
454
448
  `about_menu_item` | None | `on_clicked`
455
- `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`, `on_key_event(area_key_event)`, `on_key_down(area_key_event)`, `on_key_up(area_key_event)`
449
+ `area` | `auto_draw_enabled` | `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`, `on_key_event(area_key_event)`, `on_key_down(area_key_event)`, `on_key_up(area_key_event)`
456
450
  `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
457
451
  `background_color_column(name as String)` | None | None
458
452
  `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
@@ -462,6 +456,7 @@ Keyword(Args) | Properties | Listeners
462
456
  `checkbox_column(name as String)` | `editable` (Boolean) | None
463
457
  `checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
464
458
  `checkbox_text_color_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
459
+ `check_menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
465
460
  `combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
466
461
  `color_button` | `color` (Array of `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float`), `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float` | `on_changed`
467
462
  `date_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`
@@ -484,7 +479,7 @@ Keyword(Args) | Properties | Listeners
484
479
  `line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
485
480
  `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
486
481
  `menu(text as String)` | None | None
487
- `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
482
+ `menu_item(text as String)` | None | `on_clicked`
488
483
  `message_box` (alias for `msg_box`; see for arguments) | None | None
489
484
  `message_box_error` (alias for `msg_box_error`; see for arguments) | None | None
490
485
  `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
@@ -493,6 +488,9 @@ Keyword(Args) | Properties | Listeners
493
488
  `non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
494
489
  `password_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
495
490
  `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`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `stroke` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `:cap` as (`:round`, `:square`, `:flat`), `:join` as (`:miter`, `:round`, `:bevel`), `:thickness` as `Numeric`, `:miter_limit` as `Numeric`, `:dashes` as `Array` of `Numeric` ) | None
491
+ `polygon(point_array as Array of Arrays of Numeric or Array of Numeric)` | `point_array` (`Array of Arrays of Numeric or Array of Numeric`) | None
492
+ `polyline(point_array as Array of Arrays of Numeric or Array of Numeric)` | `point_array` (`Array of Arrays of Numeric or Array of Numeric`) | None
493
+ `polybezier(point_array as Array of Arrays of Numeric or Array of Numeric)` | `point_array` (`Array of Arrays of Numeric or Array of Numeric`) | None
496
494
  `preferences_menu_item` | None | `on_clicked`
497
495
  `progress_bar` | `value` (`Numeric`) | None
498
496
  `progress_bar_column(name as String)` | None | None
@@ -500,6 +498,7 @@ Keyword(Args) | Properties | Listeners
500
498
  `radio_buttons` | `selected` (`Integer`) | `on_selected`
501
499
  `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `width` (`Numeric`), `height` (`Numeric`) | None
502
500
  `search_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
501
+ `separator_menu_item` | None | None
503
502
  `slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
504
503
  `spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
505
504
  `square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
@@ -513,7 +512,7 @@ Keyword(Args) | Properties | Listeners
513
512
  `time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
514
513
  `vertical_box` | `padded` (Boolean) | None
515
514
  `vertical_separator` | None | None
516
- `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`
515
+ `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`), `resizable` (Boolean) | `on_closing`, `on_content_size_changed`, `on_destroy`
517
516
 
518
517
  ### Common Control Properties
519
518
  - `enabled` (Boolean)
@@ -744,6 +743,9 @@ Available nested `path` shapes:
744
743
  - `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
745
744
  - `line(x as Numeric, y as Numeric)`
746
745
  - `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)`
746
+ - `polygon(point_array as Array of Arrays of Numeric or Array of Numeric)`: closed figure of lines; can receive points as [[x1, y1], [x2, y2], ...] or [x1, y1, x2, y2, ...]
747
+ - `polyline(point_array as Array of Arrays of Numeric or Array of Numeric)`: open figure of lines; can receive points as [[x1, y1], [x2, y2], ...] or [x1, y1, x2, y2, ...]
748
+ - `polybezier(point_array as Array of Arrays of Numeric or Array of Numeric)`: open figure of beziers; can receive points as [[start_x1, start_y1], [c1_x2, c1_y2, c2_x2, c2_y2, end_x2, end_y2], [c1_x3, c1_y3, c2_x3, c2_y3, end_x3, end_y3], ...] or [start_x1, start_y1, c1_x2, c1_y2, c2_x2, c2_y2, end_x2, end_y2, c1_x3, c1_y3, c2_x3, c2_y3, end_x3, end_y3, ...]
747
749
  - `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)
748
750
 
749
751
  Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
@@ -798,6 +800,12 @@ Note that when nesting an `area` directly underneath `window` (without a layout
798
800
 
799
801
  To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
800
802
 
803
+ `area` has the following Glimmer-added API methods/attributes:
804
+ - `request_auto_redraw`: requests auto redraw upon changes to nested stable `path` or shapes
805
+ - `pause_auto_redraw`: pause auto redraw upon changes to nested stable `path` or shapes (useful to avoid too many micro-change redraws, to group all redraws as one after many micro-changes)
806
+ - `resume_auto_redraw`: resume auto redraw upon changes to nested stable `path` or shapes
807
+ - `auto_redraw_enabled`/`auto_redraw_enabled?`/`auto_redraw_enabled=`: an attribute to disable/enable auto redraw on an `area` upon changes to nested stable `path` or shapes
808
+
801
809
  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.
802
810
 
803
811
  When instantiating a `matrix` object, it always starts with identity matrix.
@@ -1076,6 +1084,7 @@ window('Method-Based Custom Keyword') {
1076
1084
  - `table` controls on Windows intentionally get an extra empty row at the end because if any row were to be deleted for the first time, double-deletion happens due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
1077
1085
  - `table` `progress_bar` column on Windows cannot be updated with a positive value if it started initially with `-1` (it ignores update to avoid crashing due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
1078
1086
  - It seems that [libui](https://github.com/andlabs/libui) does not support nesting multiple `area` controls under a `grid` as only the first one shows up in that scenario. To workaround that limitation, use a `vertical_box` with nested `horizontal_box`s instead to include multiple `area`s in a GUI.
1087
+ - As per the code of [examples/basic_transform.rb](#basic-transform), Windows requires different ordering of transforms than Mac and Linux.
1079
1088
 
1080
1089
  ### Original API
1081
1090
 
@@ -4057,31 +4066,24 @@ window('Area Gallery', 400, 400) {
4057
4066
  fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
4058
4067
  }
4059
4068
  path { # declarative stable path
4060
- figure(100, 100) {
4061
- line(100, 400)
4062
- line(400, 100)
4063
- line(400, 400)
4064
-
4065
- closed true
4066
- }
4067
-
4069
+ polygon(100, 100, 100, 400, 400, 100, 400, 400)
4070
+
4068
4071
  fill r: 202, g: 102, b: 104, a: 0.5
4069
4072
  stroke r: 0, g: 0, b: 0
4070
4073
  }
4071
4074
  path { # declarative stable path
4072
- figure(0, 0) {
4073
- bezier(200, 100, 100, 200, 400, 100)
4074
- bezier(300, 100, 100, 300, 100, 400)
4075
- bezier(100, 300, 300, 100, 400, 400)
4076
-
4077
- closed true
4078
- }
4075
+ polybezier(0, 0, 200, 100, 100, 200, 400, 100, 300, 100, 100, 300, 100, 400, 100, 300, 300, 100, 400, 400)
4079
4076
 
4080
4077
  fill r: 202, g: 102, b: 204, a: 0.5
4081
4078
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
4082
4079
  }
4083
4080
  path { # declarative stable path
4084
- arc(400, 220, 180, 90, 90, false)
4081
+ polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
4082
+
4083
+ stroke r: 0, g: 0, b: 0, thickness: 2
4084
+ }
4085
+ path { # declarative stable path
4086
+ arc(404, 216, 190, 90, 90, false)
4085
4087
 
4086
4088
  # radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
4087
4089
  fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
@@ -4093,9 +4095,9 @@ window('Area Gallery', 400, 400) {
4093
4095
  fill r: 202, g: 102, b: 204, a: 0.5
4094
4096
  stroke r: 0, g: 0, b: 0, thickness: 2
4095
4097
  }
4096
- text(160, 40, 100) { # x, y, width
4098
+ text(161, 40, 100) { # x, y, width
4097
4099
  string('Area Gallery') {
4098
- font family: 'Times', size: 14
4100
+ font family: 'Arial', size: 14
4099
4101
  color :black
4100
4102
  }
4101
4103
  }
@@ -4244,18 +4246,42 @@ window('Area Gallery', 400, 400) {
4244
4246
  end_x 400
4245
4247
  end_y 400
4246
4248
  }
4247
-
4248
- closed true
4249
4249
  }
4250
4250
 
4251
4251
  fill r: 202, g: 102, b: 204, a: 0.5
4252
4252
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
4253
4253
  }
4254
+ path { # declarative stable path
4255
+ polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
4256
+ figure {
4257
+ x 100
4258
+ y 100
4259
+
4260
+ line {
4261
+ x 400
4262
+ y 100
4263
+ }
4264
+ line {
4265
+ x 100
4266
+ y 400
4267
+ }
4268
+ line {
4269
+ x 400
4270
+ y 400
4271
+ }
4272
+ line {
4273
+ x 0
4274
+ y 0
4275
+ }
4276
+ }
4277
+
4278
+ stroke r: 0, g: 0, b: 0, thickness: 2
4279
+ }
4254
4280
  path { # declarative stable path
4255
4281
  arc {
4256
- x_center 400
4257
- y_center 220
4258
- radius 180
4282
+ x_center 404
4283
+ y_center 216
4284
+ radius 190
4259
4285
  start_angle 90
4260
4286
  sweep 90
4261
4287
  is_negative false
@@ -4276,12 +4302,12 @@ window('Area Gallery', 400, 400) {
4276
4302
  stroke r: 0, g: 0, b: 0, thickness: 2
4277
4303
  }
4278
4304
  text {
4279
- x 160
4305
+ x 161
4280
4306
  y 40
4281
4307
  width 100
4282
4308
 
4283
4309
  string {
4284
- font family: 'Times', size: 14
4310
+ font family: 'Arial', size: 14
4285
4311
  color :black
4286
4312
 
4287
4313
  'Area Gallery'
@@ -4352,42 +4378,35 @@ window('Area Gallery', 400, 400) {
4352
4378
  path { # a dynamic path is added semi-declaratively inside on_draw block
4353
4379
  square(0, 0, 100)
4354
4380
  square(100, 100, 400)
4355
-
4381
+
4356
4382
  fill r: 102, g: 102, b: 204
4357
4383
  }
4358
4384
  path { # a dynamic path is added semi-declaratively inside on_draw block
4359
4385
  rectangle(0, 100, 100, 400)
4360
4386
  rectangle(100, 0, 400, 100)
4361
-
4387
+
4362
4388
  # linear gradient (has x0, y0, x1, y1, and stops)
4363
4389
  fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
4364
4390
  }
4365
4391
  path { # a dynamic path is added semi-declaratively inside on_draw block
4366
- figure(100, 100) {
4367
- line(100, 400)
4368
- line(400, 100)
4369
- line(400, 400)
4370
-
4371
- closed true
4372
- }
4373
-
4392
+ polygon(100, 100, 100, 400, 400, 100, 400, 400)
4393
+
4374
4394
  fill r: 202, g: 102, b: 104, a: 0.5
4375
4395
  stroke r: 0, g: 0, b: 0
4376
4396
  }
4377
4397
  path { # a dynamic path is added semi-declaratively inside on_draw block
4378
- figure(0, 0) {
4379
- bezier(200, 100, 100, 200, 400, 100)
4380
- bezier(300, 100, 100, 300, 100, 400)
4381
- bezier(100, 300, 300, 100, 400, 400)
4382
-
4383
- closed true
4384
- }
4385
-
4398
+ polybezier(0, 0, 200, 100, 100, 200, 400, 100, 300, 100, 100, 300, 100, 400, 100, 300, 300, 100, 400, 400)
4399
+
4386
4400
  fill r: 202, g: 102, b: 204, a: 0.5
4387
4401
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
4388
4402
  }
4389
4403
  path { # a dynamic path is added semi-declaratively inside on_draw block
4390
- arc(400, 220, 180, 90, 90, false)
4404
+ polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
4405
+
4406
+ stroke r: 0, g: 0, b: 0, thickness: 2
4407
+ }
4408
+ path { # a dynamic path is added semi-declaratively inside on_draw block
4409
+ arc(404, 216, 190, 90, 90, false)
4391
4410
 
4392
4411
  # radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
4393
4412
  fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
@@ -4399,9 +4418,9 @@ window('Area Gallery', 400, 400) {
4399
4418
  fill r: 202, g: 102, b: 204, a: 0.5
4400
4419
  stroke r: 0, g: 0, b: 0, thickness: 2
4401
4420
  }
4402
- text(160, 40, 100) { # x, y, width
4421
+ text(161, 40, 100) { # x, y, width
4403
4422
  string('Area Gallery') {
4404
- font family: 'Times', size: 14
4423
+ font family: 'Arial', size: 14
4405
4424
  color :black
4406
4425
  }
4407
4426
  }
@@ -4516,10 +4535,10 @@ window('Area Gallery', 400, 400) {
4516
4535
  x 400
4517
4536
  y 400
4518
4537
  }
4519
-
4538
+
4520
4539
  closed true
4521
4540
  }
4522
-
4541
+
4523
4542
  fill r: 202, g: 102, b: 104, a: 0.5
4524
4543
  stroke r: 0, g: 0, b: 0
4525
4544
  }
@@ -4552,18 +4571,42 @@ window('Area Gallery', 400, 400) {
4552
4571
  end_x 400
4553
4572
  end_y 400
4554
4573
  }
4555
-
4556
- closed true
4557
4574
  }
4558
-
4575
+
4559
4576
  fill r: 202, g: 102, b: 204, a: 0.5
4560
4577
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
4561
4578
  }
4579
+ path { # a dynamic path is added semi-declaratively inside on_draw block
4580
+ polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
4581
+ figure {
4582
+ x 100
4583
+ y 100
4584
+
4585
+ line {
4586
+ x 400
4587
+ y 100
4588
+ }
4589
+ line {
4590
+ x 100
4591
+ y 400
4592
+ }
4593
+ line {
4594
+ x 400
4595
+ y 400
4596
+ }
4597
+ line {
4598
+ x 0
4599
+ y 0
4600
+ }
4601
+ }
4602
+
4603
+ stroke r: 0, g: 0, b: 0, thickness: 2
4604
+ }
4562
4605
  path { # a dynamic path is added semi-declaratively inside on_draw block
4563
4606
  arc {
4564
- x_center 400
4565
- y_center 220
4566
- radius 180
4607
+ x_center 404
4608
+ y_center 216
4609
+ radius 190
4567
4610
  start_angle 90
4568
4611
  sweep 90
4569
4612
  is_negative false
@@ -4584,12 +4627,12 @@ window('Area Gallery', 400, 400) {
4584
4627
  stroke r: 0, g: 0, b: 0, thickness: 2
4585
4628
  }
4586
4629
  text {
4587
- x 160
4630
+ x 161
4588
4631
  y 40
4589
4632
  width 100
4590
4633
 
4591
4634
  string {
4592
- font family: 'Times', size: 14
4635
+ font family: 'Arial', size: 14
4593
4636
  color :black
4594
4637
 
4595
4638
  'Area Gallery'
@@ -4906,20 +4949,13 @@ end
4906
4949
 
4907
4950
  # method-based custom control representing a graph path
4908
4951
  def graph_path(width, height, should_extend, &block)
4909
- locations = point_locations(width, height)
4952
+ locations = point_locations(width, height).flatten
4910
4953
  path {
4911
- first_location = locations[0] # x and y
4912
- figure(first_location[0], first_location[1]) {
4913
- locations.each do |loc|
4914
- line(loc[0], loc[1])
4915
- end
4916
- if should_extend
4917
- line(width, height)
4918
- line(0, height)
4919
-
4920
- closed true
4921
- end
4922
- }
4954
+ if should_extend
4955
+ polygon(locations + [width, height, 0, height])
4956
+ else
4957
+ polyline(locations)
4958
+ end
4923
4959
 
4924
4960
  # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
4925
4961
  transform {
@@ -6198,6 +6234,391 @@ window('Method-Based Custom Keyword') {
6198
6234
  }.show
6199
6235
  ```
6200
6236
 
6237
+ ### Tetris
6238
+
6239
+ Glimmer Tetris utilizes many small areas to represent Tetromino blocks because this ensures smaller redraws per tetromino block color change, thus higher performance than having one area that gets redrawn on every little change.
6240
+
6241
+ [examples/tetris.rb](examples/tetris.rb)
6242
+
6243
+ Run with this command from the root of the project if you cloned the project:
6244
+
6245
+ ```
6246
+ ruby -r './lib/glimmer-dsl-libui' examples/tetris.rb
6247
+ ```
6248
+
6249
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
6250
+
6251
+ ```
6252
+ ruby -r glimmer-dsl-libui -e "require 'examples/tetris'"
6253
+ ```
6254
+
6255
+ Mac
6256
+
6257
+ ![glimmer-dsl-libui-mac-tetris.png](images/glimmer-dsl-libui-mac-tetris.png)
6258
+
6259
+ ![glimmer-dsl-libui-mac-tetris-game-over.png](images/glimmer-dsl-libui-mac-tetris-game-over.png)
6260
+
6261
+ ![glimmer-dsl-libui-mac-tetris-high-scores.png](images/glimmer-dsl-libui-mac-tetris-high-scores.png)
6262
+
6263
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
6264
+
6265
+ ```ruby
6266
+ require 'glimmer-dsl-libui'
6267
+
6268
+ require_relative 'tetris/model/game'
6269
+
6270
+ class Tetris
6271
+ include Glimmer
6272
+
6273
+ BLOCK_SIZE = 25
6274
+ BEVEL_CONSTANT = 20
6275
+ COLOR_GRAY = {r: 192, g: 192, b: 192}
6276
+
6277
+ def initialize
6278
+ @game = Model::Game.new
6279
+ end
6280
+
6281
+ def launch
6282
+ create_gui
6283
+ register_observers
6284
+ @game.start!
6285
+ @main_window.show
6286
+ end
6287
+
6288
+ def create_gui
6289
+ menu_bar
6290
+
6291
+ @main_window = window('Glimmer Tetris') {
6292
+ content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
6293
+ resizable false
6294
+
6295
+ vertical_box {
6296
+ label { # filler
6297
+ stretchy false
6298
+ }
6299
+
6300
+ score_board(block_size: BLOCK_SIZE) {
6301
+ stretchy false
6302
+ }
6303
+
6304
+ @playfield_blocks = playfield(playfield_width: Model::Game::PLAYFIELD_WIDTH, playfield_height: Model::Game::PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
6305
+ }
6306
+ }
6307
+ end
6308
+
6309
+ def register_observers
6310
+ Glimmer::DataBinding::Observer.proc do |game_over|
6311
+ if game_over
6312
+ @pause_menu_item.enabled = false
6313
+ show_game_over_dialog
6314
+ else
6315
+ @pause_menu_item.enabled = true
6316
+ start_moving_tetrominos_down
6317
+ end
6318
+ end.observe(@game, :game_over)
6319
+
6320
+ Model::Game::PLAYFIELD_HEIGHT.times do |row|
6321
+ Model::Game::PLAYFIELD_WIDTH.times do |column|
6322
+ Glimmer::DataBinding::Observer.proc do |new_color|
6323
+ Glimmer::LibUI.queue_main do
6324
+ color = Glimmer::LibUI.interpret_color(new_color)
6325
+ block = @playfield_blocks[row][column]
6326
+ block[:background_square].fill = color
6327
+ block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
6328
+ block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6329
+ block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6330
+ block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6331
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
6332
+ end
6333
+ end.observe(@game.playfield[row][column], :color)
6334
+ end
6335
+ end
6336
+
6337
+ Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
6338
+ Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
6339
+ Glimmer::DataBinding::Observer.proc do |new_color|
6340
+ Glimmer::LibUI.queue_main do
6341
+ color = Glimmer::LibUI.interpret_color(new_color)
6342
+ block = @preview_playfield_blocks[row][column]
6343
+ block[:background_square].fill = color
6344
+ block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
6345
+ block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6346
+ block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6347
+ block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
6348
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
6349
+ end
6350
+ end.observe(@game.preview_playfield[row][column], :color)
6351
+ end
6352
+ end
6353
+
6354
+ Glimmer::DataBinding::Observer.proc do |new_score|
6355
+ Glimmer::LibUI.queue_main do
6356
+ @score_label.text = new_score.to_s
6357
+ end
6358
+ end.observe(@game, :score)
6359
+
6360
+ Glimmer::DataBinding::Observer.proc do |new_lines|
6361
+ Glimmer::LibUI.queue_main do
6362
+ @lines_label.text = new_lines.to_s
6363
+ end
6364
+ end.observe(@game, :lines)
6365
+
6366
+ Glimmer::DataBinding::Observer.proc do |new_level|
6367
+ Glimmer::LibUI.queue_main do
6368
+ @level_label.text = new_level.to_s
6369
+ end
6370
+ end.observe(@game, :level)
6371
+ end
6372
+
6373
+ def menu_bar
6374
+ menu('Game') {
6375
+ @pause_menu_item = check_menu_item('Pause') {
6376
+ enabled false
6377
+
6378
+ on_clicked do
6379
+ @game.paused = @pause_menu_item.checked?
6380
+ end
6381
+ }
6382
+ menu_item('Restart') {
6383
+ on_clicked do
6384
+ @game.restart!
6385
+ end
6386
+ }
6387
+ separator_menu_item
6388
+ menu_item('Exit') {
6389
+ on_clicked do
6390
+ exit(0)
6391
+ end
6392
+ }
6393
+ quit_menu_item if OS.mac?
6394
+ }
6395
+
6396
+ menu('View') {
6397
+ menu_item('Show High Scores') {
6398
+ on_clicked do
6399
+ show_high_scores
6400
+ end
6401
+ }
6402
+ menu_item('Clear High Scores') {
6403
+ on_clicked {
6404
+ @game.clear_high_scores!
6405
+ }
6406
+ }
6407
+ }
6408
+
6409
+ menu('Options') {
6410
+ radio_menu_item('Instant Down on Up Arrow') {
6411
+ on_clicked do
6412
+ @game.instant_down_on_up = true
6413
+ end
6414
+ }
6415
+ radio_menu_item('Rotate Right on Up Arrow') {
6416
+ on_clicked do
6417
+ @game.rotate_right_on_up = true
6418
+ end
6419
+ }
6420
+ radio_menu_item('Rotate Left on Up Arrow') {
6421
+ on_clicked do
6422
+ @game.rotate_left_on_up = true
6423
+ end
6424
+ }
6425
+ }
6426
+
6427
+ menu('Help') {
6428
+ if OS.mac?
6429
+ about_menu_item {
6430
+ on_clicked do
6431
+ show_about_dialog
6432
+ end
6433
+ }
6434
+ end
6435
+ menu_item('About') {
6436
+ on_clicked do
6437
+ show_about_dialog
6438
+ end
6439
+ }
6440
+ }
6441
+ end
6442
+
6443
+ def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
6444
+ blocks = []
6445
+ vertical_box {
6446
+ padded false
6447
+
6448
+ playfield_height.times.map do |row|
6449
+ blocks << []
6450
+ horizontal_box {
6451
+ padded false
6452
+
6453
+ playfield_width.times.map do |column|
6454
+ blocks.last << block(row: row, column: column, block_size: block_size)
6455
+ end
6456
+ }
6457
+ end
6458
+
6459
+ extra_content&.call
6460
+ }
6461
+ blocks
6462
+ end
6463
+
6464
+ def block(row: , column: , block_size: , &extra_content)
6465
+ block = {}
6466
+ bevel_pixel_size = 0.16 * block_size.to_f
6467
+ color = Glimmer::LibUI.interpret_color(Model::Block::COLOR_CLEAR)
6468
+ area {
6469
+ block[:background_square] = path {
6470
+ square(0, 0, block_size)
6471
+
6472
+ fill color
6473
+ }
6474
+ block[:top_bevel_edge] = path {
6475
+ polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
6476
+
6477
+ fill r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT
6478
+ }
6479
+ block[:right_bevel_edge] = path {
6480
+ polygon(block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size, block_size)
6481
+
6482
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
6483
+ }
6484
+ block[:bottom_bevel_edge] = path {
6485
+ polygon(block_size, block_size, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size)
6486
+
6487
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
6488
+ }
6489
+ block[:left_bevel_edge] = path {
6490
+ polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
6491
+
6492
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
6493
+ }
6494
+ block[:border_square] = path {
6495
+ square(0, 0, block_size)
6496
+
6497
+ stroke COLOR_GRAY
6498
+ }
6499
+
6500
+ on_key_down do |key_event|
6501
+ case key_event
6502
+ in ext_key: :down
6503
+ @game.down!
6504
+ in key: ' '
6505
+ @game.down!(instant: true)
6506
+ in ext_key: :up
6507
+ case @game.up_arrow_action
6508
+ when :instant_down
6509
+ @game.down!(instant: true)
6510
+ when :rotate_right
6511
+ @game.rotate!(:right)
6512
+ when :rotate_left
6513
+ @game.rotate!(:left)
6514
+ end
6515
+ in ext_key: :left
6516
+ @game.left!
6517
+ in ext_key: :right
6518
+ @game.right!
6519
+ in modifier: :shift
6520
+ @game.rotate!(:right)
6521
+ in modifier: :control
6522
+ @game.rotate!(:left)
6523
+ else
6524
+ # Do Nothing
6525
+ end
6526
+ end
6527
+
6528
+ extra_content&.call
6529
+ }
6530
+ block
6531
+ end
6532
+
6533
+ def score_board(block_size: , &extra_content)
6534
+ vertical_box {
6535
+ horizontal_box {
6536
+ label # filler
6537
+ @preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
6538
+ label # filler
6539
+ }
6540
+
6541
+ horizontal_box {
6542
+ label # filler
6543
+ grid {
6544
+ stretchy false
6545
+
6546
+ label('Score') {
6547
+ left 0
6548
+ top 0
6549
+ halign :fill
6550
+ }
6551
+ @score_label = label {
6552
+ left 0
6553
+ top 1
6554
+ halign :center
6555
+ }
6556
+
6557
+ label('Lines') {
6558
+ left 1
6559
+ top 0
6560
+ halign :fill
6561
+ }
6562
+ @lines_label = label {
6563
+ left 1
6564
+ top 1
6565
+ halign :center
6566
+ }
6567
+
6568
+ label('Level') {
6569
+ left 2
6570
+ top 0
6571
+ halign :fill
6572
+ }
6573
+ @level_label = label {
6574
+ left 2
6575
+ top 1
6576
+ halign :center
6577
+ }
6578
+ }
6579
+ label # filler
6580
+ }
6581
+
6582
+ extra_content&.call
6583
+ }
6584
+ end
6585
+
6586
+ def start_moving_tetrominos_down
6587
+ Glimmer::LibUI.timer(@game.delay) do
6588
+ @game.down! if !@game.game_over? && !@game.paused?
6589
+ end
6590
+ end
6591
+
6592
+ def show_game_over_dialog
6593
+ Glimmer::LibUI.queue_main do
6594
+ msg_box('Game Over!', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
6595
+ @game.restart!
6596
+ end
6597
+ end
6598
+
6599
+ def show_high_scores
6600
+ Glimmer::LibUI.queue_main do
6601
+ if @game.high_scores.empty?
6602
+ high_scores_string = "No games have been scored yet."
6603
+ else
6604
+ high_scores_string = @game.high_scores.map do |high_score|
6605
+ "#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
6606
+ end.join("\n")
6607
+ end
6608
+ msg_box('High Scores', high_scores_string)
6609
+ end
6610
+ end
6611
+
6612
+ def show_about_dialog
6613
+ Glimmer::LibUI.queue_main do
6614
+ msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
6615
+ end
6616
+ end
6617
+ end
6618
+
6619
+ Tetris.new.launch
6620
+ ```
6621
+
6201
6622
  ## Applications
6202
6623
 
6203
6624
  Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)