glimmer-dsl-libui 0.1.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +624 -29
- data/VERSION +1 -1
- data/examples/area_gallery.rb +7 -1
- data/examples/area_gallery2.rb +14 -4
- data/examples/area_gallery3.rb +8 -2
- data/examples/area_gallery4.rb +15 -5
- data/examples/color_the_circles.rb +223 -0
- data/examples/control_gallery.rb +1 -1
- data/examples/form_table.rb +20 -0
- data/examples/grid.rb +38 -2
- data/examples/login.rb +45 -0
- data/examples/midi_player.rb +1 -1
- data/examples/timer.rb +135 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/control_proxy/area_proxy/scrolling_area_proxy.rb +40 -0
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +9 -5
- data/lib/glimmer/libui/control_proxy/entry_proxy/password_entry_proxy.rb +36 -0
- data/lib/glimmer/libui/control_proxy/entry_proxy/search_entry_proxy.rb +36 -0
- data/lib/glimmer/libui/control_proxy/entry_proxy.rb +39 -0
- data/lib/glimmer/libui/control_proxy/grid_proxy.rb +12 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +69 -0
- data/lib/glimmer/libui/control_proxy/menu_proxy.rb +3 -0
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +3 -30
- data/lib/glimmer/libui/control_proxy.rb +8 -1
- data/lib/glimmer/libui/shape/arc.rb +6 -3
- data/lib/glimmer/libui/shape/circle.rb +50 -0
- data/lib/glimmer/libui/shape/rectangle.rb +4 -0
- data/lib/glimmer/libui/shape/square.rb +4 -0
- data/lib/glimmer/libui.rb +76 -2
- data/sounds/AlanWalker-Faded.mid +0 -0
- data/sounds/AlanWalker-SingMeToSleep.mid +0 -0
- data/sounds/CalvinHarris-Blame.mid +0 -0
- data/sounds/CalvinHarris-MyWay.mid +0 -0
- data/sounds/deadmau5-2448.mid +0 -0
- data/sounds/deadmau5-SoThereIWas.mid +0 -0
- metadata +19 -4
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.1
|
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
|
2
2
|
## Prerequisite-Free Ruby Desktop Development GUI Library
|
3
3
|
[](http://badge.fury.io/rb/glimmer-dsl-libui)
|
4
4
|
[](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
|
@@ -118,11 +118,17 @@ window('Area Gallery', 400, 400) {
|
|
118
118
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
119
119
|
}
|
120
120
|
path { # declarative stable path
|
121
|
-
|
121
|
+
circle(200, 200, 90)
|
122
122
|
|
123
123
|
fill r: 202, g: 102, b: 204, a: 0.5
|
124
124
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
125
125
|
}
|
126
|
+
path { # declarative stable path
|
127
|
+
arc(400, 220, 180, 90, 90, false)
|
128
|
+
|
129
|
+
fill r: 204, g: 102, b: 204, a: 0.5
|
130
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
131
|
+
}
|
126
132
|
|
127
133
|
on_mouse_event do |area_mouse_event|
|
128
134
|
p area_mouse_event
|
@@ -191,7 +197,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
191
197
|
|
192
198
|
## Table of Contents
|
193
199
|
|
194
|
-
- [Glimmer DSL for LibUI 0.1
|
200
|
+
- [Glimmer DSL for LibUI 0.2.1](#-glimmer-dsl-for-libui-021)
|
195
201
|
- [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
|
196
202
|
- [Usage](#usage)
|
197
203
|
- [Girb (Glimmer IRB)](#girb-glimmer-irb)
|
@@ -199,6 +205,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
199
205
|
- [Supported Controls](#supported-controls)
|
200
206
|
- [Common Control Properties](#common-control-properties)
|
201
207
|
- [Common Control Operations](#common-control-operations)
|
208
|
+
- [LibUI Operations](#libui-operations)
|
202
209
|
- [Extra Dialogs](#extra-dialogs)
|
203
210
|
- [Extra Operations](#extra-operations)
|
204
211
|
- [Table API](#table-api)
|
@@ -234,6 +241,9 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
234
241
|
- [Area Gallery](#area-gallery)
|
235
242
|
- [Histogram](#histogram)
|
236
243
|
- [Basic Transform](#basic-transform)
|
244
|
+
- [Login](#login)
|
245
|
+
- [Timer](#timer)
|
246
|
+
- [Color The Circles](#color-the-circles)
|
237
247
|
- [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
|
238
248
|
- [Help](#help)
|
239
249
|
- [Issues](#issues)
|
@@ -321,7 +331,7 @@ gem install glimmer-dsl-libui
|
|
321
331
|
Or install via Bundler `Gemfile`:
|
322
332
|
|
323
333
|
```ruby
|
324
|
-
gem 'glimmer-dsl-libui', '~> 0.1
|
334
|
+
gem 'glimmer-dsl-libui', '~> 0.2.1'
|
325
335
|
```
|
326
336
|
|
327
337
|
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.
|
@@ -429,6 +439,7 @@ Control(Args) | Properties | Listeners
|
|
429
439
|
`msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
430
440
|
`msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
431
441
|
`non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
442
|
+
`password_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
432
443
|
`path(draw_fill_mode = :winding)` | `fill` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`), `stroke` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, `:cap` as (`:round`, `:square`, `:flat`), `:join` as (`:miter`, `:round`, `:bevel`), `:thickness` as `Numeric`, `:miter_limit` as `Numeric`, `:dashes` as `Array` of `Numeric` ) | None
|
433
444
|
`preferences_menu_item` | None | `on_clicked`
|
434
445
|
`progress_bar` | `value` (`Numeric`) | None
|
@@ -436,6 +447,7 @@ Control(Args) | Properties | Listeners
|
|
436
447
|
`quit_menu_item` | None | `on_clicked`
|
437
448
|
`radio_buttons` | `selected` (`Integer`) | `on_selected`
|
438
449
|
`rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `width` (`Numeric`), `height` (`Numeric`) | None
|
450
|
+
`search_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
439
451
|
`slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
440
452
|
`spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
441
453
|
`square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
|
@@ -445,6 +457,7 @@ Control(Args) | Properties | Listeners
|
|
445
457
|
`text_column(name as String)` | `editable` (Boolean) | None
|
446
458
|
`time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
|
447
459
|
`vertical_box` | `padded` (Boolean) | None
|
460
|
+
`vertical_separator` | None | None
|
448
461
|
`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`
|
449
462
|
|
450
463
|
### Common Control Properties
|
@@ -460,9 +473,9 @@ Control(Args) | Properties | Listeners
|
|
460
473
|
- `xspan` [dsl-only] (`Integer`) [default=`1`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
461
474
|
- `yspan` [dsl-only] (`Integer`) [default=`1`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
462
475
|
- `hexpand` [dsl-only] (Boolean) [default=`false`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
463
|
-
- `halign` [dsl-only] (`
|
476
|
+
- `halign` [dsl-only] (`:fill`, `:start`, `:center`, or `:end`) [default=`:fill`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
464
477
|
- `vexpand` [dsl-only] (Boolean) [default=`false`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
465
|
-
- `valign` [dsl-only] (`
|
478
|
+
- `valign` [dsl-only] (`:fill`, `:start`, `:center`, or `:end`) [default=`:fill`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
|
466
479
|
|
467
480
|
### Common Control Operations
|
468
481
|
- `destroy`
|
@@ -471,6 +484,13 @@ Control(Args) | Properties | Listeners
|
|
471
484
|
- `hide`
|
472
485
|
- `show`
|
473
486
|
|
487
|
+
### LibUI Operations
|
488
|
+
|
489
|
+
All operations that could normally be called on `LibUI` can also be called on `Glimmer::LibUI`, but some have enhancements as detailed below.
|
490
|
+
|
491
|
+
- `Glimmer::LibUI::queue_main(&block)`: queues an operation to be run on the main event loop at the earliest opportunity possible
|
492
|
+
- `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.
|
493
|
+
|
474
494
|
### Extra Dialogs
|
475
495
|
|
476
496
|
- `open_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
|
@@ -684,7 +704,9 @@ The `area_mouse_event` `Hash` argument for mouse events that receive it (e.g. `o
|
|
684
704
|
|
685
705
|
The `area_key_event` `Hash` argument for keyboard events that receive it (e.g. `on_key_up`, `on_key_down`) consist of the following hash keys:
|
686
706
|
- `:key`: key character (`String`)
|
687
|
-
- `:
|
707
|
+
- `:key_value`: key value (`Integer`). Useful in rare cases for numeric processing of keys instead of dealing with as `:key` character `String`
|
708
|
+
- `:ext_key`: non-character extra key (`Symbol`) from `Glimmer::LibUI.enum_symbols(:ext_key)` such as `:left`, `:right`, `:escape`, `:insert`
|
709
|
+
- `:ext_key_value`: non-character extra key value (`Integer`). Useful in rare cases for numeric processing of extra keys instead of dealing with as `:ext_key` `Symbol`
|
688
710
|
- `:modifier`: modifier key pressed alone (e.g. `:shift` or `:control`)
|
689
711
|
- `:modifiers`: modifier keys pressed simultaneously with `:key`, `:ext_key`, or `:modifier`
|
690
712
|
- `:up`: indicates if key has been released or not (Boolean)
|
@@ -760,6 +782,8 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
760
782
|
|
761
783
|
`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)
|
762
784
|
|
785
|
+
Available [X11](https://en.wikipedia.org/wiki/X11_color_names) colors can be obtained through `Glimmer::LibUI.x11_colors` method.
|
786
|
+
|
763
787
|
Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
|
764
788
|
|
765
789
|
Check [Histogram](#histogram) example for use of hex colors.
|
@@ -786,7 +810,7 @@ Check [Histogram](#histogram) example for use of hex colors.
|
|
786
810
|
- When destroying a control nested under a `form`, it is automatically deleted from the form's children
|
787
811
|
- When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
|
788
812
|
- For `date_time_picker`, `date_picker`, and `time_picker`, make sure `time` hash values for `mon`, `wday`, and `yday` are 1-based instead of [libui](https://github.com/andlabs/libui) original 0-based values, and return `dst` as Boolean instead of `isdst` as `1`/`0`
|
789
|
-
- Smart defaults for `grid` child attributes are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`
|
813
|
+
- Smart defaults for `grid` child attributes are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`:fill`), `vexpand` (`false`), and `valign` (`:fill`)
|
790
814
|
- The `table` control automatically constructs required `TableModelHandler`, `TableModel`, and `TableParams`, calculating all their arguments from `cell_rows` and `editable` properties (e.g. `NumRows`) as well as nested columns (e.g. `text_column`)
|
791
815
|
- Table model instances are automatically freed from memory after `window` is destroyed.
|
792
816
|
- Table `cell_rows` data has implicit data-binding to table cell values for deletion, insertion, and change (done by diffing `cell_rows` value before and after change and auto-informing `table` of deletions [`LibUI.table_model_row_deleted`], insertions [`LibUI.table_model_row_deleted`], and changes [`LibUI.table_model_row_changed`]). When deleting data rows from `cell_rows` array, then actual rows from the `table` are automatically deleted. When inserting data rows into `cell_rows` array, then actual `table` rows are automatically inserted. When updating data rows in `cell_rows` array, then actual `table` rows are automatically updated.
|
@@ -1432,7 +1456,7 @@ class TinyMidiPlayer
|
|
1432
1456
|
end
|
1433
1457
|
|
1434
1458
|
def create_gui
|
1435
|
-
menu('Help') {
|
1459
|
+
menu('Help') {
|
1436
1460
|
menu_item('Version') {
|
1437
1461
|
on_clicked do
|
1438
1462
|
show_version
|
@@ -2097,13 +2121,15 @@ ruby -r glimmer-dsl-libui -e "require 'examples/grid'"
|
|
2097
2121
|
|
2098
2122
|
Mac
|
2099
2123
|
|
2100
|
-

|
2125
|
+

|
2126
|
+

|
2102
2127
|
|
2103
2128
|
Linux
|
2104
2129
|
|
2105
|
-

|
2131
|
+

|
2132
|
+

|
2107
2133
|
|
2108
2134
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2109
2135
|
|
@@ -2114,7 +2140,7 @@ include Glimmer
|
|
2114
2140
|
|
2115
2141
|
window('Grid') {
|
2116
2142
|
tab {
|
2117
|
-
tab_item('
|
2143
|
+
tab_item('Span') {
|
2118
2144
|
grid {
|
2119
2145
|
4.times { |top_value|
|
2120
2146
|
4.times { |left_value|
|
@@ -2154,7 +2180,7 @@ window('Grid') {
|
|
2154
2180
|
}
|
2155
2181
|
}
|
2156
2182
|
}
|
2157
|
-
tab_item('
|
2183
|
+
tab_item('Expand') {
|
2158
2184
|
grid {
|
2159
2185
|
label("(0, 0) hexpand/vexpand\nall available horizontal space is taken\nand\nall\navailable\nvertical\nspace\nis\ntaken") {
|
2160
2186
|
left 0
|
@@ -2176,6 +2202,42 @@ window('Grid') {
|
|
2176
2202
|
}
|
2177
2203
|
}
|
2178
2204
|
}
|
2205
|
+
tab_item('Align') {
|
2206
|
+
grid {
|
2207
|
+
label("(0, 0) halign/valign fill\nall available horizontal space is taken\nand\nall\navailable\nvertical\nspace\nis\ntaken") {
|
2208
|
+
left 0
|
2209
|
+
top 0
|
2210
|
+
hexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2211
|
+
vexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2212
|
+
halign :fill
|
2213
|
+
valign :fill
|
2214
|
+
}
|
2215
|
+
label("(1, 0) halign/valign start") {
|
2216
|
+
left 1
|
2217
|
+
top 0
|
2218
|
+
hexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2219
|
+
vexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2220
|
+
halign :start
|
2221
|
+
valign :start
|
2222
|
+
}
|
2223
|
+
label("(0, 1) halign/valign center") {
|
2224
|
+
left 0
|
2225
|
+
top 1
|
2226
|
+
hexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2227
|
+
vexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2228
|
+
halign :center
|
2229
|
+
valign :center
|
2230
|
+
}
|
2231
|
+
label("(1, 1) halign/valign end") {
|
2232
|
+
left 1
|
2233
|
+
top 1
|
2234
|
+
hexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2235
|
+
vexpand true unless OS.mac? # on Mac, only the first label is given all space, so avoid expanding
|
2236
|
+
halign :end
|
2237
|
+
valign :end
|
2238
|
+
}
|
2239
|
+
}
|
2240
|
+
}
|
2179
2241
|
}
|
2180
2242
|
}.show
|
2181
2243
|
```
|
@@ -2955,15 +3017,19 @@ Mac
|
|
2955
3017
|
|
2956
3018
|

|
2957
3019
|

|
3020
|
+

|
2958
3021
|
|
2959
3022
|
Linux
|
2960
3023
|
|
2961
3024
|

|
2962
3025
|

|
3026
|
+

|
2963
3027
|
|
2964
3028
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2965
3029
|
|
2966
3030
|
```ruby
|
3031
|
+
# frozen_string_literal: true
|
3032
|
+
|
2967
3033
|
require 'glimmer-dsl-libui'
|
2968
3034
|
|
2969
3035
|
include Glimmer
|
@@ -3009,6 +3075,7 @@ window('Contacts', 600, 600) { |w|
|
|
3009
3075
|
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
3010
3076
|
else
|
3011
3077
|
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
3078
|
+
@unfiltered_data = data.dup
|
3012
3079
|
@name_entry.text = ''
|
3013
3080
|
@email_entry.text = ''
|
3014
3081
|
@phone_entry.text = ''
|
@@ -3018,6 +3085,25 @@ window('Contacts', 600, 600) { |w|
|
|
3018
3085
|
end
|
3019
3086
|
}
|
3020
3087
|
|
3088
|
+
search_entry { |se|
|
3089
|
+
stretchy false
|
3090
|
+
|
3091
|
+
on_changed do
|
3092
|
+
filter_value = se.text
|
3093
|
+
@unfiltered_data ||= data.dup
|
3094
|
+
# Unfilter first to remove any previous filters
|
3095
|
+
data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
3096
|
+
# Now, apply filter if entered
|
3097
|
+
unless filter_value.empty?
|
3098
|
+
data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
3099
|
+
row_data.any? do |cell|
|
3100
|
+
cell.to_s.downcase.include?(filter_value.downcase)
|
3101
|
+
end
|
3102
|
+
end
|
3103
|
+
end
|
3104
|
+
end
|
3105
|
+
}
|
3106
|
+
|
3021
3107
|
table {
|
3022
3108
|
text_column('Name')
|
3023
3109
|
text_column('Email')
|
@@ -3455,11 +3541,17 @@ window('Area Gallery', 400, 400) {
|
|
3455
3541
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3456
3542
|
}
|
3457
3543
|
path { # declarative stable path
|
3458
|
-
|
3544
|
+
circle(200, 200, 90)
|
3459
3545
|
|
3460
3546
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3461
3547
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3462
3548
|
}
|
3549
|
+
path { # declarative stable path
|
3550
|
+
arc(400, 220, 180, 90, 90, false)
|
3551
|
+
|
3552
|
+
fill r: 204, g: 102, b: 204, a: 0.5
|
3553
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3554
|
+
}
|
3463
3555
|
|
3464
3556
|
on_mouse_event do |area_mouse_event|
|
3465
3557
|
p area_mouse_event
|
@@ -3612,18 +3704,28 @@ window('Area Gallery', 400, 400) {
|
|
3612
3704
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3613
3705
|
}
|
3614
3706
|
path { # declarative stable path
|
3615
|
-
|
3707
|
+
circle {
|
3616
3708
|
x_center 200
|
3617
3709
|
y_center 200
|
3618
3710
|
radius 90
|
3619
|
-
start_angle 0
|
3620
|
-
sweep 360
|
3621
|
-
is_negative false
|
3622
3711
|
}
|
3623
3712
|
|
3624
3713
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3625
3714
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3626
3715
|
}
|
3716
|
+
path { # declarative stable path
|
3717
|
+
arc {
|
3718
|
+
x_center 400
|
3719
|
+
y_center 220
|
3720
|
+
radius 180
|
3721
|
+
start_angle 90
|
3722
|
+
sweep 90
|
3723
|
+
is_negative false
|
3724
|
+
}
|
3725
|
+
|
3726
|
+
fill r: 204, g: 102, b: 204, a: 0.5
|
3727
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3728
|
+
}
|
3627
3729
|
|
3628
3730
|
on_mouse_event do |area_mouse_event|
|
3629
3731
|
p area_mouse_event
|
@@ -3723,13 +3825,19 @@ window('Area Gallery', 400, 400) {
|
|
3723
3825
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3724
3826
|
}
|
3725
3827
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3726
|
-
|
3727
|
-
|
3828
|
+
circle(200, 200, 90)
|
3829
|
+
|
3728
3830
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3729
3831
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3730
3832
|
}
|
3833
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3834
|
+
arc(400, 220, 180, 90, 90, false)
|
3835
|
+
|
3836
|
+
fill r: 204, g: 102, b: 204, a: 0.5
|
3837
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3838
|
+
}
|
3731
3839
|
end
|
3732
|
-
|
3840
|
+
|
3733
3841
|
on_mouse_event do |area_mouse_event|
|
3734
3842
|
p area_mouse_event
|
3735
3843
|
end
|
@@ -3882,20 +3990,30 @@ window('Area Gallery', 400, 400) {
|
|
3882
3990
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3883
3991
|
}
|
3884
3992
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3885
|
-
|
3993
|
+
circle {
|
3886
3994
|
x_center 200
|
3887
3995
|
y_center 200
|
3888
3996
|
radius 90
|
3889
|
-
start_angle 0
|
3890
|
-
sweep 360
|
3891
|
-
is_negative false
|
3892
3997
|
}
|
3893
|
-
|
3998
|
+
|
3894
3999
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3895
4000
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3896
4001
|
}
|
4002
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4003
|
+
arc {
|
4004
|
+
x_center 400
|
4005
|
+
y_center 220
|
4006
|
+
radius 180
|
4007
|
+
start_angle 90
|
4008
|
+
sweep 90
|
4009
|
+
is_negative false
|
4010
|
+
}
|
4011
|
+
|
4012
|
+
fill r: 204, g: 102, b: 204, a: 0.5
|
4013
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4014
|
+
}
|
3897
4015
|
end
|
3898
|
-
|
4016
|
+
|
3899
4017
|
on_mouse_event do |area_mouse_event|
|
3900
4018
|
p area_mouse_event
|
3901
4019
|
end
|
@@ -4344,6 +4462,483 @@ window('Basic Transform', 350, 350) {
|
|
4344
4462
|
}.show
|
4345
4463
|
```
|
4346
4464
|
|
4465
|
+
### Login
|
4466
|
+
|
4467
|
+
[examples/login.rb](examples/login.rb)
|
4468
|
+
|
4469
|
+
Run with this command from the root of the project if you cloned the project:
|
4470
|
+
|
4471
|
+
```
|
4472
|
+
ruby -r './lib/glimmer-dsl-libui' examples/login.rb
|
4473
|
+
```
|
4474
|
+
|
4475
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
4476
|
+
|
4477
|
+
```
|
4478
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/login'"
|
4479
|
+
```
|
4480
|
+
|
4481
|
+
Mac
|
4482
|
+
|
4483
|
+

|
4484
|
+

|
4485
|
+
|
4486
|
+
Linux
|
4487
|
+
|
4488
|
+

|
4489
|
+

|
4490
|
+
|
4491
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
4492
|
+
|
4493
|
+
```ruby
|
4494
|
+
require 'glimmer-dsl-libui'
|
4495
|
+
|
4496
|
+
include Glimmer
|
4497
|
+
|
4498
|
+
window('Login') {
|
4499
|
+
margined true
|
4500
|
+
|
4501
|
+
vertical_box {
|
4502
|
+
form {
|
4503
|
+
@username_entry = entry {
|
4504
|
+
label 'Username:'
|
4505
|
+
}
|
4506
|
+
|
4507
|
+
@password_entry = password_entry {
|
4508
|
+
label 'Password:'
|
4509
|
+
}
|
4510
|
+
}
|
4511
|
+
|
4512
|
+
horizontal_box {
|
4513
|
+
@login_button = button('Login') {
|
4514
|
+
on_clicked do
|
4515
|
+
@username_entry.enabled = false
|
4516
|
+
@password_entry.enabled = false
|
4517
|
+
@login_button.enabled = false
|
4518
|
+
@logout_button.enabled = true
|
4519
|
+
end
|
4520
|
+
}
|
4521
|
+
|
4522
|
+
@logout_button = button('Logout') {
|
4523
|
+
enabled false
|
4524
|
+
|
4525
|
+
on_clicked do
|
4526
|
+
@username_entry.text = ''
|
4527
|
+
@password_entry.text = ''
|
4528
|
+
@username_entry.enabled = true
|
4529
|
+
@password_entry.enabled = true
|
4530
|
+
@login_button.enabled = true
|
4531
|
+
@logout_button.enabled = false
|
4532
|
+
end
|
4533
|
+
}
|
4534
|
+
}
|
4535
|
+
}
|
4536
|
+
}.show
|
4537
|
+
```
|
4538
|
+
|
4539
|
+
### Timer
|
4540
|
+
|
4541
|
+
[examples/timer.rb](examples/timer.rb)
|
4542
|
+
|
4543
|
+
Run with this command from the root of the project if you cloned the project:
|
4544
|
+
|
4545
|
+
```
|
4546
|
+
ruby -r './lib/glimmer-dsl-libui' examples/timer.rb
|
4547
|
+
```
|
4548
|
+
|
4549
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
4550
|
+
|
4551
|
+
```
|
4552
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/timer'"
|
4553
|
+
```
|
4554
|
+
|
4555
|
+
Mac
|
4556
|
+
|
4557
|
+

|
4558
|
+

|
4559
|
+
|
4560
|
+
Linux
|
4561
|
+
|
4562
|
+

|
4563
|
+

|
4564
|
+
|
4565
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
4566
|
+
|
4567
|
+
```ruby
|
4568
|
+
# frozen_string_literal: true
|
4569
|
+
|
4570
|
+
require 'glimmer-dsl-libui'
|
4571
|
+
|
4572
|
+
class Timer
|
4573
|
+
include Glimmer
|
4574
|
+
|
4575
|
+
SECOND_MAX = 59
|
4576
|
+
MINUTE_MAX = 59
|
4577
|
+
HOUR_MAX = 23
|
4578
|
+
|
4579
|
+
def initialize
|
4580
|
+
@pid = nil
|
4581
|
+
@midi_file = File.expand_path('../sounds/AlanWalker-Faded.mid', __dir__)
|
4582
|
+
at_exit { stop_midi }
|
4583
|
+
setup_timer
|
4584
|
+
create_gui
|
4585
|
+
end
|
4586
|
+
|
4587
|
+
def stop_midi
|
4588
|
+
if @pid
|
4589
|
+
if @th.alive?
|
4590
|
+
Process.kill(:SIGKILL, @pid)
|
4591
|
+
@pid = nil
|
4592
|
+
else
|
4593
|
+
@pid = nil
|
4594
|
+
end
|
4595
|
+
end
|
4596
|
+
end
|
4597
|
+
|
4598
|
+
def play_midi
|
4599
|
+
stop_midi
|
4600
|
+
if @pid.nil?
|
4601
|
+
begin
|
4602
|
+
@pid = spawn "timidity -G 0.0-10.0 #{@midi_file}"
|
4603
|
+
@th = Process.detach @pid
|
4604
|
+
rescue Errno::ENOENT
|
4605
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
4606
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
4607
|
+
end
|
4608
|
+
end
|
4609
|
+
end
|
4610
|
+
|
4611
|
+
def setup_timer
|
4612
|
+
unless @setup_timer
|
4613
|
+
Glimmer::LibUI.timer(1) do
|
4614
|
+
if @started
|
4615
|
+
seconds = @sec_spinbox.value
|
4616
|
+
minutes = @min_spinbox.value
|
4617
|
+
hours = @hour_spinbox.value
|
4618
|
+
if seconds > 0
|
4619
|
+
@sec_spinbox.value = seconds -= 1
|
4620
|
+
end
|
4621
|
+
if seconds == 0
|
4622
|
+
if minutes > 0
|
4623
|
+
@min_spinbox.value = minutes -= 1
|
4624
|
+
@sec_spinbox.value = seconds = SECOND_MAX
|
4625
|
+
end
|
4626
|
+
if minutes == 0
|
4627
|
+
if hours > 0
|
4628
|
+
@hour_spinbox.value = hours -= 1
|
4629
|
+
@min_spinbox.value = minutes = MINUTE_MAX
|
4630
|
+
@sec_spinbox.value = seconds = SECOND_MAX
|
4631
|
+
end
|
4632
|
+
if hours == 0 && minutes == 0 && seconds == 0
|
4633
|
+
@start_button.enabled = true
|
4634
|
+
@stop_button.enabled = false
|
4635
|
+
@started = false
|
4636
|
+
unless @played
|
4637
|
+
play_midi
|
4638
|
+
@played = true
|
4639
|
+
end
|
4640
|
+
end
|
4641
|
+
end
|
4642
|
+
end
|
4643
|
+
end
|
4644
|
+
end
|
4645
|
+
@setup_timer = true
|
4646
|
+
end
|
4647
|
+
end
|
4648
|
+
|
4649
|
+
def create_gui
|
4650
|
+
window('Timer') {
|
4651
|
+
margined true
|
4652
|
+
|
4653
|
+
group('Countdown') {
|
4654
|
+
vertical_box {
|
4655
|
+
horizontal_box {
|
4656
|
+
@hour_spinbox = spinbox(0, HOUR_MAX) {
|
4657
|
+
stretchy false
|
4658
|
+
value 0
|
4659
|
+
}
|
4660
|
+
label(':') {
|
4661
|
+
stretchy false
|
4662
|
+
}
|
4663
|
+
@min_spinbox = spinbox(0, MINUTE_MAX) {
|
4664
|
+
stretchy false
|
4665
|
+
value 0
|
4666
|
+
}
|
4667
|
+
label(':') {
|
4668
|
+
stretchy false
|
4669
|
+
}
|
4670
|
+
@sec_spinbox = spinbox(0, SECOND_MAX) {
|
4671
|
+
stretchy false
|
4672
|
+
value 0
|
4673
|
+
}
|
4674
|
+
}
|
4675
|
+
horizontal_box {
|
4676
|
+
@start_button = button('Start') {
|
4677
|
+
on_clicked do
|
4678
|
+
@start_button.enabled = false
|
4679
|
+
@stop_button.enabled = true
|
4680
|
+
@started = true
|
4681
|
+
@played = false
|
4682
|
+
end
|
4683
|
+
}
|
4684
|
+
|
4685
|
+
@stop_button = button('Stop') {
|
4686
|
+
enabled false
|
4687
|
+
|
4688
|
+
on_clicked do
|
4689
|
+
@start_button.enabled = true
|
4690
|
+
@stop_button.enabled = false
|
4691
|
+
@started = false
|
4692
|
+
end
|
4693
|
+
}
|
4694
|
+
}
|
4695
|
+
}
|
4696
|
+
}
|
4697
|
+
}.show
|
4698
|
+
end
|
4699
|
+
end
|
4700
|
+
|
4701
|
+
Timer.new
|
4702
|
+
```
|
4703
|
+
|
4704
|
+
### Color The Circles
|
4705
|
+
|
4706
|
+
[examples/color_the_circles.rb](examples/color_the_circles.rb)
|
4707
|
+
|
4708
|
+
Run with this command from the root of the project if you cloned the project:
|
4709
|
+
|
4710
|
+
```
|
4711
|
+
ruby -r './lib/glimmer-dsl-libui' examples/color_the_circles.rb
|
4712
|
+
```
|
4713
|
+
|
4714
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
4715
|
+
|
4716
|
+
```
|
4717
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/color_the_circles'"
|
4718
|
+
```
|
4719
|
+
|
4720
|
+
Mac
|
4721
|
+
|
4722
|
+

|
4723
|
+

|
4724
|
+

|
4725
|
+
|
4726
|
+
Linux
|
4727
|
+
|
4728
|
+

|
4729
|
+

|
4730
|
+

|
4731
|
+
|
4732
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
4733
|
+
|
4734
|
+
```ruby
|
4735
|
+
require 'glimmer-dsl-libui'
|
4736
|
+
|
4737
|
+
class ColorTheCircles
|
4738
|
+
include Glimmer
|
4739
|
+
|
4740
|
+
WINDOW_WIDTH = 800
|
4741
|
+
WINDOW_HEIGHT = 600
|
4742
|
+
CIRCLE_MIN_RADIUS = 15
|
4743
|
+
CIRCLE_MAX_RADIUS = 50
|
4744
|
+
MARGIN_WIDTH = 55
|
4745
|
+
MARGIN_HEIGHT = 155
|
4746
|
+
TIME_MAX_EASY = 4
|
4747
|
+
TIME_MAX_MEDIUM = 3
|
4748
|
+
TIME_MAX_HARD = 2
|
4749
|
+
TIME_MAX_INSANE = 1
|
4750
|
+
|
4751
|
+
attr_accessor :score
|
4752
|
+
|
4753
|
+
def initialize
|
4754
|
+
@circles_data = []
|
4755
|
+
@score = 0
|
4756
|
+
@time_max = TIME_MAX_HARD
|
4757
|
+
register_observers
|
4758
|
+
setup_circle_factory
|
4759
|
+
end
|
4760
|
+
|
4761
|
+
def register_observers
|
4762
|
+
observer = Glimmer::DataBinding::Observer.proc do |new_score|
|
4763
|
+
@score_label.text = new_score.to_s
|
4764
|
+
if new_score == -20
|
4765
|
+
msg_box('You Lost!', 'Sorry! Your score reached -20')
|
4766
|
+
restart_game
|
4767
|
+
elsif new_score == 0
|
4768
|
+
msg_box('You Won!', 'Congratulations! Your score reached 0')
|
4769
|
+
restart_game
|
4770
|
+
end
|
4771
|
+
end
|
4772
|
+
observer.observe(self, :score) # automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer on score attribute changes
|
4773
|
+
end
|
4774
|
+
|
4775
|
+
def setup_circle_factory
|
4776
|
+
consumer = Proc.new do
|
4777
|
+
if @circles_data.empty?
|
4778
|
+
# start with 3 circles to make more challenging
|
4779
|
+
add_circle until @circles_data.size > 3
|
4780
|
+
else
|
4781
|
+
add_circle
|
4782
|
+
end
|
4783
|
+
delay = rand * @time_max
|
4784
|
+
Glimmer::LibUI.timer(delay, repeat: false, &consumer)
|
4785
|
+
end
|
4786
|
+
Glimmer::LibUI.queue_main(&consumer)
|
4787
|
+
end
|
4788
|
+
|
4789
|
+
def add_circle
|
4790
|
+
circle_x_center = rand * (WINDOW_WIDTH - MARGIN_WIDTH - CIRCLE_MAX_RADIUS) + CIRCLE_MAX_RADIUS
|
4791
|
+
circle_y_center = rand * (WINDOW_HEIGHT - MARGIN_HEIGHT - CIRCLE_MAX_RADIUS) + CIRCLE_MAX_RADIUS
|
4792
|
+
circle_radius = rand * (CIRCLE_MAX_RADIUS - CIRCLE_MIN_RADIUS) + CIRCLE_MIN_RADIUS
|
4793
|
+
stroke_color = Glimmer::LibUI.x11_colors.sample
|
4794
|
+
@circles_data << {
|
4795
|
+
args: [circle_x_center, circle_y_center, circle_radius],
|
4796
|
+
fill: nil,
|
4797
|
+
stroke: stroke_color
|
4798
|
+
}
|
4799
|
+
@area.queue_redraw_all
|
4800
|
+
self.score -= 1 # notifies score observers automatically of change
|
4801
|
+
end
|
4802
|
+
|
4803
|
+
def restart_game
|
4804
|
+
@score = 0 # update variable directly to avoid notifying observers
|
4805
|
+
@circles_data.clear
|
4806
|
+
end
|
4807
|
+
|
4808
|
+
def launch
|
4809
|
+
menu('Actions') {
|
4810
|
+
menu_item('Restart') {
|
4811
|
+
on_clicked do
|
4812
|
+
restart_game
|
4813
|
+
end
|
4814
|
+
}
|
4815
|
+
|
4816
|
+
quit_menu_item
|
4817
|
+
}
|
4818
|
+
|
4819
|
+
menu('Difficulty') {
|
4820
|
+
radio_menu_item('Easy') {
|
4821
|
+
on_clicked do
|
4822
|
+
@time_max = TIME_MAX_EASY
|
4823
|
+
end
|
4824
|
+
}
|
4825
|
+
|
4826
|
+
radio_menu_item('Medium') {
|
4827
|
+
on_clicked do
|
4828
|
+
@time_max = TIME_MAX_MEDIUM
|
4829
|
+
end
|
4830
|
+
}
|
4831
|
+
|
4832
|
+
radio_menu_item('Hard') {
|
4833
|
+
checked true
|
4834
|
+
|
4835
|
+
on_clicked do
|
4836
|
+
@time_max = TIME_MAX_HARD
|
4837
|
+
end
|
4838
|
+
}
|
4839
|
+
|
4840
|
+
radio_menu_item('Insane') {
|
4841
|
+
on_clicked do
|
4842
|
+
@time_max = TIME_MAX_INSANE
|
4843
|
+
end
|
4844
|
+
}
|
4845
|
+
}
|
4846
|
+
|
4847
|
+
menu('Help') {
|
4848
|
+
menu_item('Instructions') {
|
4849
|
+
on_clicked do
|
4850
|
+
msg_box('Instructions', "Score goes down as circles are added.\nIf it reaches -20, you lose!\n\nClick circles to color and score!\nOnce score reaches 0, you win!\n\nBeware of concealed light-colored circles!\nThey are revealed once darker circles intersect them.\n\nThere are four levels of difficulty.\nChange via difficulty menu if the game gets too tough.")
|
4851
|
+
end
|
4852
|
+
}
|
4853
|
+
}
|
4854
|
+
|
4855
|
+
window('Color The Circles', WINDOW_WIDTH, WINDOW_HEIGHT) {
|
4856
|
+
margined true
|
4857
|
+
|
4858
|
+
grid {
|
4859
|
+
button('Restart') {
|
4860
|
+
left 0
|
4861
|
+
top 0
|
4862
|
+
halign :center
|
4863
|
+
|
4864
|
+
on_clicked do
|
4865
|
+
restart_game
|
4866
|
+
end
|
4867
|
+
}
|
4868
|
+
|
4869
|
+
label('Score goes down as circles are added. If it reaches -20, you lose!') {
|
4870
|
+
left 0
|
4871
|
+
top 1
|
4872
|
+
halign :center
|
4873
|
+
}
|
4874
|
+
|
4875
|
+
label('Click circles to color and score! Once score reaches 0, you win!') {
|
4876
|
+
left 0
|
4877
|
+
top 2
|
4878
|
+
halign :center
|
4879
|
+
}
|
4880
|
+
|
4881
|
+
horizontal_box {
|
4882
|
+
left 0
|
4883
|
+
top 3
|
4884
|
+
halign :center
|
4885
|
+
|
4886
|
+
label('Score:') {
|
4887
|
+
stretchy false
|
4888
|
+
}
|
4889
|
+
|
4890
|
+
@score_label = label(@score.to_s) {
|
4891
|
+
stretchy false
|
4892
|
+
}
|
4893
|
+
}
|
4894
|
+
|
4895
|
+
vertical_box {
|
4896
|
+
left 0
|
4897
|
+
top 4
|
4898
|
+
hexpand true
|
4899
|
+
vexpand true
|
4900
|
+
halign :fill
|
4901
|
+
valign :fill
|
4902
|
+
|
4903
|
+
@area = area {
|
4904
|
+
on_draw do |area_draw_params|
|
4905
|
+
path {
|
4906
|
+
rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
|
4907
|
+
|
4908
|
+
fill :white
|
4909
|
+
}
|
4910
|
+
|
4911
|
+
@circles_data.each do |circle_data|
|
4912
|
+
path {
|
4913
|
+
circle_data[:circle] = circle(*circle_data[:args])
|
4914
|
+
|
4915
|
+
fill circle_data[:fill]
|
4916
|
+
stroke circle_data[:stroke]
|
4917
|
+
}
|
4918
|
+
end
|
4919
|
+
end
|
4920
|
+
|
4921
|
+
on_mouse_down do |area_mouse_event|
|
4922
|
+
clicked_circle_data = @circles_data.find do |circle_data|
|
4923
|
+
circle_data[:fill].nil? && circle_data[:circle].include?(area_mouse_event[:x], area_mouse_event[:y])
|
4924
|
+
end
|
4925
|
+
if clicked_circle_data
|
4926
|
+
clicked_circle_data[:fill] = clicked_circle_data[:stroke]
|
4927
|
+
@area.queue_redraw_all
|
4928
|
+
self.score += 1 # notifies score observers automatically of change
|
4929
|
+
end
|
4930
|
+
end
|
4931
|
+
}
|
4932
|
+
}
|
4933
|
+
|
4934
|
+
}
|
4935
|
+
}.show
|
4936
|
+
end
|
4937
|
+
end
|
4938
|
+
|
4939
|
+
ColorTheCircles.new.launch
|
4940
|
+
```
|
4941
|
+
|
4347
4942
|
## Contributing to glimmer-dsl-libui
|
4348
4943
|
|
4349
4944
|
- Check out the latest master to make sure the feature hasn't been
|