glimmer-dsl-libui 0.1.10 → 0.2.2

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +574 -19
  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 +220 -0
  10. data/examples/control_gallery.rb +1 -1
  11. data/examples/form_table.rb +20 -0
  12. data/examples/login.rb +45 -0
  13. data/examples/midi_player.rb +1 -1
  14. data/examples/timer.rb +135 -0
  15. data/glimmer-dsl-libui.gemspec +0 -0
  16. data/lib/glimmer/libui/control_proxy/area_proxy/scrolling_area_proxy.rb +40 -0
  17. data/lib/glimmer/libui/control_proxy/area_proxy.rb +19 -2
  18. data/lib/glimmer/libui/control_proxy/entry_proxy/password_entry_proxy.rb +36 -0
  19. data/lib/glimmer/libui/control_proxy/entry_proxy/search_entry_proxy.rb +36 -0
  20. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +39 -0
  21. data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +69 -0
  22. data/lib/glimmer/libui/control_proxy/menu_proxy.rb +3 -0
  23. data/lib/glimmer/libui/control_proxy/window_proxy.rb +0 -6
  24. data/lib/glimmer/libui/control_proxy.rb +8 -1
  25. data/lib/glimmer/libui/shape/arc.rb +6 -3
  26. data/lib/glimmer/libui/shape/circle.rb +50 -0
  27. data/lib/glimmer/libui/shape/rectangle.rb +4 -0
  28. data/lib/glimmer/libui/shape/square.rb +4 -0
  29. data/lib/glimmer/libui.rb +59 -2
  30. data/sounds/AlanWalker-Faded.mid +0 -0
  31. data/sounds/AlanWalker-SingMeToSleep.mid +0 -0
  32. data/sounds/CalvinHarris-Blame.mid +0 -0
  33. data/sounds/CalvinHarris-MyWay.mid +0 -0
  34. data/sounds/deadmau5-2448.mid +0 -0
  35. data/sounds/deadmau5-SoThereIWas.mid +0 -0
  36. 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.10
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.2
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.10](#-glimmer-dsl-for-libui-0110)
200
+ - [Glimmer DSL for LibUI 0.2.2](#-glimmer-dsl-for-libui-022)
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.10'
334
+ gem 'glimmer-dsl-libui', '~> 0.2.2'
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
@@ -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
@@ -762,6 +782,8 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
762
782
 
763
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)
764
784
 
785
+ Available [X11](https://en.wikipedia.org/wiki/X11_color_names) colors can be obtained through `Glimmer::LibUI.x11_colors` method.
786
+
765
787
  Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
766
788
 
767
789
  Check [Histogram](#histogram) example for use of hex colors.
@@ -1434,7 +1456,7 @@ class TinyMidiPlayer
1434
1456
  end
1435
1457
 
1436
1458
  def create_gui
1437
- menu('Help') { |m|
1459
+ menu('Help') {
1438
1460
  menu_item('Version') {
1439
1461
  on_clicked do
1440
1462
  show_version
@@ -2995,15 +3017,19 @@ Mac
2995
3017
 
2996
3018
  ![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png)
2997
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)
2998
3021
 
2999
3022
  Linux
3000
3023
 
3001
3024
  ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
3002
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)
3003
3027
 
3004
3028
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3005
3029
 
3006
3030
  ```ruby
3031
+ # frozen_string_literal: true
3032
+
3007
3033
  require 'glimmer-dsl-libui'
3008
3034
 
3009
3035
  include Glimmer
@@ -3049,6 +3075,7 @@ window('Contacts', 600, 600) { |w|
3049
3075
  msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
3050
3076
  else
3051
3077
  data << new_row # automatically inserts a row into the table due to implicit data-binding
3078
+ @unfiltered_data = data.dup
3052
3079
  @name_entry.text = ''
3053
3080
  @email_entry.text = ''
3054
3081
  @phone_entry.text = ''
@@ -3058,6 +3085,25 @@ window('Contacts', 600, 600) { |w|
3058
3085
  end
3059
3086
  }
3060
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
+
3061
3107
  table {
3062
3108
  text_column('Name')
3063
3109
  text_column('Email')
@@ -3495,11 +3541,17 @@ window('Area Gallery', 400, 400) {
3495
3541
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3496
3542
  }
3497
3543
  path { # declarative stable path
3498
- arc(200, 200, 90, 0, 360, false)
3544
+ circle(200, 200, 90)
3499
3545
 
3500
3546
  fill r: 202, g: 102, b: 204, a: 0.5
3501
3547
  stroke r: 0, g: 0, b: 0, thickness: 2
3502
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
+ }
3503
3555
 
3504
3556
  on_mouse_event do |area_mouse_event|
3505
3557
  p area_mouse_event
@@ -3652,18 +3704,28 @@ window('Area Gallery', 400, 400) {
3652
3704
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3653
3705
  }
3654
3706
  path { # declarative stable path
3655
- arc {
3707
+ circle {
3656
3708
  x_center 200
3657
3709
  y_center 200
3658
3710
  radius 90
3659
- start_angle 0
3660
- sweep 360
3661
- is_negative false
3662
3711
  }
3663
3712
 
3664
3713
  fill r: 202, g: 102, b: 204, a: 0.5
3665
3714
  stroke r: 0, g: 0, b: 0, thickness: 2
3666
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
+ }
3667
3729
 
3668
3730
  on_mouse_event do |area_mouse_event|
3669
3731
  p area_mouse_event
@@ -3763,13 +3825,19 @@ window('Area Gallery', 400, 400) {
3763
3825
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3764
3826
  }
3765
3827
  path { # a dynamic path is added semi-declaratively inside on_draw block
3766
- arc(200, 200, 90, 0, 360, false)
3767
-
3828
+ circle(200, 200, 90)
3829
+
3768
3830
  fill r: 202, g: 102, b: 204, a: 0.5
3769
3831
  stroke r: 0, g: 0, b: 0, thickness: 2
3770
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
+ }
3771
3839
  end
3772
-
3840
+
3773
3841
  on_mouse_event do |area_mouse_event|
3774
3842
  p area_mouse_event
3775
3843
  end
@@ -3922,20 +3990,30 @@ window('Area Gallery', 400, 400) {
3922
3990
  stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
3923
3991
  }
3924
3992
  path { # a dynamic path is added semi-declaratively inside on_draw block
3925
- arc {
3993
+ circle {
3926
3994
  x_center 200
3927
3995
  y_center 200
3928
3996
  radius 90
3929
- start_angle 0
3930
- sweep 360
3931
- is_negative false
3932
3997
  }
3933
-
3998
+
3934
3999
  fill r: 202, g: 102, b: 204, a: 0.5
3935
4000
  stroke r: 0, g: 0, b: 0, thickness: 2
3936
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
+ }
3937
4015
  end
3938
-
4016
+
3939
4017
  on_mouse_event do |area_mouse_event|
3940
4018
  p area_mouse_event
3941
4019
  end
@@ -4384,6 +4462,483 @@ window('Basic Transform', 350, 350) {
4384
4462
  }.show
4385
4463
  ```
4386
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
+
4387
4942
  ## Contributing to glimmer-dsl-libui
4388
4943
 
4389
4944
  - Check out the latest master to make sure the feature hasn't been