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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +624 -29
  4. data/VERSION +1 -1
  5. data/examples/area_gallery.rb +7 -1
  6. data/examples/area_gallery2.rb +14 -4
  7. data/examples/area_gallery3.rb +8 -2
  8. data/examples/area_gallery4.rb +15 -5
  9. data/examples/color_the_circles.rb +223 -0
  10. data/examples/control_gallery.rb +1 -1
  11. data/examples/form_table.rb +20 -0
  12. data/examples/grid.rb +38 -2
  13. data/examples/login.rb +45 -0
  14. data/examples/midi_player.rb +1 -1
  15. data/examples/timer.rb +135 -0
  16. data/glimmer-dsl-libui.gemspec +0 -0
  17. data/lib/glimmer/libui/control_proxy/area_proxy/scrolling_area_proxy.rb +40 -0
  18. data/lib/glimmer/libui/control_proxy/area_proxy.rb +9 -5
  19. data/lib/glimmer/libui/control_proxy/entry_proxy/password_entry_proxy.rb +36 -0
  20. data/lib/glimmer/libui/control_proxy/entry_proxy/search_entry_proxy.rb +36 -0
  21. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +39 -0
  22. data/lib/glimmer/libui/control_proxy/grid_proxy.rb +12 -1
  23. data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +69 -0
  24. data/lib/glimmer/libui/control_proxy/menu_proxy.rb +3 -0
  25. data/lib/glimmer/libui/control_proxy/path_proxy.rb +3 -30
  26. data/lib/glimmer/libui/control_proxy.rb +8 -1
  27. data/lib/glimmer/libui/shape/arc.rb +6 -3
  28. data/lib/glimmer/libui/shape/circle.rb +50 -0
  29. data/lib/glimmer/libui/shape/rectangle.rb +4 -0
  30. data/lib/glimmer/libui/shape/square.rb +4 -0
  31. data/lib/glimmer/libui.rb +76 -2
  32. data/sounds/AlanWalker-Faded.mid +0 -0
  33. data/sounds/AlanWalker-SingMeToSleep.mid +0 -0
  34. data/sounds/CalvinHarris-Blame.mid +0 -0
  35. data/sounds/CalvinHarris-MyWay.mid +0 -0
  36. data/sounds/deadmau5-2448.mid +0 -0
  37. data/sounds/deadmau5-SoThereIWas.mid +0 -0
  38. 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.9
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
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
@@ -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
- arc(200, 200, 90, 0, 360, false)
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.9](#-glimmer-dsl-for-libui-019)
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.9'
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] (`Integer`) [default=`0`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
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] (`Integer`) [default=`0`]: available in [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) when nested under `grid`
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
- - `:ext_key`: non-character extra key (`Symbol`) such as `:left`, `:right`, `:escape`, `:insert`
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` (`0`), `vexpand` (`false`), and `valign` (`0`)
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') { |m|
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
- ![glimmer-dsl-libui-mac-grid-spanning.png](images/glimmer-dsl-libui-mac-grid-spanning.png)
2101
- ![glimmer-dsl-libui-mac-grid-expanding.png](images/glimmer-dsl-libui-mac-grid-expanding.png)
2124
+ ![glimmer-dsl-libui-mac-grid-span.png](images/glimmer-dsl-libui-mac-grid-span.png)
2125
+ ![glimmer-dsl-libui-mac-grid-expand.png](images/glimmer-dsl-libui-mac-grid-expand.png)
2126
+ ![glimmer-dsl-libui-mac-grid-align.png](images/glimmer-dsl-libui-mac-grid-align.png)
2102
2127
 
2103
2128
  Linux
2104
2129
 
2105
- ![glimmer-dsl-libui-linux-grid-spanning.png](images/glimmer-dsl-libui-linux-grid-spanning.png)
2106
- ![glimmer-dsl-libui-linux-grid-expanding.png](images/glimmer-dsl-libui-linux-grid-expanding.png)
2130
+ ![glimmer-dsl-libui-linux-grid-span.png](images/glimmer-dsl-libui-linux-grid-span.png)
2131
+ ![glimmer-dsl-libui-linux-grid-expand.png](images/glimmer-dsl-libui-linux-grid-expand.png)
2132
+ ![glimmer-dsl-libui-linux-grid-align.png](images/glimmer-dsl-libui-linux-grid-align.png)
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('Spanning') {
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('Expanding') {
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
  ![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png)
2957
3019
  ![glimmer-dsl-libui-mac-form-table-contact-entered.png](images/glimmer-dsl-libui-mac-form-table-contact-entered.png)
3020
+ ![glimmer-dsl-libui-mac-form-table-filtered.png](images/glimmer-dsl-libui-mac-form-table-filtered.png)
2958
3021
 
2959
3022
  Linux
2960
3023
 
2961
3024
  ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
2962
3025
  ![glimmer-dsl-libui-linux-form-table-contact-entered.png](images/glimmer-dsl-libui-linux-form-table-contact-entered.png)
3026
+ ![glimmer-dsl-libui-linux-form-table-filtered.png](images/glimmer-dsl-libui-linux-form-table-filtered.png)
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
- arc(200, 200, 90, 0, 360, false)
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
- arc {
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
- arc(200, 200, 90, 0, 360, false)
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
- arc {
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
+ ![glimmer-dsl-libui-mac-login.png](images/glimmer-dsl-libui-mac-login.png)
4484
+ ![glimmer-dsl-libui-mac-login-logged-in.png](images/glimmer-dsl-libui-mac-login-logged-in.png)
4485
+
4486
+ Linux
4487
+
4488
+ ![glimmer-dsl-libui-linux-login.png](images/glimmer-dsl-libui-linux-login.png)
4489
+ ![glimmer-dsl-libui-linux-login-logged-in.png](images/glimmer-dsl-libui-linux-login-logged-in.png)
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
+ ![glimmer-dsl-libui-mac-timer.png](images/glimmer-dsl-libui-mac-timer.png)
4558
+ ![glimmer-dsl-libui-mac-timer-in-progress.png](images/glimmer-dsl-libui-mac-timer-in-progress.png)
4559
+
4560
+ Linux
4561
+
4562
+ ![glimmer-dsl-libui-linux-timer.png](images/glimmer-dsl-libui-linux-timer.png)
4563
+ ![glimmer-dsl-libui-linux-timer-in-progress.png](images/glimmer-dsl-libui-linux-timer-in-progress.png)
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
+ ![glimmer-dsl-libui-mac-color-the-circles.png](images/glimmer-dsl-libui-mac-color-the-circles.png)
4723
+ ![glimmer-dsl-libui-mac-color-the-circles-lost.png](images/glimmer-dsl-libui-mac-color-the-circles-lost.png)
4724
+ ![glimmer-dsl-libui-mac-color-the-circles-won.png](images/glimmer-dsl-libui-mac-color-the-circles-won.png)
4725
+
4726
+ Linux
4727
+
4728
+ ![glimmer-dsl-libui-linux-color-the-circles.png](images/glimmer-dsl-libui-linux-color-the-circles.png)
4729
+ ![glimmer-dsl-libui-linux-color-the-circles-lost.png](images/glimmer-dsl-libui-linux-color-the-circles-lost.png)
4730
+ ![glimmer-dsl-libui-linux-color-the-circles-won.png](images/glimmer-dsl-libui-linux-color-the-circles-won.png)
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