glimmer-dsl-libui 0.4.9 → 0.4.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +1330 -487
- data/VERSION +1 -1
- data/examples/basic_table_button.rb +54 -30
- data/examples/basic_table_button2.rb +34 -0
- 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 +36 -0
- data/examples/editable_table.rb +1 -1
- data/examples/form_table.rb +21 -17
- data/examples/form_table2.rb +104 -85
- data/examples/form_table3.rb +113 -0
- data/examples/form_table4.rb +110 -0
- data/examples/form_table5.rb +94 -0
- data/examples/meta_example.rb +6 -4
- data/examples/snake2.rb +97 -0
- data/examples/tic_tac_toe.rb +1 -0
- data/examples/tic_tac_toe2.rb +84 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/control_expression.rb +2 -1
- data/lib/glimmer/dsl/libui/shape_expression.rb +2 -2
- data/lib/glimmer/dsl/libui/string_expression.rb +2 -1
- data/lib/glimmer/libui/attributed_string.rb +3 -2
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/image_proxy.rb +16 -0
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +95 -29
- data/lib/glimmer/libui/control_proxy.rb +4 -2
- data/lib/glimmer/libui/data_bindable.rb +8 -3
- data/lib/glimmer/libui/shape.rb +3 -2
- data/lib/glimmer/libui.rb +2 -2
- data/lib/glimmer-dsl-libui.rb +1 -0
- metadata +12 -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.13
|
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)
|
@@ -77,6 +77,127 @@ Mac | Windows | Linux
|
|
77
77
|
----|---------|------
|
78
78
|
![glimmer-dsl-libui-mac-basic-table-progress-bar.png](images/glimmer-dsl-libui-mac-basic-table-progress-bar.png) | ![glimmer-dsl-libui-windows-basic-table-progress-bar.png](images/glimmer-dsl-libui-windows-basic-table-progress-bar.png) | ![glimmer-dsl-libui-linux-basic-table-progress-bar.png](images/glimmer-dsl-libui-linux-basic-table-progress-bar.png)
|
79
79
|
|
80
|
+
Form Table
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
require 'glimmer-dsl-libui'
|
84
|
+
|
85
|
+
class FormTable
|
86
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
87
|
+
|
88
|
+
include Glimmer
|
89
|
+
|
90
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
@contacts = [
|
94
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
95
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
96
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
97
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
98
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
99
|
+
]
|
100
|
+
end
|
101
|
+
|
102
|
+
def launch
|
103
|
+
window('Contacts', 600, 600) { |w|
|
104
|
+
margined true
|
105
|
+
|
106
|
+
vertical_box {
|
107
|
+
form {
|
108
|
+
stretchy false
|
109
|
+
|
110
|
+
entry {
|
111
|
+
label 'Name'
|
112
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
113
|
+
}
|
114
|
+
|
115
|
+
entry {
|
116
|
+
label 'Email'
|
117
|
+
text <=> [self, :email]
|
118
|
+
}
|
119
|
+
|
120
|
+
entry {
|
121
|
+
label 'Phone'
|
122
|
+
text <=> [self, :phone]
|
123
|
+
}
|
124
|
+
|
125
|
+
entry {
|
126
|
+
label 'City'
|
127
|
+
text <=> [self, :city]
|
128
|
+
}
|
129
|
+
|
130
|
+
entry {
|
131
|
+
label 'State'
|
132
|
+
text <=> [self, :state]
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
button('Save Contact') {
|
137
|
+
stretchy false
|
138
|
+
|
139
|
+
on_clicked do
|
140
|
+
new_row = [name, email, phone, city, state]
|
141
|
+
if new_row.include?('')
|
142
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
143
|
+
else
|
144
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
|
145
|
+
@unfiltered_contacts = @contacts.dup
|
146
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
147
|
+
self.email = ''
|
148
|
+
self.phone = ''
|
149
|
+
self.city = ''
|
150
|
+
self.state = ''
|
151
|
+
end
|
152
|
+
end
|
153
|
+
}
|
154
|
+
|
155
|
+
search_entry {
|
156
|
+
stretchy false
|
157
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
158
|
+
text <=> [self, :filter_value,
|
159
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
160
|
+
@unfiltered_contacts ||= @contacts.dup
|
161
|
+
# Unfilter first to remove any previous filters
|
162
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
163
|
+
# Now, apply filter if entered
|
164
|
+
unless filter_value.empty?
|
165
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
166
|
+
contact.members.any? do |attribute|
|
167
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
}
|
172
|
+
]
|
173
|
+
}
|
174
|
+
|
175
|
+
table {
|
176
|
+
text_column('Name')
|
177
|
+
text_column('Email')
|
178
|
+
text_column('Phone')
|
179
|
+
text_column('City')
|
180
|
+
text_column('State')
|
181
|
+
|
182
|
+
editable true
|
183
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array
|
184
|
+
|
185
|
+
on_changed do |row, type, row_data|
|
186
|
+
puts "Row #{row} #{type}: #{row_data}"
|
187
|
+
end
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}.show
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
FormTable.new.launch
|
195
|
+
```
|
196
|
+
|
197
|
+
Mac | Windows | Linux
|
198
|
+
----|---------|------
|
199
|
+
![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)
|
200
|
+
|
80
201
|
Area Gallery
|
81
202
|
|
82
203
|
```ruby
|
@@ -235,6 +356,11 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
235
356
|
- [Custom Keywords](#custom-keywords)
|
236
357
|
- [Observer Pattern](#observer-pattern)
|
237
358
|
- [Data-Binding](#data-binding)
|
359
|
+
- [Bidirectional (Two-Way) Data-Binding](#bidirectional-two-way-data-binding)
|
360
|
+
- [Table Data-Binding](#table-data-binding)
|
361
|
+
- [Unidirectional (One-Way) Data-Binding](#unidirectional-one-way-data-binding)
|
362
|
+
- [Data-Binding API](#data-binding-api)
|
363
|
+
- [Data-Binding Gotchas](#data-binding-gotchas)
|
238
364
|
- [API Gotchas](#api-gotchas)
|
239
365
|
- [Original API](#original-api)
|
240
366
|
- [Packaging](#packaging)
|
@@ -267,6 +393,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
267
393
|
- [Button Counter](#button-counter)
|
268
394
|
- [Color The Circles](#color-the-circles)
|
269
395
|
- [Control Gallery](#control-gallery)
|
396
|
+
- [CPU Percentage](#cpu-percentage)
|
270
397
|
- [Custom Draw Text](#custom-draw-text)
|
271
398
|
- [Dynamic Area](#dynamic-area)
|
272
399
|
- [Editable Column Table](#editable-column-table)
|
@@ -373,10 +500,20 @@ gem install glimmer-dsl-libui
|
|
373
500
|
Or install via Bundler `Gemfile`:
|
374
501
|
|
375
502
|
```ruby
|
376
|
-
gem 'glimmer-dsl-libui', '~> 0.4.
|
503
|
+
gem 'glimmer-dsl-libui', '~> 0.4.13'
|
504
|
+
```
|
505
|
+
|
506
|
+
Test that installation worked by running the [Meta-Example](#examples):
|
507
|
+
|
508
|
+
```
|
509
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/meta_example'"
|
377
510
|
```
|
378
511
|
|
379
|
-
|
512
|
+
Mac | Windows | Linux
|
513
|
+
----|---------|------
|
514
|
+
![glimmer-dsl-libui-mac-meta-example.png](images/glimmer-dsl-libui-mac-meta-example.png) | ![glimmer-dsl-libui-windows-meta-example.png](images/glimmer-dsl-libui-windows-meta-example.png) | ![glimmer-dsl-libui-linux-meta-example.png](images/glimmer-dsl-libui-linux-meta-example.png)
|
515
|
+
|
516
|
+
Now to use [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui), 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.
|
380
517
|
|
381
518
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
382
519
|
|
@@ -451,7 +588,7 @@ Keyword(Args) | Properties | Listeners
|
|
451
588
|
`about_menu_item` | None | `on_clicked`
|
452
589
|
`area` | `auto_draw_enabled` | `on_draw(area_draw_params)`, `on_mouse_event(area_mouse_event)`, `on_mouse_down(area_mouse_event)`, `on_mouse_up(area_mouse_event)`, `on_mouse_drag_started(area_mouse_event)`, `on_mouse_dragged(area_mouse_event)`, `on_mouse_dropped(area_mouse_event)`, `on_mouse_entered`, `on_mouse_exited`, `on_key_event(area_key_event)`, `on_key_down(area_key_event)`, `on_key_up(area_key_event)`
|
453
590
|
`arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)` | `x_center` (`Numeric`), `y_center` (`Numeric`), `radius` (`Numeric`), `start_angle` (`Numeric`), `sweep` (`Numeric`), `is_negative` (Boolean) | None
|
454
|
-
`background_color_column
|
591
|
+
`background_color_column` | None | None
|
455
592
|
`bezier(c1_x as Numeric, c1_y as Numeric, c2_x as Numeric, c2_y as Numeric, end_x as Numeric, end_y as Numeric)` | `c1_x` (`Numeric`), `c1_y` (`Numeric`), `c2_x` (`Numeric`), `c2_y` (`Numeric`), `end_x` (`Numeric`), `end_y` (`Numeric`) | None
|
456
593
|
`button(text as String)` | `text` (`String`) | `on_clicked`
|
457
594
|
`button_column(name as String)` | `enabled` (Boolean) | None
|
@@ -615,155 +752,145 @@ Note that the `cell_rows` property declaration results in "implicit data-binding
|
|
615
752
|
- Inserting cell rows: Calling `Array#<<`, `Array#push`, `Array#prepend`, or any insertion/addition `Array` method automatically inserts rows in actual `table` control
|
616
753
|
- Changing cell rows: Calling `Array#[]=`, `Array#map!`, or any update `Array` method automatically updates rows in actual `table` control
|
617
754
|
|
618
|
-
|
619
|
-
|
620
|
-
```ruby
|
621
|
-
require 'glimmer-dsl-libui'
|
622
|
-
|
623
|
-
class FormTable
|
624
|
-
include Glimmer
|
625
|
-
|
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
|
641
|
-
|
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 = ''
|
687
|
-
end
|
688
|
-
end
|
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')
|
716
|
-
|
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
|
727
|
-
|
728
|
-
FormTable.new.launch
|
729
|
-
```
|
730
|
-
|
731
|
-
![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
|
732
|
-
|
733
|
-
Learn more by checking out [examples](#examples).
|
734
|
-
|
735
|
-
### Area API
|
736
|
-
|
737
|
-
The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
|
738
|
-
- Declaratively via stable paths: useful for stable paths that will not change often later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be relatively few stable paths (mostly for decorative reasons).
|
739
|
-
- Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change very often. Open an `on_draw` listener block that receives an [`area_draw_params`](#area-draw-params) argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
|
740
|
-
|
741
|
-
Note that when nesting an `area` directly underneath `window` (without a layout control like `vertical_box`), it is automatically reparented with `vertical_box` in between the `window` and `area` since it would not show up on Linux otherwise.
|
755
|
+
([explicit data-binding](#data-binding) supports everything available with implicit data-binding too)
|
742
756
|
|
743
|
-
|
757
|
+
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
744
758
|
|
745
759
|
```ruby
|
746
760
|
require 'glimmer-dsl-libui'
|
747
761
|
|
748
762
|
include Glimmer
|
749
763
|
|
750
|
-
|
764
|
+
data = [
|
765
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
766
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
767
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
768
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
769
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
770
|
+
]
|
771
|
+
|
772
|
+
window('Contacts', 600, 600) { |w|
|
751
773
|
margined true
|
752
774
|
|
753
775
|
vertical_box {
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
776
|
+
form {
|
777
|
+
stretchy false
|
778
|
+
|
779
|
+
@name_entry = entry {
|
780
|
+
label 'Name'
|
781
|
+
}
|
782
|
+
|
783
|
+
@email_entry = entry {
|
784
|
+
label 'Email'
|
785
|
+
}
|
786
|
+
|
787
|
+
@phone_entry = entry {
|
788
|
+
label 'Phone'
|
789
|
+
}
|
790
|
+
|
791
|
+
@city_entry = entry {
|
792
|
+
label 'City'
|
793
|
+
}
|
794
|
+
|
795
|
+
@state_entry = entry {
|
796
|
+
label 'State'
|
759
797
|
}
|
760
798
|
}
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
799
|
+
|
800
|
+
button('Save Contact') {
|
801
|
+
stretchy false
|
802
|
+
|
803
|
+
on_clicked do
|
804
|
+
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
805
|
+
if new_row.include?('')
|
806
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
807
|
+
else
|
808
|
+
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
809
|
+
@unfiltered_data = data.dup
|
810
|
+
@name_entry.text = ''
|
811
|
+
@email_entry.text = ''
|
812
|
+
@phone_entry.text = ''
|
813
|
+
@city_entry.text = ''
|
814
|
+
@state_entry.text = ''
|
815
|
+
end
|
816
|
+
end
|
817
|
+
}
|
818
|
+
|
819
|
+
search_entry { |se|
|
820
|
+
stretchy false
|
821
|
+
|
822
|
+
on_changed do
|
823
|
+
filter_value = se.text
|
824
|
+
@unfiltered_data ||= data.dup
|
825
|
+
# Unfilter first to remove any previous filters
|
826
|
+
data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
827
|
+
# Now, apply filter if entered
|
828
|
+
unless filter_value.empty?
|
829
|
+
data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
830
|
+
row_data.any? do |cell|
|
831
|
+
cell.to_s.downcase.include?(filter_value.downcase)
|
832
|
+
end
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
}
|
837
|
+
|
838
|
+
table {
|
839
|
+
text_column('Name')
|
840
|
+
text_column('Email')
|
841
|
+
text_column('Phone')
|
842
|
+
text_column('City')
|
843
|
+
text_column('State')
|
844
|
+
|
845
|
+
editable true
|
846
|
+
cell_rows data # implicit data-binding to raw data Array of Arrays
|
847
|
+
|
848
|
+
on_changed do |row, type, row_data|
|
849
|
+
puts "Row #{row} #{type}: #{row_data}"
|
850
|
+
end
|
851
|
+
}
|
852
|
+
}
|
853
|
+
}.show
|
854
|
+
```
|
855
|
+
|
856
|
+
Mac | Windows | Linux
|
857
|
+
----|---------|------
|
858
|
+
![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)
|
859
|
+
|
860
|
+
Learn more by checking out [examples](#examples).
|
861
|
+
|
862
|
+
### Area API
|
863
|
+
|
864
|
+
The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
|
865
|
+
- Declaratively via stable paths: useful for stable paths that will not change often later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be relatively few stable paths (mostly for decorative reasons).
|
866
|
+
- Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change very often. Open an `on_draw` listener block that receives an [`area_draw_params`](#area-draw-params) argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
|
867
|
+
|
868
|
+
Note that when nesting an `area` directly underneath `window` (without a layout control like `vertical_box`), it is automatically reparented with `vertical_box` in between the `window` and `area` since it would not show up on Linux otherwise.
|
869
|
+
|
870
|
+
Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
871
|
+
|
872
|
+
```ruby
|
873
|
+
require 'glimmer-dsl-libui'
|
874
|
+
|
875
|
+
include Glimmer
|
876
|
+
|
877
|
+
window('Basic Area', 400, 400) {
|
878
|
+
margined true
|
879
|
+
|
880
|
+
vertical_box {
|
881
|
+
area {
|
882
|
+
path { # a stable path is added declaratively
|
883
|
+
rectangle(0, 0, 400, 400)
|
884
|
+
|
885
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
886
|
+
}
|
887
|
+
}
|
888
|
+
}
|
889
|
+
}.show
|
890
|
+
```
|
891
|
+
|
892
|
+
Mac | Windows | Linux
|
893
|
+
----|---------|------
|
767
894
|
![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png) | ![glimmer-dsl-libui-windows-basic-area.png](images/glimmer-dsl-libui-windows-basic-area.png) | ![glimmer-dsl-libui-linux-basic-area.png](images/glimmer-dsl-libui-linux-basic-area.png)
|
768
895
|
|
769
896
|
Here is the same example using a semi-declarative `area` with `on_draw` listener that receives a [`area_draw_params`](#area-draw-params) argument and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
@@ -798,17 +925,23 @@ Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declara
|
|
798
925
|
- `scroll_to(x as Numeric, y as Numeric, width as Numeric = main_window.width, height as Numeric = main_window.height)`: scrolls to `x`/`y` location with `width` and `height` viewport size.
|
799
926
|
- `set_size(width as Numeric, height as Numeric)`: set size of scrolling area, which must must exceed that of visible viewport in order for scrolling to be enabled.
|
800
927
|
|
801
|
-
Mac |Linux
|
802
|
-
|
803
|
-
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-basic-scrolling-area.png) ![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-basic-scrolling-area.png) ![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-basic-scrolling-area-scrolled.png)
|
928
|
+
Mac | Windows | Linux
|
929
|
+
----|---------|------
|
930
|
+
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-basic-scrolling-area.png) ![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-windows-dynamic-area.png](images/glimmer-dsl-libui-windows-basic-scrolling-area.png) ![glimmer-dsl-libui-windows-dynamic-area-updated.png](images/glimmer-dsl-libui-windows-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-basic-scrolling-area.png) ![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-basic-scrolling-area-scrolled.png)
|
804
931
|
|
805
932
|
Check [examples/basic_scrolling_area.rb](#basic-scrolling-area) for a more detailed example.
|
806
933
|
|
807
934
|
#### Area Path Shapes
|
808
935
|
|
936
|
+
`area` can have geometric shapes drawn by adding `path` elements.
|
937
|
+
|
938
|
+
To add `path` shapes under an `area`, you can do so:
|
939
|
+
- Explicitly: by adding `path` under `area` and nesting shapes (e.g. `rectangle`) underneath that share the same `fill`/`stroke`/`transform` properties
|
940
|
+
- 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`)
|
941
|
+
|
809
942
|
`path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
|
810
943
|
|
811
|
-
Available nested `path`
|
944
|
+
Available `path` shapes (that can be nested explicitly under `path` or implicitly under `area` directly):
|
812
945
|
- `rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)`
|
813
946
|
- `square(x as Numeric, y as Numeric, length as Numeric)`
|
814
947
|
- `arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)`
|
@@ -1216,6 +1349,7 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
1216
1349
|
- When destroying a control nested under a `horizontal_box` or `vertical_box`, it is automatically deleted from the box's children
|
1217
1350
|
- When destroying a control nested under a `form`, it is automatically deleted from the form's children
|
1218
1351
|
- When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
|
1352
|
+
- When destroying a control that has a data-binding to a model attribute, the data-binding observer registration is automatically deregistered
|
1219
1353
|
- For `date_time_picker`, `date_picker`, and `time_picker`, make sure `time` hash values for `mon`, `wday`, and `yday` are 1-based instead of [libui](https://github.com/andlabs/libui) original 0-based values, and return `dst` as Boolean instead of `isdst` as `1`/`0`
|
1220
1354
|
- Smart defaults for `grid` child properties are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`:fill`), `vexpand` (`false`), and `valign` (`:fill`)
|
1221
1355
|
- The `table` control automatically constructs required `TableModelHandler`, `TableModel`, and `TableParams`, calculating all their arguments from `cell_rows` and `editable` properties (e.g. `NumRows`) as well as nested columns (e.g. `text_column`)
|
@@ -1226,7 +1360,8 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
1226
1360
|
- Automatically provide shifted `:key` characters in `area_key_event` provided in `area` key listeners `on_key_event`, `on_key_down`, and `on_key_up`
|
1227
1361
|
- `scrolling_area` `width` and `height` default to main window width and height if not specified.
|
1228
1362
|
- `scrolling_area` `#scroll_to` 3rd and 4th arguments (`width` and `height`) default to main window width and height if not specified.
|
1229
|
-
- `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
|
1363
|
+
- `area` paths are specified declaratively with shapes/figures underneath (e.g. `rectangle`), and `area` draw listener is automatically generated
|
1364
|
+
- `area` path shapes can be added directly under `area` without declaring `path` explicitly as a convenient shorthand
|
1230
1365
|
- Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
|
1231
1366
|
- Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
|
1232
1367
|
- Observe `text` and `string` properties for changes and automatically redraw containing area accordingly
|
@@ -1381,6 +1516,8 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
|
|
1381
1516
|
|
1382
1517
|
![MVP](https://www.researchgate.net/profile/Gilles-Perrouin/publication/320249584/figure/fig8/AS:668260987068418@1536337243385/Model-view-presenter-architecture.png)
|
1383
1518
|
|
1519
|
+
#### Bidirectional (Two-Way) Data-Binding
|
1520
|
+
|
1384
1521
|
[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):
|
1385
1522
|
- `checkbox`: `checked`
|
1386
1523
|
- `check_menu_item`: `checked`
|
@@ -1398,7 +1535,7 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
|
|
1398
1535
|
- `search_entry`: `text`
|
1399
1536
|
- `slider`: `value`
|
1400
1537
|
- `spinbox`: `value`
|
1401
|
-
- `table`: `cell_rows` (explicit data-binding using `<=>` and [implicit data-binding](#table-api) by assigning value directly)
|
1538
|
+
- `table`: `cell_rows` (explicit data-binding by using `<=>` and [implicit data-binding](#table-api) by assigning value directly)
|
1402
1539
|
- `time_picker`: `time`
|
1403
1540
|
|
1404
1541
|
Example of bidirectional data-binding:
|
@@ -1421,6 +1558,162 @@ entry {
|
|
1421
1558
|
|
1422
1559
|
That is data-binding `entered_text` attribute on `self` to `entry` `text` property and printing text after write to the model.
|
1423
1560
|
|
1561
|
+
##### Table Data-Binding
|
1562
|
+
|
1563
|
+
One note about `table` `cell_rows` data-binding is that it works with either:
|
1564
|
+
- Raw data `Array` (rows) of `Array`s (column cells)
|
1565
|
+
- 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.
|
1566
|
+
|
1567
|
+
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)):
|
1568
|
+
|
1569
|
+
```ruby
|
1570
|
+
require 'glimmer-dsl-libui'
|
1571
|
+
|
1572
|
+
include Glimmer
|
1573
|
+
|
1574
|
+
data = [
|
1575
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
1576
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
1577
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
1578
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
1579
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
1580
|
+
]
|
1581
|
+
|
1582
|
+
window('Contacts', 600, 600) {
|
1583
|
+
table {
|
1584
|
+
text_column('Name')
|
1585
|
+
text_column('Email')
|
1586
|
+
text_column('Phone')
|
1587
|
+
text_column('City')
|
1588
|
+
text_column('State')
|
1589
|
+
|
1590
|
+
cell_rows data
|
1591
|
+
}
|
1592
|
+
}.show
|
1593
|
+
```
|
1594
|
+
|
1595
|
+
Example of `table` explicit data-binding of `cell_rows` to Model `Array` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1596
|
+
|
1597
|
+
```ruby
|
1598
|
+
require 'glimmer-dsl-libui'
|
1599
|
+
|
1600
|
+
class SomeTable
|
1601
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1602
|
+
|
1603
|
+
include Glimmer
|
1604
|
+
|
1605
|
+
attr_accessor :contacts
|
1606
|
+
|
1607
|
+
def initialize
|
1608
|
+
@contacts = [
|
1609
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1610
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1611
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1612
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1613
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1614
|
+
]
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
def launch
|
1618
|
+
window('Contacts', 600, 200) {
|
1619
|
+
table {
|
1620
|
+
text_column('Name')
|
1621
|
+
text_column('Email')
|
1622
|
+
text_column('Phone')
|
1623
|
+
text_column('City')
|
1624
|
+
text_column('State')
|
1625
|
+
|
1626
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array auto-inferring model attribute names from underscored table column names by convention
|
1627
|
+
}
|
1628
|
+
}.show
|
1629
|
+
end
|
1630
|
+
end
|
1631
|
+
|
1632
|
+
SomeTable.new.launch
|
1633
|
+
```
|
1634
|
+
|
1635
|
+
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)):
|
1636
|
+
|
1637
|
+
```ruby
|
1638
|
+
require 'glimmer-dsl-libui'
|
1639
|
+
|
1640
|
+
class SomeTable
|
1641
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1642
|
+
|
1643
|
+
include Glimmer
|
1644
|
+
|
1645
|
+
attr_accessor :contacts
|
1646
|
+
|
1647
|
+
def initialize
|
1648
|
+
@contacts = [
|
1649
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1650
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1651
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1652
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1653
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1654
|
+
]
|
1655
|
+
end
|
1656
|
+
|
1657
|
+
def launch
|
1658
|
+
window('Contacts', 600, 200) {
|
1659
|
+
table {
|
1660
|
+
text_column('Name')
|
1661
|
+
text_column('Email')
|
1662
|
+
text_column('Phone')
|
1663
|
+
text_column('City/Town')
|
1664
|
+
text_column('State/Province')
|
1665
|
+
|
1666
|
+
cell_rows <=> [self, :contacts, column_attributes: {'City/Town' => :city, 'State/Province' => :state}]
|
1667
|
+
}
|
1668
|
+
}.show
|
1669
|
+
end
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
SomeTable.new.launch
|
1673
|
+
```
|
1674
|
+
|
1675
|
+
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)):
|
1676
|
+
|
1677
|
+
```ruby
|
1678
|
+
require 'glimmer-dsl-libui'
|
1679
|
+
|
1680
|
+
class SomeTable
|
1681
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1682
|
+
|
1683
|
+
include Glimmer
|
1684
|
+
|
1685
|
+
attr_accessor :contacts
|
1686
|
+
|
1687
|
+
def initialize
|
1688
|
+
@contacts = [
|
1689
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1690
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1691
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1692
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1693
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1694
|
+
]
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
def launch
|
1698
|
+
window('Contacts', 600, 200) {
|
1699
|
+
table {
|
1700
|
+
text_column('Full Name')
|
1701
|
+
text_column('Email Address')
|
1702
|
+
text_column('Phone Number')
|
1703
|
+
text_column('City or Town')
|
1704
|
+
text_column('State or Province')
|
1705
|
+
|
1706
|
+
cell_rows <=> [self, :contacts, column_attributes: [:name, :email, :phone, :city, :state]]
|
1707
|
+
}
|
1708
|
+
}.show
|
1709
|
+
end
|
1710
|
+
end
|
1711
|
+
|
1712
|
+
SomeTable.new.launch
|
1713
|
+
```
|
1714
|
+
|
1715
|
+
#### Unidirectional (One-Way) Data-Binding
|
1716
|
+
|
1424
1717
|
[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).
|
1425
1718
|
|
1426
1719
|
Example of unidirectional data-binding:
|
@@ -1443,6 +1736,8 @@ window {
|
|
1443
1736
|
|
1444
1737
|
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`.
|
1445
1738
|
|
1739
|
+
#### Data-Binding API
|
1740
|
+
|
1446
1741
|
To summarize the data-binding API:
|
1447
1742
|
- `view_property <=> [model, attribute, *read_or_write_options]`: Bidirectional (two-way) data-binding to Model attribute accessor
|
1448
1743
|
- `view_property <= [model, attribute, *read_only_options]`: Unidirectional (one-way) data-binding to Model attribute reader
|
@@ -1473,11 +1768,13 @@ entry {
|
|
1473
1768
|
}
|
1474
1769
|
```
|
1475
1770
|
|
1476
|
-
|
1771
|
+
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.
|
1772
|
+
|
1773
|
+
#### Data-Binding Gotchas
|
1774
|
+
|
1477
1775
|
- 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)
|
1478
1776
|
- 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.
|
1479
|
-
|
1480
|
-
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.
|
1777
|
+
- 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.
|
1481
1778
|
|
1482
1779
|
### API Gotchas
|
1483
1780
|
|
@@ -1490,272 +1787,12 @@ Learn more from data-binding usage in [Login](#login) (4 data-binding versions),
|
|
1490
1787
|
- `table` `progress_bar` column on Windows cannot be updated with a positive value if it started initially with `-1` (it ignores update to avoid crashing due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
|
1491
1788
|
- It seems that [libui](https://github.com/andlabs/libui) does not support nesting multiple `area` controls under a `grid` as only the first one shows up in that scenario. To workaround that limitation, use a `vertical_box` with nested `horizontal_box`s instead to include multiple `area`s in a GUI.
|
1492
1789
|
- As per the code of [examples/basic_transform.rb](#basic-transform), Windows requires different ordering of transforms than Mac and Linux.
|
1790
|
+
- `scrolling_area#scroll_to` does not seem to work on Windows and Linux, but works fine on Mac
|
1493
1791
|
|
1494
1792
|
### Original API
|
1495
1793
|
|
1496
1794
|
Here are all the lower-level [LibUI](https://github.com/kojix2/LibUI) API methods utilized by [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui):
|
1497
|
-
|
1498
|
-
- `area_begin_user_window_move`
|
1499
|
-
- `area_begin_user_window_resize`
|
1500
|
-
- `area_queue_redraw_all`
|
1501
|
-
- `area_scroll_to`
|
1502
|
-
- `area_set_size`
|
1503
|
-
- `attribute_color`
|
1504
|
-
- `attribute_family`
|
1505
|
-
- `attribute_features`
|
1506
|
-
- `attribute_get_type`
|
1507
|
-
- `attribute_italic`
|
1508
|
-
- `attribute_size`
|
1509
|
-
- `attribute_stretch`
|
1510
|
-
- `attribute_underline`
|
1511
|
-
- `attribute_underline_color`
|
1512
|
-
- `attribute_weight`
|
1513
|
-
- `attributed_string_append_unattributed`
|
1514
|
-
- `attributed_string_byte_index_to_grapheme`
|
1515
|
-
- `attributed_string_delete`
|
1516
|
-
- `attributed_string_for_each_attribute`
|
1517
|
-
- `attributed_string_grapheme_to_byte_index`
|
1518
|
-
- `attributed_string_insert_at_unattributed`
|
1519
|
-
- `attributed_string_len`
|
1520
|
-
- `attributed_string_num_graphemes`
|
1521
|
-
- `attributed_string_set_attribute`
|
1522
|
-
- `attributed_string_string`
|
1523
|
-
- `box_append`
|
1524
|
-
- `box_delete`
|
1525
|
-
- `box_padded`
|
1526
|
-
- `box_set_padded`
|
1527
|
-
- `button_on_clicked`
|
1528
|
-
- `button_set_text`
|
1529
|
-
- `button_text`
|
1530
|
-
- `checkbox_checked`
|
1531
|
-
- `checkbox_on_toggled`
|
1532
|
-
- `checkbox_set_checked`
|
1533
|
-
- `checkbox_set_text`
|
1534
|
-
- `checkbox_text`
|
1535
|
-
- `color_button_color`
|
1536
|
-
- `color_button_on_changed`
|
1537
|
-
- `color_button_set_color`
|
1538
|
-
- `combobox_append`
|
1539
|
-
- `combobox_on_selected`
|
1540
|
-
- `combobox_selected`
|
1541
|
-
- `combobox_set_selected`
|
1542
|
-
- `control_destroy`
|
1543
|
-
- `control_disable`
|
1544
|
-
- `control_enable`
|
1545
|
-
- `control_enabled`
|
1546
|
-
- `control_enabled_to_user`
|
1547
|
-
- `control_handle`
|
1548
|
-
- `control_hide`
|
1549
|
-
- `control_parent`
|
1550
|
-
- `control_set_parent`
|
1551
|
-
- `control_show`
|
1552
|
-
- `control_toplevel`
|
1553
|
-
- `control_verify_set_parent`
|
1554
|
-
- `control_visible`
|
1555
|
-
- `date_time_picker_on_changed`
|
1556
|
-
- `date_time_picker_set_time`
|
1557
|
-
- `date_time_picker_time`
|
1558
|
-
- `draw_clip`
|
1559
|
-
- `draw_fill`
|
1560
|
-
- `draw_free_path`
|
1561
|
-
- `draw_free_text_layout`
|
1562
|
-
- `draw_matrix_invert`
|
1563
|
-
- `draw_matrix_invertible`
|
1564
|
-
- `draw_matrix_multiply`
|
1565
|
-
- `draw_matrix_rotate`
|
1566
|
-
- `draw_matrix_scale`
|
1567
|
-
- `draw_matrix_set_identity`
|
1568
|
-
- `draw_matrix_skew`
|
1569
|
-
- `draw_matrix_transform_point`
|
1570
|
-
- `draw_matrix_transform_size`
|
1571
|
-
- `draw_matrix_translate`
|
1572
|
-
- `draw_new_path`
|
1573
|
-
- `draw_new_text_layout`
|
1574
|
-
- `draw_path_add_rectangle`
|
1575
|
-
- `draw_path_arc_to`
|
1576
|
-
- `draw_path_bezier_to`
|
1577
|
-
- `draw_path_close_figure`
|
1578
|
-
- `draw_path_end`
|
1579
|
-
- `draw_path_line_to`
|
1580
|
-
- `draw_path_new_figure`
|
1581
|
-
- `draw_path_new_figure_with_arc`
|
1582
|
-
- `draw_restore`
|
1583
|
-
- `draw_save`
|
1584
|
-
- `draw_stroke`
|
1585
|
-
- `draw_text`
|
1586
|
-
- `draw_text_layout_extents`
|
1587
|
-
- `draw_transform`
|
1588
|
-
- `editable_combobox_append`
|
1589
|
-
- `editable_combobox_on_changed`
|
1590
|
-
- `editable_combobox_set_text`
|
1591
|
-
- `editable_combobox_text`
|
1592
|
-
- `entry_on_changed`
|
1593
|
-
- `entry_read_only`
|
1594
|
-
- `entry_set_read_only`
|
1595
|
-
- `entry_set_text`
|
1596
|
-
- `entry_text`
|
1597
|
-
- `ffi_lib`
|
1598
|
-
- `ffi_lib=`
|
1599
|
-
- `font_button_font`
|
1600
|
-
- `font_button_on_changed`
|
1601
|
-
- `form_append`
|
1602
|
-
- `form_delete`
|
1603
|
-
- `form_padded`
|
1604
|
-
- `form_set_padded`
|
1605
|
-
- `free_attribute`
|
1606
|
-
- `free_attributed_string`
|
1607
|
-
- `free_control`
|
1608
|
-
- `free_font_button_font`
|
1609
|
-
- `free_image`
|
1610
|
-
- `free_init_error`
|
1611
|
-
- `free_open_type_features`
|
1612
|
-
- `free_table_model`
|
1613
|
-
- `free_table_value`
|
1614
|
-
- `free_text`
|
1615
|
-
- `grid_append`
|
1616
|
-
- `grid_insert_at`
|
1617
|
-
- `grid_padded`
|
1618
|
-
- `grid_set_padded`
|
1619
|
-
- `group_margined`
|
1620
|
-
- `group_set_child`
|
1621
|
-
- `group_set_margined`
|
1622
|
-
- `group_set_title`
|
1623
|
-
- `group_title`
|
1624
|
-
- `image_append`
|
1625
|
-
- `init`
|
1626
|
-
- `label_set_text`
|
1627
|
-
- `label_text`
|
1628
|
-
- `main`
|
1629
|
-
- `main_step`
|
1630
|
-
- `main_steps`
|
1631
|
-
- `menu_append_about_item`
|
1632
|
-
- `menu_append_check_item`
|
1633
|
-
- `menu_append_item`
|
1634
|
-
- `menu_append_preferences_item`
|
1635
|
-
- `menu_append_quit_item`
|
1636
|
-
- `menu_append_separator`
|
1637
|
-
- `menu_item_checked`
|
1638
|
-
- `menu_item_disable`
|
1639
|
-
- `menu_item_enable`
|
1640
|
-
- `menu_item_on_clicked`
|
1641
|
-
- `menu_item_set_checked`
|
1642
|
-
- `msg_box`
|
1643
|
-
- `msg_box_error`
|
1644
|
-
- `multiline_entry_append`
|
1645
|
-
- `multiline_entry_on_changed`
|
1646
|
-
- `multiline_entry_read_only`
|
1647
|
-
- `multiline_entry_set_read_only`
|
1648
|
-
- `multiline_entry_set_text`
|
1649
|
-
- `multiline_entry_text`
|
1650
|
-
- `new_area`
|
1651
|
-
- `new_attributed_string`
|
1652
|
-
- `new_background_attribute`
|
1653
|
-
- `new_button`
|
1654
|
-
- `new_checkbox`
|
1655
|
-
- `new_color_attribute`
|
1656
|
-
- `new_color_button`
|
1657
|
-
- `new_combobox`
|
1658
|
-
- `new_date_picker`
|
1659
|
-
- `new_date_time_picker`
|
1660
|
-
- `new_editable_combobox`
|
1661
|
-
- `new_entry`
|
1662
|
-
- `new_family_attribute`
|
1663
|
-
- `new_features_attribute`
|
1664
|
-
- `new_font_button`
|
1665
|
-
- `new_form`
|
1666
|
-
- `new_grid`
|
1667
|
-
- `new_group`
|
1668
|
-
- `new_horizontal_box`
|
1669
|
-
- `new_horizontal_separator`
|
1670
|
-
- `new_image`
|
1671
|
-
- `new_italic_attribute`
|
1672
|
-
- `new_label`
|
1673
|
-
- `new_menu`
|
1674
|
-
- `new_multiline_entry`
|
1675
|
-
- `new_non_wrapping_multiline_entry`
|
1676
|
-
- `new_open_type_features`
|
1677
|
-
- `new_password_entry`
|
1678
|
-
- `new_progress_bar`
|
1679
|
-
- `new_radio_buttons`
|
1680
|
-
- `new_scrolling_area`
|
1681
|
-
- `new_search_entry`
|
1682
|
-
- `new_size_attribute`
|
1683
|
-
- `new_slider`
|
1684
|
-
- `new_spinbox`
|
1685
|
-
- `new_stretch_attribute`
|
1686
|
-
- `new_tab`
|
1687
|
-
- `new_table`
|
1688
|
-
- `new_table_model`
|
1689
|
-
- `new_table_value_color`
|
1690
|
-
- `new_table_value_image`
|
1691
|
-
- `new_table_value_int`
|
1692
|
-
- `new_table_value_string`
|
1693
|
-
- `new_time_picker`
|
1694
|
-
- `new_underline_attribute`
|
1695
|
-
- `new_underline_color_attribute`
|
1696
|
-
- `new_vertical_box`
|
1697
|
-
- `new_vertical_separator`
|
1698
|
-
- `new_weight_attribute`
|
1699
|
-
- `new_window`
|
1700
|
-
- `on_should_quit`
|
1701
|
-
- `open_file`
|
1702
|
-
- `open_type_features_add`
|
1703
|
-
- `open_type_features_clone`
|
1704
|
-
- `open_type_features_for_each`
|
1705
|
-
- `open_type_features_get`
|
1706
|
-
- `open_type_features_remove`
|
1707
|
-
- `progress_bar_set_value`
|
1708
|
-
- `progress_bar_value`
|
1709
|
-
- `queue_main`
|
1710
|
-
- `quit`
|
1711
|
-
- `radio_buttons_append`
|
1712
|
-
- `radio_buttons_on_selected`
|
1713
|
-
- `radio_buttons_selected`
|
1714
|
-
- `radio_buttons_set_selected`
|
1715
|
-
- `save_file`
|
1716
|
-
- `slider_on_changed`
|
1717
|
-
- `slider_set_value`
|
1718
|
-
- `slider_value`
|
1719
|
-
- `spinbox_on_changed`
|
1720
|
-
- `spinbox_set_value`
|
1721
|
-
- `spinbox_value`
|
1722
|
-
- `tab_append`
|
1723
|
-
- `tab_delete`
|
1724
|
-
- `tab_insert_at`
|
1725
|
-
- `tab_margined`
|
1726
|
-
- `tab_num_pages`
|
1727
|
-
- `tab_set_margined`
|
1728
|
-
- `table_append_button_column`
|
1729
|
-
- `table_append_checkbox_column`
|
1730
|
-
- `table_append_checkbox_text_column`
|
1731
|
-
- `table_append_image_column`
|
1732
|
-
- `table_append_image_text_column`
|
1733
|
-
- `table_append_progress_bar_column`
|
1734
|
-
- `table_append_text_column`
|
1735
|
-
- `table_model_row_changed`
|
1736
|
-
- `table_model_row_deleted`
|
1737
|
-
- `table_model_row_inserted`
|
1738
|
-
- `table_value_color`
|
1739
|
-
- `table_value_get_type`
|
1740
|
-
- `table_value_image`
|
1741
|
-
- `table_value_int`
|
1742
|
-
- `table_value_string`
|
1743
|
-
- `timer`
|
1744
|
-
- `uninit`
|
1745
|
-
- `user_bug_cannot_set_parent_on_toplevel`
|
1746
|
-
- `window_borderless`
|
1747
|
-
- `window_content_size`
|
1748
|
-
- `window_fullscreen`
|
1749
|
-
- `window_margined`
|
1750
|
-
- `window_on_closing`
|
1751
|
-
- `window_on_content_size_changed`
|
1752
|
-
- `window_set_borderless`
|
1753
|
-
- `window_set_child`
|
1754
|
-
- `window_set_content_size`
|
1755
|
-
- `window_set_fullscreen`
|
1756
|
-
- `window_set_margined`
|
1757
|
-
- `window_set_title`
|
1758
|
-
- `window_title`
|
1795
|
+
`alloc_control`, `append_features`, `area_begin_user_window_move`, `area_begin_user_window_resize`, `area_queue_redraw_all`, `area_scroll_to`, `area_set_size`, `attribute_color`, `attribute_family`, `attribute_features`, `attribute_get_type`, `attribute_italic`, `attribute_size`, `attribute_stretch`, `attribute_underline`, `attribute_underline_color`, `attribute_weight`, `attributed_string_append_unattributed`, `attributed_string_byte_index_to_grapheme`, `attributed_string_delete`, `attributed_string_for_each_attribute`, `attributed_string_grapheme_to_byte_index`, `attributed_string_insert_at_unattributed`, `attributed_string_len`, `attributed_string_num_graphemes`, `attributed_string_set_attribute`, `attributed_string_string`, `box_append`, `box_delete`, `box_padded`, `box_set_padded`, `button_on_clicked`, `button_set_text`, `button_text`, `checkbox_checked`, `checkbox_on_toggled`, `checkbox_set_checked`, `checkbox_set_text`, `checkbox_text`, `color_button_color`, `color_button_on_changed`, `color_button_set_color`, `combobox_append`, `combobox_on_selected`, `combobox_selected`, `combobox_set_selected`, `control_destroy`, `control_disable`, `control_enable`, `control_enabled`, `control_enabled_to_user`, `control_handle`, `control_hide`, `control_parent`, `control_set_parent`, `control_show`, `control_toplevel`, `control_verify_set_parent`, `control_visible`, `date_time_picker_on_changed`, `date_time_picker_set_time`, `date_time_picker_time`, `draw_clip`, `draw_fill`, `draw_free_path`, `draw_free_text_layout`, `draw_matrix_invert`, `draw_matrix_invertible`, `draw_matrix_multiply`, `draw_matrix_rotate`, `draw_matrix_scale`, `draw_matrix_set_identity`, `draw_matrix_skew`, `draw_matrix_transform_point`, `draw_matrix_transform_size`, `draw_matrix_translate`, `draw_new_path`, `draw_new_text_layout`, `draw_path_add_rectangle`, `draw_path_arc_to`, `draw_path_bezier_to`, `draw_path_close_figure`, `draw_path_end`, `draw_path_line_to`, `draw_path_new_figure`, `draw_path_new_figure_with_arc`, `draw_restore`, `draw_save`, `draw_stroke`, `draw_text`, `draw_text_layout_extents`, `draw_transform`, `editable_combobox_append`, `editable_combobox_on_changed`, `editable_combobox_set_text`, `editable_combobox_text`, `entry_on_changed`, `entry_read_only`, `entry_set_read_only`, `entry_set_text`, `entry_text`, `ffi_lib`, `ffi_lib=`, `font_button_font`, `font_button_on_changed`, `form_append`, `form_delete`, `form_padded`, `form_set_padded`, `free_attribute`, `free_attributed_string`, `free_control`, `free_font_button_font`, `free_image`, `free_init_error`, `free_open_type_features`, `free_table_model`, `free_table_value`, `free_text`, `grid_append`, `grid_insert_at`, `grid_padded`, `grid_set_padded`, `group_margined`, `group_set_child`, `group_set_margined`, `group_set_title`, `group_title`, `image_append`, `init`, `label_set_text`, `label_text`, `main`, `main_step`, `main_steps`, `menu_append_about_item`, `menu_append_check_item`, `menu_append_item`, `menu_append_preferences_item`, `menu_append_quit_item`, `menu_append_separator`, `menu_item_checked`, `menu_item_disable`, `menu_item_enable`, `menu_item_on_clicked`, `menu_item_set_checked`, `msg_box`, `msg_box_error`, `multiline_entry_append`, `multiline_entry_on_changed`, `multiline_entry_read_only`, `multiline_entry_set_read_only`, `multiline_entry_set_text`, `multiline_entry_text`, `new_area`, `new_attributed_string`, `new_background_attribute`, `new_button`, `new_checkbox`, `new_color_attribute`, `new_color_button`, `new_combobox`, `new_date_picker`, `new_date_time_picker`, `new_editable_combobox`, `new_entry`, `new_family_attribute`, `new_features_attribute`, `new_font_button`, `new_form`, `new_grid`, `new_group`, `new_horizontal_box`, `new_horizontal_separator`, `new_image`, `new_italic_attribute`, `new_label`, `new_menu`, `new_multiline_entry`, `new_non_wrapping_multiline_entry`, `new_open_type_features`, `new_password_entry`, `new_progress_bar`, `new_radio_buttons`, `new_scrolling_area`, `new_search_entry`, `new_size_attribute`, `new_slider`, `new_spinbox`, `new_stretch_attribute`, `new_tab`, `new_table`, `new_table_model`, `new_table_value_color`, `new_table_value_image`, `new_table_value_int`, `new_table_value_string`, `new_time_picker`, `new_underline_attribute`, `new_underline_color_attribute`, `new_vertical_box`, `new_vertical_separator`, `new_weight_attribute`, `new_window`, `on_should_quit`, `open_file`, `open_type_features_add`, `open_type_features_clone`, `open_type_features_for_each`, `open_type_features_get`, `open_type_features_remove`, `progress_bar_set_value`, `progress_bar_value`, `queue_main`, `quit`, `radio_buttons_append`, `radio_buttons_on_selected`, `radio_buttons_selected`, `radio_buttons_set_selected`, `save_file`, `slider_on_changed`, `slider_set_value`, `slider_value`, `spinbox_on_changed`, `spinbox_set_value`, `spinbox_value`, `tab_append`, `tab_delete`, `tab_insert_at`, `tab_margined`, `tab_num_pages`, `tab_set_margined`, `table_append_button_column`, `table_append_checkbox_column`, `table_append_checkbox_text_column`, `table_append_image_column`, `table_append_image_text_column`, `table_append_progress_bar_column`, `table_append_text_column`, `table_model_row_changed`, `table_model_row_deleted`, `table_model_row_inserted`, `table_value_color`, `table_value_get_type`, `table_value_image`, `table_value_int`, `table_value_string`, `timer`, `uninit`, `user_bug_cannot_set_parent_on_toplevel`, `window_borderless`, `window_content_size`, `window_fullscreen`, `window_margined`, `window_on_closing`, `window_on_content_size_changed`, `window_set_borderless`, `window_set_child`, `window_set_content_size`, `window_set_fullscreen`, `window_set_margined`, `window_set_title`, `window_title`
|
1759
1796
|
|
1760
1797
|
To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed through [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui):
|
1761
1798
|
- Check out [LibUI ffi.rb](https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb)
|
@@ -3064,7 +3101,44 @@ UI.main
|
|
3064
3101
|
UI.quit
|
3065
3102
|
```
|
3066
3103
|
|
3067
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3104
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3105
|
+
|
3106
|
+
```ruby
|
3107
|
+
# frozen_string_literal: true
|
3108
|
+
|
3109
|
+
# NOTE:
|
3110
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3111
|
+
|
3112
|
+
require 'glimmer-dsl-libui'
|
3113
|
+
|
3114
|
+
include Glimmer
|
3115
|
+
|
3116
|
+
IMAGE_ROWS = []
|
3117
|
+
|
3118
|
+
50.times do |i|
|
3119
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3120
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3121
|
+
IMAGE_ROWS << [url] # array of one column cell
|
3122
|
+
rescue StandardError => e
|
3123
|
+
warn url, e.message
|
3124
|
+
end
|
3125
|
+
|
3126
|
+
window('The Red Turtle', 310, 350, false) {
|
3127
|
+
horizontal_box {
|
3128
|
+
table {
|
3129
|
+
image_column('www.ghibli.jp/works/red-turtle')
|
3130
|
+
|
3131
|
+
cell_rows IMAGE_ROWS
|
3132
|
+
}
|
3133
|
+
}
|
3134
|
+
|
3135
|
+
on_closing do
|
3136
|
+
puts 'Bye Bye'
|
3137
|
+
end
|
3138
|
+
}.show
|
3139
|
+
```
|
3140
|
+
|
3141
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
3068
3142
|
|
3069
3143
|
```ruby
|
3070
3144
|
# NOTE:
|
@@ -3099,7 +3173,7 @@ window('The Red Turtle', 310, 350, false) {
|
|
3099
3173
|
}.show
|
3100
3174
|
```
|
3101
3175
|
|
3102
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3176
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (manual construction of `image` from `image_part`):
|
3103
3177
|
|
3104
3178
|
```ruby
|
3105
3179
|
# NOTE:
|
@@ -3167,7 +3241,44 @@ Mac | Windows | Linux
|
|
3167
3241
|
----|---------|------
|
3168
3242
|
![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)
|
3169
3243
|
|
3170
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3244
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3245
|
+
|
3246
|
+
```ruby
|
3247
|
+
# frozen_string_literal: true
|
3248
|
+
|
3249
|
+
# NOTE:
|
3250
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3251
|
+
|
3252
|
+
require 'glimmer-dsl-libui'
|
3253
|
+
|
3254
|
+
include Glimmer
|
3255
|
+
|
3256
|
+
IMAGE_ROWS = []
|
3257
|
+
|
3258
|
+
5.times do |i|
|
3259
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3260
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3261
|
+
text = url.sub('https://www.ghibli.jp/gallery/thumb-redturtle', '').sub('.png', '')
|
3262
|
+
IMAGE_ROWS << [[url, text], [url, text]] # cell values are dual-element arrays
|
3263
|
+
rescue StandardError => e
|
3264
|
+
warn url, e.message
|
3265
|
+
end
|
3266
|
+
|
3267
|
+
window('The Red Turtle', 670, 350) {
|
3268
|
+
horizontal_box {
|
3269
|
+
table {
|
3270
|
+
image_text_column('image/number')
|
3271
|
+
image_text_column('image/number (editable)') {
|
3272
|
+
editable true
|
3273
|
+
}
|
3274
|
+
|
3275
|
+
cell_rows IMAGE_ROWS
|
3276
|
+
}
|
3277
|
+
}
|
3278
|
+
}.show
|
3279
|
+
```
|
3280
|
+
|
3281
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
3171
3282
|
|
3172
3283
|
```ruby
|
3173
3284
|
# NOTE:
|
@@ -3272,22 +3383,28 @@ Mac | Windows | Linux
|
|
3272
3383
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
3273
3384
|
|
3274
3385
|
```ruby
|
3275
|
-
# frozen_string_literal: true
|
3276
|
-
|
3277
3386
|
require 'glimmer-dsl-libui'
|
3278
3387
|
|
3279
3388
|
class BasicTableButton
|
3389
|
+
BasicAnimal = Struct.new(:name, :sound)
|
3390
|
+
|
3391
|
+
class Animal < BasicAnimal
|
3392
|
+
def action
|
3393
|
+
'delete'
|
3394
|
+
end
|
3395
|
+
end
|
3396
|
+
|
3280
3397
|
include Glimmer
|
3281
3398
|
|
3282
|
-
attr_accessor :
|
3399
|
+
attr_accessor :animals
|
3283
3400
|
|
3284
3401
|
def initialize
|
3285
|
-
@
|
3286
|
-
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3290
|
-
|
3402
|
+
@animals = [
|
3403
|
+
Animal.new('cat', 'meow'),
|
3404
|
+
Animal.new('dog', 'woof'),
|
3405
|
+
Animal.new('chicken', 'cock-a-doodle-doo'),
|
3406
|
+
Animal.new('horse', 'neigh'),
|
3407
|
+
Animal.new('cow', 'moo'),
|
3291
3408
|
]
|
3292
3409
|
end
|
3293
3410
|
|
@@ -3300,17 +3417,19 @@ class BasicTableButton
|
|
3300
3417
|
button_column('Action') {
|
3301
3418
|
on_clicked do |row|
|
3302
3419
|
# Option 1: direct data deletion is the simpler solution
|
3303
|
-
# @
|
3420
|
+
# @animals.delete_at(row) # automatically deletes actual table row due to explicit data-binding
|
3304
3421
|
|
3305
|
-
# Option 2: cloning only to demonstrate table row deletion upon explicit setting of
|
3306
|
-
|
3307
|
-
|
3308
|
-
self.
|
3422
|
+
# Option 2: cloning only to demonstrate table row deletion upon explicit setting of animals attribute (cloning is not recommended beyond demonstrating this point)
|
3423
|
+
new_animals = @animals.clone
|
3424
|
+
new_animals.delete_at(row)
|
3425
|
+
self.animals = new_animals # automatically loses deleted table row due to explicit data-binding
|
3309
3426
|
end
|
3310
3427
|
}
|
3311
3428
|
|
3312
|
-
cell_rows <=> [self, :data] # explicit data-binding of table cell_rows to self.data
|
3313
3429
|
|
3430
|
+
cell_rows <= [self, :animals, column_attributes: {'Animal' => :name, 'Description' => :sound}]
|
3431
|
+
|
3432
|
+
# explicit unidirectional data-binding of table cell_rows to self.animals
|
3314
3433
|
on_changed do |row, type, row_data|
|
3315
3434
|
puts "Row #{row} #{type}: #{row_data}"
|
3316
3435
|
$stdout.flush
|
@@ -3533,16 +3652,126 @@ Mac | Windows | Linux
|
|
3533
3652
|
----|---------|------
|
3534
3653
|
![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)
|
3535
3654
|
|
3536
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3655
|
+
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):
|
3537
3656
|
|
3538
3657
|
```ruby
|
3539
|
-
|
3658
|
+
require 'glimmer-dsl-libui'
|
3540
3659
|
|
3660
|
+
class BasicTableColor
|
3661
|
+
Animal = Struct.new(:name, :sound, :mammal)
|
3662
|
+
|
3663
|
+
class AnimalPresenter < Animal
|
3664
|
+
def name_color
|
3665
|
+
color = case name
|
3666
|
+
when 'cat'
|
3667
|
+
:red
|
3668
|
+
when 'dog'
|
3669
|
+
:yellow
|
3670
|
+
when 'chicken'
|
3671
|
+
:beige
|
3672
|
+
when 'horse'
|
3673
|
+
:purple
|
3674
|
+
when 'cow'
|
3675
|
+
:gray
|
3676
|
+
end
|
3677
|
+
[name, color]
|
3678
|
+
end
|
3679
|
+
|
3680
|
+
def sound_color
|
3681
|
+
color = case name
|
3682
|
+
when 'cat', 'chicken', 'cow'
|
3683
|
+
:blue
|
3684
|
+
when 'dog', 'horse'
|
3685
|
+
{r: 240, g: 32, b: 32}
|
3686
|
+
end
|
3687
|
+
[sound, color]
|
3688
|
+
end
|
3689
|
+
|
3690
|
+
def mammal_description_color
|
3691
|
+
color = case name
|
3692
|
+
when 'cat', 'dog', 'horse', 'cow'
|
3693
|
+
:green
|
3694
|
+
when 'chicken'
|
3695
|
+
:red
|
3696
|
+
end
|
3697
|
+
[mammal, 'mammal', color]
|
3698
|
+
end
|
3699
|
+
|
3700
|
+
def image_description_color
|
3701
|
+
color = case name
|
3702
|
+
when 'cat', 'dog', 'horse'
|
3703
|
+
:dark_blue
|
3704
|
+
when 'chicken'
|
3705
|
+
:beige
|
3706
|
+
when 'cow'
|
3707
|
+
:brown
|
3708
|
+
end
|
3709
|
+
[img, 'Glimmer', color]
|
3710
|
+
end
|
3711
|
+
|
3712
|
+
def img
|
3713
|
+
# scale image to 24x24 (can be passed as file path String only instead of Array to avoid scaling)
|
3714
|
+
[File.expand_path('../icons/glimmer.png', __dir__), 24, 24]
|
3715
|
+
end
|
3716
|
+
|
3717
|
+
def background_color
|
3718
|
+
case name
|
3719
|
+
when 'cat'
|
3720
|
+
{r: 255, g: 120, b: 0, a: 0.5}
|
3721
|
+
when 'dog'
|
3722
|
+
:skyblue
|
3723
|
+
when 'chicken'
|
3724
|
+
{r: 5, g: 120, b: 110}
|
3725
|
+
when 'horse'
|
3726
|
+
'#13a1fb'
|
3727
|
+
when 'cow'
|
3728
|
+
0x12ff02
|
3729
|
+
end
|
3730
|
+
end
|
3731
|
+
end
|
3732
|
+
|
3733
|
+
include Glimmer
|
3734
|
+
|
3735
|
+
attr_accessor :animals
|
3736
|
+
|
3737
|
+
def initialize
|
3738
|
+
@animals = [
|
3739
|
+
AnimalPresenter.new('cat', 'meow', true),
|
3740
|
+
AnimalPresenter.new('dog', 'woof', true),
|
3741
|
+
AnimalPresenter.new('chicken', 'cock-a-doodle-doo', false),
|
3742
|
+
AnimalPresenter.new('horse', 'neigh', true),
|
3743
|
+
AnimalPresenter.new('cow', 'moo', true),
|
3744
|
+
]
|
3745
|
+
end
|
3746
|
+
|
3747
|
+
def launch
|
3748
|
+
window('Animals', 500, 200) {
|
3749
|
+
horizontal_box {
|
3750
|
+
table {
|
3751
|
+
text_color_column('Animal')
|
3752
|
+
text_color_column('Sound')
|
3753
|
+
checkbox_text_color_column('Description')
|
3754
|
+
image_text_color_column('GUI')
|
3755
|
+
background_color_column # must always be the last column and always expects data-binding model attribute `background_color` when binding to Array of models
|
3756
|
+
|
3757
|
+
cell_rows <= [self, :animals, column_attributes: {'Animal' => :name_color, 'Sound' => :sound_color, 'Description' => :mammal_description_color, 'GUI' => :image_description_color}]
|
3758
|
+
}
|
3759
|
+
}
|
3760
|
+
}.show
|
3761
|
+
end
|
3762
|
+
end
|
3763
|
+
|
3764
|
+
BasicTableColor.new.launch
|
3765
|
+
```
|
3766
|
+
|
3767
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with implicit [data-binding](#data-binding) to raw data rows):
|
3768
|
+
|
3769
|
+
```ruby
|
3541
3770
|
require 'glimmer-dsl-libui'
|
3542
3771
|
|
3543
3772
|
include Glimmer
|
3544
3773
|
|
3545
|
-
img =
|
3774
|
+
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)
|
3546
3775
|
|
3547
3776
|
data = [
|
3548
3777
|
[['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
|
@@ -3559,7 +3788,7 @@ window('Animals', 500, 200) {
|
|
3559
3788
|
text_color_column('Sound')
|
3560
3789
|
checkbox_text_color_column('Description')
|
3561
3790
|
image_text_color_column('GUI')
|
3562
|
-
background_color_column
|
3791
|
+
background_color_column # must be the last column
|
3563
3792
|
|
3564
3793
|
cell_rows data
|
3565
3794
|
}
|
@@ -3567,7 +3796,7 @@ window('Animals', 500, 200) {
|
|
3567
3796
|
}.show
|
3568
3797
|
```
|
3569
3798
|
|
3570
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3799
|
+
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`):
|
3571
3800
|
|
3572
3801
|
```ruby
|
3573
3802
|
require 'glimmer-dsl-libui'
|
@@ -3601,7 +3830,7 @@ window('Animals', 500, 200) {
|
|
3601
3830
|
text_color_column('Sound')
|
3602
3831
|
checkbox_text_color_column('Description')
|
3603
3832
|
image_text_color_column('GUI')
|
3604
|
-
background_color_column
|
3833
|
+
background_color_column
|
3605
3834
|
|
3606
3835
|
cell_rows data
|
3607
3836
|
}
|
@@ -3743,9 +3972,9 @@ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/
|
|
3743
3972
|
ruby -r glimmer-dsl-libui -e "require 'examples/basic_scrolling_area'"
|
3744
3973
|
```
|
3745
3974
|
|
3746
|
-
Mac | Linux
|
3747
|
-
|
3748
|
-
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-basic-scrolling-area.png) ![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-basic-scrolling-area.png) ![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-basic-scrolling-area-scrolled.png)
|
3975
|
+
Mac | Windows | Linux
|
3976
|
+
----|---------|------
|
3977
|
+
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-basic-scrolling-area.png) ![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-windows-dynamic-area.png](images/glimmer-dsl-libui-windows-basic-scrolling-area.png) ![glimmer-dsl-libui-windows-dynamic-area-updated.png](images/glimmer-dsl-libui-windows-basic-scrolling-area-scrolled.png) | ![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-basic-scrolling-area.png) ![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-basic-scrolling-area-scrolled.png)
|
3749
3978
|
|
3750
3979
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3751
3980
|
|
@@ -3832,6 +4061,8 @@ BasicScrollingArea.new.launch
|
|
3832
4061
|
|
3833
4062
|
#### Basic Image
|
3834
4063
|
|
4064
|
+
Please note the caveats of [Area Image](#area-image) **(Alpha Feature)** with regards to this example.
|
4065
|
+
|
3835
4066
|
[examples/basic_image.rb](examples/basic_image.rb)
|
3836
4067
|
|
3837
4068
|
Run with this command from the root of the project if you cloned the project:
|
@@ -5082,9 +5313,9 @@ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/
|
|
5082
5313
|
ruby -r glimmer-dsl-libui -e "require 'examples/button_counter'"
|
5083
5314
|
```
|
5084
5315
|
|
5085
|
-
Mac | Linux
|
5086
|
-
|
5087
|
-
![glimmer-dsl-libui-mac-button-counter.png](images/glimmer-dsl-libui-mac-button-counter.png) | ![glimmer-dsl-libui-linux-button-counter.png](images/glimmer-dsl-libui-linux-button-counter.png)
|
5316
|
+
Mac | Windows | Linux
|
5317
|
+
----|---------|------
|
5318
|
+
![glimmer-dsl-libui-mac-button-counter.png](images/glimmer-dsl-libui-mac-button-counter.png) | ![glimmer-dsl-libui-windows-button-counter.png](images/glimmer-dsl-libui-windows-button-counter.png) | ![glimmer-dsl-libui-linux-button-counter.png](images/glimmer-dsl-libui-linux-button-counter.png)
|
5088
5319
|
|
5089
5320
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5090
5321
|
|
@@ -5748,6 +5979,71 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
|
|
5748
5979
|
MAIN_WINDOW.show
|
5749
5980
|
```
|
5750
5981
|
|
5982
|
+
#### CPU Percentage
|
5983
|
+
|
5984
|
+
This example shows CPU usage percentage second by second.
|
5985
|
+
|
5986
|
+
Note that it is highly dependent on low-level OS terminal commands, so if anything changes in their output formatting, the code could break. Please report any issues you might encounter.
|
5987
|
+
|
5988
|
+
[examples/cpu_percentage.rb](examples/cpu_percentage.rb)
|
5989
|
+
|
5990
|
+
Run with this command from the root of the project if you cloned the project:
|
5991
|
+
|
5992
|
+
```
|
5993
|
+
ruby -r './lib/glimmer-dsl-libui' examples/cpu_percentage.rb
|
5994
|
+
```
|
5995
|
+
|
5996
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
5997
|
+
|
5998
|
+
```
|
5999
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/cpu_percentage'"
|
6000
|
+
```
|
6001
|
+
|
6002
|
+
Mac | Windows | Linux
|
6003
|
+
----|---------|------
|
6004
|
+
![glimmer-dsl-libui-mac-cpu-percentage.png](images/glimmer-dsl-libui-mac-cpu-percentage.png) | ![glimmer-dsl-libui-windows-cpu-percentage.png](images/glimmer-dsl-libui-windows-cpu-percentage.png) | ![glimmer-dsl-libui-linux-cpu-percentage.png](images/glimmer-dsl-libui-linux-cpu-percentage.png)
|
6005
|
+
|
6006
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6007
|
+
|
6008
|
+
```ruby
|
6009
|
+
require 'glimmer-dsl-libui'
|
6010
|
+
require 'bigdecimal'
|
6011
|
+
|
6012
|
+
include Glimmer
|
6013
|
+
|
6014
|
+
data = [
|
6015
|
+
['CPU', '0%', 0],
|
6016
|
+
]
|
6017
|
+
|
6018
|
+
Glimmer::LibUI.timer(1) do
|
6019
|
+
cpu_percentage_value = nil
|
6020
|
+
if OS.windows?
|
6021
|
+
cpu_percentage_raw_value = `wmic cpu get loadpercentage`
|
6022
|
+
cpu_percentage_value = cpu_percentage_raw_value.split("\n")[2].to_i
|
6023
|
+
elsif OS.mac?
|
6024
|
+
cpu_percentage_value = `ps -A -o %cpu | awk '{s+=$1} END {print s}'`.to_i
|
6025
|
+
elsif OS.linux?
|
6026
|
+
stats = `top -n 1`
|
6027
|
+
idle_percentage = stats.split("\n")[2].match(/ni,.* (.*) .*id/)[1]
|
6028
|
+
cpu_percentage_value = (BigDecimal(100) - BigDecimal(idle_percentage)).to_i
|
6029
|
+
end
|
6030
|
+
data[0][1] = "#{cpu_percentage_value}%"
|
6031
|
+
data[0][2] = cpu_percentage_value
|
6032
|
+
end
|
6033
|
+
|
6034
|
+
window('CPU Percentage', 400, 50) {
|
6035
|
+
vertical_box {
|
6036
|
+
table {
|
6037
|
+
text_column('Name')
|
6038
|
+
text_column('Value')
|
6039
|
+
progress_bar_column('Percentage')
|
6040
|
+
|
6041
|
+
cell_rows data # implicit data-binding
|
6042
|
+
}
|
6043
|
+
}
|
6044
|
+
}.show
|
6045
|
+
```
|
6046
|
+
|
5751
6047
|
#### Custom Draw Text
|
5752
6048
|
|
5753
6049
|
[examples/custom_draw_text.rb](examples/custom_draw_text.rb)
|
@@ -6458,8 +6754,8 @@ window('Editable animal sounds', 300, 200) {
|
|
6458
6754
|
text_column('Animal')
|
6459
6755
|
text_column('Description')
|
6460
6756
|
|
6461
|
-
cell_rows data
|
6462
6757
|
editable true
|
6758
|
+
cell_rows data
|
6463
6759
|
|
6464
6760
|
on_changed do |row, type, row_data| # fires on all changes (even ones happening through data array)
|
6465
6761
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -6474,30 +6770,382 @@ window('Editable animal sounds', 300, 200) {
|
|
6474
6770
|
on_closing do
|
6475
6771
|
puts 'Bye Bye'
|
6476
6772
|
end
|
6477
|
-
}.show
|
6478
|
-
```
|
6479
|
-
|
6480
|
-
#### Form Table
|
6481
|
-
|
6482
|
-
[examples/form_table.rb](examples/form_table.rb)
|
6483
|
-
|
6484
|
-
Run with this command from the root of the project if you cloned the project:
|
6485
|
-
|
6486
|
-
```
|
6487
|
-
ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
|
6488
|
-
```
|
6489
|
-
|
6490
|
-
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6773
|
+
}.show
|
6774
|
+
```
|
6775
|
+
|
6776
|
+
#### Form Table
|
6777
|
+
|
6778
|
+
[examples/form_table.rb](examples/form_table.rb)
|
6779
|
+
|
6780
|
+
Run with this command from the root of the project if you cloned the project:
|
6781
|
+
|
6782
|
+
```
|
6783
|
+
ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
|
6784
|
+
```
|
6785
|
+
|
6786
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6787
|
+
|
6788
|
+
```
|
6789
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
|
6790
|
+
```
|
6791
|
+
|
6792
|
+
Mac | Windows | Linux
|
6793
|
+
----|---------|------
|
6794
|
+
![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png) ![glimmer-dsl-libui-mac-form-table-contact-entered.png](images/glimmer-dsl-libui-mac-form-table-contact-entered.png) ![glimmer-dsl-libui-mac-form-table-filtered.png](images/glimmer-dsl-libui-mac-form-table-filtered.png) | ![glimmer-dsl-libui-windows-form-table.png](images/glimmer-dsl-libui-windows-form-table.png) ![glimmer-dsl-libui-windows-form-table-contact-entered.png](images/glimmer-dsl-libui-windows-form-table-contact-entered.png) ![glimmer-dsl-libui-windows-form-table-filtered.png](images/glimmer-dsl-libui-windows-form-table-filtered.png) | ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png) ![glimmer-dsl-libui-linux-form-table-contact-entered.png](images/glimmer-dsl-libui-linux-form-table-contact-entered.png) ![glimmer-dsl-libui-linux-form-table-filtered.png](images/glimmer-dsl-libui-linux-form-table-filtered.png)
|
6795
|
+
|
6796
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
6797
|
+
|
6798
|
+
```ruby
|
6799
|
+
require 'glimmer-dsl-libui'
|
6800
|
+
|
6801
|
+
class FormTable
|
6802
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
6803
|
+
|
6804
|
+
include Glimmer
|
6805
|
+
|
6806
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
6807
|
+
|
6808
|
+
def initialize
|
6809
|
+
@contacts = [
|
6810
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
6811
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
6812
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
6813
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
6814
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
6815
|
+
]
|
6816
|
+
end
|
6817
|
+
|
6818
|
+
def launch
|
6819
|
+
window('Contacts', 600, 600) { |w|
|
6820
|
+
margined true
|
6821
|
+
|
6822
|
+
vertical_box {
|
6823
|
+
form {
|
6824
|
+
stretchy false
|
6825
|
+
|
6826
|
+
entry {
|
6827
|
+
label 'Name'
|
6828
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6829
|
+
}
|
6830
|
+
|
6831
|
+
entry {
|
6832
|
+
label 'Email'
|
6833
|
+
text <=> [self, :email]
|
6834
|
+
}
|
6835
|
+
|
6836
|
+
entry {
|
6837
|
+
label 'Phone'
|
6838
|
+
text <=> [self, :phone]
|
6839
|
+
}
|
6840
|
+
|
6841
|
+
entry {
|
6842
|
+
label 'City'
|
6843
|
+
text <=> [self, :city]
|
6844
|
+
}
|
6845
|
+
|
6846
|
+
entry {
|
6847
|
+
label 'State'
|
6848
|
+
text <=> [self, :state]
|
6849
|
+
}
|
6850
|
+
}
|
6851
|
+
|
6852
|
+
button('Save Contact') {
|
6853
|
+
stretchy false
|
6854
|
+
|
6855
|
+
on_clicked do
|
6856
|
+
new_row = [name, email, phone, city, state]
|
6857
|
+
if new_row.include?('')
|
6858
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6859
|
+
else
|
6860
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
|
6861
|
+
@unfiltered_contacts = @contacts.dup
|
6862
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
6863
|
+
self.email = ''
|
6864
|
+
self.phone = ''
|
6865
|
+
self.city = ''
|
6866
|
+
self.state = ''
|
6867
|
+
end
|
6868
|
+
end
|
6869
|
+
}
|
6870
|
+
|
6871
|
+
search_entry {
|
6872
|
+
stretchy false
|
6873
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
6874
|
+
text <=> [self, :filter_value,
|
6875
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6876
|
+
@unfiltered_contacts ||= @contacts.dup
|
6877
|
+
# Unfilter first to remove any previous filters
|
6878
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
6879
|
+
# Now, apply filter if entered
|
6880
|
+
unless filter_value.empty?
|
6881
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
6882
|
+
contact.members.any? do |attribute|
|
6883
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
6884
|
+
end
|
6885
|
+
end
|
6886
|
+
end
|
6887
|
+
}
|
6888
|
+
]
|
6889
|
+
}
|
6890
|
+
|
6891
|
+
table {
|
6892
|
+
text_column('Name')
|
6893
|
+
text_column('Email')
|
6894
|
+
text_column('Phone')
|
6895
|
+
text_column('City')
|
6896
|
+
text_column('State')
|
6897
|
+
|
6898
|
+
editable true
|
6899
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array auto-inferring model attribute names from underscored table column names by convention
|
6900
|
+
|
6901
|
+
on_changed do |row, type, row_data|
|
6902
|
+
puts "Row #{row} #{type}: #{row_data}"
|
6903
|
+
end
|
6904
|
+
}
|
6905
|
+
}
|
6906
|
+
}.show
|
6907
|
+
end
|
6908
|
+
end
|
6909
|
+
|
6910
|
+
FormTable.new.launch
|
6911
|
+
```
|
6912
|
+
|
6913
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
6914
|
+
|
6915
|
+
```ruby
|
6916
|
+
require 'glimmer-dsl-libui'
|
6917
|
+
|
6918
|
+
class FormTable
|
6919
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
6920
|
+
|
6921
|
+
include Glimmer
|
6922
|
+
|
6923
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
6924
|
+
|
6925
|
+
def initialize
|
6926
|
+
@contacts = [
|
6927
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
6928
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
6929
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
6930
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
6931
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
6932
|
+
]
|
6933
|
+
end
|
6934
|
+
|
6935
|
+
def launch
|
6936
|
+
window('Contacts', 600, 600) { |w|
|
6937
|
+
margined true
|
6938
|
+
|
6939
|
+
vertical_box {
|
6940
|
+
form {
|
6941
|
+
stretchy false
|
6942
|
+
|
6943
|
+
entry {
|
6944
|
+
label 'Name'
|
6945
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6946
|
+
}
|
6947
|
+
|
6948
|
+
entry {
|
6949
|
+
label 'Email'
|
6950
|
+
text <=> [self, :email]
|
6951
|
+
}
|
6952
|
+
|
6953
|
+
entry {
|
6954
|
+
label 'Phone'
|
6955
|
+
text <=> [self, :phone]
|
6956
|
+
}
|
6957
|
+
|
6958
|
+
entry {
|
6959
|
+
label 'City'
|
6960
|
+
text <=> [self, :city]
|
6961
|
+
}
|
6962
|
+
|
6963
|
+
entry {
|
6964
|
+
label 'State'
|
6965
|
+
text <=> [self, :state]
|
6966
|
+
}
|
6967
|
+
}
|
6968
|
+
|
6969
|
+
button('Save Contact') {
|
6970
|
+
stretchy false
|
6971
|
+
|
6972
|
+
on_clicked do
|
6973
|
+
new_row = [name, email, phone, city, state]
|
6974
|
+
if new_row.include?('')
|
6975
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6976
|
+
else
|
6977
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
6978
|
+
@unfiltered_contacts = @contacts.dup
|
6979
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
6980
|
+
self.email = ''
|
6981
|
+
self.phone = ''
|
6982
|
+
self.city = ''
|
6983
|
+
self.state = ''
|
6984
|
+
end
|
6985
|
+
end
|
6986
|
+
}
|
6987
|
+
|
6988
|
+
search_entry {
|
6989
|
+
stretchy false
|
6990
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
6991
|
+
text <=> [self, :filter_value,
|
6992
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6993
|
+
@unfiltered_contacts ||= @contacts.dup
|
6994
|
+
# Unfilter first to remove any previous filters
|
6995
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
6996
|
+
# Now, apply filter if entered
|
6997
|
+
unless filter_value.empty?
|
6998
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
6999
|
+
contact.members.any? do |attribute|
|
7000
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
7001
|
+
end
|
7002
|
+
end
|
7003
|
+
end
|
7004
|
+
}
|
7005
|
+
]
|
7006
|
+
}
|
7007
|
+
|
7008
|
+
table {
|
7009
|
+
text_column('Name')
|
7010
|
+
text_column('Email')
|
7011
|
+
text_column('Phone')
|
7012
|
+
text_column('City')
|
7013
|
+
text_column('State/Province')
|
7014
|
+
|
7015
|
+
editable true
|
7016
|
+
cell_rows <=> [self, :contacts, column_attributes: {'State/Province' => :state}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
|
7017
|
+
|
7018
|
+
on_changed do |row, type, row_data|
|
7019
|
+
puts "Row #{row} #{type}: #{row_data}"
|
7020
|
+
end
|
7021
|
+
}
|
7022
|
+
}
|
7023
|
+
}.show
|
7024
|
+
end
|
7025
|
+
end
|
7026
|
+
|
7027
|
+
FormTable.new.launch
|
7028
|
+
```
|
7029
|
+
|
7030
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
7031
|
+
|
7032
|
+
```ruby
|
7033
|
+
|
7034
|
+
require 'glimmer-dsl-libui'
|
7035
|
+
|
7036
|
+
class FormTable
|
7037
|
+
Contact = Struct.new(:full_name, :email_address, :phone_number, :city_or_town, :state_or_province)
|
7038
|
+
|
7039
|
+
include Glimmer
|
7040
|
+
|
7041
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
7042
|
+
|
7043
|
+
def initialize
|
7044
|
+
@contacts = [
|
7045
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
7046
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
7047
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
7048
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
7049
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
7050
|
+
]
|
7051
|
+
end
|
7052
|
+
|
7053
|
+
def launch
|
7054
|
+
window('Contacts', 600, 600) { |w|
|
7055
|
+
margined true
|
7056
|
+
|
7057
|
+
vertical_box {
|
7058
|
+
form {
|
7059
|
+
stretchy false
|
7060
|
+
|
7061
|
+
entry {
|
7062
|
+
label 'Name'
|
7063
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
7064
|
+
}
|
7065
|
+
|
7066
|
+
entry {
|
7067
|
+
label 'Email'
|
7068
|
+
text <=> [self, :email]
|
7069
|
+
}
|
7070
|
+
|
7071
|
+
entry {
|
7072
|
+
label 'Phone'
|
7073
|
+
text <=> [self, :phone]
|
7074
|
+
}
|
7075
|
+
|
7076
|
+
entry {
|
7077
|
+
label 'City'
|
7078
|
+
text <=> [self, :city]
|
7079
|
+
}
|
7080
|
+
|
7081
|
+
entry {
|
7082
|
+
label 'State'
|
7083
|
+
text <=> [self, :state]
|
7084
|
+
}
|
7085
|
+
}
|
7086
|
+
|
7087
|
+
button('Save Contact') {
|
7088
|
+
stretchy false
|
7089
|
+
|
7090
|
+
on_clicked do
|
7091
|
+
new_row = [name, email, phone, city, state]
|
7092
|
+
if new_row.include?('')
|
7093
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
7094
|
+
else
|
7095
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
7096
|
+
@unfiltered_contacts = @contacts.dup
|
7097
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
7098
|
+
self.email = ''
|
7099
|
+
self.phone = ''
|
7100
|
+
self.city = ''
|
7101
|
+
self.state = ''
|
7102
|
+
end
|
7103
|
+
end
|
7104
|
+
}
|
7105
|
+
|
7106
|
+
search_entry {
|
7107
|
+
stretchy false
|
7108
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
7109
|
+
text <=> [self, :filter_value,
|
7110
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
7111
|
+
@unfiltered_contacts ||= @contacts.dup
|
7112
|
+
# Unfilter first to remove any previous filters
|
7113
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
7114
|
+
# Now, apply filter if entered
|
7115
|
+
unless filter_value.empty?
|
7116
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
7117
|
+
contact.members.any? do |attribute|
|
7118
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
7119
|
+
end
|
7120
|
+
end
|
7121
|
+
end
|
7122
|
+
}
|
7123
|
+
]
|
7124
|
+
}
|
7125
|
+
|
7126
|
+
table {
|
7127
|
+
text_column('Name')
|
7128
|
+
text_column('Email')
|
7129
|
+
text_column('Phone')
|
7130
|
+
text_column('City')
|
7131
|
+
text_column('State')
|
7132
|
+
|
7133
|
+
editable true
|
7134
|
+
cell_rows <=> [self, :contacts, column_attributes: [:full_name, :email_address, :phone_number, :city_or_town, :state_or_province]] # explicit data-binding to Model Array with column_attributes mapping for all columns
|
7135
|
+
|
7136
|
+
on_changed do |row, type, row_data|
|
7137
|
+
puts "Row #{row} #{type}: #{row_data}"
|
7138
|
+
end
|
7139
|
+
}
|
7140
|
+
}
|
7141
|
+
}.show
|
7142
|
+
end
|
7143
|
+
end
|
6491
7144
|
|
7145
|
+
FormTable.new.launch
|
6492
7146
|
```
|
6493
|
-
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
|
6494
|
-
```
|
6495
|
-
|
6496
|
-
Mac | Windows | Linux
|
6497
|
-
----|---------|------
|
6498
|
-
![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png) ![glimmer-dsl-libui-mac-form-table-contact-entered.png](images/glimmer-dsl-libui-mac-form-table-contact-entered.png) ![glimmer-dsl-libui-mac-form-table-filtered.png](images/glimmer-dsl-libui-mac-form-table-filtered.png) | ![glimmer-dsl-libui-windows-form-table.png](images/glimmer-dsl-libui-windows-form-table.png) ![glimmer-dsl-libui-windows-form-table-contact-entered.png](images/glimmer-dsl-libui-windows-form-table-contact-entered.png) ![glimmer-dsl-libui-windows-form-table-filtered.png](images/glimmer-dsl-libui-windows-form-table-filtered.png) | ![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png) ![glimmer-dsl-libui-linux-form-table-contact-entered.png](images/glimmer-dsl-libui-linux-form-table-contact-entered.png) ![glimmer-dsl-libui-linux-form-table-filtered.png](images/glimmer-dsl-libui-linux-form-table-filtered.png)
|
6499
7147
|
|
6500
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
7148
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (with explicit [data-binding](#data-binding) to raw data):
|
6501
7149
|
|
6502
7150
|
```ruby
|
6503
7151
|
require 'glimmer-dsl-libui'
|
@@ -6509,11 +7157,11 @@ class FormTable
|
|
6509
7157
|
|
6510
7158
|
def initialize
|
6511
7159
|
@data = [
|
6512
|
-
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'
|
6513
|
-
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'
|
6514
|
-
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'
|
6515
|
-
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'
|
6516
|
-
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'
|
7160
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
7161
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
7162
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
7163
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
7164
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
6517
7165
|
]
|
6518
7166
|
end
|
6519
7167
|
|
@@ -6527,7 +7175,7 @@ class FormTable
|
|
6527
7175
|
|
6528
7176
|
entry {
|
6529
7177
|
label 'Name'
|
6530
|
-
text <=> [self, :name]
|
7178
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6531
7179
|
}
|
6532
7180
|
|
6533
7181
|
entry {
|
@@ -6559,8 +7207,8 @@ class FormTable
|
|
6559
7207
|
if new_row.include?('')
|
6560
7208
|
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6561
7209
|
else
|
6562
|
-
|
6563
|
-
@unfiltered_data =
|
7210
|
+
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
7211
|
+
@unfiltered_data = data.dup
|
6564
7212
|
self.name = '' # automatically clears name entry through explicit data-binding
|
6565
7213
|
self.email = ''
|
6566
7214
|
self.phone = ''
|
@@ -6572,14 +7220,15 @@ class FormTable
|
|
6572
7220
|
|
6573
7221
|
search_entry {
|
6574
7222
|
stretchy false
|
6575
|
-
|
7223
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
7224
|
+
text <=> [self, :filter_value,
|
6576
7225
|
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6577
|
-
@unfiltered_data ||=
|
7226
|
+
@unfiltered_data ||= data.dup
|
6578
7227
|
# Unfilter first to remove any previous filters
|
6579
|
-
|
7228
|
+
data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
6580
7229
|
# Now, apply filter if entered
|
6581
7230
|
unless filter_value.empty?
|
6582
|
-
|
7231
|
+
data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
6583
7232
|
row_data.any? do |cell|
|
6584
7233
|
cell.to_s.downcase.include?(filter_value.downcase)
|
6585
7234
|
end
|
@@ -6595,8 +7244,9 @@ class FormTable
|
|
6595
7244
|
text_column('Phone')
|
6596
7245
|
text_column('City')
|
6597
7246
|
text_column('State')
|
6598
|
-
|
6599
|
-
|
7247
|
+
|
7248
|
+
editable true
|
7249
|
+
cell_rows <=> [self, :data] # explicit data-binding to raw data Array of Arrays
|
6600
7250
|
|
6601
7251
|
on_changed do |row, type, row_data|
|
6602
7252
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -6610,7 +7260,7 @@ end
|
|
6610
7260
|
FormTable.new.launch
|
6611
7261
|
```
|
6612
7262
|
|
6613
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
7263
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 5 (with implicit [data-binding](#data-binding)):
|
6614
7264
|
|
6615
7265
|
```ruby
|
6616
7266
|
require 'glimmer-dsl-libui'
|
@@ -6618,11 +7268,11 @@ require 'glimmer-dsl-libui'
|
|
6618
7268
|
include Glimmer
|
6619
7269
|
|
6620
7270
|
data = [
|
6621
|
-
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'
|
6622
|
-
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'
|
6623
|
-
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'
|
6624
|
-
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'
|
6625
|
-
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'
|
7271
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
7272
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
7273
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
7274
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
7275
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
6626
7276
|
]
|
6627
7277
|
|
6628
7278
|
window('Contacts', 600, 600) { |w|
|
@@ -6698,7 +7348,8 @@ window('Contacts', 600, 600) { |w|
|
|
6698
7348
|
text_column('City')
|
6699
7349
|
text_column('State')
|
6700
7350
|
|
6701
|
-
|
7351
|
+
editable true
|
7352
|
+
cell_rows data # implicit data-binding to raw data Array of Arrays
|
6702
7353
|
|
6703
7354
|
on_changed do |row, type, row_data|
|
6704
7355
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -8234,7 +8885,7 @@ Mac | Windows | Linux
|
|
8234
8885
|
----|---------|------
|
8235
8886
|
![glimmer-dsl-libui-mac-snake.png](images/glimmer-dsl-libui-mac-snake.png) ![glimmer-dsl-libui-mac-snake-game-over.png](images/glimmer-dsl-libui-mac-snake-game-over.png) | ![glimmer-dsl-libui-windows-snake.png](images/glimmer-dsl-libui-windows-snake.png) ![glimmer-dsl-libui-windows-snake-game-over.png](images/glimmer-dsl-libui-windows-snake-game-over.png) | ![glimmer-dsl-libui-linux-snake.png](images/glimmer-dsl-libui-linux-snake.png) ![glimmer-dsl-libui-linux-snake-game-over.png](images/glimmer-dsl-libui-linux-snake-game-over.png)
|
8236
8887
|
|
8237
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
8888
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
8238
8889
|
|
8239
8890
|
```ruby
|
8240
8891
|
require 'glimmer-dsl-libui'
|
@@ -8326,6 +8977,108 @@ end
|
|
8326
8977
|
Snake.new.launch
|
8327
8978
|
```
|
8328
8979
|
|
8980
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
8981
|
+
|
8982
|
+
```ruby
|
8983
|
+
require 'glimmer-dsl-libui'
|
8984
|
+
|
8985
|
+
require_relative 'snake/presenter/grid'
|
8986
|
+
|
8987
|
+
class Snake
|
8988
|
+
include Glimmer
|
8989
|
+
|
8990
|
+
CELL_SIZE = 15
|
8991
|
+
SNAKE_MOVE_DELAY = 0.1
|
8992
|
+
|
8993
|
+
def initialize
|
8994
|
+
@game = Model::Game.new
|
8995
|
+
@grid = Presenter::Grid.new(@game)
|
8996
|
+
@game.start
|
8997
|
+
@keypress_queue = []
|
8998
|
+
create_gui
|
8999
|
+
register_observers
|
9000
|
+
end
|
9001
|
+
|
9002
|
+
def launch
|
9003
|
+
@main_window.show
|
9004
|
+
end
|
9005
|
+
|
9006
|
+
def register_observers
|
9007
|
+
@game.height.times do |row|
|
9008
|
+
@game.width.times do |column|
|
9009
|
+
observe(@grid.cells[row][column], :color) do |new_color|
|
9010
|
+
@cell_grid[row][column].fill = new_color
|
9011
|
+
end
|
9012
|
+
end
|
9013
|
+
end
|
9014
|
+
|
9015
|
+
observe(@game, :over) do |game_over|
|
9016
|
+
Glimmer::LibUI.queue_main do
|
9017
|
+
if game_over
|
9018
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
9019
|
+
@game.start
|
9020
|
+
end
|
9021
|
+
end
|
9022
|
+
end
|
9023
|
+
|
9024
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
9025
|
+
unless @game.over?
|
9026
|
+
process_queued_keypress
|
9027
|
+
@game.snake.move
|
9028
|
+
end
|
9029
|
+
end
|
9030
|
+
end
|
9031
|
+
|
9032
|
+
def process_queued_keypress
|
9033
|
+
# key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
|
9034
|
+
key = @keypress_queue.shift
|
9035
|
+
case [@game.snake.head.orientation, key]
|
9036
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
9037
|
+
@game.snake.turn_right
|
9038
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
9039
|
+
@game.snake.turn_left
|
9040
|
+
else
|
9041
|
+
# No Op
|
9042
|
+
end
|
9043
|
+
end
|
9044
|
+
|
9045
|
+
def create_gui
|
9046
|
+
@cell_grid = []
|
9047
|
+
@main_window = window {
|
9048
|
+
# data-bind window title to game score, converting it to a title string on read from the model
|
9049
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
9050
|
+
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
9051
|
+
resizable false
|
9052
|
+
|
9053
|
+
vertical_box {
|
9054
|
+
padded false
|
9055
|
+
|
9056
|
+
@game.height.times do |row|
|
9057
|
+
@cell_grid << []
|
9058
|
+
horizontal_box {
|
9059
|
+
padded false
|
9060
|
+
|
9061
|
+
@game.width.times do |column|
|
9062
|
+
area {
|
9063
|
+
@cell_grid.last << square(0, 0, CELL_SIZE) {
|
9064
|
+
fill Presenter::Cell::COLOR_CLEAR
|
9065
|
+
}
|
9066
|
+
|
9067
|
+
on_key_up do |area_key_event|
|
9068
|
+
@keypress_queue << area_key_event[:ext_key]
|
9069
|
+
end
|
9070
|
+
}
|
9071
|
+
end
|
9072
|
+
}
|
9073
|
+
end
|
9074
|
+
}
|
9075
|
+
}
|
9076
|
+
end
|
9077
|
+
end
|
9078
|
+
|
9079
|
+
Snake.new.launch
|
9080
|
+
```
|
9081
|
+
|
8329
9082
|
#### Tetris
|
8330
9083
|
|
8331
9084
|
Glimmer Tetris utilizes many small areas to represent Tetromino blocks because this ensures smaller redraws per tetromino block color change, thus achieving higher performance than redrawing one large area on every little change.
|
@@ -8741,7 +9494,7 @@ Mac | Windows | Linux
|
|
8741
9494
|
----|---------|------
|
8742
9495
|
![glimmer-dsl-libui-mac-tic-tac-toe.png](images/glimmer-dsl-libui-mac-tic-tac-toe.png) ![glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-o-wins.png) ![glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-mac-tic-tac-toe-player-x-wins.png) ![glimmer-dsl-libui-mac-tic-tac-toe-draw.png](images/glimmer-dsl-libui-mac-tic-tac-toe-draw.png) | ![glimmer-dsl-libui-windows-tic-tac-toe.png](images/glimmer-dsl-libui-windows-tic-tac-toe.png) ![glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png) ![glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png) ![glimmer-dsl-libui-windows-tic-tac-toe-draw.png](images/glimmer-dsl-libui-windows-tic-tac-toe-draw.png) | ![glimmer-dsl-libui-linux-tic-tac-toe.png](images/glimmer-dsl-libui-linux-tic-tac-toe.png) ![glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png) ![glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png) ![glimmer-dsl-libui-linux-tic-tac-toe-draw.png](images/glimmer-dsl-libui-linux-tic-tac-toe-draw.png)
|
8743
9496
|
|
8744
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
9497
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
8745
9498
|
|
8746
9499
|
```ruby
|
8747
9500
|
require 'glimmer-dsl-libui'
|
@@ -8787,6 +9540,7 @@ class TicTacToe
|
|
8787
9540
|
text(23, 19) {
|
8788
9541
|
string {
|
8789
9542
|
font family: 'Arial', size: OS.mac? ? 20 : 16
|
9543
|
+
# data-bind string property of area text attributed string to tic tac toe board cell sign
|
8790
9544
|
string <= [@tic_tac_toe_board[row + 1, column + 1], :sign] # board model is 1-based
|
8791
9545
|
}
|
8792
9546
|
}
|
@@ -8820,6 +9574,95 @@ end
|
|
8820
9574
|
TicTacToe.new.launch
|
8821
9575
|
```
|
8822
9576
|
|
9577
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
9578
|
+
|
9579
|
+
```ruby
|
9580
|
+
|
9581
|
+
require 'glimmer-dsl-libui'
|
9582
|
+
|
9583
|
+
require_relative "tic_tac_toe/board"
|
9584
|
+
|
9585
|
+
class TicTacToe
|
9586
|
+
include Glimmer
|
9587
|
+
|
9588
|
+
def initialize
|
9589
|
+
@tic_tac_toe_board = Board.new
|
9590
|
+
end
|
9591
|
+
|
9592
|
+
def launch
|
9593
|
+
create_gui
|
9594
|
+
register_observers
|
9595
|
+
@main_window.show
|
9596
|
+
end
|
9597
|
+
|
9598
|
+
def register_observers
|
9599
|
+
observe(@tic_tac_toe_board, :game_status) do |game_status|
|
9600
|
+
display_win_message if game_status == Board::WIN
|
9601
|
+
display_draw_message if game_status == Board::DRAW
|
9602
|
+
end
|
9603
|
+
|
9604
|
+
3.times.map do |row|
|
9605
|
+
3.times.map do |column|
|
9606
|
+
observe(@tic_tac_toe_board[row + 1, column + 1], :sign) do |sign| # board model is 1-based
|
9607
|
+
@cells[row][column].string = sign
|
9608
|
+
end
|
9609
|
+
end
|
9610
|
+
end
|
9611
|
+
end
|
9612
|
+
|
9613
|
+
def create_gui
|
9614
|
+
@main_window = window('Tic-Tac-Toe', 180, 180) {
|
9615
|
+
resizable false
|
9616
|
+
|
9617
|
+
@cells = []
|
9618
|
+
vertical_box {
|
9619
|
+
padded false
|
9620
|
+
|
9621
|
+
3.times.map do |row|
|
9622
|
+
@cells << []
|
9623
|
+
horizontal_box {
|
9624
|
+
padded false
|
9625
|
+
|
9626
|
+
3.times.map do |column|
|
9627
|
+
area {
|
9628
|
+
square(0, 0, 60) {
|
9629
|
+
stroke :black, thickness: 2
|
9630
|
+
}
|
9631
|
+
text(23, 19) {
|
9632
|
+
@cells[row] << string('') {
|
9633
|
+
font family: 'Arial', size: OS.mac? ? 20 : 16
|
9634
|
+
}
|
9635
|
+
}
|
9636
|
+
on_mouse_up do
|
9637
|
+
@tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
|
9638
|
+
end
|
9639
|
+
}
|
9640
|
+
end
|
9641
|
+
}
|
9642
|
+
end
|
9643
|
+
}
|
9644
|
+
}
|
9645
|
+
end
|
9646
|
+
|
9647
|
+
def display_win_message
|
9648
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
9649
|
+
end
|
9650
|
+
|
9651
|
+
def display_draw_message
|
9652
|
+
display_game_over_message("Draw!")
|
9653
|
+
end
|
9654
|
+
|
9655
|
+
def display_game_over_message(message_text)
|
9656
|
+
Glimmer::LibUI.queue_main do
|
9657
|
+
msg_box('Game Over', message_text)
|
9658
|
+
@tic_tac_toe_board.reset!
|
9659
|
+
end
|
9660
|
+
end
|
9661
|
+
end
|
9662
|
+
|
9663
|
+
TicTacToe.new.launch
|
9664
|
+
```
|
9665
|
+
|
8823
9666
|
#### Timer
|
8824
9667
|
|
8825
9668
|
To run this example, install [TiMidity](http://timidity.sourceforge.net) and ensure `timidity` command is in `PATH` (can be installed via [Homebrew](https://brew.sh) on Mac or [apt-get](https://help.ubuntu.com/community/AptGet/Howto) on Linux).
|