glimmer-dsl-libui 0.4.3 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -1
- data/README.md +926 -153
- data/VERSION +1 -1
- data/examples/color_button.rb +18 -13
- data/examples/color_button2.rb +14 -0
- data/examples/date_time_picker.rb +19 -14
- data/examples/date_time_picker2.rb +20 -0
- data/examples/dynamic_area.rb +77 -90
- data/examples/dynamic_area2.rb +14 -12
- data/examples/dynamic_area3.rb +90 -0
- data/examples/dynamic_area4.rb +95 -0
- data/examples/font_button.rb +17 -12
- data/examples/font_button2.rb +18 -0
- data/examples/form_table.rb +0 -2
- data/examples/form_table2.rb +0 -2
- data/examples/histogram.rb +93 -91
- data/examples/histogram2.rb +109 -0
- data/examples/midi_player.rb +4 -5
- data/examples/midi_player2.rb +83 -0
- data/examples/midi_player3.rb +84 -0
- data/examples/timer.rb +28 -31
- data/examples/timer2.rb +129 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/attributed_string.rb +3 -0
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +18 -2
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +38 -0
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
- data/lib/glimmer/libui/control_proxy.rb +4 -12
- data/lib/glimmer/libui/data_bindable.rb +39 -0
- data/lib/glimmer/libui/shape.rb +2 -0
- metadata +14 -2
data/README.md
CHANGED
@@ -1,9 +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.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.4.7
|
2
2
|
## Prerequisite-Free Ruby Desktop Development GUI Library
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
|
4
4
|
[![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
5
5
|
|
6
|
-
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/kojix2/LibUI) is a prerequisite-free Ruby desktop development GUI library. No need to pre-install any prerequisites. Just install the gem and have platform-independent native GUI that just works!
|
6
|
+
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/kojix2/LibUI) is a prerequisite-free Ruby desktop development GUI (Graphical User Interface) library. No need to pre-install any prerequisites. Just install the [gem](https://rubygems.org/gems/glimmer-dsl-libui) and have platform-independent native GUI that just works!
|
7
7
|
|
8
8
|
Mac | Windows | Linux
|
9
9
|
----|---------|------
|
@@ -373,7 +373,7 @@ gem install glimmer-dsl-libui
|
|
373
373
|
Or install via Bundler `Gemfile`:
|
374
374
|
|
375
375
|
```ruby
|
376
|
-
gem 'glimmer-dsl-libui', '~> 0.4.
|
376
|
+
gem 'glimmer-dsl-libui', '~> 0.4.7'
|
377
377
|
```
|
378
378
|
|
379
379
|
Add `require 'glimmer-dsl-libui'` at the top, and then `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
|
@@ -460,7 +460,7 @@ Keyword(Args) | Properties | Listeners
|
|
460
460
|
`checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
461
461
|
`checkbox_text_color_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
462
462
|
`check_menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
|
463
|
-
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
|
463
|
+
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`), `selected_item` (`String`) | `on_selected`
|
464
464
|
`color_button` | `color` (Array of `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float`), `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float` | `on_changed`
|
465
465
|
`date_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
|
466
466
|
`date_time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
|
@@ -620,93 +620,112 @@ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
|
620
620
|
```ruby
|
621
621
|
require 'glimmer-dsl-libui'
|
622
622
|
|
623
|
-
|
624
|
-
|
625
|
-
data = [
|
626
|
-
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
|
627
|
-
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
|
628
|
-
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
|
629
|
-
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
|
630
|
-
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
|
631
|
-
]
|
632
|
-
|
633
|
-
window('Contacts', 600, 600) { |w|
|
634
|
-
margined true
|
623
|
+
class FormTable
|
624
|
+
include Glimmer
|
635
625
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
@
|
641
|
-
|
642
|
-
|
643
|
-
@
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
}
|
652
|
-
@state_entry = entry {
|
653
|
-
label 'State'
|
654
|
-
}
|
655
|
-
}
|
656
|
-
|
657
|
-
button('Save Contact') {
|
658
|
-
stretchy false
|
659
|
-
|
660
|
-
on_clicked do
|
661
|
-
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
662
|
-
if new_row.include?('')
|
663
|
-
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
664
|
-
else
|
665
|
-
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
666
|
-
@unfiltered_data = data.dup
|
667
|
-
@name_entry.text = ''
|
668
|
-
@email_entry.text = ''
|
669
|
-
@phone_entry.text = ''
|
670
|
-
@city_entry.text = ''
|
671
|
-
@state_entry.text = ''
|
672
|
-
end
|
673
|
-
end
|
674
|
-
}
|
675
|
-
|
676
|
-
search_entry { |se|
|
677
|
-
stretchy false
|
626
|
+
attr_accessor :name, :email, :phone, :city, :state, :filter_value
|
627
|
+
|
628
|
+
def initialize
|
629
|
+
@data = [
|
630
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
|
631
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
|
632
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
|
633
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
|
634
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
|
635
|
+
]
|
636
|
+
end
|
637
|
+
|
638
|
+
def launch
|
639
|
+
window('Contacts', 600, 600) { |w|
|
640
|
+
margined true
|
678
641
|
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
642
|
+
vertical_box {
|
643
|
+
form {
|
644
|
+
stretchy false
|
645
|
+
|
646
|
+
entry {
|
647
|
+
label 'Name'
|
648
|
+
text <=> [self, :name]
|
649
|
+
}
|
650
|
+
|
651
|
+
entry {
|
652
|
+
label 'Email'
|
653
|
+
text <=> [self, :email]
|
654
|
+
}
|
655
|
+
|
656
|
+
entry {
|
657
|
+
label 'Phone'
|
658
|
+
text <=> [self, :phone]
|
659
|
+
}
|
660
|
+
|
661
|
+
entry {
|
662
|
+
label 'City'
|
663
|
+
text <=> [self, :city]
|
664
|
+
}
|
665
|
+
|
666
|
+
entry {
|
667
|
+
label 'State'
|
668
|
+
text <=> [self, :state]
|
669
|
+
}
|
670
|
+
}
|
671
|
+
|
672
|
+
button('Save Contact') {
|
673
|
+
stretchy false
|
674
|
+
|
675
|
+
on_clicked do
|
676
|
+
new_row = [name, email, phone, city, state]
|
677
|
+
if new_row.include?('')
|
678
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
679
|
+
else
|
680
|
+
@data << new_row # automatically inserts a row into the table due to implicit data-binding
|
681
|
+
@unfiltered_data = @data.dup
|
682
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
683
|
+
self.email = ''
|
684
|
+
self.phone = ''
|
685
|
+
self.city = ''
|
686
|
+
self.state = ''
|
689
687
|
end
|
690
688
|
end
|
691
|
-
|
692
|
-
|
693
|
-
|
689
|
+
}
|
690
|
+
|
691
|
+
search_entry {
|
692
|
+
stretchy false
|
693
|
+
text <=> [self, :filter_value, # bidirectional data-binding of text to self.filter_value with after_write option
|
694
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
695
|
+
@unfiltered_data ||= @data.dup
|
696
|
+
# Unfilter first to remove any previous filters
|
697
|
+
@data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
698
|
+
# Now, apply filter if entered
|
699
|
+
unless filter_value.empty?
|
700
|
+
@data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
701
|
+
row_data.any? do |cell|
|
702
|
+
cell.to_s.downcase.include?(filter_value.downcase)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
}
|
707
|
+
]
|
708
|
+
}
|
709
|
+
|
710
|
+
table {
|
711
|
+
text_column('Name')
|
712
|
+
text_column('Email')
|
713
|
+
text_column('Phone')
|
714
|
+
text_column('City')
|
715
|
+
text_column('State')
|
694
716
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
717
|
+
cell_rows @data # implicit data-binding
|
718
|
+
|
719
|
+
on_changed do |row, type, row_data|
|
720
|
+
puts "Row #{row} #{type}: #{row_data}"
|
721
|
+
end
|
722
|
+
}
|
723
|
+
}
|
724
|
+
}.show
|
725
|
+
end
|
726
|
+
end
|
701
727
|
|
702
|
-
|
703
|
-
|
704
|
-
on_changed do |row, type, row_data|
|
705
|
-
puts "Row #{row} #{type}: #{row_data}"
|
706
|
-
end
|
707
|
-
}
|
708
|
-
}
|
709
|
-
}.show
|
728
|
+
FormTable.new.launch
|
710
729
|
```
|
711
730
|
|
712
731
|
![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
|
@@ -877,7 +896,7 @@ Given that it is very new and is not a [libui](https://github.com/andlabs/libui)
|
|
877
896
|
- Including an `image` inside an `area` `on_draw` listener improves performance due to not retaining pixel/line data in memory.
|
878
897
|
- Supplying `width` and `height` (2nd and 3rd arguments) greatly improves performance when shrinking image.
|
879
898
|
|
880
|
-
Currently, it is recommended to use `image` with very small `width` and `height` values only.
|
899
|
+
Currently, it is recommended to use `image` with very small `width` and `height` values only (e.g. 24x24).
|
881
900
|
|
882
901
|
Setting a [`transform` `matrix`](#area-transform-matrix) is supported under `image` just like it is under `path` and `text` inside `area`.
|
883
902
|
|
@@ -1033,6 +1052,8 @@ window('Basic Image', 96, 96) {
|
|
1033
1052
|
|
1034
1053
|
One final note is that in Linux, table images grow and shrink with the image size unlike on the Mac where table row heights are constant regardless of image sizes. As such, you may be able to repurpose a table with a single image column and a single row as an image control with more native libui rendering if you are only targeting Linux with your app.
|
1035
1054
|
|
1055
|
+
![linux table image](images/glimmer-dsl-libui-linux-basic-table-image.png)
|
1056
|
+
|
1036
1057
|
Check out [examples/basic_image.rb](#basic-image) (all versions) for examples of using `image` Glimmer custom control.
|
1037
1058
|
|
1038
1059
|
#### Colors
|
@@ -1352,11 +1373,28 @@ See examples of the `observe` keyword at [Color The Circles](#color-the-circles)
|
|
1352
1373
|
|
1353
1374
|
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) supports both bidirectional (two-way) data-binding and unidirectional (one-way) data-binding.
|
1354
1375
|
|
1376
|
+
Data-binding enables writing very expressive, terse, and declarative code to synchronize View properties with Model attributes without writing many lines or pages of imperative code doing the same thing, increasing productivity immensely.
|
1377
|
+
|
1378
|
+
Data-binding automatically takes advantage of the [Observer Pattern](#observer-pattern) behind the scenes and is very well suited to declaring View property data sources piecemeal. On the other hand, explicit use of the [Observer Pattern](#observer-pattern) is sometimes more suitable when needing to make multiple View updates upon a single Model attribute change.
|
1379
|
+
|
1380
|
+
Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) flavor of [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) by observing both the View and a Presenter for changes and updating the opposite side upon encountering them. This enables writing more decoupled cleaner code that keeps View code and Model code disentangled and highly maintainable. For example, check out the Snake game presenters for [Grid](/examples/snake/presenter/grid.rb) and [Cell](/examples/snake/presenter/cell.rb), which act as proxies for the actual Snake game models [Snake](/examples/snake/model/snake.rb) and [Apple](/examples/snake/model/apple.rb), mediating synchronization of data between them and the [Snake View GUI](/examples/snake.rb).
|
1381
|
+
|
1382
|
+
![MVP](https://www.researchgate.net/profile/Gilles-Perrouin/publication/320249584/figure/fig8/AS:668260987068418@1536337243385/Model-view-presenter-architecture.png)
|
1383
|
+
|
1355
1384
|
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) supports bidirectional (two-way) data-binding of the following controls/properties via the `<=>` operator (indicating data is moving in both directions between View and Model):
|
1356
|
-
- `
|
1357
|
-
- `
|
1358
|
-
- `
|
1359
|
-
- `
|
1385
|
+
- `color_button`: `color`
|
1386
|
+
- `combobox`: `selected`, `selected_item`
|
1387
|
+
- `date_picker`: `time`
|
1388
|
+
- `date_time_picker`: `time`
|
1389
|
+
- `editable_combobox`: `text`
|
1390
|
+
- `entry`: `text`
|
1391
|
+
- `font_button`: `font`
|
1392
|
+
- `multiline_entry`: `text`
|
1393
|
+
- `non_wrapping_multiline_entry`: `text`
|
1394
|
+
- `search_entry`: `text`
|
1395
|
+
- `slider`: `value`
|
1396
|
+
- `spinbox`: `value`
|
1397
|
+
- `time_picker`: `time`
|
1360
1398
|
|
1361
1399
|
Example of bidirectional data-binding:
|
1362
1400
|
|
@@ -1372,11 +1410,11 @@ Another example of bidirectional data-binding with an option:
|
|
1372
1410
|
|
1373
1411
|
```ruby
|
1374
1412
|
entry {
|
1375
|
-
text <=> [self, :
|
1413
|
+
text <=> [self, :entered_text, after_write: ->(text) {puts text}]
|
1376
1414
|
}
|
1377
1415
|
```
|
1378
1416
|
|
1379
|
-
That is data-binding `
|
1417
|
+
That is data-binding `entered_text` attribute on `self` to `entry` `text` property and printing text after write to the model.
|
1380
1418
|
|
1381
1419
|
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) supports unidirectional (one-way) data-binding of any control/shape/attributed-string property via the `<=` operator (indicating data is moving from the right side, which is the Model, to the left side, which is the GUI View object).
|
1382
1420
|
|
@@ -1400,19 +1438,16 @@ window {
|
|
1400
1438
|
|
1401
1439
|
That is data-binding the `window` `title` property to the `score` attribute of a `@game`, but converting on read from the Model to a `String`.
|
1402
1440
|
|
1403
|
-
|
1404
|
-
- Bidirectional (two-way) data-binding to
|
1405
|
-
- Unidirectional (one-way) data-binding to
|
1441
|
+
To summarize the data-binding API:
|
1442
|
+
- `view_property <=> [model, attribute, *read_or_write_options]`: Bidirectional (two-way) data-binding to Model attribute accessor
|
1443
|
+
- `view_property <= [model, attribute, *read_only_options]`: Unidirectional (one-way) data-binding to Model attribute reader
|
1406
1444
|
|
1407
1445
|
This is also known as the [Glimmer Shine](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#shine) syntax for data-binding, a [Glimmer](https://github.com/AndyObtiva/glimmer)-only unique innovation that takes advantage of [Ruby](https://www.ruby-lang.org/en/)'s highly expressive syntax and malleable DSL support.
|
1408
1446
|
|
1409
|
-
Data-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) flavor of [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) by observing both the View and a Presenter for changes and updating the opposite side upon encountering them. This enables writing more decoupled cleaner code that keeps View code and Model code disentangled and highly maintainable. For example, check out the Snake game presenters for [Grid](/examples/snake/presenter/grid.rb) and [Cell](/examples/snake/presenter/cell.rb), which act as proxies for the actual Snake game models [Snake](/examples/snake/model/snake.rb) and [Apple](/examples/snake/model/apple.rb), mediating synchronization of data between them and the [Snake View GUI](/examples/snake.rb).
|
1414
|
-
|
1415
|
-
![MVP](https://www.researchgate.net/profile/Gilles-Perrouin/publication/320249584/figure/fig8/AS:668260987068418@1536337243385/Model-view-presenter-architecture.png)
|
1447
|
+
Data-bound model attribute can be:
|
1448
|
+
- **Direct:** `Symbol` representing attribute reader/writer (e.g. `[person, :name`])
|
1449
|
+
- **Nested:** `String` representing nested attribute path (e.g. `[company, 'address.street']`). That results in "nested data-binding"
|
1450
|
+
- **Indexed:** `String` containing array attribute index (e.g. `[customer, 'addresses[0].street']`). That results in "indexed data-binding"
|
1416
1451
|
|
1417
1452
|
Data-binding options include:
|
1418
1453
|
- `before_read {|value| ...}`: performs an operation before reading data from Model to update the View.
|
@@ -1421,6 +1456,7 @@ Data-binding options include:
|
|
1421
1456
|
- `before_write {|value| ...}`: performs an operation before writing data to Model from View.
|
1422
1457
|
- `on_write {|value| ...}`: converts value read from View to update the Model.
|
1423
1458
|
- `after_write {|converted_value| ...}`: performs an operation after writing to Model from View.
|
1459
|
+
- `computed_by attribute` or `computed_by [attribute1, attribute2, ...]`: indicates model attribute is computed from specified attribute(s), thus updated when they are updated (see in [Login example version 2](/examples/login2.rb)). That is known as "computed data-binding".
|
1424
1460
|
|
1425
1461
|
Note that with both `on_read` and `on_write` converters, you could pass a `Symbol` representing the name of a method on the value object to invoke.
|
1426
1462
|
|
@@ -1432,9 +1468,11 @@ entry {
|
|
1432
1468
|
}
|
1433
1469
|
```
|
1434
1470
|
|
1435
|
-
|
1471
|
+
Data-binding gotchas:
|
1472
|
+
- Never data-bind a control property to an attribute on the same view object with the same exact name (e.g. binding `entry` `text` property to `self` `text` attribute) as it would conflict with it. Instead, data-bind view property to an attribute with a different name on the view object or with the same name, but on a presenter or model object (e.g. data-bind `entry` `text` to `self` `legal_text` attribute or to `contract` model `text` attribute)
|
1473
|
+
- Data-binding a property utilizes the control's listener associated with the property (e.g. `on_changed` for `entry` `text`), so you cannot hook into the listener directly anymore as that would negate data-binding. Instead, you can add an `after_write: ->(val) {}` option to perform something on trigger of the control listener instead.
|
1436
1474
|
|
1437
|
-
Learn more from data-binding usage in [Basic Entry](#basic-entry), [Form](#form), [Form Table](#form-table), [
|
1475
|
+
Learn more from data-binding usage in [Login](#login) (4 data-binding versions), [Basic Entry](#basic-entry), [Form](#form), [Form Table](#form-table), [Method-Based Custom Keyword](#method-based-custom-keyword), [Snake](#snake) and [Tic Tac Toe](#tic_tac_toe) examples.
|
1438
1476
|
|
1439
1477
|
### API Gotchas
|
1440
1478
|
|
@@ -1850,7 +1888,7 @@ Example:
|
|
1850
1888
|
|
1851
1889
|
## Examples
|
1852
1890
|
|
1853
|
-
The following examples include reimplementions of the examples in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) as well as brand new examples.
|
1891
|
+
The following examples include reimplementions of the examples in the [LibUI](https://github.com/kojix2/LibUI) project utilizing the [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) (with and without [data-binding](#data-binding)) as well as brand new examples.
|
1854
1892
|
|
1855
1893
|
To browse all examples, simply launch the [Meta-Example](examples/meta_example.rb), which lists all examples and displays each example's code when selected. It also enables code editing to facilitate experimentation and learning.
|
1856
1894
|
|
@@ -1877,17 +1915,23 @@ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
|
1877
1915
|
```ruby
|
1878
1916
|
require 'glimmer-dsl-libui'
|
1879
1917
|
require 'facets'
|
1918
|
+
require 'fileutils'
|
1880
1919
|
|
1881
1920
|
class MetaExample
|
1882
1921
|
include Glimmer
|
1883
1922
|
|
1923
|
+
ADDITIONAL_BASIC_EXAMPLES = ['Color Button', 'Font Button', 'Form', 'Date Time Picker', 'Simple Notepad']
|
1924
|
+
|
1925
|
+
attr_accessor :code_text
|
1926
|
+
|
1884
1927
|
def initialize
|
1885
|
-
@selected_example_index =
|
1928
|
+
@selected_example_index = examples_with_versions.index(basic_examples_with_versions.first)
|
1929
|
+
@code_text = File.read(file_path_for(selected_example))
|
1886
1930
|
end
|
1887
1931
|
|
1888
1932
|
def examples
|
1889
1933
|
if @examples.nil?
|
1890
|
-
example_files = Dir.glob(File.join(File.expand_path('.', __dir__), '
|
1934
|
+
example_files = Dir.glob(File.join(File.expand_path('.', __dir__), '*.rb'))
|
1891
1935
|
example_file_names = example_files.map { |f| File.basename(f, '.rb') }
|
1892
1936
|
example_file_names = example_file_names.reject { |f| f == 'meta_example' || f.match(/\d$/) }
|
1893
1937
|
@examples = example_file_names.map { |f| f.underscore.titlecase }
|
@@ -1901,12 +1945,20 @@ class MetaExample
|
|
1901
1945
|
end
|
1902
1946
|
end
|
1903
1947
|
|
1948
|
+
def basic_examples_with_versions
|
1949
|
+
examples_with_versions.select {|example| example.start_with?('Basic') || ADDITIONAL_BASIC_EXAMPLES.include?(example) }
|
1950
|
+
end
|
1951
|
+
|
1952
|
+
def advanced_examples_with_versions
|
1953
|
+
examples_with_versions - basic_examples_with_versions
|
1954
|
+
end
|
1955
|
+
|
1904
1956
|
def file_path_for(example)
|
1905
1957
|
File.join(File.expand_path('.', __dir__), "#{example.underscore}.rb")
|
1906
1958
|
end
|
1907
1959
|
|
1908
1960
|
def version_count_for(example)
|
1909
|
-
Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(
|
1961
|
+
Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/#{example.underscore}\d\.rb$/)}.count + 1
|
1910
1962
|
end
|
1911
1963
|
|
1912
1964
|
def glimmer_dsl_libui_file
|
@@ -1942,17 +1994,47 @@ class MetaExample
|
|
1942
1994
|
vertical_box {
|
1943
1995
|
stretchy false
|
1944
1996
|
|
1945
|
-
|
1997
|
+
tab {
|
1946
1998
|
stretchy false
|
1947
|
-
items examples_with_versions
|
1948
|
-
selected @selected_example_index
|
1949
1999
|
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
2000
|
+
tab_item('Basic') {
|
2001
|
+
vertical_box {
|
2002
|
+
@basic_example_radio_buttons = radio_buttons {
|
2003
|
+
stretchy false
|
2004
|
+
items basic_examples_with_versions
|
2005
|
+
selected basic_examples_with_versions.index(examples_with_versions[@selected_example_index])
|
2006
|
+
|
2007
|
+
on_selected do
|
2008
|
+
@selected_example_index = examples_with_versions.index(basic_examples_with_versions[@basic_example_radio_buttons.selected])
|
2009
|
+
example = selected_example
|
2010
|
+
self.code_text = File.read(file_path_for(example))
|
2011
|
+
@version_spinbox.value = 1
|
2012
|
+
end
|
2013
|
+
}
|
2014
|
+
|
2015
|
+
label # filler
|
2016
|
+
label # filler
|
2017
|
+
}
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
tab_item('Advanced') {
|
2021
|
+
vertical_box {
|
2022
|
+
@advanced_example_radio_buttons = radio_buttons {
|
2023
|
+
stretchy false
|
2024
|
+
items advanced_examples_with_versions
|
2025
|
+
|
2026
|
+
on_selected do
|
2027
|
+
@selected_example_index = examples_with_versions.index(advanced_examples_with_versions[@advanced_example_radio_buttons.selected])
|
2028
|
+
example = selected_example
|
2029
|
+
self.code_text = File.read(file_path_for(example))
|
2030
|
+
@version_spinbox.value = 1
|
2031
|
+
end
|
2032
|
+
}
|
2033
|
+
|
2034
|
+
label # filler
|
2035
|
+
label # filler
|
2036
|
+
}
|
2037
|
+
}
|
1956
2038
|
}
|
1957
2039
|
|
1958
2040
|
horizontal_box {
|
@@ -1970,7 +2052,7 @@ class MetaExample
|
|
1970
2052
|
else
|
1971
2053
|
version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
|
1972
2054
|
example = "#{selected_example}#{version_number}"
|
1973
|
-
|
2055
|
+
self.code_text = File.read(file_path_for(example))
|
1974
2056
|
end
|
1975
2057
|
end
|
1976
2058
|
}
|
@@ -1982,9 +2064,15 @@ class MetaExample
|
|
1982
2064
|
button('Launch') {
|
1983
2065
|
on_clicked do
|
1984
2066
|
begin
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
2067
|
+
parent_dir = File.join(Dir.home, '.glimmer-dsl-libui', 'examples')
|
2068
|
+
FileUtils.mkdir_p(parent_dir)
|
2069
|
+
example_file = File.join(parent_dir, "#{selected_example.underscore}.rb")
|
2070
|
+
File.write(example_file, code_text)
|
2071
|
+
example_supporting_directory = File.expand_path(selected_example.underscore, __dir__)
|
2072
|
+
FileUtils.cp_r(example_supporting_directory, parent_dir) if Dir.exist?(example_supporting_directory)
|
2073
|
+
FileUtils.cp_r(File.expand_path('../icons', __dir__), File.dirname(parent_dir))
|
2074
|
+
FileUtils.cp_r(File.expand_path('../sounds', __dir__), File.dirname(parent_dir))
|
2075
|
+
run_example(example_file)
|
1988
2076
|
rescue => e
|
1989
2077
|
puts e.full_message
|
1990
2078
|
puts 'Unable to write code changes! Running original example...'
|
@@ -1994,14 +2082,14 @@ class MetaExample
|
|
1994
2082
|
}
|
1995
2083
|
button('Reset') {
|
1996
2084
|
on_clicked do
|
1997
|
-
|
2085
|
+
self.code_text = File.read(file_path_for(selected_example))
|
1998
2086
|
end
|
1999
2087
|
}
|
2000
2088
|
}
|
2001
2089
|
}
|
2002
2090
|
|
2003
2091
|
@code_entry = non_wrapping_multiline_entry {
|
2004
|
-
text
|
2092
|
+
text <=> [self, :code_text]
|
2005
2093
|
}
|
2006
2094
|
}
|
2007
2095
|
}.show
|
@@ -2415,7 +2503,33 @@ UI.quit
|
|
2415
2503
|
|
2416
2504
|
```
|
2417
2505
|
|
2418
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2506
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
2507
|
+
|
2508
|
+
```ruby
|
2509
|
+
require 'glimmer-dsl-libui'
|
2510
|
+
|
2511
|
+
class FontButton
|
2512
|
+
include Glimmer
|
2513
|
+
|
2514
|
+
attr_accessor :font_descriptor
|
2515
|
+
|
2516
|
+
def launch
|
2517
|
+
window('hello world', 300, 200) {
|
2518
|
+
font_button {
|
2519
|
+
font <=> [self, :font_descriptor, after_write: -> { p font_descriptor }]
|
2520
|
+
}
|
2521
|
+
|
2522
|
+
on_closing do
|
2523
|
+
puts 'Bye Bye'
|
2524
|
+
end
|
2525
|
+
}.show
|
2526
|
+
end
|
2527
|
+
end
|
2528
|
+
|
2529
|
+
FontButton.new.launch
|
2530
|
+
```
|
2531
|
+
|
2532
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
2419
2533
|
|
2420
2534
|
```ruby
|
2421
2535
|
require 'glimmer-dsl-libui'
|
@@ -2456,18 +2570,44 @@ Mac | Windows | Linux
|
|
2456
2570
|
----|---------|------
|
2457
2571
|
![glimmer-dsl-libui-mac-color-button.png](images/glimmer-dsl-libui-mac-color-button.png) ![glimmer-dsl-libui-mac-color-button-selection.png](images/glimmer-dsl-libui-mac-color-button-selection.png) | ![glimmer-dsl-libui-windows-color-button.png](images/glimmer-dsl-libui-windows-color-button.png) ![glimmer-dsl-libui-windows-color-button-selection.png](images/glimmer-dsl-libui-windows-color-button-selection.png) | ![glimmer-dsl-libui-linux-color-button.png](images/glimmer-dsl-libui-linux-color-button.png) ![glimmer-dsl-libui-linux-color-button-selection.png](images/glimmer-dsl-libui-linux-color-button-selection.png)
|
2458
2572
|
|
2459
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2573
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
2460
2574
|
|
2461
2575
|
```ruby
|
2462
2576
|
require 'glimmer-dsl-libui'
|
2463
2577
|
|
2464
|
-
|
2578
|
+
class ColorButton
|
2579
|
+
include Glimmer
|
2580
|
+
|
2581
|
+
attr_accessor :selected_color
|
2582
|
+
|
2583
|
+
def initialize
|
2584
|
+
@selected_color = :blue
|
2585
|
+
end
|
2586
|
+
|
2587
|
+
def launch
|
2588
|
+
window('color button', 240) {
|
2589
|
+
color_button {
|
2590
|
+
color <=> [self, :selected_color, after_write: ->(color) {p color}]
|
2591
|
+
}
|
2592
|
+
}.show
|
2593
|
+
end
|
2594
|
+
end
|
2465
2595
|
|
2466
|
-
|
2467
|
-
|
2468
|
-
|
2469
|
-
|
2470
|
-
|
2596
|
+
ColorButton.new.launch
|
2597
|
+
```
|
2598
|
+
|
2599
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
2600
|
+
|
2601
|
+
```ruby
|
2602
|
+
require 'glimmer-dsl-libui'
|
2603
|
+
|
2604
|
+
include Glimmer
|
2605
|
+
|
2606
|
+
window('color button', 240) {
|
2607
|
+
color_button { |cb|
|
2608
|
+
color :blue
|
2609
|
+
|
2610
|
+
on_changed do
|
2471
2611
|
rgba = cb.color
|
2472
2612
|
p rgba
|
2473
2613
|
end
|
@@ -2538,7 +2678,35 @@ UI.main
|
|
2538
2678
|
UI.quit
|
2539
2679
|
```
|
2540
2680
|
|
2541
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2681
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
2682
|
+
|
2683
|
+
```ruby
|
2684
|
+
require 'glimmer-dsl-libui'
|
2685
|
+
|
2686
|
+
class DateTimePicker
|
2687
|
+
include Glimmer
|
2688
|
+
|
2689
|
+
attr_accessor :picked_time
|
2690
|
+
|
2691
|
+
def launch
|
2692
|
+
window('Date Time Pickers', 300, 200) {
|
2693
|
+
vertical_box {
|
2694
|
+
date_time_picker {
|
2695
|
+
time <=> [self, :picked_time, after_write: ->(time) { p time }]
|
2696
|
+
}
|
2697
|
+
}
|
2698
|
+
|
2699
|
+
on_closing do
|
2700
|
+
puts 'Bye Bye'
|
2701
|
+
end
|
2702
|
+
}.show
|
2703
|
+
end
|
2704
|
+
end
|
2705
|
+
|
2706
|
+
DateTimePicker.new.launch
|
2707
|
+
```
|
2708
|
+
|
2709
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
2542
2710
|
|
2543
2711
|
```ruby
|
2544
2712
|
require 'glimmer-dsl-libui'
|
@@ -5748,7 +5916,96 @@ Mac | Windows | Linux
|
|
5748
5916
|
----|---------|------
|
5749
5917
|
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-dynamic-area.png) ![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-dynamic-area-updated.png) | ![glimmer-dsl-libui-windows-dynamic-area.png](images/glimmer-dsl-libui-windows-dynamic-area.png) ![glimmer-dsl-libui-windows-dynamic-area-updated.png](images/glimmer-dsl-libui-windows-dynamic-area-updated.png) | ![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-dynamic-area.png) ![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-dynamic-area-updated.png)
|
5750
5918
|
|
5751
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5919
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
5920
|
+
|
5921
|
+
```ruby
|
5922
|
+
require 'glimmer-dsl-libui'
|
5923
|
+
|
5924
|
+
class DynamicArea
|
5925
|
+
include Glimmer
|
5926
|
+
|
5927
|
+
attr_accessor :rectangle_x, :rectangle_y, :rectangle_width, :rectangle_height, :rectangle_red, :rectangle_green, :rectangle_blue, :rectangle_alpha
|
5928
|
+
|
5929
|
+
def initialize
|
5930
|
+
@rectangle_x = 25
|
5931
|
+
@rectangle_y = 25
|
5932
|
+
@rectangle_width = 150
|
5933
|
+
@rectangle_height = 150
|
5934
|
+
@rectangle_red = 102
|
5935
|
+
@rectangle_green = 102
|
5936
|
+
@rectangle_blue = 204
|
5937
|
+
@rectangle_alpha = 100
|
5938
|
+
end
|
5939
|
+
|
5940
|
+
def launch
|
5941
|
+
window('Dynamic Area', 240, 600) {
|
5942
|
+
margined true
|
5943
|
+
|
5944
|
+
vertical_box {
|
5945
|
+
label('Rectangle Properties') {
|
5946
|
+
stretchy false
|
5947
|
+
}
|
5948
|
+
|
5949
|
+
form {
|
5950
|
+
stretchy false
|
5951
|
+
|
5952
|
+
spinbox(0, 1000) {
|
5953
|
+
label 'x'
|
5954
|
+
value <=> [self, :rectangle_x, after_write: -> {@area.queue_redraw_all}]
|
5955
|
+
}
|
5956
|
+
|
5957
|
+
spinbox(0, 1000) {
|
5958
|
+
label 'y'
|
5959
|
+
value <=> [self, :rectangle_y, after_write: -> {@area.queue_redraw_all}]
|
5960
|
+
}
|
5961
|
+
|
5962
|
+
spinbox(0, 1000) {
|
5963
|
+
label 'width'
|
5964
|
+
value <=> [self, :rectangle_width, after_write: -> {@area.queue_redraw_all}]
|
5965
|
+
}
|
5966
|
+
|
5967
|
+
spinbox(0, 1000) {
|
5968
|
+
label 'height'
|
5969
|
+
value <=> [self, :rectangle_height, after_write: -> {@area.queue_redraw_all}]
|
5970
|
+
}
|
5971
|
+
|
5972
|
+
spinbox(0, 255) {
|
5973
|
+
label 'red'
|
5974
|
+
value <=> [self, :rectangle_red, after_write: -> {@area.queue_redraw_all}]
|
5975
|
+
}
|
5976
|
+
|
5977
|
+
spinbox(0, 255) {
|
5978
|
+
label 'green'
|
5979
|
+
value <=> [self, :rectangle_green, after_write: -> {@area.queue_redraw_all}]
|
5980
|
+
}
|
5981
|
+
|
5982
|
+
spinbox(0, 255) {
|
5983
|
+
label 'blue'
|
5984
|
+
value <=> [self, :rectangle_blue, after_write: -> {@area.queue_redraw_all}]
|
5985
|
+
}
|
5986
|
+
|
5987
|
+
spinbox(0, 100) {
|
5988
|
+
label 'alpha'
|
5989
|
+
value <=> [self, :rectangle_alpha, after_write: -> {@area.queue_redraw_all}]
|
5990
|
+
}
|
5991
|
+
}
|
5992
|
+
|
5993
|
+
@area = area {
|
5994
|
+
on_draw do |area_draw_params|
|
5995
|
+
rectangle(rectangle_x, rectangle_y, rectangle_width, rectangle_height) { # a dynamic path is added semi-declaratively inside on_draw block
|
5996
|
+
fill r: rectangle_red, g: rectangle_green, b: rectangle_blue, a: rectangle_alpha / 100.0
|
5997
|
+
}
|
5998
|
+
end
|
5999
|
+
}
|
6000
|
+
}
|
6001
|
+
}.show
|
6002
|
+
end
|
6003
|
+
end
|
6004
|
+
|
6005
|
+
DynamicArea.new.launch
|
6006
|
+
```
|
6007
|
+
|
6008
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
5752
6009
|
|
5753
6010
|
```ruby
|
5754
6011
|
require 'glimmer-dsl-libui'
|
@@ -5850,7 +6107,102 @@ window('Dynamic Area', 240, 600) {
|
|
5850
6107
|
}.show
|
5851
6108
|
```
|
5852
6109
|
|
5853
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
6110
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (declarative stable `path` approach with [data-binding](#data-binding)):
|
6111
|
+
|
6112
|
+
```ruby
|
6113
|
+
require 'glimmer-dsl-libui'
|
6114
|
+
|
6115
|
+
class DynamicArea
|
6116
|
+
include Glimmer
|
6117
|
+
|
6118
|
+
attr_accessor :rectangle_x, :rectangle_y, :rectangle_width, :rectangle_height, :rectangle_red, :rectangle_green, :rectangle_blue, :rectangle_alpha
|
6119
|
+
|
6120
|
+
def initialize
|
6121
|
+
@rectangle_x = 25
|
6122
|
+
@rectangle_y = 25
|
6123
|
+
@rectangle_width = 150
|
6124
|
+
@rectangle_height = 150
|
6125
|
+
@rectangle_red = 102
|
6126
|
+
@rectangle_green = 102
|
6127
|
+
@rectangle_blue = 204
|
6128
|
+
@rectangle_alpha = 100
|
6129
|
+
end
|
6130
|
+
|
6131
|
+
def rectangle_fill
|
6132
|
+
{ r: rectangle_red, g: rectangle_green, b: rectangle_blue, a: rectangle_alpha / 100.0 }
|
6133
|
+
end
|
6134
|
+
|
6135
|
+
def launch
|
6136
|
+
window('Dynamic Area', 240, 600) {
|
6137
|
+
margined true
|
6138
|
+
|
6139
|
+
vertical_box {
|
6140
|
+
label('Rectangle Properties') {
|
6141
|
+
stretchy false
|
6142
|
+
}
|
6143
|
+
|
6144
|
+
form {
|
6145
|
+
stretchy false
|
6146
|
+
|
6147
|
+
@x_spinbox = spinbox(0, 1000) {
|
6148
|
+
label 'x'
|
6149
|
+
value <=> [self, :rectangle_x]
|
6150
|
+
}
|
6151
|
+
|
6152
|
+
@y_spinbox = spinbox(0, 1000) {
|
6153
|
+
label 'y'
|
6154
|
+
value <=> [self, :rectangle_y]
|
6155
|
+
}
|
6156
|
+
|
6157
|
+
@width_spinbox = spinbox(0, 1000) {
|
6158
|
+
label 'width'
|
6159
|
+
value <=> [self, :rectangle_width]
|
6160
|
+
}
|
6161
|
+
|
6162
|
+
@height_spinbox = spinbox(0, 1000) {
|
6163
|
+
label 'height'
|
6164
|
+
value <=> [self, :rectangle_height]
|
6165
|
+
}
|
6166
|
+
|
6167
|
+
@red_spinbox = spinbox(0, 255) {
|
6168
|
+
label 'red'
|
6169
|
+
value <=> [self, :rectangle_red]
|
6170
|
+
}
|
6171
|
+
|
6172
|
+
@green_spinbox = spinbox(0, 255) {
|
6173
|
+
label 'green'
|
6174
|
+
value <=> [self, :rectangle_green]
|
6175
|
+
}
|
6176
|
+
|
6177
|
+
@blue_spinbox = spinbox(0, 255) {
|
6178
|
+
label 'blue'
|
6179
|
+
value <=> [self, :rectangle_blue]
|
6180
|
+
}
|
6181
|
+
|
6182
|
+
@alpha_spinbox = spinbox(0, 100) {
|
6183
|
+
label 'alpha'
|
6184
|
+
value <=> [self, :rectangle_alpha]
|
6185
|
+
}
|
6186
|
+
}
|
6187
|
+
|
6188
|
+
area {
|
6189
|
+
@rectangle = rectangle { # stable implicit path shape
|
6190
|
+
x <= [self, :rectangle_x]
|
6191
|
+
y <= [self, :rectangle_y]
|
6192
|
+
width <= [self, :rectangle_width]
|
6193
|
+
height <= [self, :rectangle_height]
|
6194
|
+
fill <= [self, :rectangle_fill, computed_by: [:rectangle_red, :rectangle_green, :rectangle_blue, :rectangle_alpha]]
|
6195
|
+
}
|
6196
|
+
}
|
6197
|
+
}
|
6198
|
+
}.show
|
6199
|
+
end
|
6200
|
+
end
|
6201
|
+
|
6202
|
+
DynamicArea.new.launch
|
6203
|
+
```
|
6204
|
+
|
6205
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (declarative stable `path` approach without [data-binding](#data-binding)):
|
5854
6206
|
|
5855
6207
|
```ruby
|
5856
6208
|
require 'glimmer-dsl-libui'
|
@@ -5942,7 +6294,7 @@ window('Dynamic Area', 240, 600) {
|
|
5942
6294
|
}
|
5943
6295
|
|
5944
6296
|
area {
|
5945
|
-
@rectangle = rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value) { # stable path
|
6297
|
+
@rectangle = rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value) { # stable implicit path shape
|
5946
6298
|
fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
|
5947
6299
|
}
|
5948
6300
|
}
|
@@ -6640,7 +6992,121 @@ UI.main
|
|
6640
6992
|
UI.quit
|
6641
6993
|
```
|
6642
6994
|
|
6643
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6995
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
6996
|
+
|
6997
|
+
```ruby
|
6998
|
+
# https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
|
6999
|
+
|
7000
|
+
require 'glimmer-dsl-libui'
|
7001
|
+
|
7002
|
+
class Histogram
|
7003
|
+
include Glimmer
|
7004
|
+
|
7005
|
+
X_OFF_LEFT = 20
|
7006
|
+
Y_OFF_TOP = 20
|
7007
|
+
X_OFF_RIGHT = 20
|
7008
|
+
Y_OFF_BOTTOM = 20
|
7009
|
+
POINT_RADIUS = 5
|
7010
|
+
COLOR_BLUE = Glimmer::LibUI.interpret_color(0x1E90FF)
|
7011
|
+
|
7012
|
+
attr_accessor :datapoints, :histogram_color
|
7013
|
+
|
7014
|
+
def initialize
|
7015
|
+
@datapoints = 10.times.map {Random.new.rand(90)}
|
7016
|
+
@histogram_color = COLOR_BLUE
|
7017
|
+
end
|
7018
|
+
|
7019
|
+
def graph_size(area_width, area_height)
|
7020
|
+
graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
|
7021
|
+
graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
|
7022
|
+
[graph_width, graph_height]
|
7023
|
+
end
|
7024
|
+
|
7025
|
+
def point_locations(width, height)
|
7026
|
+
xincr = width / 9.0 # 10 - 1 to make the last point be at the end
|
7027
|
+
yincr = height / 100.0
|
7028
|
+
|
7029
|
+
@datapoints.each_with_index.map do |value, i|
|
7030
|
+
val = 100 - value
|
7031
|
+
[xincr * i, yincr * val]
|
7032
|
+
end
|
7033
|
+
end
|
7034
|
+
|
7035
|
+
# method-based custom control representing a graph path
|
7036
|
+
def graph_path(width, height, should_extend, &block)
|
7037
|
+
locations = point_locations(width, height).flatten
|
7038
|
+
path {
|
7039
|
+
if should_extend
|
7040
|
+
polygon(locations + [width, height, 0, height])
|
7041
|
+
else
|
7042
|
+
polyline(locations)
|
7043
|
+
end
|
7044
|
+
|
7045
|
+
# apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
|
7046
|
+
transform {
|
7047
|
+
translate X_OFF_LEFT, Y_OFF_TOP
|
7048
|
+
}
|
7049
|
+
|
7050
|
+
block.call
|
7051
|
+
}
|
7052
|
+
end
|
7053
|
+
|
7054
|
+
def launch
|
7055
|
+
window('histogram example', 640, 480) {
|
7056
|
+
margined true
|
7057
|
+
|
7058
|
+
horizontal_box {
|
7059
|
+
vertical_box {
|
7060
|
+
stretchy false
|
7061
|
+
|
7062
|
+
10.times do |i|
|
7063
|
+
spinbox(0, 100) { |sb|
|
7064
|
+
stretchy false
|
7065
|
+
value <=> [self, "datapoints[#{i}]", after_write: -> { @area.queue_redraw_all }]
|
7066
|
+
}
|
7067
|
+
end
|
7068
|
+
|
7069
|
+
color_button { |cb|
|
7070
|
+
stretchy false
|
7071
|
+
color <=> [self, :histogram_color, after_write: -> { @area.queue_redraw_all }]
|
7072
|
+
}
|
7073
|
+
}
|
7074
|
+
|
7075
|
+
@area = area {
|
7076
|
+
on_draw do |area_draw_params|
|
7077
|
+
rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height]) {
|
7078
|
+
fill 0xFFFFFF
|
7079
|
+
}
|
7080
|
+
|
7081
|
+
graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
|
7082
|
+
|
7083
|
+
figure(X_OFF_LEFT, Y_OFF_TOP) {
|
7084
|
+
line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
|
7085
|
+
line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
|
7086
|
+
|
7087
|
+
stroke 0x000000, thickness: 2, miter_limit: 10
|
7088
|
+
}
|
7089
|
+
|
7090
|
+
# now create the fill for the graph below the graph line
|
7091
|
+
graph_path(graph_width, graph_height, true) {
|
7092
|
+
fill @histogram_color.merge(a: 0.5)
|
7093
|
+
}
|
7094
|
+
|
7095
|
+
# now draw the histogram line
|
7096
|
+
graph_path(graph_width, graph_height, false) {
|
7097
|
+
stroke @histogram_color.merge(thickness: 2, miter_limit: 10)
|
7098
|
+
}
|
7099
|
+
end
|
7100
|
+
}
|
7101
|
+
}
|
7102
|
+
}.show
|
7103
|
+
end
|
7104
|
+
end
|
7105
|
+
|
7106
|
+
Histogram.new.launch
|
7107
|
+
```
|
7108
|
+
|
7109
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
6644
7110
|
|
6645
7111
|
```ruby
|
6646
7112
|
# https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
|
@@ -6654,9 +7120,10 @@ Y_OFF_TOP = 20
|
|
6654
7120
|
X_OFF_RIGHT = 20
|
6655
7121
|
Y_OFF_BOTTOM = 20
|
6656
7122
|
POINT_RADIUS = 5
|
6657
|
-
COLOR_BLUE = 0x1E90FF
|
7123
|
+
COLOR_BLUE = Glimmer::LibUI.interpret_color(0x1E90FF)
|
6658
7124
|
|
6659
7125
|
@datapoints = 10.times.map {Random.new.rand(90)}
|
7126
|
+
@color = COLOR_BLUE
|
6660
7127
|
|
6661
7128
|
def graph_size(area_width, area_height)
|
6662
7129
|
graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
|
@@ -6712,11 +7179,12 @@ window('histogram example', 640, 480) {
|
|
6712
7179
|
}
|
6713
7180
|
end
|
6714
7181
|
|
6715
|
-
|
7182
|
+
color_button { |cb|
|
6716
7183
|
stretchy false
|
6717
7184
|
color COLOR_BLUE
|
6718
7185
|
|
6719
7186
|
on_changed do
|
7187
|
+
@color = cb.color
|
6720
7188
|
@area.queue_redraw_all
|
6721
7189
|
end
|
6722
7190
|
}
|
@@ -6724,31 +7192,27 @@ window('histogram example', 640, 480) {
|
|
6724
7192
|
|
6725
7193
|
@area = area {
|
6726
7194
|
on_draw do |area_draw_params|
|
6727
|
-
|
6728
|
-
rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height])
|
6729
|
-
|
7195
|
+
rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height]) {
|
6730
7196
|
fill 0xFFFFFF
|
6731
7197
|
}
|
6732
7198
|
|
6733
7199
|
graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
|
6734
7200
|
|
6735
|
-
|
6736
|
-
|
6737
|
-
|
6738
|
-
line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
|
6739
|
-
}
|
7201
|
+
figure(X_OFF_LEFT, Y_OFF_TOP) {
|
7202
|
+
line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
|
7203
|
+
line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
|
6740
7204
|
|
6741
7205
|
stroke 0x000000, thickness: 2, miter_limit: 10
|
6742
7206
|
}
|
6743
7207
|
|
6744
7208
|
# now create the fill for the graph below the graph line
|
6745
7209
|
graph_path(graph_width, graph_height, true) {
|
6746
|
-
fill @
|
7210
|
+
fill @color.merge(a: 0.5)
|
6747
7211
|
}
|
6748
7212
|
|
6749
7213
|
# now draw the histogram line
|
6750
7214
|
graph_path(graph_width, graph_height, false) {
|
6751
|
-
stroke @
|
7215
|
+
stroke @color.merge(thickness: 2, miter_limit: 10)
|
6752
7216
|
}
|
6753
7217
|
end
|
6754
7218
|
}
|
@@ -6892,7 +7356,7 @@ end
|
|
6892
7356
|
Login.new.launch
|
6893
7357
|
```
|
6894
7358
|
|
6895
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
7359
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (with [data-binding](#data-binding)):
|
6896
7360
|
|
6897
7361
|
```ruby
|
6898
7362
|
require 'glimmer-dsl-libui'
|
@@ -6962,7 +7426,7 @@ end
|
|
6962
7426
|
Login.new.launch
|
6963
7427
|
```
|
6964
7428
|
|
6965
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
7429
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (with [data-binding](#data-binding)):
|
6966
7430
|
|
6967
7431
|
```ruby
|
6968
7432
|
require 'glimmer-dsl-libui'
|
@@ -7426,7 +7890,181 @@ end
|
|
7426
7890
|
TinyMidiPlayer.new
|
7427
7891
|
```
|
7428
7892
|
|
7429
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
7893
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
7894
|
+
|
7895
|
+
```ruby
|
7896
|
+
# frozen_string_literal: true
|
7897
|
+
|
7898
|
+
require 'glimmer-dsl-libui'
|
7899
|
+
|
7900
|
+
class TinyMidiPlayer
|
7901
|
+
include Glimmer
|
7902
|
+
|
7903
|
+
VERSION = '0.0.1'
|
7904
|
+
|
7905
|
+
attr_accessor :selected_file
|
7906
|
+
|
7907
|
+
def initialize
|
7908
|
+
@pid = nil
|
7909
|
+
@music_directory = File.expand_path('../sounds', __dir__)
|
7910
|
+
@midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
|
7911
|
+
.sort_by { |path| File.basename(path) }
|
7912
|
+
at_exit { stop_midi }
|
7913
|
+
create_gui
|
7914
|
+
end
|
7915
|
+
|
7916
|
+
def stop_midi
|
7917
|
+
if @pid
|
7918
|
+
Process.kill(:SIGKILL, @pid) if @th.alive?
|
7919
|
+
@pid = nil
|
7920
|
+
end
|
7921
|
+
end
|
7922
|
+
|
7923
|
+
def play_midi
|
7924
|
+
stop_midi
|
7925
|
+
if @pid.nil? && @selected_file
|
7926
|
+
begin
|
7927
|
+
@pid = spawn "timidity #{@selected_file}"
|
7928
|
+
@th = Process.detach @pid
|
7929
|
+
rescue Errno::ENOENT
|
7930
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
7931
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
7932
|
+
end
|
7933
|
+
end
|
7934
|
+
end
|
7935
|
+
|
7936
|
+
def show_version
|
7937
|
+
msg_box('Tiny Midi Player',
|
7938
|
+
"Written in Ruby\n" \
|
7939
|
+
"https://github.com/kojix2/libui\n" \
|
7940
|
+
"Version #{VERSION}")
|
7941
|
+
end
|
7942
|
+
|
7943
|
+
def create_gui
|
7944
|
+
menu('Help') {
|
7945
|
+
menu_item('Version') {
|
7946
|
+
on_clicked do
|
7947
|
+
show_version
|
7948
|
+
end
|
7949
|
+
}
|
7950
|
+
}
|
7951
|
+
window('Tiny Midi Player', 200, 50) {
|
7952
|
+
horizontal_box {
|
7953
|
+
vertical_box {
|
7954
|
+
stretchy false
|
7955
|
+
|
7956
|
+
button('▶') {
|
7957
|
+
on_clicked do
|
7958
|
+
play_midi
|
7959
|
+
end
|
7960
|
+
}
|
7961
|
+
button('■') {
|
7962
|
+
on_clicked do
|
7963
|
+
stop_midi
|
7964
|
+
end
|
7965
|
+
}
|
7966
|
+
}
|
7967
|
+
|
7968
|
+
combobox { |c|
|
7969
|
+
items @midi_files.map { |path| File.basename(path) }
|
7970
|
+
# data-bind selected item (String) to self.selected_file with on-read/on-write converters and after_write operation
|
7971
|
+
selected_item <=> [self, :selected_file, on_read: ->(f) {File.basename(f.to_s)}, on_write: ->(f) {File.join(@music_directory, f)}, after_write: -> { play_midi if @th&.alive? }]
|
7972
|
+
}
|
7973
|
+
}
|
7974
|
+
}.show
|
7975
|
+
end
|
7976
|
+
end
|
7977
|
+
|
7978
|
+
TinyMidiPlayer.new
|
7979
|
+
```
|
7980
|
+
|
7981
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with [data-binding](#data-binding)):
|
7982
|
+
|
7983
|
+
```ruby
|
7984
|
+
require 'glimmer-dsl-libui'
|
7985
|
+
|
7986
|
+
class TinyMidiPlayer
|
7987
|
+
include Glimmer
|
7988
|
+
|
7989
|
+
VERSION = '0.0.1'
|
7990
|
+
|
7991
|
+
attr_accessor :selected_file
|
7992
|
+
|
7993
|
+
def initialize
|
7994
|
+
@pid = nil
|
7995
|
+
@music_directory = File.expand_path('../sounds', __dir__)
|
7996
|
+
@midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
|
7997
|
+
.sort_by { |path| File.basename(path) }
|
7998
|
+
at_exit { stop_midi }
|
7999
|
+
create_gui
|
8000
|
+
end
|
8001
|
+
|
8002
|
+
def stop_midi
|
8003
|
+
if @pid
|
8004
|
+
Process.kill(:SIGKILL, @pid) if @th.alive?
|
8005
|
+
@pid = nil
|
8006
|
+
end
|
8007
|
+
end
|
8008
|
+
|
8009
|
+
def play_midi
|
8010
|
+
stop_midi
|
8011
|
+
if @pid.nil? && @selected_file
|
8012
|
+
begin
|
8013
|
+
@pid = spawn "timidity #{@selected_file}"
|
8014
|
+
@th = Process.detach @pid
|
8015
|
+
rescue Errno::ENOENT
|
8016
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
8017
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
8018
|
+
end
|
8019
|
+
end
|
8020
|
+
end
|
8021
|
+
|
8022
|
+
def show_version
|
8023
|
+
msg_box('Tiny Midi Player',
|
8024
|
+
"Written in Ruby\n" \
|
8025
|
+
"https://github.com/kojix2/libui\n" \
|
8026
|
+
"Version #{VERSION}")
|
8027
|
+
end
|
8028
|
+
|
8029
|
+
def create_gui
|
8030
|
+
menu('Help') {
|
8031
|
+
menu_item('Version') {
|
8032
|
+
on_clicked do
|
8033
|
+
show_version
|
8034
|
+
end
|
8035
|
+
}
|
8036
|
+
}
|
8037
|
+
window('Tiny Midi Player', 200, 50) {
|
8038
|
+
horizontal_box {
|
8039
|
+
vertical_box {
|
8040
|
+
stretchy false
|
8041
|
+
|
8042
|
+
button('▶') {
|
8043
|
+
on_clicked do
|
8044
|
+
play_midi
|
8045
|
+
end
|
8046
|
+
}
|
8047
|
+
button('■') {
|
8048
|
+
on_clicked do
|
8049
|
+
stop_midi
|
8050
|
+
end
|
8051
|
+
}
|
8052
|
+
}
|
8053
|
+
|
8054
|
+
combobox { |c|
|
8055
|
+
items @midi_files.map { |path| File.basename(path) }
|
8056
|
+
# data-bind selected index (Integer) to self.selected_file with on-read/on-write converters and after_write operation
|
8057
|
+
selected <=> [self, :selected_file, on_read: ->(f) {@midi_files.index(f)}, on_write: ->(i) {@midi_files[i]}, after_write: -> { play_midi if @th&.alive? }]
|
8058
|
+
}
|
8059
|
+
}
|
8060
|
+
}.show
|
8061
|
+
end
|
8062
|
+
end
|
8063
|
+
|
8064
|
+
TinyMidiPlayer.new
|
8065
|
+
```
|
8066
|
+
|
8067
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (without [data-binding](#data-binding)):
|
7430
8068
|
|
7431
8069
|
```ruby
|
7432
8070
|
require 'glimmer-dsl-libui'
|
@@ -8137,7 +8775,140 @@ Mac | Windows | Linux
|
|
8137
8775
|
----|---------|------
|
8138
8776
|
![glimmer-dsl-libui-mac-timer.png](images/glimmer-dsl-libui-mac-timer.png) ![glimmer-dsl-libui-mac-timer-in-progress.png](images/glimmer-dsl-libui-mac-timer-in-progress.png) | ![glimmer-dsl-libui-windows-timer.png](images/glimmer-dsl-libui-windows-timer.png) ![glimmer-dsl-libui-windows-timer-in-progress.png](images/glimmer-dsl-libui-windows-timer-in-progress.png) | ![glimmer-dsl-libui-linux-timer.png](images/glimmer-dsl-libui-linux-timer.png) ![glimmer-dsl-libui-linux-timer-in-progress.png](images/glimmer-dsl-libui-linux-timer-in-progress.png)
|
8139
8777
|
|
8140
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
8778
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
8779
|
+
|
8780
|
+
```ruby
|
8781
|
+
require 'glimmer-dsl-libui'
|
8782
|
+
|
8783
|
+
class Timer
|
8784
|
+
include Glimmer
|
8785
|
+
|
8786
|
+
SECOND_MAX = 59
|
8787
|
+
MINUTE_MAX = 59
|
8788
|
+
HOUR_MAX = 23
|
8789
|
+
|
8790
|
+
attr_accessor :hour, :min, :sec, :started, :played
|
8791
|
+
|
8792
|
+
def initialize
|
8793
|
+
@pid = nil
|
8794
|
+
@alarm_file = File.expand_path('../sounds/AlanWalker-Faded.mid', __dir__)
|
8795
|
+
@hour = @min = @sec = 0
|
8796
|
+
at_exit { stop_alarm }
|
8797
|
+
setup_timer
|
8798
|
+
create_gui
|
8799
|
+
end
|
8800
|
+
|
8801
|
+
def stop_alarm
|
8802
|
+
if @pid
|
8803
|
+
Process.kill(:SIGKILL, @pid) if @th.alive?
|
8804
|
+
@pid = nil
|
8805
|
+
end
|
8806
|
+
end
|
8807
|
+
|
8808
|
+
def play_alarm
|
8809
|
+
stop_alarm
|
8810
|
+
if @pid.nil?
|
8811
|
+
begin
|
8812
|
+
@pid = spawn "timidity -G 0.0-10.0 #{@alarm_file}"
|
8813
|
+
@th = Process.detach @pid
|
8814
|
+
rescue Errno::ENOENT
|
8815
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
8816
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
8817
|
+
end
|
8818
|
+
end
|
8819
|
+
end
|
8820
|
+
|
8821
|
+
def setup_timer
|
8822
|
+
unless @setup_timer
|
8823
|
+
Glimmer::LibUI.timer(1) do
|
8824
|
+
if @started
|
8825
|
+
seconds = @sec
|
8826
|
+
minutes = @min
|
8827
|
+
hours = @hour
|
8828
|
+
if seconds > 0
|
8829
|
+
self.sec = seconds -= 1
|
8830
|
+
end
|
8831
|
+
if seconds == 0
|
8832
|
+
if minutes > 0
|
8833
|
+
self.min = minutes -= 1
|
8834
|
+
self.sec = seconds = SECOND_MAX
|
8835
|
+
end
|
8836
|
+
if minutes == 0
|
8837
|
+
if hours > 0
|
8838
|
+
self.hour = hours -= 1
|
8839
|
+
self.min = minutes = MINUTE_MAX
|
8840
|
+
self.sec = seconds = SECOND_MAX
|
8841
|
+
end
|
8842
|
+
if hours == 0 && minutes == 0 && seconds == 0
|
8843
|
+
self.started = false
|
8844
|
+
unless @played
|
8845
|
+
play_alarm
|
8846
|
+
msg_box('Alarm', 'Countdown Is Finished!')
|
8847
|
+
self.played = true
|
8848
|
+
end
|
8849
|
+
end
|
8850
|
+
end
|
8851
|
+
end
|
8852
|
+
end
|
8853
|
+
end
|
8854
|
+
@setup_timer = true
|
8855
|
+
end
|
8856
|
+
end
|
8857
|
+
|
8858
|
+
def create_gui
|
8859
|
+
window('Timer') {
|
8860
|
+
margined true
|
8861
|
+
|
8862
|
+
group('Countdown') {
|
8863
|
+
vertical_box {
|
8864
|
+
horizontal_box {
|
8865
|
+
spinbox(0, HOUR_MAX) {
|
8866
|
+
stretchy false
|
8867
|
+
value <=> [self, :hour]
|
8868
|
+
}
|
8869
|
+
label(':') {
|
8870
|
+
stretchy false
|
8871
|
+
}
|
8872
|
+
spinbox(0, MINUTE_MAX) {
|
8873
|
+
stretchy false
|
8874
|
+
value <=> [self, :min]
|
8875
|
+
}
|
8876
|
+
label(':') {
|
8877
|
+
stretchy false
|
8878
|
+
}
|
8879
|
+
spinbox(0, SECOND_MAX) {
|
8880
|
+
stretchy false
|
8881
|
+
value <=> [self, :sec]
|
8882
|
+
}
|
8883
|
+
}
|
8884
|
+
horizontal_box {
|
8885
|
+
button('Start') {
|
8886
|
+
enabled <= [self, :started, on_read: :!]
|
8887
|
+
|
8888
|
+
on_clicked do
|
8889
|
+
self.started = true
|
8890
|
+
self.played = false
|
8891
|
+
end
|
8892
|
+
}
|
8893
|
+
|
8894
|
+
button('Stop') {
|
8895
|
+
enabled <= [self, :started]
|
8896
|
+
|
8897
|
+
on_clicked do
|
8898
|
+
self.started = false
|
8899
|
+
end
|
8900
|
+
}
|
8901
|
+
}
|
8902
|
+
}
|
8903
|
+
}
|
8904
|
+
}.show
|
8905
|
+
end
|
8906
|
+
end
|
8907
|
+
|
8908
|
+
Timer.new
|
8909
|
+
```
|
8910
|
+
|
8911
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
8141
8912
|
|
8142
8913
|
```ruby
|
8143
8914
|
require 'glimmer-dsl-libui'
|
@@ -8310,7 +9081,7 @@ https://github.com/iraamaro/i3off-gtk-ruby
|
|
8310
9081
|
|
8311
9082
|
### Issues
|
8312
9083
|
|
8313
|
-
If you encounter [issues](https://github.com/AndyObtiva/glimmer-dsl-libui/issues) that are not reported, discover missing features that are not mentioned in [TODO.md](TODO.md), or think up better ways to use [libui](https://github.com/andlabs/libui) than what is possible with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), you may submit an [issue](https://github.com/AndyObtiva/glimmer-dsl-libui/issues/new) or [pull request](https://github.com/AndyObtiva/glimmer-dsl-libui/compare) on [GitHub](https://github.com).
|
9084
|
+
If you encounter [issues](https://github.com/AndyObtiva/glimmer-dsl-libui/issues) that are not reported, discover missing features that are not mentioned in [TODO.md](TODO.md), or think up better ways to use [libui](https://github.com/andlabs/libui) than what is possible with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), you may submit an [issue](https://github.com/AndyObtiva/glimmer-dsl-libui/issues/new) or [pull request](https://github.com/AndyObtiva/glimmer-dsl-libui/compare) on [GitHub](https://github.com). In the meantime, you may try older gem versions of [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) till you find one that works until issues are resolved.
|
8314
9085
|
|
8315
9086
|
### Chat
|
8316
9087
|
|
@@ -8342,6 +9113,8 @@ These features have been planned or suggested. You might see them in a future ve
|
|
8342
9113
|
is fine, but please isolate to its own commit so I can cherry-pick
|
8343
9114
|
around it.
|
8344
9115
|
|
9116
|
+
Note that the latest development sometimes takes place in [development](https://github.com/AndyObtiva/glimmer-dsl-libui/tree/development) branch (which is deleted once merged back to [master](https://github.com/AndyObtiva/glimmer-dsl-libui)).
|
9117
|
+
|
8345
9118
|
## Contributors
|
8346
9119
|
|
8347
9120
|
* [Andy Maleh](https://github.com/AndyObtiva) (Founder)
|