glimmer-dsl-libui 0.2.19 → 0.2.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +467 -35
- data/VERSION +1 -1
- data/examples/area_gallery.rb +1 -1
- data/examples/area_gallery2.rb +1 -1
- data/examples/area_gallery3.rb +1 -1
- data/examples/area_gallery4.rb +1 -1
- data/examples/meta_example.rb +1 -1
- data/examples/snake/model/apple.rb +33 -0
- data/examples/snake/model/game.rb +51 -0
- data/examples/snake/model/snake.rb +95 -0
- data/examples/snake/model/vertebra.rb +22 -0
- data/examples/snake/presenter/cell.rb +27 -0
- data/examples/snake/presenter/grid.rb +47 -0
- data/examples/snake.rb +90 -0
- data/examples/tetris/model/game.rb +3 -1
- data/examples/tetris.rb +127 -15
- 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/libui/control_proxy/window_proxy.rb +40 -1
- data/lib/glimmer/libui.rb +34 -6
- metadata +12 -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.23
|
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)
|
@@ -143,7 +143,7 @@ window('Area Gallery', 400, 400) {
|
|
143
143
|
}
|
144
144
|
text(161, 40, 100) { # x, y, width
|
145
145
|
string('Area Gallery') {
|
146
|
-
font family: 'Arial', size: 14
|
146
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
147
147
|
color :black
|
148
148
|
}
|
149
149
|
}
|
@@ -218,9 +218,10 @@ NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is fe
|
|
218
218
|
Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
|
219
219
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
|
220
220
|
- [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps)
|
221
|
+
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
222
|
+
- [glimmer-dsl-gtk](https://github.com/AndyObtiva/glimmer-dsl-gtk): Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library)
|
221
223
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
222
224
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
|
223
|
-
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
224
225
|
|
225
226
|
## Table of Contents
|
226
227
|
|
@@ -278,6 +279,8 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
278
279
|
- [Custom Draw Text](#custom-draw-text)
|
279
280
|
- [Method-Based Custom Keyword](#method-based-custom-keyword)
|
280
281
|
- [Tetris](#tetris)
|
282
|
+
- [Tic Tac Toe](#tic-tac-toe)
|
283
|
+
- [Snake](#snake)
|
281
284
|
- [Applications](#applications)
|
282
285
|
- [Manga2PDF](#manga2pdf)
|
283
286
|
- [Befunge98 GUI](#befunge98-gui)
|
@@ -370,7 +373,7 @@ gem install glimmer-dsl-libui
|
|
370
373
|
Or install via Bundler `Gemfile`:
|
371
374
|
|
372
375
|
```ruby
|
373
|
-
gem 'glimmer-dsl-libui', '~> 0.2.
|
376
|
+
gem 'glimmer-dsl-libui', '~> 0.2.23'
|
374
377
|
```
|
375
378
|
|
376
379
|
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.
|
@@ -456,6 +459,7 @@ Keyword(Args) | Properties | Listeners
|
|
456
459
|
`checkbox_column(name as String)` | `editable` (Boolean) | None
|
457
460
|
`checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
458
461
|
`checkbox_text_color_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
462
|
+
`check_menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
|
459
463
|
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
|
460
464
|
`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`
|
461
465
|
`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`
|
@@ -478,7 +482,7 @@ Keyword(Args) | Properties | Listeners
|
|
478
482
|
`line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
|
479
483
|
`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
|
480
484
|
`menu(text as String)` | None | None
|
481
|
-
`menu_item(text as String)` |
|
485
|
+
`menu_item(text as String)` | None | `on_clicked`
|
482
486
|
`message_box` (alias for `msg_box`; see for arguments) | None | None
|
483
487
|
`message_box_error` (alias for `msg_box_error`; see for arguments) | None | None
|
484
488
|
`multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
@@ -497,6 +501,7 @@ Keyword(Args) | Properties | Listeners
|
|
497
501
|
`radio_buttons` | `selected` (`Integer`) | `on_selected`
|
498
502
|
`rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `width` (`Numeric`), `height` (`Numeric`) | None
|
499
503
|
`search_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
504
|
+
`separator_menu_item` | None | None
|
500
505
|
`slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
501
506
|
`spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
502
507
|
`square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
|
@@ -510,7 +515,7 @@ Keyword(Args) | Properties | Listeners
|
|
510
515
|
`time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
|
511
516
|
`vertical_box` | `padded` (Boolean) | None
|
512
517
|
`vertical_separator` | None | None
|
513
|
-
`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`
|
518
|
+
`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`
|
514
519
|
|
515
520
|
### Common Control Properties
|
516
521
|
- `enabled` (Boolean)
|
@@ -543,6 +548,35 @@ All operations that could normally be called on `LibUI` can also be called on `G
|
|
543
548
|
- `Glimmer::LibUI::queue_main(&block)`: queues an operation to be run on the main event loop at the earliest opportunity possible
|
544
549
|
- `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.
|
545
550
|
|
551
|
+
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:
|
552
|
+
- `Glimmer::LibUI::integer_to_boolean(int, allow_nil: true)`
|
553
|
+
- `Glimmer::LibUI::boolean_to_integer(int, allow_nil: true)`
|
554
|
+
- `Glimmer::LibUI::degrees_to_radians(degrees)`
|
555
|
+
- `Glimmer::LibUI::interpret_color(value)`: interprets a color in any form like `String`, `Symbol`, or hex into an rgb `Hash`
|
556
|
+
- `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash`
|
557
|
+
- `Glimmer::LibUI::enum_names`: provides all possible enum names to use with `Glimmer::LibUI::enum_symbols(enum_name)`
|
558
|
+
- `Glimmer::LibUI::enum_symbols(enum_name)`: returns all possible values for an enum. `enum_name` can be:
|
559
|
+
- `:draw_brush_type`: `[:solid, :linear_gradient, :radial_gradient, :image]`
|
560
|
+
- `:draw_line_cap`: `[:flat, :round, :square]`
|
561
|
+
- `:draw_line_join`: `[:miter, :round, :bevel]`
|
562
|
+
- `:draw_fill_mode`: `[:winding, :alternate]`
|
563
|
+
- `:attribute_type`: attributes for attributed `string`s: `[:family, :size, weight, :italic, :stretch, :color, :background, :underline, :underline_color, :features]`
|
564
|
+
- `:text_weight`: `[:minimum, :thin, :ultra_light, :light, :book, :normal, :medium, :semi_bold, :bold, :ultra_bold, :heavy, :ultra_heavy, :maximum]`
|
565
|
+
- `:text_italic`: `[:normal, :oblique, :italic]`
|
566
|
+
- `:text_stretch`: `[:ultra_condensed, :extra_condensed, :condensed, :semi_condensed, :normal, :semi_expanded, :expanded, :extra_expanded, :ultra_expanded]`
|
567
|
+
- `:underline`: `[:none, :single, :double, :suggestion, :color_custom, :color_spelling, :color_grammar, :color_auxiliary]`
|
568
|
+
- `:underline_color`: `[:custom, :spelling, :grammar, :auxiliary]`
|
569
|
+
- `:draw_text_align`: `[:left, :center, :right]`
|
570
|
+
- `:modifier`: `[:ctrl, :alt, :shift, :super]`
|
571
|
+
- `: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]`
|
572
|
+
- `:at`: for inserting `grid` controls: `[:leading, :top, :trailing, :bottom]`
|
573
|
+
- `:align`: `[:fill, :start, :center, :end]`
|
574
|
+
- `:table_value_type`: `[:string, :image, :int, :color]`
|
575
|
+
- `:table_model_column`: `[:never_editable, :always_editable]`
|
576
|
+
- `Glimmer::LibUI::enum_symbol_to_value(enum_name, enum_symbol, default_symbol: nil, default_index: 0)`
|
577
|
+
- `Glimmer::LibUI::enum_value_to_symbol(enum_name, enum_value)`
|
578
|
+
- `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]`
|
579
|
+
|
546
580
|
### Extra Dialogs
|
547
581
|
|
548
582
|
- `open_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
|
@@ -871,7 +905,7 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
871
905
|
|
872
906
|
`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)
|
873
907
|
|
874
|
-
Available [X11](https://en.wikipedia.org/wiki/X11_color_names)
|
908
|
+
Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
|
875
909
|
|
876
910
|
Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
|
877
911
|
|
@@ -1088,8 +1122,8 @@ window('Method-Based Custom Keyword') {
|
|
1088
1122
|
|
1089
1123
|
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):
|
1090
1124
|
- Check out [LibUI ffi.rb](https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb)
|
1091
|
-
- Check out the [libui C
|
1092
|
-
- Check out the [Go UI (Golang LibUI)
|
1125
|
+
- Check out the [libui C Headers](https://github.com/andlabs/libui/blob/master/ui.h)
|
1126
|
+
- 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.
|
1093
1127
|
|
1094
1128
|
## Packaging
|
1095
1129
|
|
@@ -1189,7 +1223,7 @@ class MetaExample
|
|
1189
1223
|
|
1190
1224
|
def run_example(example)
|
1191
1225
|
Thread.new do
|
1192
|
-
command = "ruby -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
1226
|
+
command = "#{RbConfig.ruby} -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
1193
1227
|
result = ''
|
1194
1228
|
IO.popen(command) do |f|
|
1195
1229
|
sleep(0.0001) # yield to main thread
|
@@ -1726,11 +1760,11 @@ class TinyMidiPlayer
|
|
1726
1760
|
|
1727
1761
|
UI.new_horizontal_box.tap do |hbox|
|
1728
1762
|
UI.new_vertical_box.tap do |vbox|
|
1729
|
-
UI.new_button('
|
1763
|
+
UI.new_button('â–¶').tap do |button1|
|
1730
1764
|
UI.button_on_clicked(button1) { play_midi }
|
1731
1765
|
UI.box_append(vbox, button1, 1)
|
1732
1766
|
end
|
1733
|
-
UI.new_button('
|
1767
|
+
UI.new_button('â– ').tap do |button2|
|
1734
1768
|
UI.button_on_clicked(button2) { stop_midi }
|
1735
1769
|
UI.box_append(vbox, button2, 1)
|
1736
1770
|
end
|
@@ -1824,12 +1858,12 @@ class TinyMidiPlayer
|
|
1824
1858
|
vertical_box {
|
1825
1859
|
stretchy false
|
1826
1860
|
|
1827
|
-
button('
|
1861
|
+
button('â–¶') {
|
1828
1862
|
on_clicked do
|
1829
1863
|
play_midi
|
1830
1864
|
end
|
1831
1865
|
}
|
1832
|
-
button('
|
1866
|
+
button('â– ') {
|
1833
1867
|
on_clicked do
|
1834
1868
|
stop_midi
|
1835
1869
|
end
|
@@ -4095,7 +4129,7 @@ window('Area Gallery', 400, 400) {
|
|
4095
4129
|
}
|
4096
4130
|
text(161, 40, 100) { # x, y, width
|
4097
4131
|
string('Area Gallery') {
|
4098
|
-
font family: 'Arial', size: 14
|
4132
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4099
4133
|
color :black
|
4100
4134
|
}
|
4101
4135
|
}
|
@@ -4305,7 +4339,7 @@ window('Area Gallery', 400, 400) {
|
|
4305
4339
|
width 100
|
4306
4340
|
|
4307
4341
|
string {
|
4308
|
-
font family: 'Arial', size: 14
|
4342
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4309
4343
|
color :black
|
4310
4344
|
|
4311
4345
|
'Area Gallery'
|
@@ -4418,7 +4452,7 @@ window('Area Gallery', 400, 400) {
|
|
4418
4452
|
}
|
4419
4453
|
text(161, 40, 100) { # x, y, width
|
4420
4454
|
string('Area Gallery') {
|
4421
|
-
font family: 'Arial', size: 14
|
4455
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4422
4456
|
color :black
|
4423
4457
|
}
|
4424
4458
|
}
|
@@ -4630,7 +4664,7 @@ window('Area Gallery', 400, 400) {
|
|
4630
4664
|
width 100
|
4631
4665
|
|
4632
4666
|
string {
|
4633
|
-
font family: 'Arial', size: 14
|
4667
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4634
4668
|
color :black
|
4635
4669
|
|
4636
4670
|
'Area Gallery'
|
@@ -6234,6 +6268,8 @@ window('Method-Based Custom Keyword') {
|
|
6234
6268
|
|
6235
6269
|
### Tetris
|
6236
6270
|
|
6271
|
+
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.
|
6272
|
+
|
6237
6273
|
[examples/tetris.rb](examples/tetris.rb)
|
6238
6274
|
|
6239
6275
|
Run with this command from the root of the project if you cloned the project:
|
@@ -6254,6 +6290,24 @@ Mac
|
|
6254
6290
|
|
6255
6291
|
![glimmer-dsl-libui-mac-tetris-game-over.png](images/glimmer-dsl-libui-mac-tetris-game-over.png)
|
6256
6292
|
|
6293
|
+
![glimmer-dsl-libui-mac-tetris-high-scores.png](images/glimmer-dsl-libui-mac-tetris-high-scores.png)
|
6294
|
+
|
6295
|
+
Windows
|
6296
|
+
|
6297
|
+
![glimmer-dsl-libui-windows-tetris.png](images/glimmer-dsl-libui-windows-tetris.png)
|
6298
|
+
|
6299
|
+
![glimmer-dsl-libui-windows-tetris-game-over.png](images/glimmer-dsl-libui-windows-tetris-game-over.png)
|
6300
|
+
|
6301
|
+
![glimmer-dsl-libui-windows-tetris-high-scores.png](images/glimmer-dsl-libui-windows-tetris-high-scores.png)
|
6302
|
+
|
6303
|
+
Linux
|
6304
|
+
|
6305
|
+
![glimmer-dsl-libui-linux-tetris.png](images/glimmer-dsl-libui-linux-tetris.png)
|
6306
|
+
|
6307
|
+
![glimmer-dsl-libui-linux-tetris-game-over.png](images/glimmer-dsl-libui-linux-tetris-game-over.png)
|
6308
|
+
|
6309
|
+
![glimmer-dsl-libui-linux-tetris-high-scores.png](images/glimmer-dsl-libui-linux-tetris-high-scores.png)
|
6310
|
+
|
6257
6311
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6258
6312
|
|
6259
6313
|
```ruby
|
@@ -6268,8 +6322,6 @@ class Tetris
|
|
6268
6322
|
BEVEL_CONSTANT = 20
|
6269
6323
|
COLOR_GRAY = {r: 192, g: 192, b: 192}
|
6270
6324
|
|
6271
|
-
attr_reader :game
|
6272
|
-
|
6273
6325
|
def initialize
|
6274
6326
|
@game = Model::Game.new
|
6275
6327
|
end
|
@@ -6282,8 +6334,11 @@ class Tetris
|
|
6282
6334
|
end
|
6283
6335
|
|
6284
6336
|
def create_gui
|
6337
|
+
menu_bar
|
6338
|
+
|
6285
6339
|
@main_window = window('Glimmer Tetris') {
|
6286
6340
|
content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
|
6341
|
+
resizable false
|
6287
6342
|
|
6288
6343
|
vertical_box {
|
6289
6344
|
label { # filler
|
@@ -6302,8 +6357,10 @@ class Tetris
|
|
6302
6357
|
def register_observers
|
6303
6358
|
Glimmer::DataBinding::Observer.proc do |game_over|
|
6304
6359
|
if game_over
|
6360
|
+
@pause_menu_item.enabled = false
|
6305
6361
|
show_game_over_dialog
|
6306
6362
|
else
|
6363
|
+
@pause_menu_item.enabled = true
|
6307
6364
|
start_moving_tetrominos_down
|
6308
6365
|
end
|
6309
6366
|
end.observe(@game, :game_over)
|
@@ -6361,6 +6418,76 @@ class Tetris
|
|
6361
6418
|
end.observe(@game, :level)
|
6362
6419
|
end
|
6363
6420
|
|
6421
|
+
def menu_bar
|
6422
|
+
menu('Game') {
|
6423
|
+
@pause_menu_item = check_menu_item('Pause') {
|
6424
|
+
enabled false
|
6425
|
+
|
6426
|
+
on_clicked do
|
6427
|
+
@game.paused = @pause_menu_item.checked?
|
6428
|
+
end
|
6429
|
+
}
|
6430
|
+
menu_item('Restart') {
|
6431
|
+
on_clicked do
|
6432
|
+
@game.restart!
|
6433
|
+
end
|
6434
|
+
}
|
6435
|
+
separator_menu_item
|
6436
|
+
menu_item('Exit') {
|
6437
|
+
on_clicked do
|
6438
|
+
exit(0)
|
6439
|
+
end
|
6440
|
+
}
|
6441
|
+
quit_menu_item if OS.mac?
|
6442
|
+
}
|
6443
|
+
|
6444
|
+
menu('View') {
|
6445
|
+
menu_item('Show High Scores') {
|
6446
|
+
on_clicked do
|
6447
|
+
show_high_scores
|
6448
|
+
end
|
6449
|
+
}
|
6450
|
+
menu_item('Clear High Scores') {
|
6451
|
+
on_clicked {
|
6452
|
+
@game.clear_high_scores!
|
6453
|
+
}
|
6454
|
+
}
|
6455
|
+
}
|
6456
|
+
|
6457
|
+
menu('Options') {
|
6458
|
+
radio_menu_item('Instant Down on Up Arrow') {
|
6459
|
+
on_clicked do
|
6460
|
+
@game.instant_down_on_up = true
|
6461
|
+
end
|
6462
|
+
}
|
6463
|
+
radio_menu_item('Rotate Right on Up Arrow') {
|
6464
|
+
on_clicked do
|
6465
|
+
@game.rotate_right_on_up = true
|
6466
|
+
end
|
6467
|
+
}
|
6468
|
+
radio_menu_item('Rotate Left on Up Arrow') {
|
6469
|
+
on_clicked do
|
6470
|
+
@game.rotate_left_on_up = true
|
6471
|
+
end
|
6472
|
+
}
|
6473
|
+
}
|
6474
|
+
|
6475
|
+
menu('Help') {
|
6476
|
+
if OS.mac?
|
6477
|
+
about_menu_item {
|
6478
|
+
on_clicked do
|
6479
|
+
show_about_dialog
|
6480
|
+
end
|
6481
|
+
}
|
6482
|
+
end
|
6483
|
+
menu_item('About') {
|
6484
|
+
on_clicked do
|
6485
|
+
show_about_dialog
|
6486
|
+
end
|
6487
|
+
}
|
6488
|
+
}
|
6489
|
+
end
|
6490
|
+
|
6364
6491
|
def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
|
6365
6492
|
blocks = []
|
6366
6493
|
vertical_box {
|
@@ -6421,26 +6548,38 @@ class Tetris
|
|
6421
6548
|
on_key_down do |key_event|
|
6422
6549
|
case key_event
|
6423
6550
|
in ext_key: :down
|
6424
|
-
|
6551
|
+
if OS.windows?
|
6552
|
+
# rate limit downs in Windows as they go too fast when key is held
|
6553
|
+
@queued_downs ||= 0
|
6554
|
+
if @queued_downs < 2
|
6555
|
+
@queued_downs += 1
|
6556
|
+
Glimmer::LibUI.timer(0.01, repeat: false) do
|
6557
|
+
@game.down! if @queued_downs < 2
|
6558
|
+
@queued_downs -= 1
|
6559
|
+
end
|
6560
|
+
end
|
6561
|
+
else
|
6562
|
+
@game.down!
|
6563
|
+
end
|
6425
6564
|
in key: ' '
|
6426
|
-
game.down!(instant: true)
|
6565
|
+
@game.down!(instant: true)
|
6427
6566
|
in ext_key: :up
|
6428
|
-
case game.up_arrow_action
|
6567
|
+
case @game.up_arrow_action
|
6429
6568
|
when :instant_down
|
6430
|
-
game.down!(instant: true)
|
6569
|
+
@game.down!(instant: true)
|
6431
6570
|
when :rotate_right
|
6432
|
-
game.rotate!(:right)
|
6571
|
+
@game.rotate!(:right)
|
6433
6572
|
when :rotate_left
|
6434
|
-
game.rotate!(:left)
|
6573
|
+
@game.rotate!(:left)
|
6435
6574
|
end
|
6436
6575
|
in ext_key: :left
|
6437
|
-
game.left!
|
6576
|
+
@game.left!
|
6438
6577
|
in ext_key: :right
|
6439
|
-
game.right!
|
6578
|
+
@game.right!
|
6440
6579
|
in modifier: :shift
|
6441
|
-
game.rotate!(:right)
|
6580
|
+
@game.rotate!(:right)
|
6442
6581
|
in modifier: :control
|
6443
|
-
game.rotate!(:left)
|
6582
|
+
@game.rotate!(:left)
|
6444
6583
|
else
|
6445
6584
|
# Do Nothing
|
6446
6585
|
end
|
@@ -6505,22 +6644,314 @@ class Tetris
|
|
6505
6644
|
end
|
6506
6645
|
|
6507
6646
|
def start_moving_tetrominos_down
|
6508
|
-
|
6509
|
-
@
|
6647
|
+
unless @tetrominos_start_moving_down
|
6648
|
+
@tetrominos_start_moving_down = true
|
6649
|
+
Glimmer::LibUI.timer(@game.delay) do
|
6650
|
+
@game.down! if !@game.game_over? && !@game.paused?
|
6651
|
+
end
|
6510
6652
|
end
|
6511
6653
|
end
|
6512
6654
|
|
6513
6655
|
def show_game_over_dialog
|
6514
6656
|
Glimmer::LibUI.queue_main do
|
6515
|
-
msg_box('Game Over', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
|
6657
|
+
msg_box('Game Over!', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
|
6516
6658
|
@game.restart!
|
6517
6659
|
end
|
6518
6660
|
end
|
6661
|
+
|
6662
|
+
def show_high_scores
|
6663
|
+
Glimmer::LibUI.queue_main do
|
6664
|
+
game_paused = !!@game.paused
|
6665
|
+
@game.paused = true
|
6666
|
+
if @game.high_scores.empty?
|
6667
|
+
high_scores_string = "No games have been scored yet."
|
6668
|
+
else
|
6669
|
+
high_scores_string = @game.high_scores.map do |high_score|
|
6670
|
+
"#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
|
6671
|
+
end.join("\n")
|
6672
|
+
end
|
6673
|
+
msg_box('High Scores', high_scores_string)
|
6674
|
+
@game.paused = game_paused
|
6675
|
+
end
|
6676
|
+
end
|
6677
|
+
|
6678
|
+
def show_about_dialog
|
6679
|
+
Glimmer::LibUI.queue_main do
|
6680
|
+
msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
|
6681
|
+
end
|
6682
|
+
end
|
6519
6683
|
end
|
6520
6684
|
|
6521
6685
|
Tetris.new.launch
|
6522
6686
|
```
|
6523
6687
|
|
6688
|
+
### Tic Tac Toe
|
6689
|
+
|
6690
|
+
[examples/tic_tac_toe.rb](examples/tic_tac_toe.rb)
|
6691
|
+
|
6692
|
+
Run with this command from the root of the project if you cloned the project:
|
6693
|
+
|
6694
|
+
```
|
6695
|
+
ruby -r './lib/glimmer-dsl-libui' examples/tic_tac_toe.rb
|
6696
|
+
```
|
6697
|
+
|
6698
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6699
|
+
|
6700
|
+
```
|
6701
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/tic_tac_toe'"
|
6702
|
+
```
|
6703
|
+
|
6704
|
+
Mac
|
6705
|
+
|
6706
|
+
![glimmer-dsl-libui-mac-tic-tac-toe.png](images/glimmer-dsl-libui-mac-tic-tac-toe.png)
|
6707
|
+
|
6708
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png)
|
6709
|
+
|
6710
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png)
|
6711
|
+
|
6712
|
+
![glimmer-dsl-libui-mac-tic-tac-toe-draw.png](images/glimmer-dsl-libui-mac-tic-tac-toe-draw.png)
|
6713
|
+
|
6714
|
+
Windows
|
6715
|
+
|
6716
|
+
![glimmer-dsl-libui-windows-tic-tac-toe.png](images/glimmer-dsl-libui-windows-tic-tac-toe.png)
|
6717
|
+
|
6718
|
+
![glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png)
|
6719
|
+
|
6720
|
+
![glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png)
|
6721
|
+
|
6722
|
+
![glimmer-dsl-libui-windows-tic-tac-toe-draw.png](images/glimmer-dsl-libui-windows-tic-tac-toe-draw.png)
|
6723
|
+
|
6724
|
+
Linux
|
6725
|
+
|
6726
|
+
![glimmer-dsl-libui-linux-tic-tac-toe.png](images/glimmer-dsl-libui-linux-tic-tac-toe.png)
|
6727
|
+
|
6728
|
+
![glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png)
|
6729
|
+
|
6730
|
+
![glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png)
|
6731
|
+
|
6732
|
+
![glimmer-dsl-libui-linux-tic-tac-toe-draw.png](images/glimmer-dsl-libui-linux-tic-tac-toe-draw.png)
|
6733
|
+
|
6734
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6735
|
+
|
6736
|
+
```ruby
|
6737
|
+
require 'glimmer-dsl-libui'
|
6738
|
+
|
6739
|
+
require_relative "tic_tac_toe/board"
|
6740
|
+
|
6741
|
+
class TicTacToe
|
6742
|
+
include Glimmer
|
6743
|
+
|
6744
|
+
def initialize
|
6745
|
+
@tic_tac_toe_board = Board.new
|
6746
|
+
end
|
6747
|
+
|
6748
|
+
def launch
|
6749
|
+
create_gui
|
6750
|
+
register_observers
|
6751
|
+
@main_window.show
|
6752
|
+
end
|
6753
|
+
|
6754
|
+
def register_observers
|
6755
|
+
Glimmer::DataBinding::Observer.proc do |game_status|
|
6756
|
+
display_win_message if game_status == Board::WIN
|
6757
|
+
display_draw_message if game_status == Board::DRAW
|
6758
|
+
end.observe(@tic_tac_toe_board, :game_status)
|
6759
|
+
|
6760
|
+
3.times.map do |row|
|
6761
|
+
3.times.map do |column|
|
6762
|
+
Glimmer::DataBinding::Observer.proc do |sign|
|
6763
|
+
@cells[row][column].string = sign
|
6764
|
+
end.observe(@tic_tac_toe_board[row + 1, column + 1], :sign) # board model is 1-based
|
6765
|
+
end
|
6766
|
+
end
|
6767
|
+
end
|
6768
|
+
|
6769
|
+
def create_gui
|
6770
|
+
@main_window = window('Tic-Tac-Toe', 180, 180) {
|
6771
|
+
resizable false
|
6772
|
+
|
6773
|
+
@cells = []
|
6774
|
+
vertical_box {
|
6775
|
+
padded false
|
6776
|
+
|
6777
|
+
3.times.map do |row|
|
6778
|
+
@cells << []
|
6779
|
+
horizontal_box {
|
6780
|
+
padded false
|
6781
|
+
|
6782
|
+
3.times.map do |column|
|
6783
|
+
area {
|
6784
|
+
path {
|
6785
|
+
square(0, 0, 60)
|
6786
|
+
|
6787
|
+
stroke :black, thickness: 2
|
6788
|
+
}
|
6789
|
+
text(23, 19) {
|
6790
|
+
@cells[row] << string('') {
|
6791
|
+
font family: 'Arial', size: 20
|
6792
|
+
}
|
6793
|
+
}
|
6794
|
+
on_mouse_up do
|
6795
|
+
@tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
|
6796
|
+
end
|
6797
|
+
}
|
6798
|
+
end
|
6799
|
+
}
|
6800
|
+
end
|
6801
|
+
}
|
6802
|
+
}
|
6803
|
+
end
|
6804
|
+
|
6805
|
+
def display_win_message
|
6806
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
6807
|
+
end
|
6808
|
+
|
6809
|
+
def display_draw_message
|
6810
|
+
display_game_over_message("Draw!")
|
6811
|
+
end
|
6812
|
+
|
6813
|
+
def display_game_over_message(message_text)
|
6814
|
+
Glimmer::LibUI.queue_main do
|
6815
|
+
msg_box('Game Over', message_text)
|
6816
|
+
@tic_tac_toe_board.reset!
|
6817
|
+
end
|
6818
|
+
end
|
6819
|
+
end
|
6820
|
+
|
6821
|
+
TicTacToe.new.launch
|
6822
|
+
```
|
6823
|
+
|
6824
|
+
### Snake
|
6825
|
+
|
6826
|
+
Snake provides an example of building a desktop application [test-first](/spec/examples/snake/model/game_spec.rb) following the MVP ([Model](/examples/snake/model/game.rb) / [View](/examples/snake.rb) / [Presenter](/examples/snake/presenter/grid.rb)) architectural pattern.
|
6827
|
+
|
6828
|
+
[examples/snake.rb](examples/snake.rb)
|
6829
|
+
|
6830
|
+
Run with this command from the root of the project if you cloned the project:
|
6831
|
+
|
6832
|
+
```
|
6833
|
+
ruby -r './lib/glimmer-dsl-libui' examples/snake.rb
|
6834
|
+
```
|
6835
|
+
|
6836
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6837
|
+
|
6838
|
+
```
|
6839
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/snake'"
|
6840
|
+
```
|
6841
|
+
|
6842
|
+
Mac
|
6843
|
+
|
6844
|
+
![glimmer-dsl-libui-mac-snake.png](images/glimmer-dsl-libui-mac-snake.png)
|
6845
|
+
|
6846
|
+
![glimmer-dsl-libui-mac-snake-game-over.png](images/glimmer-dsl-libui-mac-snake-game-over.png)
|
6847
|
+
|
6848
|
+
Windows
|
6849
|
+
|
6850
|
+
![glimmer-dsl-libui-windows-snake.png](images/glimmer-dsl-libui-windows-snake.png)
|
6851
|
+
|
6852
|
+
![glimmer-dsl-libui-windows-snake-game-over.png](images/glimmer-dsl-libui-windows-snake-game-over.png)
|
6853
|
+
|
6854
|
+
Linux
|
6855
|
+
|
6856
|
+
![glimmer-dsl-libui-linux-snake.png](images/glimmer-dsl-libui-linux-snake.png)
|
6857
|
+
|
6858
|
+
![glimmer-dsl-libui-linux-snake-game-over.png](images/glimmer-dsl-libui-linux-snake-game-over.png)
|
6859
|
+
|
6860
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6861
|
+
|
6862
|
+
```ruby
|
6863
|
+
require 'glimmer-dsl-libui'
|
6864
|
+
require 'glimmer/data_binding/observer'
|
6865
|
+
|
6866
|
+
require_relative 'snake/presenter/grid'
|
6867
|
+
|
6868
|
+
class Snake
|
6869
|
+
CELL_SIZE = 15
|
6870
|
+
SNAKE_MOVE_DELAY = 0.1
|
6871
|
+
include Glimmer
|
6872
|
+
|
6873
|
+
def initialize
|
6874
|
+
@game = Model::Game.new
|
6875
|
+
@grid = Presenter::Grid.new(@game)
|
6876
|
+
@game.start
|
6877
|
+
create_gui
|
6878
|
+
register_observers
|
6879
|
+
end
|
6880
|
+
|
6881
|
+
def launch
|
6882
|
+
@main_window.show
|
6883
|
+
end
|
6884
|
+
|
6885
|
+
def register_observers
|
6886
|
+
@game.height.times do |row|
|
6887
|
+
@game.width.times do |column|
|
6888
|
+
Glimmer::DataBinding::Observer.proc do |new_color|
|
6889
|
+
@cell_grid[row][column].fill = new_color
|
6890
|
+
end.observe(@grid.cells[row][column], :color)
|
6891
|
+
end
|
6892
|
+
end
|
6893
|
+
|
6894
|
+
Glimmer::DataBinding::Observer.proc do |game_over|
|
6895
|
+
Glimmer::LibUI.queue_main do
|
6896
|
+
if game_over
|
6897
|
+
msg_box('Game Over!', "Score: #{@game.score}")
|
6898
|
+
@game.start
|
6899
|
+
end
|
6900
|
+
end
|
6901
|
+
end.observe(@game, :over)
|
6902
|
+
|
6903
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
6904
|
+
unless @game.over?
|
6905
|
+
@game.snake.move
|
6906
|
+
@main_window.title = "Glimmer Snake (Score: #{@game.score})"
|
6907
|
+
end
|
6908
|
+
end
|
6909
|
+
end
|
6910
|
+
|
6911
|
+
def create_gui
|
6912
|
+
@cell_grid = []
|
6913
|
+
@main_window = window('Glimmer Snake', @game.width * CELL_SIZE, @game.height * CELL_SIZE) {
|
6914
|
+
resizable false
|
6915
|
+
|
6916
|
+
vertical_box {
|
6917
|
+
padded false
|
6918
|
+
|
6919
|
+
@game.height.times do |row|
|
6920
|
+
@cell_grid << []
|
6921
|
+
horizontal_box {
|
6922
|
+
padded false
|
6923
|
+
|
6924
|
+
@game.width.times do |column|
|
6925
|
+
area {
|
6926
|
+
@cell_grid.last << path {
|
6927
|
+
square(0, 0, CELL_SIZE)
|
6928
|
+
|
6929
|
+
fill Presenter::Cell::COLOR_CLEAR
|
6930
|
+
}
|
6931
|
+
|
6932
|
+
on_key_up do |area_key_event|
|
6933
|
+
orientation_and_key = [@game.snake.head.orientation, area_key_event[:ext_key]]
|
6934
|
+
case orientation_and_key
|
6935
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
6936
|
+
@game.snake.turn_right
|
6937
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
6938
|
+
@game.snake.turn_left
|
6939
|
+
else
|
6940
|
+
# No Op
|
6941
|
+
end
|
6942
|
+
end
|
6943
|
+
}
|
6944
|
+
end
|
6945
|
+
}
|
6946
|
+
end
|
6947
|
+
}
|
6948
|
+
}
|
6949
|
+
end
|
6950
|
+
end
|
6951
|
+
|
6952
|
+
Snake.new.launch
|
6953
|
+
```
|
6954
|
+
|
6524
6955
|
## Applications
|
6525
6956
|
|
6526
6957
|
Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
@@ -6551,9 +6982,10 @@ https://github.com/iraamaro/i3off-gtk-ruby
|
|
6551
6982
|
|
6552
6983
|
## Resources
|
6553
6984
|
|
6554
|
-
- [libui C Library](https://github.com/andlabs/libui)
|
6555
|
-
- [LibUI Ruby Bindings](https://github.com/kojix2/LibUI)
|
6556
6985
|
- [Code Master Blog](https://andymaleh.blogspot.com/search/label/LibUI)
|
6986
|
+
- [LibUI Ruby Bindings](https://github.com/kojix2/LibUI)
|
6987
|
+
- [libui C Library](https://github.com/andlabs/libui)
|
6988
|
+
- [Go UI (Golang LibUI) API Documentation](https://pkg.go.dev/github.com/andlabs/ui)
|
6557
6989
|
|
6558
6990
|
## Help
|
6559
6991
|
|