glimmer-dsl-libui 0.2.17 → 0.2.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +563 -125
- data/VERSION +1 -1
- data/examples/area_gallery.rb +11 -18
- data/examples/area_gallery2.rb +31 -7
- data/examples/area_gallery3.rb +14 -21
- data/examples/area_gallery4.rb +34 -10
- data/examples/histogram.rb +6 -13
- data/examples/tetris/model/game.rb +2 -0
- data/examples/tetris/model/tetromino.rb +2 -2
- data/examples/tetris.rb +279 -49
- data/examples/tic_tac_toe/board.rb +145 -0
- data/examples/tic_tac_toe/cell.rb +48 -0
- data/examples/tic_tac_toe.rb +85 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/shape_expression.rb +1 -0
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +25 -0
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +19 -7
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +40 -1
- data/lib/glimmer/libui/shape/figure.rb +4 -2
- data/lib/glimmer/libui/shape/polybezier.rb +45 -0
- data/lib/glimmer/libui/shape/polygon.rb +46 -0
- data/lib/glimmer/libui/shape/polyline.rb +45 -0
- data/lib/glimmer/libui/shape.rb +9 -3
- data/lib/glimmer/libui.rb +29 -1
- metadata +8 -2
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.
|
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.21
|
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
|
-
|
116
|
-
|
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
|
-
|
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
|
-
|
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(
|
144
|
+
text(161, 40, 100) { # x, y, width
|
152
145
|
string('Area Gallery') {
|
153
|
-
font family: '
|
146
|
+
font family: 'Arial', size: 14
|
154
147
|
color :black
|
155
148
|
}
|
156
149
|
}
|
@@ -285,6 +278,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
285
278
|
- [Custom Draw Text](#custom-draw-text)
|
286
279
|
- [Method-Based Custom Keyword](#method-based-custom-keyword)
|
287
280
|
- [Tetris](#tetris)
|
281
|
+
- [Tic Tac Toe](#tic-tac-toe)
|
288
282
|
- [Applications](#applications)
|
289
283
|
- [Manga2PDF](#manga2pdf)
|
290
284
|
- [Befunge98 GUI](#befunge98-gui)
|
@@ -377,7 +371,7 @@ gem install glimmer-dsl-libui
|
|
377
371
|
Or install via Bundler `Gemfile`:
|
378
372
|
|
379
373
|
```ruby
|
380
|
-
gem 'glimmer-dsl-libui', '~> 0.2.
|
374
|
+
gem 'glimmer-dsl-libui', '~> 0.2.21'
|
381
375
|
```
|
382
376
|
|
383
377
|
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.
|
@@ -453,7 +447,7 @@ These are all the supported keywords. Note that some keywords do not represent c
|
|
453
447
|
Keyword(Args) | Properties | Listeners
|
454
448
|
------------- | ---------- | ---------
|
455
449
|
`about_menu_item` | None | `on_clicked`
|
456
|
-
`area` |
|
450
|
+
`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)`
|
457
451
|
`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
|
458
452
|
`background_color_column(name as String)` | None | None
|
459
453
|
`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
|
@@ -463,6 +457,7 @@ Keyword(Args) | Properties | Listeners
|
|
463
457
|
`checkbox_column(name as String)` | `editable` (Boolean) | None
|
464
458
|
`checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
465
459
|
`checkbox_text_color_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
460
|
+
`check_menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
|
466
461
|
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
|
467
462
|
`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`
|
468
463
|
`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`
|
@@ -485,7 +480,7 @@ Keyword(Args) | Properties | Listeners
|
|
485
480
|
`line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
|
486
481
|
`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
|
487
482
|
`menu(text as String)` | None | None
|
488
|
-
`menu_item(text as String)` |
|
483
|
+
`menu_item(text as String)` | None | `on_clicked`
|
489
484
|
`message_box` (alias for `msg_box`; see for arguments) | None | None
|
490
485
|
`message_box_error` (alias for `msg_box_error`; see for arguments) | None | None
|
491
486
|
`multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
@@ -494,6 +489,9 @@ Keyword(Args) | Properties | Listeners
|
|
494
489
|
`non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
495
490
|
`password_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
496
491
|
`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
|
492
|
+
`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
|
493
|
+
`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
|
494
|
+
`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
|
497
495
|
`preferences_menu_item` | None | `on_clicked`
|
498
496
|
`progress_bar` | `value` (`Numeric`) | None
|
499
497
|
`progress_bar_column(name as String)` | None | None
|
@@ -501,6 +499,7 @@ Keyword(Args) | Properties | Listeners
|
|
501
499
|
`radio_buttons` | `selected` (`Integer`) | `on_selected`
|
502
500
|
`rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `width` (`Numeric`), `height` (`Numeric`) | None
|
503
501
|
`search_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
502
|
+
`separator_menu_item` | None | None
|
504
503
|
`slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
505
504
|
`spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
506
505
|
`square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
|
@@ -514,7 +513,7 @@ Keyword(Args) | Properties | Listeners
|
|
514
513
|
`time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
|
515
514
|
`vertical_box` | `padded` (Boolean) | None
|
516
515
|
`vertical_separator` | None | None
|
517
|
-
`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`
|
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`), `resizable` (Boolean) | `on_closing`, `on_content_size_changed`, `on_destroy`
|
518
517
|
|
519
518
|
### Common Control Properties
|
520
519
|
- `enabled` (Boolean)
|
@@ -547,6 +546,35 @@ All operations that could normally be called on `LibUI` can also be called on `G
|
|
547
546
|
- `Glimmer::LibUI::queue_main(&block)`: queues an operation to be run on the main event loop at the earliest opportunity possible
|
548
547
|
- `Glimmer::LibUI::timer(time_in_seconds=0.1, repeat: true, &block)`: calls block after time_in_seconds has elapsed, repeating indefinitely unless repeat is `false` or an `Integer` for finite number of repeats. Block can return `false` or `true` to override next repetition.
|
549
548
|
|
549
|
+
There are additional useful `Glimmer::LibUI` operations that are not found in `LibUI`, which mostly help if you would like to do advanced lower level [LibUI](https://github.com/kojix2/LibUI) programming:
|
550
|
+
- `Glimmer::LibUI::integer_to_boolean(int, allow_nil: true)`
|
551
|
+
- `Glimmer::LibUI::boolean_to_integer(int, allow_nil: true)`
|
552
|
+
- `Glimmer::LibUI::degrees_to_radians(degrees)`
|
553
|
+
- `Glimmer::LibUI::interpret_color(value)`: interprets a color in any form like `String`, `Symbol`, or hex into an rgb `Hash`
|
554
|
+
- `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash`
|
555
|
+
- `Glimmer::LibUI::enum_names`: provides all possible enum names to use with `Glimmer::LibUI::enum_symbols(enum_name)`
|
556
|
+
- `Glimmer::LibUI::enum_symbols(enum_name)`: returns all possible values for an enum. `enum_name` can be:
|
557
|
+
- `:draw_brush_type`: `[:solid, :linear_gradient, :radial_gradient, :image]`
|
558
|
+
- `:draw_line_cap`: `[:flat, :round, :square]`
|
559
|
+
- `:draw_line_join`: `[:miter, :round, :bevel]`
|
560
|
+
- `:draw_fill_mode`: `[:winding, :alternate]`
|
561
|
+
- `:attribute_type`: attributes for attributed `string`s: `[:family, :size, weight, :italic, :stretch, :color, :background, :underline, :underline_color, :features]`
|
562
|
+
- `:text_weight`: `[:minimum, :thin, :ultra_light, :light, :book, :normal, :medium, :semi_bold, :bold, :ultra_bold, :heavy, :ultra_heavy, :maximum]`
|
563
|
+
- `:text_italic`: `[:normal, :oblique, :italic]`
|
564
|
+
- `:text_stretch`: `[:ultra_condensed, :extra_condensed, :condensed, :semi_condensed, :normal, :semi_expanded, :expanded, :extra_expanded, :ultra_expanded]`
|
565
|
+
- `:underline`: `[:none, :single, :double, :suggestion, :color_custom, :color_spelling, :color_grammar, :color_auxiliary]`
|
566
|
+
- `:underline_color`: `[:custom, :spelling, :grammar, :auxiliary]`
|
567
|
+
- `:draw_text_align`: `[:left, :center, :right]`
|
568
|
+
- `:modifier`: `[:ctrl, :alt, :shift, :super]`
|
569
|
+
- `:ext_key`: `[:escape, :insert, :delete, :home, :end, :page_up, :page_down, :up, :down, :left, :right, :f1, :f2, :f3, :f4, :f5, :f6, :f7, :f8, :f9, :f10, :f11, :f12, :n0, :n1, :n2, :n3, :n4, :n5, :n6, :n7, :n8, :n9, :n_dot, :n_enter, :n_add, :n_subtract, :n_multiply, :n_divide]`
|
570
|
+
- `:at`: for inserting `grid` controls: `[:leading, :top, :trailing, :bottom]`
|
571
|
+
- `:align`: `[:fill, :start, :center, :end]`
|
572
|
+
- `:table_value_type`: `[:string, :image, :int, :color]`
|
573
|
+
- `:table_model_column`: `[:never_editable, :always_editable]`
|
574
|
+
- `Glimmer::LibUI::enum_symbol_to_value(enum_name, enum_symbol, default_symbol: nil, default_index: 0)`
|
575
|
+
- `Glimmer::LibUI::enum_value_to_symbol(enum_name, enum_value)`
|
576
|
+
- `Glimmer::LibUI::x11_colors`: returns all [X11 colors](https://en.wikipedia.org/wiki/X11_color_names): `[:alice_blue, :antique_white, :aqua, :aquamarine, :azure, :beige, :bisque, :rebecca_purple, :becca_purple, :blanched_almond, :blue, :blue_violet, :brown, :burly_wood, :burlywood, :cadet_blue, :carnation, :cayenne, :chartreuse, :chocolate, :coral, :cornflower_blue, :cornsilk, :crimson, :cyan, :dark_blue, :dark_cyan, :dark_golden_rod, :dark_goldenrod, :dark_gray, :dark_grey, :dark_green, :dark_khaki, :dark_magenta, :dark_olive_green, :darkolive_green, :dark_orange, :dark_orchid, :dark_red, :dark_salmon, :darksalmon, :dark_sea_green, :dark_slate_blue, :dark_slate_gray, :dark_slate_grey, :dark_turquoise, :dark_violet, :darkorange, :deep_pink, :deep_sky_blue, :dim_gray, :dim_grey, :dodger_blue, :feldspar, :fire_brick, :firebrick, :floral_white, :forest_green, :fuchsia, :gainsboro, :ghost_white, :gold, :golden_rod, :goldenrod, :gray, :grey, :gray10, :grey10, :gray20, :grey20, :gray30, :grey30, :gray40, :grey40, :gray50, :grey50, :gray60, :grey60, :gray70, :grey70, :gray80, :grey80, :gray90, :grey90, :green, :green_yellow, :honey_dew, :honeydew, :hot_pink, :indian_red, :indigo, :ivory, :khaki, :lavender, :lavender_blush, :lawn_green, :lemon_chiffon, :light_blue, :light_coral, :light_cyan, :light_golden_rod_yellow, :light_goldenrod_yellow, :light_gray, :light_grey, :light_green, :light_pink, :light_salmon, :lightsalmon, :light_sea_green, :light_sky_blue, :light_slate_blue, :light_slate_gray, :light_slate_grey, :light_steel_blue, :lightsteel_blue, :light_yellow, :lime, :lime_green, :linen, :magenta, :maroon, :medium_aqua_marine, :medium_aquamarine, :medium_blue, :medium_orchid, :medium_purple, :medium_sea_green, :medium_slate_blue, :medium_spring_green, :medium_turquoise, :medium_violet_red, :midnight_blue, :mint_cream, :misty_rose, :moccasin, :navajo_white, :navy, :old_lace, :olive, :olive_drab, :olivedrab, :orange, :orange_red, :orchid, :pale_golden_rod, :pale_goldenrod, :pale_green, :pale_turquoise, :pale_violet_red, :papaya_whip, :peach_puff, :peachpuff, :peru, :pink, :plum, :powder_blue, :purple, :red, :rosy_brown, :royal_blue, :saddle_brown, :salmon, :sandy_brown, :sea_green, :sea_shell, :seashell, :sienna, :silver, :sky_blue, :slate_blue, :slate_gray, :slate_grey, :snow, :spring_green, :steel_blue, :tan, :teal, :thistle, :tomato, :turquoise, :violet, :violet_red, :wheat, :white_smoke, :yellow, :yellow_green, :metallic, :white, :black, :gray_scale, :grey_scale]`
|
577
|
+
|
550
578
|
### Extra Dialogs
|
551
579
|
|
552
580
|
- `open_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
|
@@ -745,6 +773,9 @@ Available nested `path` shapes:
|
|
745
773
|
- `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
|
746
774
|
- `line(x as Numeric, y as Numeric)`
|
747
775
|
- `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)`
|
776
|
+
- `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, ...]
|
777
|
+
- `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, ...]
|
778
|
+
- `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, ...]
|
748
779
|
- `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)
|
749
780
|
|
750
781
|
Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
|
@@ -799,6 +830,12 @@ Note that when nesting an `area` directly underneath `window` (without a layout
|
|
799
830
|
|
800
831
|
To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
|
801
832
|
|
833
|
+
`area` has the following Glimmer-added API methods/attributes:
|
834
|
+
- `request_auto_redraw`: requests auto redraw upon changes to nested stable `path` or shapes
|
835
|
+
- `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)
|
836
|
+
- `resume_auto_redraw`: resume auto redraw upon changes to nested stable `path` or shapes
|
837
|
+
- `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
|
838
|
+
|
802
839
|
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.
|
803
840
|
|
804
841
|
When instantiating a `matrix` object, it always starts with identity matrix.
|
@@ -866,7 +903,7 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
866
903
|
|
867
904
|
`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)
|
868
905
|
|
869
|
-
Available [X11](https://en.wikipedia.org/wiki/X11_color_names)
|
906
|
+
Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
|
870
907
|
|
871
908
|
Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
|
872
909
|
|
@@ -1083,8 +1120,8 @@ window('Method-Based Custom Keyword') {
|
|
1083
1120
|
|
1084
1121
|
To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed through [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui):
|
1085
1122
|
- Check out [LibUI ffi.rb](https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb)
|
1086
|
-
- Check out the [libui C
|
1087
|
-
- Check out the [Go UI (Golang LibUI)
|
1123
|
+
- Check out the [libui C Headers](https://github.com/andlabs/libui/blob/master/ui.h)
|
1124
|
+
- Check out the [Go UI (Golang LibUI) API Documentation](https://pkg.go.dev/github.com/andlabs/ui) for an alternative well-documented [libui](https://github.com/andlabs/libui) reference.
|
1088
1125
|
|
1089
1126
|
## Packaging
|
1090
1127
|
|
@@ -4059,31 +4096,24 @@ window('Area Gallery', 400, 400) {
|
|
4059
4096
|
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}]
|
4060
4097
|
}
|
4061
4098
|
path { # declarative stable path
|
4062
|
-
|
4063
|
-
|
4064
|
-
line(400, 100)
|
4065
|
-
line(400, 400)
|
4066
|
-
|
4067
|
-
closed true
|
4068
|
-
}
|
4069
|
-
|
4099
|
+
polygon(100, 100, 100, 400, 400, 100, 400, 400)
|
4100
|
+
|
4070
4101
|
fill r: 202, g: 102, b: 104, a: 0.5
|
4071
4102
|
stroke r: 0, g: 0, b: 0
|
4072
4103
|
}
|
4073
4104
|
path { # declarative stable path
|
4074
|
-
|
4075
|
-
bezier(200, 100, 100, 200, 400, 100)
|
4076
|
-
bezier(300, 100, 100, 300, 100, 400)
|
4077
|
-
bezier(100, 300, 300, 100, 400, 400)
|
4078
|
-
|
4079
|
-
closed true
|
4080
|
-
}
|
4105
|
+
polybezier(0, 0, 200, 100, 100, 200, 400, 100, 300, 100, 100, 300, 100, 400, 100, 300, 300, 100, 400, 400)
|
4081
4106
|
|
4082
4107
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4083
4108
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4084
4109
|
}
|
4085
4110
|
path { # declarative stable path
|
4086
|
-
|
4111
|
+
polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
|
4112
|
+
|
4113
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4114
|
+
}
|
4115
|
+
path { # declarative stable path
|
4116
|
+
arc(404, 216, 190, 90, 90, false)
|
4087
4117
|
|
4088
4118
|
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4089
4119
|
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}]
|
@@ -4095,9 +4125,9 @@ window('Area Gallery', 400, 400) {
|
|
4095
4125
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4096
4126
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
4097
4127
|
}
|
4098
|
-
text(
|
4128
|
+
text(161, 40, 100) { # x, y, width
|
4099
4129
|
string('Area Gallery') {
|
4100
|
-
font family: '
|
4130
|
+
font family: 'Arial', size: 14
|
4101
4131
|
color :black
|
4102
4132
|
}
|
4103
4133
|
}
|
@@ -4246,18 +4276,42 @@ window('Area Gallery', 400, 400) {
|
|
4246
4276
|
end_x 400
|
4247
4277
|
end_y 400
|
4248
4278
|
}
|
4249
|
-
|
4250
|
-
closed true
|
4251
4279
|
}
|
4252
4280
|
|
4253
4281
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4254
4282
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4255
4283
|
}
|
4284
|
+
path { # declarative stable path
|
4285
|
+
polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
|
4286
|
+
figure {
|
4287
|
+
x 100
|
4288
|
+
y 100
|
4289
|
+
|
4290
|
+
line {
|
4291
|
+
x 400
|
4292
|
+
y 100
|
4293
|
+
}
|
4294
|
+
line {
|
4295
|
+
x 100
|
4296
|
+
y 400
|
4297
|
+
}
|
4298
|
+
line {
|
4299
|
+
x 400
|
4300
|
+
y 400
|
4301
|
+
}
|
4302
|
+
line {
|
4303
|
+
x 0
|
4304
|
+
y 0
|
4305
|
+
}
|
4306
|
+
}
|
4307
|
+
|
4308
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4309
|
+
}
|
4256
4310
|
path { # declarative stable path
|
4257
4311
|
arc {
|
4258
|
-
x_center
|
4259
|
-
y_center
|
4260
|
-
radius
|
4312
|
+
x_center 404
|
4313
|
+
y_center 216
|
4314
|
+
radius 190
|
4261
4315
|
start_angle 90
|
4262
4316
|
sweep 90
|
4263
4317
|
is_negative false
|
@@ -4278,12 +4332,12 @@ window('Area Gallery', 400, 400) {
|
|
4278
4332
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
4279
4333
|
}
|
4280
4334
|
text {
|
4281
|
-
x
|
4335
|
+
x 161
|
4282
4336
|
y 40
|
4283
4337
|
width 100
|
4284
4338
|
|
4285
4339
|
string {
|
4286
|
-
font family: '
|
4340
|
+
font family: 'Arial', size: 14
|
4287
4341
|
color :black
|
4288
4342
|
|
4289
4343
|
'Area Gallery'
|
@@ -4354,42 +4408,35 @@ window('Area Gallery', 400, 400) {
|
|
4354
4408
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4355
4409
|
square(0, 0, 100)
|
4356
4410
|
square(100, 100, 400)
|
4357
|
-
|
4411
|
+
|
4358
4412
|
fill r: 102, g: 102, b: 204
|
4359
4413
|
}
|
4360
4414
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4361
4415
|
rectangle(0, 100, 100, 400)
|
4362
4416
|
rectangle(100, 0, 400, 100)
|
4363
|
-
|
4417
|
+
|
4364
4418
|
# linear gradient (has x0, y0, x1, y1, and stops)
|
4365
4419
|
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}]
|
4366
4420
|
}
|
4367
4421
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4368
|
-
|
4369
|
-
|
4370
|
-
line(400, 100)
|
4371
|
-
line(400, 400)
|
4372
|
-
|
4373
|
-
closed true
|
4374
|
-
}
|
4375
|
-
|
4422
|
+
polygon(100, 100, 100, 400, 400, 100, 400, 400)
|
4423
|
+
|
4376
4424
|
fill r: 202, g: 102, b: 104, a: 0.5
|
4377
4425
|
stroke r: 0, g: 0, b: 0
|
4378
4426
|
}
|
4379
4427
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4380
|
-
|
4381
|
-
|
4382
|
-
bezier(300, 100, 100, 300, 100, 400)
|
4383
|
-
bezier(100, 300, 300, 100, 400, 400)
|
4384
|
-
|
4385
|
-
closed true
|
4386
|
-
}
|
4387
|
-
|
4428
|
+
polybezier(0, 0, 200, 100, 100, 200, 400, 100, 300, 100, 100, 300, 100, 400, 100, 300, 300, 100, 400, 400)
|
4429
|
+
|
4388
4430
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4389
4431
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4390
4432
|
}
|
4391
4433
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4392
|
-
|
4434
|
+
polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
|
4435
|
+
|
4436
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4437
|
+
}
|
4438
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4439
|
+
arc(404, 216, 190, 90, 90, false)
|
4393
4440
|
|
4394
4441
|
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4395
4442
|
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}]
|
@@ -4401,9 +4448,9 @@ window('Area Gallery', 400, 400) {
|
|
4401
4448
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4402
4449
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
4403
4450
|
}
|
4404
|
-
text(
|
4451
|
+
text(161, 40, 100) { # x, y, width
|
4405
4452
|
string('Area Gallery') {
|
4406
|
-
font family: '
|
4453
|
+
font family: 'Arial', size: 14
|
4407
4454
|
color :black
|
4408
4455
|
}
|
4409
4456
|
}
|
@@ -4518,10 +4565,10 @@ window('Area Gallery', 400, 400) {
|
|
4518
4565
|
x 400
|
4519
4566
|
y 400
|
4520
4567
|
}
|
4521
|
-
|
4568
|
+
|
4522
4569
|
closed true
|
4523
4570
|
}
|
4524
|
-
|
4571
|
+
|
4525
4572
|
fill r: 202, g: 102, b: 104, a: 0.5
|
4526
4573
|
stroke r: 0, g: 0, b: 0
|
4527
4574
|
}
|
@@ -4554,18 +4601,42 @@ window('Area Gallery', 400, 400) {
|
|
4554
4601
|
end_x 400
|
4555
4602
|
end_y 400
|
4556
4603
|
}
|
4557
|
-
|
4558
|
-
closed true
|
4559
4604
|
}
|
4560
|
-
|
4605
|
+
|
4561
4606
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4562
4607
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4563
4608
|
}
|
4609
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4610
|
+
polyline(100, 100, 400, 100, 100, 400, 400, 400, 0, 0)
|
4611
|
+
figure {
|
4612
|
+
x 100
|
4613
|
+
y 100
|
4614
|
+
|
4615
|
+
line {
|
4616
|
+
x 400
|
4617
|
+
y 100
|
4618
|
+
}
|
4619
|
+
line {
|
4620
|
+
x 100
|
4621
|
+
y 400
|
4622
|
+
}
|
4623
|
+
line {
|
4624
|
+
x 400
|
4625
|
+
y 400
|
4626
|
+
}
|
4627
|
+
line {
|
4628
|
+
x 0
|
4629
|
+
y 0
|
4630
|
+
}
|
4631
|
+
}
|
4632
|
+
|
4633
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4634
|
+
}
|
4564
4635
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4565
4636
|
arc {
|
4566
|
-
x_center
|
4567
|
-
y_center
|
4568
|
-
radius
|
4637
|
+
x_center 404
|
4638
|
+
y_center 216
|
4639
|
+
radius 190
|
4569
4640
|
start_angle 90
|
4570
4641
|
sweep 90
|
4571
4642
|
is_negative false
|
@@ -4586,12 +4657,12 @@ window('Area Gallery', 400, 400) {
|
|
4586
4657
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
4587
4658
|
}
|
4588
4659
|
text {
|
4589
|
-
x
|
4660
|
+
x 161
|
4590
4661
|
y 40
|
4591
4662
|
width 100
|
4592
4663
|
|
4593
4664
|
string {
|
4594
|
-
font family: '
|
4665
|
+
font family: 'Arial', size: 14
|
4595
4666
|
color :black
|
4596
4667
|
|
4597
4668
|
'Area Gallery'
|
@@ -4908,20 +4979,13 @@ end
|
|
4908
4979
|
|
4909
4980
|
# method-based custom control representing a graph path
|
4910
4981
|
def graph_path(width, height, should_extend, &block)
|
4911
|
-
locations = point_locations(width, height)
|
4982
|
+
locations = point_locations(width, height).flatten
|
4912
4983
|
path {
|
4913
|
-
|
4914
|
-
|
4915
|
-
|
4916
|
-
|
4917
|
-
|
4918
|
-
if should_extend
|
4919
|
-
line(width, height)
|
4920
|
-
line(0, height)
|
4921
|
-
|
4922
|
-
closed true
|
4923
|
-
end
|
4924
|
-
}
|
4984
|
+
if should_extend
|
4985
|
+
polygon(locations + [width, height, 0, height])
|
4986
|
+
else
|
4987
|
+
polyline(locations)
|
4988
|
+
end
|
4925
4989
|
|
4926
4990
|
# apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
|
4927
4991
|
transform {
|
@@ -6202,6 +6266,8 @@ window('Method-Based Custom Keyword') {
|
|
6202
6266
|
|
6203
6267
|
### Tetris
|
6204
6268
|
|
6269
|
+
Glimmer Tetris utilizes many small areas to represent Tetromino blocks because this ensures smaller redraws per tetromino block color change, thus achieving higher performance than redrawing one large area on every little change.
|
6270
|
+
|
6205
6271
|
[examples/tetris.rb](examples/tetris.rb)
|
6206
6272
|
|
6207
6273
|
Run with this command from the root of the project if you cloned the project:
|
@@ -6220,6 +6286,10 @@ Mac
|
|
6220
6286
|
|
6221
6287
|
![glimmer-dsl-libui-mac-tetris.png](images/glimmer-dsl-libui-mac-tetris.png)
|
6222
6288
|
|
6289
|
+
![glimmer-dsl-libui-mac-tetris-game-over.png](images/glimmer-dsl-libui-mac-tetris-game-over.png)
|
6290
|
+
|
6291
|
+
![glimmer-dsl-libui-mac-tetris-high-scores.png](images/glimmer-dsl-libui-mac-tetris-high-scores.png)
|
6292
|
+
|
6223
6293
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6224
6294
|
|
6225
6295
|
```ruby
|
@@ -6232,85 +6302,314 @@ class Tetris
|
|
6232
6302
|
|
6233
6303
|
BLOCK_SIZE = 25
|
6234
6304
|
BEVEL_CONSTANT = 20
|
6305
|
+
COLOR_GRAY = {r: 192, g: 192, b: 192}
|
6235
6306
|
|
6236
|
-
attr_reader :game
|
6237
|
-
|
6238
6307
|
def initialize
|
6239
6308
|
@game = Model::Game.new
|
6240
|
-
create_gui
|
6241
|
-
register_observers
|
6242
6309
|
end
|
6243
6310
|
|
6244
6311
|
def launch
|
6312
|
+
create_gui
|
6313
|
+
register_observers
|
6245
6314
|
@game.start!
|
6246
6315
|
@main_window.show
|
6247
6316
|
end
|
6248
6317
|
|
6249
6318
|
def create_gui
|
6250
|
-
|
6251
|
-
|
6319
|
+
menu_bar
|
6320
|
+
|
6321
|
+
@main_window = window('Glimmer Tetris') {
|
6322
|
+
content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
|
6323
|
+
resizable false
|
6324
|
+
|
6325
|
+
vertical_box {
|
6326
|
+
label { # filler
|
6327
|
+
stretchy false
|
6328
|
+
}
|
6329
|
+
|
6330
|
+
score_board(block_size: BLOCK_SIZE) {
|
6331
|
+
stretchy false
|
6332
|
+
}
|
6333
|
+
|
6334
|
+
@playfield_blocks = playfield(playfield_width: Model::Game::PLAYFIELD_WIDTH, playfield_height: Model::Game::PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
|
6335
|
+
}
|
6252
6336
|
}
|
6253
6337
|
end
|
6254
6338
|
|
6255
6339
|
def register_observers
|
6256
6340
|
Glimmer::DataBinding::Observer.proc do |game_over|
|
6257
6341
|
if game_over
|
6342
|
+
@pause_menu_item.enabled = false
|
6258
6343
|
show_game_over_dialog
|
6259
6344
|
else
|
6345
|
+
@pause_menu_item.enabled = true
|
6260
6346
|
start_moving_tetrominos_down
|
6261
6347
|
end
|
6262
6348
|
end.observe(@game, :game_over)
|
6263
6349
|
|
6264
6350
|
Model::Game::PLAYFIELD_HEIGHT.times do |row|
|
6265
|
-
Model::Game::
|
6351
|
+
Model::Game::PLAYFIELD_WIDTH.times do |column|
|
6266
6352
|
Glimmer::DataBinding::Observer.proc do |new_color|
|
6267
|
-
|
6353
|
+
Glimmer::LibUI.queue_main do
|
6354
|
+
color = Glimmer::LibUI.interpret_color(new_color)
|
6355
|
+
block = @playfield_blocks[row][column]
|
6356
|
+
block[:background_square].fill = color
|
6357
|
+
block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
|
6358
|
+
block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6359
|
+
block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6360
|
+
block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6361
|
+
block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
|
6362
|
+
end
|
6268
6363
|
end.observe(@game.playfield[row][column], :color)
|
6269
6364
|
end
|
6270
6365
|
end
|
6366
|
+
|
6367
|
+
Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
|
6368
|
+
Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
|
6369
|
+
Glimmer::DataBinding::Observer.proc do |new_color|
|
6370
|
+
Glimmer::LibUI.queue_main do
|
6371
|
+
color = Glimmer::LibUI.interpret_color(new_color)
|
6372
|
+
block = @preview_playfield_blocks[row][column]
|
6373
|
+
block[:background_square].fill = color
|
6374
|
+
block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
|
6375
|
+
block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6376
|
+
block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6377
|
+
block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
6378
|
+
block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
|
6379
|
+
end
|
6380
|
+
end.observe(@game.preview_playfield[row][column], :color)
|
6381
|
+
end
|
6382
|
+
end
|
6383
|
+
|
6384
|
+
Glimmer::DataBinding::Observer.proc do |new_score|
|
6385
|
+
Glimmer::LibUI.queue_main do
|
6386
|
+
@score_label.text = new_score.to_s
|
6387
|
+
end
|
6388
|
+
end.observe(@game, :score)
|
6389
|
+
|
6390
|
+
Glimmer::DataBinding::Observer.proc do |new_lines|
|
6391
|
+
Glimmer::LibUI.queue_main do
|
6392
|
+
@lines_label.text = new_lines.to_s
|
6393
|
+
end
|
6394
|
+
end.observe(@game, :lines)
|
6395
|
+
|
6396
|
+
Glimmer::DataBinding::Observer.proc do |new_level|
|
6397
|
+
Glimmer::LibUI.queue_main do
|
6398
|
+
@level_label.text = new_level.to_s
|
6399
|
+
end
|
6400
|
+
end.observe(@game, :level)
|
6271
6401
|
end
|
6272
6402
|
|
6273
|
-
def
|
6274
|
-
|
6275
|
-
@
|
6276
|
-
|
6277
|
-
|
6403
|
+
def menu_bar
|
6404
|
+
menu('Game') {
|
6405
|
+
@pause_menu_item = check_menu_item('Pause') {
|
6406
|
+
enabled false
|
6407
|
+
|
6408
|
+
on_clicked do
|
6409
|
+
@game.paused = @pause_menu_item.checked?
|
6410
|
+
end
|
6411
|
+
}
|
6412
|
+
menu_item('Restart') {
|
6413
|
+
on_clicked do
|
6414
|
+
@game.restart!
|
6415
|
+
end
|
6416
|
+
}
|
6417
|
+
separator_menu_item
|
6418
|
+
menu_item('Exit') {
|
6419
|
+
on_clicked do
|
6420
|
+
exit(0)
|
6421
|
+
end
|
6422
|
+
}
|
6423
|
+
quit_menu_item if OS.mac?
|
6424
|
+
}
|
6425
|
+
|
6426
|
+
menu('View') {
|
6427
|
+
menu_item('Show High Scores') {
|
6428
|
+
on_clicked do
|
6429
|
+
show_high_scores
|
6430
|
+
end
|
6431
|
+
}
|
6432
|
+
menu_item('Clear High Scores') {
|
6433
|
+
on_clicked {
|
6434
|
+
@game.clear_high_scores!
|
6435
|
+
}
|
6436
|
+
}
|
6437
|
+
}
|
6438
|
+
|
6439
|
+
menu('Options') {
|
6440
|
+
radio_menu_item('Instant Down on Up Arrow') {
|
6441
|
+
on_clicked do
|
6442
|
+
@game.instant_down_on_up = true
|
6443
|
+
end
|
6444
|
+
}
|
6445
|
+
radio_menu_item('Rotate Right on Up Arrow') {
|
6446
|
+
on_clicked do
|
6447
|
+
@game.rotate_right_on_up = true
|
6448
|
+
end
|
6449
|
+
}
|
6450
|
+
radio_menu_item('Rotate Left on Up Arrow') {
|
6451
|
+
on_clicked do
|
6452
|
+
@game.rotate_left_on_up = true
|
6453
|
+
end
|
6454
|
+
}
|
6455
|
+
}
|
6456
|
+
|
6457
|
+
menu('Help') {
|
6458
|
+
if OS.mac?
|
6459
|
+
about_menu_item {
|
6460
|
+
on_clicked do
|
6461
|
+
show_about_dialog
|
6462
|
+
end
|
6463
|
+
}
|
6464
|
+
end
|
6465
|
+
menu_item('About') {
|
6466
|
+
on_clicked do
|
6467
|
+
show_about_dialog
|
6278
6468
|
end
|
6469
|
+
}
|
6470
|
+
}
|
6471
|
+
end
|
6472
|
+
|
6473
|
+
def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
|
6474
|
+
blocks = []
|
6475
|
+
vertical_box {
|
6476
|
+
padded false
|
6477
|
+
|
6478
|
+
playfield_height.times.map do |row|
|
6479
|
+
blocks << []
|
6480
|
+
horizontal_box {
|
6481
|
+
padded false
|
6482
|
+
|
6483
|
+
playfield_width.times.map do |column|
|
6484
|
+
blocks.last << block(row: row, column: column, block_size: block_size)
|
6485
|
+
end
|
6486
|
+
}
|
6279
6487
|
end
|
6280
6488
|
|
6489
|
+
extra_content&.call
|
6490
|
+
}
|
6491
|
+
blocks
|
6492
|
+
end
|
6493
|
+
|
6494
|
+
def block(row: , column: , block_size: , &extra_content)
|
6495
|
+
block = {}
|
6496
|
+
bevel_pixel_size = 0.16 * block_size.to_f
|
6497
|
+
color = Glimmer::LibUI.interpret_color(Model::Block::COLOR_CLEAR)
|
6498
|
+
area {
|
6499
|
+
block[:background_square] = path {
|
6500
|
+
square(0, 0, block_size)
|
6501
|
+
|
6502
|
+
fill color
|
6503
|
+
}
|
6504
|
+
block[:top_bevel_edge] = path {
|
6505
|
+
polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
|
6506
|
+
|
6507
|
+
fill r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT
|
6508
|
+
}
|
6509
|
+
block[:right_bevel_edge] = path {
|
6510
|
+
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)
|
6511
|
+
|
6512
|
+
fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
|
6513
|
+
}
|
6514
|
+
block[:bottom_bevel_edge] = path {
|
6515
|
+
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)
|
6516
|
+
|
6517
|
+
fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
|
6518
|
+
}
|
6519
|
+
block[:left_bevel_edge] = path {
|
6520
|
+
polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
|
6521
|
+
|
6522
|
+
fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
|
6523
|
+
}
|
6524
|
+
block[:border_square] = path {
|
6525
|
+
square(0, 0, block_size)
|
6526
|
+
|
6527
|
+
stroke COLOR_GRAY
|
6528
|
+
}
|
6529
|
+
|
6281
6530
|
on_key_down do |key_event|
|
6282
6531
|
case key_event
|
6283
6532
|
in ext_key: :down
|
6284
|
-
game.down!
|
6533
|
+
@game.down!
|
6534
|
+
in key: ' '
|
6535
|
+
@game.down!(instant: true)
|
6285
6536
|
in ext_key: :up
|
6286
|
-
case game.up_arrow_action
|
6537
|
+
case @game.up_arrow_action
|
6287
6538
|
when :instant_down
|
6288
|
-
game.down!(instant: true)
|
6539
|
+
@game.down!(instant: true)
|
6289
6540
|
when :rotate_right
|
6290
|
-
game.rotate!(:right)
|
6541
|
+
@game.rotate!(:right)
|
6291
6542
|
when :rotate_left
|
6292
|
-
game.rotate!(:left)
|
6543
|
+
@game.rotate!(:left)
|
6293
6544
|
end
|
6294
6545
|
in ext_key: :left
|
6295
|
-
game.left!
|
6546
|
+
@game.left!
|
6296
6547
|
in ext_key: :right
|
6297
|
-
game.right!
|
6548
|
+
@game.right!
|
6298
6549
|
in modifier: :shift
|
6299
|
-
game.rotate!(:right)
|
6550
|
+
@game.rotate!(:right)
|
6300
6551
|
in modifier: :control
|
6301
|
-
game.rotate!(:left)
|
6552
|
+
@game.rotate!(:left)
|
6302
6553
|
else
|
6303
6554
|
# Do Nothing
|
6304
6555
|
end
|
6305
6556
|
end
|
6557
|
+
|
6558
|
+
extra_content&.call
|
6306
6559
|
}
|
6560
|
+
block
|
6307
6561
|
end
|
6308
6562
|
|
6309
|
-
def
|
6310
|
-
|
6311
|
-
|
6312
|
-
|
6313
|
-
|
6563
|
+
def score_board(block_size: , &extra_content)
|
6564
|
+
vertical_box {
|
6565
|
+
horizontal_box {
|
6566
|
+
label # filler
|
6567
|
+
@preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
|
6568
|
+
label # filler
|
6569
|
+
}
|
6570
|
+
|
6571
|
+
horizontal_box {
|
6572
|
+
label # filler
|
6573
|
+
grid {
|
6574
|
+
stretchy false
|
6575
|
+
|
6576
|
+
label('Score') {
|
6577
|
+
left 0
|
6578
|
+
top 0
|
6579
|
+
halign :fill
|
6580
|
+
}
|
6581
|
+
@score_label = label {
|
6582
|
+
left 0
|
6583
|
+
top 1
|
6584
|
+
halign :center
|
6585
|
+
}
|
6586
|
+
|
6587
|
+
label('Lines') {
|
6588
|
+
left 1
|
6589
|
+
top 0
|
6590
|
+
halign :fill
|
6591
|
+
}
|
6592
|
+
@lines_label = label {
|
6593
|
+
left 1
|
6594
|
+
top 1
|
6595
|
+
halign :center
|
6596
|
+
}
|
6597
|
+
|
6598
|
+
label('Level') {
|
6599
|
+
left 2
|
6600
|
+
top 0
|
6601
|
+
halign :fill
|
6602
|
+
}
|
6603
|
+
@level_label = label {
|
6604
|
+
left 2
|
6605
|
+
top 1
|
6606
|
+
halign :center
|
6607
|
+
}
|
6608
|
+
}
|
6609
|
+
label # filler
|
6610
|
+
}
|
6611
|
+
|
6612
|
+
extra_content&.call
|
6314
6613
|
}
|
6315
6614
|
end
|
6316
6615
|
|
@@ -6321,13 +6620,151 @@ class Tetris
|
|
6321
6620
|
end
|
6322
6621
|
|
6323
6622
|
def show_game_over_dialog
|
6324
|
-
|
6623
|
+
Glimmer::LibUI.queue_main do
|
6624
|
+
msg_box('Game Over!', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
|
6625
|
+
@game.restart!
|
6626
|
+
end
|
6627
|
+
end
|
6628
|
+
|
6629
|
+
def show_high_scores
|
6630
|
+
Glimmer::LibUI.queue_main do
|
6631
|
+
if @game.high_scores.empty?
|
6632
|
+
high_scores_string = "No games have been scored yet."
|
6633
|
+
else
|
6634
|
+
high_scores_string = @game.high_scores.map do |high_score|
|
6635
|
+
"#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
|
6636
|
+
end.join("\n")
|
6637
|
+
end
|
6638
|
+
msg_box('High Scores', high_scores_string)
|
6639
|
+
end
|
6640
|
+
end
|
6641
|
+
|
6642
|
+
def show_about_dialog
|
6643
|
+
Glimmer::LibUI.queue_main do
|
6644
|
+
msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
|
6645
|
+
end
|
6325
6646
|
end
|
6326
6647
|
end
|
6327
6648
|
|
6328
6649
|
Tetris.new.launch
|
6329
6650
|
```
|
6330
6651
|
|
6652
|
+
### Tic Tac Toe
|
6653
|
+
|
6654
|
+
[examples/tic_tac_toe.rb](examples/tic_tac_toe.rb)
|
6655
|
+
|
6656
|
+
Run with this command from the root of the project if you cloned the project:
|
6657
|
+
|
6658
|
+
```
|
6659
|
+
ruby -r './lib/glimmer-dsl-libui' examples/tic_tac_toe.rb
|
6660
|
+
```
|
6661
|
+
|
6662
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6663
|
+
|
6664
|
+
```
|
6665
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/tic_tac_toe'"
|
6666
|
+
```
|
6667
|
+
|
6668
|
+
Mac
|
6669
|
+
|
6670
|
+
![glimmer-dsl-libui-mac-tic-tac-toe.png](images/glimmer-dsl-libui-mac-tic-tac-toe.png)
|
6671
|
+
|
6672
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png)
|
6673
|
+
|
6674
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png)
|
6675
|
+
|
6676
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-draw.png](images/glimmer-dsl-libui-mac-tic-tac-toe-draw.png)
|
6677
|
+
|
6678
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6679
|
+
|
6680
|
+
```ruby
|
6681
|
+
require 'glimmer-dsl-libui'
|
6682
|
+
|
6683
|
+
require_relative "tic_tac_toe/board"
|
6684
|
+
|
6685
|
+
class TicTacToe
|
6686
|
+
include Glimmer
|
6687
|
+
|
6688
|
+
def initialize
|
6689
|
+
@tic_tac_toe_board = Board.new
|
6690
|
+
end
|
6691
|
+
|
6692
|
+
def launch
|
6693
|
+
create_gui
|
6694
|
+
register_observers
|
6695
|
+
@main_window.show
|
6696
|
+
end
|
6697
|
+
|
6698
|
+
def register_observers
|
6699
|
+
Glimmer::DataBinding::Observer.proc do |game_status|
|
6700
|
+
display_win_message if game_status == Board::WIN
|
6701
|
+
display_draw_message if game_status == Board::DRAW
|
6702
|
+
end.observe(@tic_tac_toe_board, :game_status)
|
6703
|
+
|
6704
|
+
3.times.map do |row|
|
6705
|
+
3.times.map do |column|
|
6706
|
+
Glimmer::DataBinding::Observer.proc do |sign|
|
6707
|
+
@cells[row][column].string = sign
|
6708
|
+
end.observe(@tic_tac_toe_board[row + 1, column + 1], :sign) # board model is 1-based
|
6709
|
+
end
|
6710
|
+
end
|
6711
|
+
end
|
6712
|
+
|
6713
|
+
def create_gui
|
6714
|
+
@main_window = window('Tic-Tac-Toe', 180, 180) {
|
6715
|
+
resizable false
|
6716
|
+
|
6717
|
+
@cells = []
|
6718
|
+
vertical_box {
|
6719
|
+
padded false
|
6720
|
+
|
6721
|
+
3.times.map do |row|
|
6722
|
+
@cells << []
|
6723
|
+
horizontal_box {
|
6724
|
+
padded false
|
6725
|
+
|
6726
|
+
3.times.map do |column|
|
6727
|
+
area {
|
6728
|
+
path {
|
6729
|
+
square(0, 0, 60)
|
6730
|
+
|
6731
|
+
stroke :black, thickness: 2
|
6732
|
+
}
|
6733
|
+
text(23, 19) {
|
6734
|
+
@cells[row] << string('') {
|
6735
|
+
font family: 'Arial', size: 20
|
6736
|
+
}
|
6737
|
+
}
|
6738
|
+
on_mouse_up do
|
6739
|
+
@tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
|
6740
|
+
end
|
6741
|
+
}
|
6742
|
+
end
|
6743
|
+
}
|
6744
|
+
end
|
6745
|
+
}
|
6746
|
+
}
|
6747
|
+
end
|
6748
|
+
|
6749
|
+
def display_win_message
|
6750
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
6751
|
+
end
|
6752
|
+
|
6753
|
+
def display_draw_message
|
6754
|
+
display_game_over_message("Draw!")
|
6755
|
+
end
|
6756
|
+
|
6757
|
+
def display_game_over_message(message_text)
|
6758
|
+
Glimmer::LibUI.queue_main do
|
6759
|
+
msg_box('Game Over', message_text)
|
6760
|
+
@tic_tac_toe_board.reset!
|
6761
|
+
end
|
6762
|
+
end
|
6763
|
+
end
|
6764
|
+
|
6765
|
+
TicTacToe.new.launch
|
6766
|
+
```
|
6767
|
+
|
6331
6768
|
## Applications
|
6332
6769
|
|
6333
6770
|
Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
@@ -6358,9 +6795,10 @@ https://github.com/iraamaro/i3off-gtk-ruby
|
|
6358
6795
|
|
6359
6796
|
## Resources
|
6360
6797
|
|
6361
|
-
- [libui C Library](https://github.com/andlabs/libui)
|
6362
|
-
- [LibUI Ruby Bindings](https://github.com/kojix2/LibUI)
|
6363
6798
|
- [Code Master Blog](https://andymaleh.blogspot.com/search/label/LibUI)
|
6799
|
+
- [LibUI Ruby Bindings](https://github.com/kojix2/LibUI)
|
6800
|
+
- [libui C Library](https://github.com/andlabs/libui)
|
6801
|
+
- [Go UI (Golang LibUI) API Documentation](https://pkg.go.dev/github.com/andlabs/ui)
|
6364
6802
|
|
6365
6803
|
## Help
|
6366
6804
|
|