glimmer-dsl-libui 0.4.11 → 0.4.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +473 -57
- data/VERSION +1 -1
- data/examples/basic_image.rb +5 -3
- data/examples/basic_image2.rb +1 -3
- data/examples/basic_image3.rb +3 -3
- data/examples/basic_image4.rb +0 -3
- data/examples/basic_image5.rb +0 -2
- data/examples/basic_table_color.rb +104 -26
- data/examples/basic_table_color2.rb +2 -14
- data/examples/basic_table_color3.rb +37 -0
- data/examples/basic_table_image.rb +1 -1
- data/examples/basic_table_image2.rb +2 -14
- data/examples/basic_table_image3.rb +44 -0
- data/examples/basic_table_image_text.rb +1 -2
- data/examples/basic_table_image_text2.rb +2 -13
- data/examples/basic_table_image_text3.rb +44 -0
- data/examples/cpu_percentage.rb +1 -1
- data/examples/editable_column_table.rb +5 -0
- data/examples/form_table.rb +10 -4
- data/examples/form_table2.rb +12 -6
- data/examples/form_table3.rb +9 -3
- data/examples/form_table4.rb +9 -3
- data/examples/form_table5.rb +9 -3
- data/examples/meta_example.rb +3 -1
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/attributed_string.rb +17 -8
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +17 -17
- data/lib/glimmer/libui/control_proxy/box.rb +1 -0
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +1 -29
- data/lib/glimmer/libui/control_proxy/form_proxy.rb +1 -0
- data/lib/glimmer/libui/control_proxy/image_proxy.rb +92 -10
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +18 -8
- data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +11 -2
- data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +2 -0
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +2 -0
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +14 -12
- data/lib/glimmer/libui/control_proxy/text_proxy.rb +2 -0
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +34 -35
- data/lib/glimmer/libui/control_proxy.rb +45 -9
- data/lib/glimmer/libui/shape.rb +1 -0
- data/lib/glimmer/libui.rb +2 -2
- metadata +5 -2
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.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.15
|
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)
|
@@ -100,7 +100,7 @@ class FormTable
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def launch
|
103
|
-
window('Contacts', 600, 600) {
|
103
|
+
window('Contacts', 600, 600) {
|
104
104
|
margined true
|
105
105
|
|
106
106
|
vertical_box {
|
@@ -138,8 +138,8 @@ class FormTable
|
|
138
138
|
|
139
139
|
on_clicked do
|
140
140
|
new_row = [name, email, phone, city, state]
|
141
|
-
if new_row.include?('')
|
142
|
-
msg_box_error(
|
141
|
+
if new_row.map(&:to_s).include?('')
|
142
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
143
143
|
else
|
144
144
|
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
|
145
145
|
@unfiltered_contacts = @contacts.dup
|
@@ -180,10 +180,16 @@ class FormTable
|
|
180
180
|
text_column('State')
|
181
181
|
|
182
182
|
editable true
|
183
|
-
cell_rows <=> [self, :contacts] # explicit data-binding to
|
183
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to self.contacts Modal Array, auto-inferring model attribute names from underscored table column names by convention
|
184
184
|
|
185
185
|
on_changed do |row, type, row_data|
|
186
186
|
puts "Row #{row} #{type}: #{row_data}"
|
187
|
+
$stdout.flush # for Windows
|
188
|
+
end
|
189
|
+
|
190
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
191
|
+
puts "Row #{row} edited: #{row_data}"
|
192
|
+
$stdout.flush # for Windows
|
187
193
|
end
|
188
194
|
}
|
189
195
|
}
|
@@ -356,6 +362,11 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
356
362
|
- [Custom Keywords](#custom-keywords)
|
357
363
|
- [Observer Pattern](#observer-pattern)
|
358
364
|
- [Data-Binding](#data-binding)
|
365
|
+
- [Bidirectional (Two-Way) Data-Binding](#bidirectional-two-way-data-binding)
|
366
|
+
- [Table Data-Binding](#table-data-binding)
|
367
|
+
- [Unidirectional (One-Way) Data-Binding](#unidirectional-one-way-data-binding)
|
368
|
+
- [Data-Binding API](#data-binding-api)
|
369
|
+
- [Data-Binding Gotchas](#data-binding-gotchas)
|
359
370
|
- [API Gotchas](#api-gotchas)
|
360
371
|
- [Original API](#original-api)
|
361
372
|
- [Packaging](#packaging)
|
@@ -495,7 +506,7 @@ gem install glimmer-dsl-libui
|
|
495
506
|
Or install via Bundler `Gemfile`:
|
496
507
|
|
497
508
|
```ruby
|
498
|
-
gem 'glimmer-dsl-libui', '~> 0.4.
|
509
|
+
gem 'glimmer-dsl-libui', '~> 0.4.15'
|
499
510
|
```
|
500
511
|
|
501
512
|
Test that installation worked by running the [Meta-Example](#examples):
|
@@ -764,7 +775,7 @@ data = [
|
|
764
775
|
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
765
776
|
]
|
766
777
|
|
767
|
-
window('Contacts', 600, 600) {
|
778
|
+
window('Contacts', 600, 600) {
|
768
779
|
margined true
|
769
780
|
|
770
781
|
vertical_box {
|
@@ -797,8 +808,8 @@ window('Contacts', 600, 600) { |w|
|
|
797
808
|
|
798
809
|
on_clicked do
|
799
810
|
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
800
|
-
if new_row.include?('')
|
801
|
-
msg_box_error(
|
811
|
+
if new_row.map(&:to_s).include?('')
|
812
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
802
813
|
else
|
803
814
|
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
804
815
|
@unfiltered_data = data.dup
|
@@ -842,13 +853,21 @@ window('Contacts', 600, 600) { |w|
|
|
842
853
|
|
843
854
|
on_changed do |row, type, row_data|
|
844
855
|
puts "Row #{row} #{type}: #{row_data}"
|
856
|
+
$stdout.flush # for Windows
|
857
|
+
end
|
858
|
+
|
859
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
860
|
+
puts "Row #{row} edited: #{row_data}"
|
861
|
+
$stdout.flush # for Windows
|
845
862
|
end
|
846
863
|
}
|
847
864
|
}
|
848
865
|
}.show
|
849
866
|
```
|
850
867
|
|
851
|
-
|
868
|
+
Mac | Windows | Linux
|
869
|
+
----|---------|------
|
870
|
+
![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png) | ![glimmer-dsl-libui-windows-form-table.png](images/glimmer-dsl-libui-windows-form-table.png) | ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
|
852
871
|
|
853
872
|
Learn more by checking out [examples](#examples).
|
854
873
|
|
@@ -926,9 +945,15 @@ Check [examples/basic_scrolling_area.rb](#basic-scrolling-area) for a more detai
|
|
926
945
|
|
927
946
|
#### Area Path Shapes
|
928
947
|
|
948
|
+
`area` can have geometric shapes drawn by adding `path` elements.
|
949
|
+
|
950
|
+
To add `path` shapes under an `area`, you can do so:
|
951
|
+
- Explicitly: by adding `path` under `area` and nesting shapes (e.g. `rectangle`) underneath that share the same `fill`/`stroke`/`transform` properties
|
952
|
+
- Implicitly: by adding shapes directly under `area` when the shapes have unique `fill`/`stroke`/`transform` properties ([Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) automatically constructs `path`s as intermediary parents for shapes directly added under `area`)
|
953
|
+
|
929
954
|
`path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
|
930
955
|
|
931
|
-
Available nested `path`
|
956
|
+
Available `path` shapes (that can be nested explicitly under `path` or implicitly under `area` directly):
|
932
957
|
- `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)`
|
933
958
|
- `square(x as Numeric, y as Numeric, length as Numeric)`
|
934
959
|
- `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
|
@@ -1014,7 +1039,8 @@ Given that it is very new and is not a [libui](https://github.com/andlabs/libui)
|
|
1014
1039
|
- It only supports the `.png` file format.
|
1015
1040
|
- [libui](https://github.com/andlabs/libui) pixel-by-pixel rendering performance is slow.
|
1016
1041
|
- Including an `image` inside an `area` `on_draw` listener improves performance due to not retaining pixel/line data in memory.
|
1017
|
-
- Supplying `width` and `height`
|
1042
|
+
- Supplying `width` and `height` options greatly improves performance when shrinking image (e.g. `image('somefile.png', width: 24, height: 24)`). You can also supply one of the two dimensions, and the other one gets calculated automatically while preserving original aspect ratio (e.g. `image('somefile.png', height: 24)`)
|
1043
|
+
- [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) lets you optionally specify `x` and `y` in addition to `file`, `width` and `height` (5 arguments total) to offset image location.
|
1018
1044
|
|
1019
1045
|
Currently, it is recommended to use `image` with very small `width` and `height` values only (e.g. 24x24).
|
1020
1046
|
|
@@ -1033,7 +1059,11 @@ include Glimmer
|
|
1033
1059
|
|
1034
1060
|
window('Basic Image', 96, 96) {
|
1035
1061
|
area {
|
1036
|
-
image(File.expand_path('icons/glimmer.png', __dir__),
|
1062
|
+
image(File.expand_path('icons/glimmer.png', __dir__), height: 96) # width is automatically calculated from height while preserving original aspect ratio
|
1063
|
+
# image(File.expand_path('icons/glimmer.png', __dir__), width: 96, height: 96) # you can specify both width and height options
|
1064
|
+
# image(File.expand_path('icons/glimmer.png', __dir__), 96, 96) # you can specify width, height as args
|
1065
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), 0, 0, 96, 96) # you can specify x, y, width, height args as alternative
|
1066
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), x: 0, y: 0, width: 96, height: 96) # you can specify x, y, width, height options as alternative
|
1037
1067
|
}
|
1038
1068
|
}.show
|
1039
1069
|
```
|
@@ -1065,6 +1095,8 @@ window('Basic Image', 96, 96) {
|
|
1065
1095
|
area {
|
1066
1096
|
image {
|
1067
1097
|
file File.expand_path('icons/glimmer.png', __dir__)
|
1098
|
+
# x 0 # default
|
1099
|
+
# y 0 # default
|
1068
1100
|
width 96
|
1069
1101
|
height 96
|
1070
1102
|
}
|
@@ -1320,13 +1352,16 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
1320
1352
|
- `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
|
1321
1353
|
- `group` controls have `margined` as `true` upon instantiation to ensure more user-friendly GUI by default
|
1322
1354
|
- All controls nested under a `horizontal_box`, `vertical_box`, and `form` have `stretchy` property (fill maximum space) as `true` by default (passed to `box_append`/`form_append` method)
|
1355
|
+
- If an event listener is repeated under a control (e.g. two `on_clicked {}` listeners under `button`), it does not overwrite the previous listener, yet it is added to an `Array` of listeners for the event. [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) provides multiple-event-listener support unlike [LibUI](https://github.com/kojix2/LibUI)
|
1323
1356
|
- `window` instatiation args can be left off, having the following defaults when unspecified: `title` as `''`, `width` as `190`, `height` as `150`, and `has_menubar` as `true`)
|
1324
1357
|
- `window` has an `on_closing` listener by default that quits application upon hitting the close button (can be overridden with a manual `on_closing` implementation that returns integer `0` for success)
|
1325
1358
|
- `group` has `title` property default to `''` if not specified in instantiation args, so it can be instantiated without args with `title` property specified in nested block (e.g. `group {title 'Address'; ...}`)
|
1326
1359
|
- `button`, `checkbox`, and `label` have `text` default to `''` if not specified in instantiation args, so they can be instantiated without args with `text` property specified in nested block (e.g. `button {text 'Greet'; on_clicked {puts 'Hello'}}`)
|
1327
1360
|
- `quit_menu_item` has an `on_clicked` listener by default that quits application upon selecting the quit menu item (can be overridden with a manual `on_clicked` implementation that returns integer `0` for success)
|
1328
1361
|
- If an `on_closing` listener was defined on `window` and it does not return an integer, default exit behavior is assumed (`window.destroy` is called followed by `LibUI.quit`, returning `0`).
|
1329
|
-
- If
|
1362
|
+
- If multiple `on_closing` listeners were added for `window`, and none return an integer, they are all executed. On the other hand, if one of them returns an integer, it is counted as the final return value and stops the chain of listener execution.
|
1363
|
+
- If an `on_clicked` listener was defined on `quit_menu_item` and it does not return an integer, default exit behavior is assumed (`quit_menu_item.destroy` and `main_window.destroy` are called followed by `LibUI.quit`, returning `0`).
|
1364
|
+
- If multiple `on_clicked` listeners were added for `quit_menu_item`, and none return an integer, they are all executed. On the other hand, if one of them returns an integer, it is counted as the final return value and stops the chain of listener execution.
|
1330
1365
|
- All boolean property readers return `true` or `false` in Ruby instead of the [libui](https://github.com/andlabs/libui) original `0` or `1` in C.
|
1331
1366
|
- All boolean property writers accept `true`/`false` in addition to `1`/`0` in Ruby
|
1332
1367
|
- All string property readers return a `String` object in Ruby instead of the [libui](https://github.com/andlabs/libui) Fiddle pointer object.
|
@@ -1347,7 +1382,8 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
1347
1382
|
- Automatically provide shifted `:key` characters in `area_key_event` provided in `area` key listeners `on_key_event`, `on_key_down`, and `on_key_up`
|
1348
1383
|
- `scrolling_area` `width` and `height` default to main window width and height if not specified.
|
1349
1384
|
- `scrolling_area` `#scroll_to` 3rd and 4th arguments (`width` and `height`) default to main window width and height if not specified.
|
1350
|
-
- `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
|
1385
|
+
- `area` paths are specified declaratively with shapes/figures underneath (e.g. `rectangle`), and `area` draw listener is automatically generated
|
1386
|
+
- `area` path shapes can be added directly under `area` without declaring `path` explicitly as a convenient shorthand
|
1351
1387
|
- Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
|
1352
1388
|
- Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
|
1353
1389
|
- Observe `text` and `string` properties for changes and automatically redraw containing area accordingly
|
@@ -1502,6 +1538,8 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
|
|
1502
1538
|
|
1503
1539
|
![MVP](https://www.researchgate.net/profile/Gilles-Perrouin/publication/320249584/figure/fig8/AS:668260987068418@1536337243385/Model-view-presenter-architecture.png)
|
1504
1540
|
|
1541
|
+
#### Bidirectional (Two-Way) Data-Binding
|
1542
|
+
|
1505
1543
|
[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):
|
1506
1544
|
- `checkbox`: `checked`
|
1507
1545
|
- `check_menu_item`: `checked`
|
@@ -1542,6 +1580,162 @@ entry {
|
|
1542
1580
|
|
1543
1581
|
That is data-binding `entered_text` attribute on `self` to `entry` `text` property and printing text after write to the model.
|
1544
1582
|
|
1583
|
+
##### Table Data-Binding
|
1584
|
+
|
1585
|
+
One note about `table` `cell_rows` data-binding is that it works with either:
|
1586
|
+
- Raw data `Array` (rows) of `Array`s (column cells)
|
1587
|
+
- Model `Array` (rows) of objects having attributes (column cells) matching the underscored names of `table` columns by convention. Model attribute names can be overridden when needed by passing an `Array` enumerating all mapped model attributes in the order of `table` columns or alternatively a `Hash` mapping only the column names that have model attribute names different from their table column underscored version.
|
1588
|
+
|
1589
|
+
Example of `table` implicit data-binding of `cell_rows` to raw data `Array` of `Array`s (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1590
|
+
|
1591
|
+
```ruby
|
1592
|
+
require 'glimmer-dsl-libui'
|
1593
|
+
|
1594
|
+
include Glimmer
|
1595
|
+
|
1596
|
+
data = [
|
1597
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
1598
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
1599
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
1600
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
1601
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
1602
|
+
]
|
1603
|
+
|
1604
|
+
window('Contacts', 600, 600) {
|
1605
|
+
table {
|
1606
|
+
text_column('Name')
|
1607
|
+
text_column('Email')
|
1608
|
+
text_column('Phone')
|
1609
|
+
text_column('City')
|
1610
|
+
text_column('State')
|
1611
|
+
|
1612
|
+
cell_rows data
|
1613
|
+
}
|
1614
|
+
}.show
|
1615
|
+
```
|
1616
|
+
|
1617
|
+
Example of `table` explicit data-binding of `cell_rows` to Model `Array` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1618
|
+
|
1619
|
+
```ruby
|
1620
|
+
require 'glimmer-dsl-libui'
|
1621
|
+
|
1622
|
+
class SomeTable
|
1623
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1624
|
+
|
1625
|
+
include Glimmer
|
1626
|
+
|
1627
|
+
attr_accessor :contacts
|
1628
|
+
|
1629
|
+
def initialize
|
1630
|
+
@contacts = [
|
1631
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1632
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1633
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1634
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1635
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1636
|
+
]
|
1637
|
+
end
|
1638
|
+
|
1639
|
+
def launch
|
1640
|
+
window('Contacts', 600, 200) {
|
1641
|
+
table {
|
1642
|
+
text_column('Name')
|
1643
|
+
text_column('Email')
|
1644
|
+
text_column('Phone')
|
1645
|
+
text_column('City')
|
1646
|
+
text_column('State')
|
1647
|
+
|
1648
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to self.contacts Model Array, auto-inferring model attribute names from underscored table column names by convention
|
1649
|
+
}
|
1650
|
+
}.show
|
1651
|
+
end
|
1652
|
+
end
|
1653
|
+
|
1654
|
+
SomeTable.new.launch
|
1655
|
+
```
|
1656
|
+
|
1657
|
+
Example of `table` explicit data-binding of `cell_rows` to Model `Array` with `column_attributes` `Hash` mapping for custom column names (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1658
|
+
|
1659
|
+
```ruby
|
1660
|
+
require 'glimmer-dsl-libui'
|
1661
|
+
|
1662
|
+
class SomeTable
|
1663
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1664
|
+
|
1665
|
+
include Glimmer
|
1666
|
+
|
1667
|
+
attr_accessor :contacts
|
1668
|
+
|
1669
|
+
def initialize
|
1670
|
+
@contacts = [
|
1671
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1672
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1673
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1674
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1675
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1676
|
+
]
|
1677
|
+
end
|
1678
|
+
|
1679
|
+
def launch
|
1680
|
+
window('Contacts', 600, 200) {
|
1681
|
+
table {
|
1682
|
+
text_column('Name')
|
1683
|
+
text_column('Email')
|
1684
|
+
text_column('Phone')
|
1685
|
+
text_column('City/Town')
|
1686
|
+
text_column('State/Province')
|
1687
|
+
|
1688
|
+
cell_rows <=> [self, :contacts, column_attributes: {'City/Town' => :city, 'State/Province' => :state}]
|
1689
|
+
}
|
1690
|
+
}.show
|
1691
|
+
end
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
SomeTable.new.launch
|
1695
|
+
```
|
1696
|
+
|
1697
|
+
Example of `table` explicit data-binding of `cell_rows` to Model `Array` with complete `column_attributes` `Array` mapping (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1698
|
+
|
1699
|
+
```ruby
|
1700
|
+
require 'glimmer-dsl-libui'
|
1701
|
+
|
1702
|
+
class SomeTable
|
1703
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1704
|
+
|
1705
|
+
include Glimmer
|
1706
|
+
|
1707
|
+
attr_accessor :contacts
|
1708
|
+
|
1709
|
+
def initialize
|
1710
|
+
@contacts = [
|
1711
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1712
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1713
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1714
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1715
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1716
|
+
]
|
1717
|
+
end
|
1718
|
+
|
1719
|
+
def launch
|
1720
|
+
window('Contacts', 600, 200) {
|
1721
|
+
table {
|
1722
|
+
text_column('Full Name')
|
1723
|
+
text_column('Email Address')
|
1724
|
+
text_column('Phone Number')
|
1725
|
+
text_column('City or Town')
|
1726
|
+
text_column('State or Province')
|
1727
|
+
|
1728
|
+
cell_rows <=> [self, :contacts, column_attributes: [:name, :email, :phone, :city, :state]]
|
1729
|
+
}
|
1730
|
+
}.show
|
1731
|
+
end
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
SomeTable.new.launch
|
1735
|
+
```
|
1736
|
+
|
1737
|
+
#### Unidirectional (One-Way) Data-Binding
|
1738
|
+
|
1545
1739
|
[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).
|
1546
1740
|
|
1547
1741
|
Example of unidirectional data-binding:
|
@@ -1564,6 +1758,8 @@ window {
|
|
1564
1758
|
|
1565
1759
|
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`.
|
1566
1760
|
|
1761
|
+
#### Data-Binding API
|
1762
|
+
|
1567
1763
|
To summarize the data-binding API:
|
1568
1764
|
- `view_property <=> [model, attribute, *read_or_write_options]`: Bidirectional (two-way) data-binding to Model attribute accessor
|
1569
1765
|
- `view_property <= [model, attribute, *read_only_options]`: Unidirectional (one-way) data-binding to Model attribute reader
|
@@ -1594,11 +1790,13 @@ entry {
|
|
1594
1790
|
}
|
1595
1791
|
```
|
1596
1792
|
|
1597
|
-
|
1793
|
+
Learn more from data-binding usage in [Login](#login) (4 data-binding versions), [Basic Entry](#basic-entry), [Form](#form), [Form Table](#form-table) (5 data-binding versions), [Method-Based Custom Keyword](#method-based-custom-keyword), [Snake](#snake) and [Tic Tac Toe](#tic_tac_toe) examples.
|
1794
|
+
|
1795
|
+
#### Data-Binding Gotchas
|
1796
|
+
|
1598
1797
|
- 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)
|
1599
1798
|
- 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.
|
1600
|
-
|
1601
|
-
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.
|
1799
|
+
- Data-binding a View control to another View control directly is not a good idea. Instead, data-bind both View controls to the same Presenter/Model attribute, and that keeps them in sync while keeping the code decoupled.
|
1602
1800
|
|
1603
1801
|
### API Gotchas
|
1604
1802
|
|
@@ -2925,7 +3123,44 @@ UI.main
|
|
2925
3123
|
UI.quit
|
2926
3124
|
```
|
2927
3125
|
|
2928
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3126
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3127
|
+
|
3128
|
+
```ruby
|
3129
|
+
# frozen_string_literal: true
|
3130
|
+
|
3131
|
+
# NOTE:
|
3132
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3133
|
+
|
3134
|
+
require 'glimmer-dsl-libui'
|
3135
|
+
|
3136
|
+
include Glimmer
|
3137
|
+
|
3138
|
+
IMAGE_ROWS = []
|
3139
|
+
|
3140
|
+
50.times do |i|
|
3141
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3142
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3143
|
+
IMAGE_ROWS << [url] # array of one column cell
|
3144
|
+
rescue StandardError => e
|
3145
|
+
warn url, e.message
|
3146
|
+
end
|
3147
|
+
|
3148
|
+
window('The Red Turtle', 310, 350, false) {
|
3149
|
+
horizontal_box {
|
3150
|
+
table {
|
3151
|
+
image_column('www.ghibli.jp/works/red-turtle')
|
3152
|
+
|
3153
|
+
cell_rows IMAGE_ROWS
|
3154
|
+
}
|
3155
|
+
}
|
3156
|
+
|
3157
|
+
on_closing do
|
3158
|
+
puts 'Bye Bye'
|
3159
|
+
end
|
3160
|
+
}.show
|
3161
|
+
```
|
3162
|
+
|
3163
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
2929
3164
|
|
2930
3165
|
```ruby
|
2931
3166
|
# NOTE:
|
@@ -2960,7 +3195,7 @@ window('The Red Turtle', 310, 350, false) {
|
|
2960
3195
|
}.show
|
2961
3196
|
```
|
2962
3197
|
|
2963
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3198
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (manual construction of `image` from `image_part`):
|
2964
3199
|
|
2965
3200
|
```ruby
|
2966
3201
|
# NOTE:
|
@@ -3028,7 +3263,44 @@ Mac | Windows | Linux
|
|
3028
3263
|
----|---------|------
|
3029
3264
|
![glimmer-dsl-libui-mac-basic-table-image-text.png](images/glimmer-dsl-libui-mac-basic-table-image-text.png) | ![glimmer-dsl-libui-windows-basic-table-image-text.png](images/glimmer-dsl-libui-windows-basic-table-image-text.png) | ![glimmer-dsl-libui-linux-basic-table-image-text.png](images/glimmer-dsl-libui-linux-basic-table-image-text.png)
|
3030
3265
|
|
3031
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3266
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3267
|
+
|
3268
|
+
```ruby
|
3269
|
+
# frozen_string_literal: true
|
3270
|
+
|
3271
|
+
# NOTE:
|
3272
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3273
|
+
|
3274
|
+
require 'glimmer-dsl-libui'
|
3275
|
+
|
3276
|
+
include Glimmer
|
3277
|
+
|
3278
|
+
IMAGE_ROWS = []
|
3279
|
+
|
3280
|
+
5.times do |i|
|
3281
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3282
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3283
|
+
text = url.sub('https://www.ghibli.jp/gallery/thumb-redturtle', '').sub('.png', '')
|
3284
|
+
IMAGE_ROWS << [[url, text], [url, text]] # cell values are dual-element arrays
|
3285
|
+
rescue StandardError => e
|
3286
|
+
warn url, e.message
|
3287
|
+
end
|
3288
|
+
|
3289
|
+
window('The Red Turtle', 670, 350) {
|
3290
|
+
horizontal_box {
|
3291
|
+
table {
|
3292
|
+
image_text_column('image/number')
|
3293
|
+
image_text_column('image/number (editable)') {
|
3294
|
+
editable true
|
3295
|
+
}
|
3296
|
+
|
3297
|
+
cell_rows IMAGE_ROWS
|
3298
|
+
}
|
3299
|
+
}
|
3300
|
+
}.show
|
3301
|
+
```
|
3302
|
+
|
3303
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
3032
3304
|
|
3033
3305
|
```ruby
|
3034
3306
|
# NOTE:
|
@@ -3402,16 +3674,126 @@ Mac | Windows | Linux
|
|
3402
3674
|
----|---------|------
|
3403
3675
|
![glimmer-dsl-libui-mac-basic-table-color.png](images/glimmer-dsl-libui-mac-basic-table-color.png) | ![glimmer-dsl-libui-windows-basic-table-color.png](images/glimmer-dsl-libui-windows-basic-table-color.png) | ![glimmer-dsl-libui-linux-basic-table-color.png](images/glimmer-dsl-libui-linux-basic-table-color.png)
|
3404
3676
|
|
3405
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3677
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding) to model rows using a presenter):
|
3406
3678
|
|
3407
3679
|
```ruby
|
3408
|
-
|
3680
|
+
require 'glimmer-dsl-libui'
|
3409
3681
|
|
3682
|
+
class BasicTableColor
|
3683
|
+
Animal = Struct.new(:name, :sound, :mammal)
|
3684
|
+
|
3685
|
+
class AnimalPresenter < Animal
|
3686
|
+
def name_color
|
3687
|
+
color = case name
|
3688
|
+
when 'cat'
|
3689
|
+
:red
|
3690
|
+
when 'dog'
|
3691
|
+
:yellow
|
3692
|
+
when 'chicken'
|
3693
|
+
:beige
|
3694
|
+
when 'horse'
|
3695
|
+
:purple
|
3696
|
+
when 'cow'
|
3697
|
+
:gray
|
3698
|
+
end
|
3699
|
+
[name, color]
|
3700
|
+
end
|
3701
|
+
|
3702
|
+
def sound_color
|
3703
|
+
color = case name
|
3704
|
+
when 'cat', 'chicken', 'cow'
|
3705
|
+
:blue
|
3706
|
+
when 'dog', 'horse'
|
3707
|
+
{r: 240, g: 32, b: 32}
|
3708
|
+
end
|
3709
|
+
[sound, color]
|
3710
|
+
end
|
3711
|
+
|
3712
|
+
def mammal_description_color
|
3713
|
+
color = case name
|
3714
|
+
when 'cat', 'dog', 'horse', 'cow'
|
3715
|
+
:green
|
3716
|
+
when 'chicken'
|
3717
|
+
:red
|
3718
|
+
end
|
3719
|
+
[mammal, 'mammal', color]
|
3720
|
+
end
|
3721
|
+
|
3722
|
+
def image_description_color
|
3723
|
+
color = case name
|
3724
|
+
when 'cat', 'dog', 'horse'
|
3725
|
+
:dark_blue
|
3726
|
+
when 'chicken'
|
3727
|
+
:beige
|
3728
|
+
when 'cow'
|
3729
|
+
:brown
|
3730
|
+
end
|
3731
|
+
[img, 'Glimmer', color]
|
3732
|
+
end
|
3733
|
+
|
3734
|
+
def img
|
3735
|
+
# scale image to 24x24 (can be passed as file path String only instead of Array to avoid scaling)
|
3736
|
+
[File.expand_path('../icons/glimmer.png', __dir__), 24, 24]
|
3737
|
+
end
|
3738
|
+
|
3739
|
+
def background_color
|
3740
|
+
case name
|
3741
|
+
when 'cat'
|
3742
|
+
{r: 255, g: 120, b: 0, a: 0.5}
|
3743
|
+
when 'dog'
|
3744
|
+
:skyblue
|
3745
|
+
when 'chicken'
|
3746
|
+
{r: 5, g: 120, b: 110}
|
3747
|
+
when 'horse'
|
3748
|
+
'#13a1fb'
|
3749
|
+
when 'cow'
|
3750
|
+
0x12ff02
|
3751
|
+
end
|
3752
|
+
end
|
3753
|
+
end
|
3754
|
+
|
3755
|
+
include Glimmer
|
3756
|
+
|
3757
|
+
attr_accessor :animals
|
3758
|
+
|
3759
|
+
def initialize
|
3760
|
+
@animals = [
|
3761
|
+
AnimalPresenter.new('cat', 'meow', true),
|
3762
|
+
AnimalPresenter.new('dog', 'woof', true),
|
3763
|
+
AnimalPresenter.new('chicken', 'cock-a-doodle-doo', false),
|
3764
|
+
AnimalPresenter.new('horse', 'neigh', true),
|
3765
|
+
AnimalPresenter.new('cow', 'moo', true),
|
3766
|
+
]
|
3767
|
+
end
|
3768
|
+
|
3769
|
+
def launch
|
3770
|
+
window('Animals', 500, 200) {
|
3771
|
+
horizontal_box {
|
3772
|
+
table {
|
3773
|
+
text_color_column('Animal')
|
3774
|
+
text_color_column('Sound')
|
3775
|
+
checkbox_text_color_column('Description')
|
3776
|
+
image_text_color_column('GUI')
|
3777
|
+
background_color_column # must always be the last column and always expects data-binding model attribute `background_color` when binding to Array of models
|
3778
|
+
|
3779
|
+
cell_rows <= [self, :animals, column_attributes: {'Animal' => :name_color, 'Sound' => :sound_color, 'Description' => :mammal_description_color, 'GUI' => :image_description_color}]
|
3780
|
+
}
|
3781
|
+
}
|
3782
|
+
}.show
|
3783
|
+
end
|
3784
|
+
end
|
3785
|
+
|
3786
|
+
BasicTableColor.new.launch
|
3787
|
+
```
|
3788
|
+
|
3789
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with implicit [data-binding](#data-binding) to raw data rows):
|
3790
|
+
|
3791
|
+
```ruby
|
3410
3792
|
require 'glimmer-dsl-libui'
|
3411
3793
|
|
3412
3794
|
include Glimmer
|
3413
3795
|
|
3414
|
-
img =
|
3796
|
+
img = [File.expand_path('../icons/glimmer.png', __dir__), 24, 24] # scales image to 24x24 (can be passed as file path String only instead of Array to avoid scaling)
|
3415
3797
|
|
3416
3798
|
data = [
|
3417
3799
|
[['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
|
@@ -3436,7 +3818,7 @@ window('Animals', 500, 200) {
|
|
3436
3818
|
}.show
|
3437
3819
|
```
|
3438
3820
|
|
3439
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3821
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (with implicit [data-binding](#data-binding) to raw data rows and manual construction of [libui](https://github.com/andlabs/libui) `image` from `image_part`):
|
3440
3822
|
|
3441
3823
|
```ruby
|
3442
3824
|
require 'glimmer-dsl-libui'
|
@@ -3738,7 +4120,11 @@ window('Basic Image', 96, 96) {
|
|
3738
4120
|
# image pixel rendered. Check basic_image2.rb for a faster alternative using on_draw manually.
|
3739
4121
|
#
|
3740
4122
|
# It is recommended to pass width/height args to shrink image and achieve faster performance.
|
3741
|
-
image(File.expand_path('../icons/glimmer.png', __dir__),
|
4123
|
+
image(File.expand_path('../icons/glimmer.png', __dir__), height: 96) # width is automatically calculated from height while preserving original aspect ratio
|
4124
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), width: 96, height: 96) # you can specify both width, height options as alternative
|
4125
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96) # you can specify width, height args as alternative
|
4126
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), 0, 0, 96, 96) # you can specify x, y, width, height args as alternative
|
4127
|
+
# image(File.expand_path('../icons/glimmer.png', __dir__), x: 0, y: 0, width: 96, height: 96) # you can specify x, y, width, height options as alternative
|
3742
4128
|
}
|
3743
4129
|
}.show
|
3744
4130
|
```
|
@@ -3746,8 +4132,6 @@ window('Basic Image', 96, 96) {
|
|
3746
4132
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (better performance via `on_draw`):
|
3747
4133
|
|
3748
4134
|
```ruby
|
3749
|
-
# frozen_string_literal: true
|
3750
|
-
|
3751
4135
|
require 'glimmer-dsl-libui'
|
3752
4136
|
|
3753
4137
|
include Glimmer
|
@@ -3755,7 +4139,7 @@ include Glimmer
|
|
3755
4139
|
window('Basic Image', 96, 96) {
|
3756
4140
|
area {
|
3757
4141
|
on_draw do |area_draw_params|
|
3758
|
-
image(File.expand_path('../icons/glimmer.png', __dir__),
|
4142
|
+
image(File.expand_path('../icons/glimmer.png', __dir__), height: 96)
|
3759
4143
|
end
|
3760
4144
|
}
|
3761
4145
|
}.show
|
@@ -3764,8 +4148,6 @@ window('Basic Image', 96, 96) {
|
|
3764
4148
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (explicit properties):
|
3765
4149
|
|
3766
4150
|
```ruby
|
3767
|
-
# frozen_string_literal: true
|
3768
|
-
|
3769
4151
|
require 'glimmer-dsl-libui'
|
3770
4152
|
|
3771
4153
|
include Glimmer
|
@@ -3782,7 +4164,9 @@ window('Basic Image', 96, 96) {
|
|
3782
4164
|
# It is recommended to pass width/height args to shrink image and achieve faster performance.
|
3783
4165
|
image {
|
3784
4166
|
file File.expand_path('../icons/glimmer.png', __dir__)
|
3785
|
-
|
4167
|
+
# x 0 # default
|
4168
|
+
# y 0 # default
|
4169
|
+
# width 96 # gets calculated from height while preserving original aspect ratio of 512x512
|
3786
4170
|
height 96
|
3787
4171
|
}
|
3788
4172
|
}
|
@@ -3792,8 +4176,6 @@ window('Basic Image', 96, 96) {
|
|
3792
4176
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (better performance with `on_draw` when setting explicit properties):
|
3793
4177
|
|
3794
4178
|
```ruby
|
3795
|
-
# frozen_string_literal: true
|
3796
|
-
|
3797
4179
|
require 'glimmer-dsl-libui'
|
3798
4180
|
|
3799
4181
|
include Glimmer
|
@@ -3803,7 +4185,6 @@ window('Basic Image', 96, 96) {
|
|
3803
4185
|
on_draw do |area_draw_params|
|
3804
4186
|
image {
|
3805
4187
|
file File.expand_path('../icons/glimmer.png', __dir__)
|
3806
|
-
width 96
|
3807
4188
|
height 96
|
3808
4189
|
}
|
3809
4190
|
end
|
@@ -5671,7 +6052,7 @@ Glimmer::LibUI.timer(1) do
|
|
5671
6052
|
data[0][2] = cpu_percentage_value
|
5672
6053
|
end
|
5673
6054
|
|
5674
|
-
window('CPU Percentage', 400,
|
6055
|
+
window('CPU Percentage', 400, 50) {
|
5675
6056
|
vertical_box {
|
5676
6057
|
table {
|
5677
6058
|
text_column('Name')
|
@@ -6344,6 +6725,11 @@ window('Editable column animal sounds', 400, 200) {
|
|
6344
6725
|
}
|
6345
6726
|
|
6346
6727
|
cell_rows data
|
6728
|
+
|
6729
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
6730
|
+
puts "Row #{row} edited: #{row_data}"
|
6731
|
+
$stdout.flush
|
6732
|
+
end
|
6347
6733
|
}
|
6348
6734
|
}
|
6349
6735
|
|
@@ -6456,7 +6842,7 @@ class FormTable
|
|
6456
6842
|
end
|
6457
6843
|
|
6458
6844
|
def launch
|
6459
|
-
window('Contacts', 600, 600) {
|
6845
|
+
window('Contacts', 600, 600) {
|
6460
6846
|
margined true
|
6461
6847
|
|
6462
6848
|
vertical_box {
|
@@ -6494,8 +6880,8 @@ class FormTable
|
|
6494
6880
|
|
6495
6881
|
on_clicked do
|
6496
6882
|
new_row = [name, email, phone, city, state]
|
6497
|
-
if new_row.include?('')
|
6498
|
-
msg_box_error(
|
6883
|
+
if new_row.map(&:to_s).include?('')
|
6884
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6499
6885
|
else
|
6500
6886
|
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
|
6501
6887
|
@unfiltered_contacts = @contacts.dup
|
@@ -6536,10 +6922,16 @@ class FormTable
|
|
6536
6922
|
text_column('State')
|
6537
6923
|
|
6538
6924
|
editable true
|
6539
|
-
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array
|
6925
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to self.contacts Model Array, auto-inferring model attribute names from underscored table column names by convention
|
6540
6926
|
|
6541
6927
|
on_changed do |row, type, row_data|
|
6542
6928
|
puts "Row #{row} #{type}: #{row_data}"
|
6929
|
+
$stdout.flush # for Windows
|
6930
|
+
end
|
6931
|
+
|
6932
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
6933
|
+
puts "Row #{row} edited: #{row_data}"
|
6934
|
+
$stdout.flush # for Windows
|
6543
6935
|
end
|
6544
6936
|
}
|
6545
6937
|
}
|
@@ -6550,13 +6942,13 @@ end
|
|
6550
6942
|
FormTable.new.launch
|
6551
6943
|
```
|
6552
6944
|
|
6553
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
6945
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with explicit [data-binding](#data-binding)):
|
6554
6946
|
|
6555
6947
|
```ruby
|
6556
6948
|
require 'glimmer-dsl-libui'
|
6557
6949
|
|
6558
6950
|
class FormTable
|
6559
|
-
Contact = Struct.new(:name, :email, :phone, :city, :
|
6951
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state_province)
|
6560
6952
|
|
6561
6953
|
include Glimmer
|
6562
6954
|
|
@@ -6573,7 +6965,7 @@ class FormTable
|
|
6573
6965
|
end
|
6574
6966
|
|
6575
6967
|
def launch
|
6576
|
-
window('Contacts', 600, 600) {
|
6968
|
+
window('Contacts', 600, 600) {
|
6577
6969
|
margined true
|
6578
6970
|
|
6579
6971
|
vertical_box {
|
@@ -6611,8 +7003,8 @@ class FormTable
|
|
6611
7003
|
|
6612
7004
|
on_clicked do
|
6613
7005
|
new_row = [name, email, phone, city, state]
|
6614
|
-
if new_row.include?('')
|
6615
|
-
msg_box_error(
|
7006
|
+
if new_row.map(&:to_s).include?('')
|
7007
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6616
7008
|
else
|
6617
7009
|
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
6618
7010
|
@unfiltered_contacts = @contacts.dup
|
@@ -6650,13 +7042,19 @@ class FormTable
|
|
6650
7042
|
text_column('Email')
|
6651
7043
|
text_column('Phone')
|
6652
7044
|
text_column('City')
|
6653
|
-
text_column('State
|
7045
|
+
text_column('State')
|
6654
7046
|
|
6655
7047
|
editable true
|
6656
|
-
cell_rows <=> [self, :contacts, column_attributes: {'State
|
7048
|
+
cell_rows <=> [self, :contacts, column_attributes: {'State' => :state_province}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
|
6657
7049
|
|
6658
7050
|
on_changed do |row, type, row_data|
|
6659
7051
|
puts "Row #{row} #{type}: #{row_data}"
|
7052
|
+
$stdout.flush # for Windows
|
7053
|
+
end
|
7054
|
+
|
7055
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
7056
|
+
puts "Row #{row} edited: #{row_data}"
|
7057
|
+
$stdout.flush # for Windows
|
6660
7058
|
end
|
6661
7059
|
}
|
6662
7060
|
}
|
@@ -6667,7 +7065,7 @@ end
|
|
6667
7065
|
FormTable.new.launch
|
6668
7066
|
```
|
6669
7067
|
|
6670
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
7068
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (with explicit [data-binding](#data-binding)):
|
6671
7069
|
|
6672
7070
|
```ruby
|
6673
7071
|
|
@@ -6691,7 +7089,7 @@ class FormTable
|
|
6691
7089
|
end
|
6692
7090
|
|
6693
7091
|
def launch
|
6694
|
-
window('Contacts', 600, 600) {
|
7092
|
+
window('Contacts', 600, 600) {
|
6695
7093
|
margined true
|
6696
7094
|
|
6697
7095
|
vertical_box {
|
@@ -6729,8 +7127,8 @@ class FormTable
|
|
6729
7127
|
|
6730
7128
|
on_clicked do
|
6731
7129
|
new_row = [name, email, phone, city, state]
|
6732
|
-
if new_row.include?('')
|
6733
|
-
msg_box_error(
|
7130
|
+
if new_row.map(&:to_s).include?('')
|
7131
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6734
7132
|
else
|
6735
7133
|
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
6736
7134
|
@unfiltered_contacts = @contacts.dup
|
@@ -6775,6 +7173,12 @@ class FormTable
|
|
6775
7173
|
|
6776
7174
|
on_changed do |row, type, row_data|
|
6777
7175
|
puts "Row #{row} #{type}: #{row_data}"
|
7176
|
+
$stdout.flush # for Windows
|
7177
|
+
end
|
7178
|
+
|
7179
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
7180
|
+
puts "Row #{row} edited: #{row_data}"
|
7181
|
+
$stdout.flush # for Windows
|
6778
7182
|
end
|
6779
7183
|
}
|
6780
7184
|
}
|
@@ -6806,7 +7210,7 @@ class FormTable
|
|
6806
7210
|
end
|
6807
7211
|
|
6808
7212
|
def launch
|
6809
|
-
window('Contacts', 600, 600) {
|
7213
|
+
window('Contacts', 600, 600) {
|
6810
7214
|
margined true
|
6811
7215
|
|
6812
7216
|
vertical_box {
|
@@ -6844,8 +7248,8 @@ class FormTable
|
|
6844
7248
|
|
6845
7249
|
on_clicked do
|
6846
7250
|
new_row = [name, email, phone, city, state]
|
6847
|
-
if new_row.include?('')
|
6848
|
-
msg_box_error(
|
7251
|
+
if new_row.map(&:to_s).include?('')
|
7252
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6849
7253
|
else
|
6850
7254
|
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
6851
7255
|
@unfiltered_data = data.dup
|
@@ -6890,6 +7294,12 @@ class FormTable
|
|
6890
7294
|
|
6891
7295
|
on_changed do |row, type, row_data|
|
6892
7296
|
puts "Row #{row} #{type}: #{row_data}"
|
7297
|
+
$stdout.flush # for Windows
|
7298
|
+
end
|
7299
|
+
|
7300
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
7301
|
+
puts "Row #{row} edited: #{row_data}"
|
7302
|
+
$stdout.flush # for Windows
|
6893
7303
|
end
|
6894
7304
|
}
|
6895
7305
|
}
|
@@ -6915,7 +7325,7 @@ data = [
|
|
6915
7325
|
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
6916
7326
|
]
|
6917
7327
|
|
6918
|
-
window('Contacts', 600, 600) {
|
7328
|
+
window('Contacts', 600, 600) {
|
6919
7329
|
margined true
|
6920
7330
|
|
6921
7331
|
vertical_box {
|
@@ -6948,8 +7358,8 @@ window('Contacts', 600, 600) { |w|
|
|
6948
7358
|
|
6949
7359
|
on_clicked do
|
6950
7360
|
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
6951
|
-
if new_row.include?('')
|
6952
|
-
msg_box_error(
|
7361
|
+
if new_row.map(&:to_s).include?('')
|
7362
|
+
msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6953
7363
|
else
|
6954
7364
|
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
6955
7365
|
@unfiltered_data = data.dup
|
@@ -6993,6 +7403,12 @@ window('Contacts', 600, 600) { |w|
|
|
6993
7403
|
|
6994
7404
|
on_changed do |row, type, row_data|
|
6995
7405
|
puts "Row #{row} #{type}: #{row_data}"
|
7406
|
+
$stdout.flush # for Windows
|
7407
|
+
end
|
7408
|
+
|
7409
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
7410
|
+
puts "Row #{row} edited: #{row_data}"
|
7411
|
+
$stdout.flush # for Windows
|
6996
7412
|
end
|
6997
7413
|
}
|
6998
7414
|
}
|