glimmer-dsl-libui 0.4.8 → 0.4.12
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 +1361 -461
- 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/snake.rb +19 -10
- 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/checkbox_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/entry_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +5 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +1 -2
- 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 +34 -4
- 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.12
|
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.12'
|
377
504
|
```
|
378
505
|
|
379
|
-
|
506
|
+
Test that installation worked by running the [Meta-Example](#examples):
|
507
|
+
|
508
|
+
```
|
509
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/meta_example'"
|
510
|
+
```
|
511
|
+
|
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,120 +752,110 @@ 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
|
|
755
|
+
([explicit data-binding](#data-binding) supports everything available with implicit data-binding too)
|
756
|
+
|
618
757
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
619
758
|
|
620
759
|
```ruby
|
621
760
|
require 'glimmer-dsl-libui'
|
622
761
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
]
|
636
|
-
end
|
762
|
+
include Glimmer
|
763
|
+
|
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|
|
773
|
+
margined true
|
637
774
|
|
638
|
-
|
639
|
-
|
640
|
-
|
775
|
+
vertical_box {
|
776
|
+
form {
|
777
|
+
stretchy false
|
641
778
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
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'
|
797
|
+
}
|
798
|
+
}
|
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)
|
687
832
|
end
|
688
833
|
end
|
689
|
-
|
690
|
-
|
691
|
-
|
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')
|
834
|
+
end
|
835
|
+
end
|
836
|
+
}
|
716
837
|
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
}
|
724
|
-
}.show
|
725
|
-
end
|
726
|
-
end
|
838
|
+
table {
|
839
|
+
text_column('Name')
|
840
|
+
text_column('Email')
|
841
|
+
text_column('Phone')
|
842
|
+
text_column('City')
|
843
|
+
text_column('State')
|
727
844
|
|
728
|
-
|
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
|
729
854
|
```
|
730
855
|
|
731
|
-
|
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)
|
732
859
|
|
733
860
|
Learn more by checking out [examples](#examples).
|
734
861
|
|
@@ -798,9 +925,9 @@ 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
|
|
@@ -1216,6 +1343,7 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
|
|
1216
1343
|
- When destroying a control nested under a `horizontal_box` or `vertical_box`, it is automatically deleted from the box's children
|
1217
1344
|
- When destroying a control nested under a `form`, it is automatically deleted from the form's children
|
1218
1345
|
- When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
|
1346
|
+
- When destroying a control that has a data-binding to a model attribute, the data-binding observer registration is automatically deregistered
|
1219
1347
|
- 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
1348
|
- 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
1349
|
- 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`)
|
@@ -1381,6 +1509,8 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
|
|
1381
1509
|
|
1382
1510
|
![MVP](https://www.researchgate.net/profile/Gilles-Perrouin/publication/320249584/figure/fig8/AS:668260987068418@1536337243385/Model-view-presenter-architecture.png)
|
1383
1511
|
|
1512
|
+
#### Bidirectional (Two-Way) Data-Binding
|
1513
|
+
|
1384
1514
|
[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
1515
|
- `checkbox`: `checked`
|
1386
1516
|
- `check_menu_item`: `checked`
|
@@ -1398,27 +1528,184 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
|
|
1398
1528
|
- `search_entry`: `text`
|
1399
1529
|
- `slider`: `value`
|
1400
1530
|
- `spinbox`: `value`
|
1531
|
+
- `table`: `cell_rows` (explicit data-binding by using `<=>` and [implicit data-binding](#table-api) by assigning value directly)
|
1401
1532
|
- `time_picker`: `time`
|
1402
1533
|
|
1403
|
-
Example of bidirectional data-binding:
|
1534
|
+
Example of bidirectional data-binding:
|
1535
|
+
|
1536
|
+
```ruby
|
1537
|
+
entry {
|
1538
|
+
text <=> [contract, :legal_text]
|
1539
|
+
}
|
1540
|
+
```
|
1541
|
+
|
1542
|
+
That is data-binding a contract's legal text to an `entry` `text` property.
|
1543
|
+
|
1544
|
+
Another example of bidirectional data-binding with an option:
|
1545
|
+
|
1546
|
+
```ruby
|
1547
|
+
entry {
|
1548
|
+
text <=> [self, :entered_text, after_write: ->(text) {puts text}]
|
1549
|
+
}
|
1550
|
+
```
|
1551
|
+
|
1552
|
+
That is data-binding `entered_text` attribute on `self` to `entry` `text` property and printing text after write to the model.
|
1553
|
+
|
1554
|
+
##### Table Data-Binding
|
1555
|
+
|
1556
|
+
One note about `table` `cell_rows` data-binding is that it works with either:
|
1557
|
+
- Raw data `Array` (rows) of `Array`s (column cells)
|
1558
|
+
- 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.
|
1559
|
+
|
1560
|
+
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)):
|
1561
|
+
|
1562
|
+
```ruby
|
1563
|
+
require 'glimmer-dsl-libui'
|
1564
|
+
|
1565
|
+
include Glimmer
|
1566
|
+
|
1567
|
+
data = [
|
1568
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
1569
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
1570
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
1571
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
1572
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
1573
|
+
]
|
1574
|
+
|
1575
|
+
window('Contacts', 600, 600) {
|
1576
|
+
table {
|
1577
|
+
text_column('Name')
|
1578
|
+
text_column('Email')
|
1579
|
+
text_column('Phone')
|
1580
|
+
text_column('City')
|
1581
|
+
text_column('State')
|
1582
|
+
|
1583
|
+
cell_rows data
|
1584
|
+
}
|
1585
|
+
}.show
|
1586
|
+
```
|
1587
|
+
|
1588
|
+
Example of `table` explicit data-binding of `cell_rows` to Model `Array` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1589
|
+
|
1590
|
+
```ruby
|
1591
|
+
require 'glimmer-dsl-libui'
|
1592
|
+
|
1593
|
+
class SomeTable
|
1594
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1595
|
+
|
1596
|
+
include Glimmer
|
1597
|
+
|
1598
|
+
attr_accessor :contacts
|
1599
|
+
|
1600
|
+
def initialize
|
1601
|
+
@contacts = [
|
1602
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1603
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1604
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1605
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1606
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1607
|
+
]
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
def launch
|
1611
|
+
window('Contacts', 600, 200) {
|
1612
|
+
table {
|
1613
|
+
text_column('Name')
|
1614
|
+
text_column('Email')
|
1615
|
+
text_column('Phone')
|
1616
|
+
text_column('City')
|
1617
|
+
text_column('State')
|
1618
|
+
|
1619
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array auto-inferring model attribute names from underscored table column names by convention
|
1620
|
+
}
|
1621
|
+
}.show
|
1622
|
+
end
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
SomeTable.new.launch
|
1626
|
+
```
|
1627
|
+
|
1628
|
+
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)):
|
1404
1629
|
|
1405
1630
|
```ruby
|
1406
|
-
|
1407
|
-
text <=> [contract, :legal_text]
|
1408
|
-
}
|
1409
|
-
```
|
1631
|
+
require 'glimmer-dsl-libui'
|
1410
1632
|
|
1411
|
-
|
1633
|
+
class SomeTable
|
1634
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1635
|
+
|
1636
|
+
include Glimmer
|
1637
|
+
|
1638
|
+
attr_accessor :contacts
|
1639
|
+
|
1640
|
+
def initialize
|
1641
|
+
@contacts = [
|
1642
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1643
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1644
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1645
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1646
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1647
|
+
]
|
1648
|
+
end
|
1649
|
+
|
1650
|
+
def launch
|
1651
|
+
window('Contacts', 600, 200) {
|
1652
|
+
table {
|
1653
|
+
text_column('Name')
|
1654
|
+
text_column('Email')
|
1655
|
+
text_column('Phone')
|
1656
|
+
text_column('City/Town')
|
1657
|
+
text_column('State/Province')
|
1658
|
+
|
1659
|
+
cell_rows <=> [self, :contacts, column_attributes: {'City/Town' => :city, 'State/Province' => :state}]
|
1660
|
+
}
|
1661
|
+
}.show
|
1662
|
+
end
|
1663
|
+
end
|
1412
1664
|
|
1413
|
-
|
1665
|
+
SomeTable.new.launch
|
1666
|
+
```
|
1667
|
+
|
1668
|
+
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)):
|
1414
1669
|
|
1415
1670
|
```ruby
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1671
|
+
require 'glimmer-dsl-libui'
|
1672
|
+
|
1673
|
+
class SomeTable
|
1674
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
1675
|
+
|
1676
|
+
include Glimmer
|
1677
|
+
|
1678
|
+
attr_accessor :contacts
|
1679
|
+
|
1680
|
+
def initialize
|
1681
|
+
@contacts = [
|
1682
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
1683
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
1684
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
1685
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
1686
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
1687
|
+
]
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
def launch
|
1691
|
+
window('Contacts', 600, 200) {
|
1692
|
+
table {
|
1693
|
+
text_column('Full Name')
|
1694
|
+
text_column('Email Address')
|
1695
|
+
text_column('Phone Number')
|
1696
|
+
text_column('City or Town')
|
1697
|
+
text_column('State or Province')
|
1698
|
+
|
1699
|
+
cell_rows <=> [self, :contacts, column_attributes: [:name, :email, :phone, :city, :state]]
|
1700
|
+
}
|
1701
|
+
}.show
|
1702
|
+
end
|
1703
|
+
end
|
1704
|
+
|
1705
|
+
SomeTable.new.launch
|
1419
1706
|
```
|
1420
1707
|
|
1421
|
-
|
1708
|
+
#### Unidirectional (One-Way) Data-Binding
|
1422
1709
|
|
1423
1710
|
[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).
|
1424
1711
|
|
@@ -1442,6 +1729,8 @@ window {
|
|
1442
1729
|
|
1443
1730
|
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`.
|
1444
1731
|
|
1732
|
+
#### Data-Binding API
|
1733
|
+
|
1445
1734
|
To summarize the data-binding API:
|
1446
1735
|
- `view_property <=> [model, attribute, *read_or_write_options]`: Bidirectional (two-way) data-binding to Model attribute accessor
|
1447
1736
|
- `view_property <= [model, attribute, *read_only_options]`: Unidirectional (one-way) data-binding to Model attribute reader
|
@@ -1472,12 +1761,13 @@ entry {
|
|
1472
1761
|
}
|
1473
1762
|
```
|
1474
1763
|
|
1475
|
-
|
1764
|
+
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.
|
1765
|
+
|
1766
|
+
#### Data-Binding Gotchas
|
1767
|
+
|
1476
1768
|
- 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)
|
1477
1769
|
- 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.
|
1478
1770
|
|
1479
|
-
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.
|
1480
|
-
|
1481
1771
|
### API Gotchas
|
1482
1772
|
|
1483
1773
|
- There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`).
|
@@ -1489,272 +1779,12 @@ Learn more from data-binding usage in [Login](#login) (4 data-binding versions),
|
|
1489
1779
|
- `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.
|
1490
1780
|
- 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.
|
1491
1781
|
- As per the code of [examples/basic_transform.rb](#basic-transform), Windows requires different ordering of transforms than Mac and Linux.
|
1782
|
+
- `scrolling_area#scroll_to` does not seem to work on Windows and Linux, but works fine on Mac
|
1492
1783
|
|
1493
1784
|
### Original API
|
1494
1785
|
|
1495
1786
|
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):
|
1496
|
-
|
1497
|
-
- `area_begin_user_window_move`
|
1498
|
-
- `area_begin_user_window_resize`
|
1499
|
-
- `area_queue_redraw_all`
|
1500
|
-
- `area_scroll_to`
|
1501
|
-
- `area_set_size`
|
1502
|
-
- `attribute_color`
|
1503
|
-
- `attribute_family`
|
1504
|
-
- `attribute_features`
|
1505
|
-
- `attribute_get_type`
|
1506
|
-
- `attribute_italic`
|
1507
|
-
- `attribute_size`
|
1508
|
-
- `attribute_stretch`
|
1509
|
-
- `attribute_underline`
|
1510
|
-
- `attribute_underline_color`
|
1511
|
-
- `attribute_weight`
|
1512
|
-
- `attributed_string_append_unattributed`
|
1513
|
-
- `attributed_string_byte_index_to_grapheme`
|
1514
|
-
- `attributed_string_delete`
|
1515
|
-
- `attributed_string_for_each_attribute`
|
1516
|
-
- `attributed_string_grapheme_to_byte_index`
|
1517
|
-
- `attributed_string_insert_at_unattributed`
|
1518
|
-
- `attributed_string_len`
|
1519
|
-
- `attributed_string_num_graphemes`
|
1520
|
-
- `attributed_string_set_attribute`
|
1521
|
-
- `attributed_string_string`
|
1522
|
-
- `box_append`
|
1523
|
-
- `box_delete`
|
1524
|
-
- `box_padded`
|
1525
|
-
- `box_set_padded`
|
1526
|
-
- `button_on_clicked`
|
1527
|
-
- `button_set_text`
|
1528
|
-
- `button_text`
|
1529
|
-
- `checkbox_checked`
|
1530
|
-
- `checkbox_on_toggled`
|
1531
|
-
- `checkbox_set_checked`
|
1532
|
-
- `checkbox_set_text`
|
1533
|
-
- `checkbox_text`
|
1534
|
-
- `color_button_color`
|
1535
|
-
- `color_button_on_changed`
|
1536
|
-
- `color_button_set_color`
|
1537
|
-
- `combobox_append`
|
1538
|
-
- `combobox_on_selected`
|
1539
|
-
- `combobox_selected`
|
1540
|
-
- `combobox_set_selected`
|
1541
|
-
- `control_destroy`
|
1542
|
-
- `control_disable`
|
1543
|
-
- `control_enable`
|
1544
|
-
- `control_enabled`
|
1545
|
-
- `control_enabled_to_user`
|
1546
|
-
- `control_handle`
|
1547
|
-
- `control_hide`
|
1548
|
-
- `control_parent`
|
1549
|
-
- `control_set_parent`
|
1550
|
-
- `control_show`
|
1551
|
-
- `control_toplevel`
|
1552
|
-
- `control_verify_set_parent`
|
1553
|
-
- `control_visible`
|
1554
|
-
- `date_time_picker_on_changed`
|
1555
|
-
- `date_time_picker_set_time`
|
1556
|
-
- `date_time_picker_time`
|
1557
|
-
- `draw_clip`
|
1558
|
-
- `draw_fill`
|
1559
|
-
- `draw_free_path`
|
1560
|
-
- `draw_free_text_layout`
|
1561
|
-
- `draw_matrix_invert`
|
1562
|
-
- `draw_matrix_invertible`
|
1563
|
-
- `draw_matrix_multiply`
|
1564
|
-
- `draw_matrix_rotate`
|
1565
|
-
- `draw_matrix_scale`
|
1566
|
-
- `draw_matrix_set_identity`
|
1567
|
-
- `draw_matrix_skew`
|
1568
|
-
- `draw_matrix_transform_point`
|
1569
|
-
- `draw_matrix_transform_size`
|
1570
|
-
- `draw_matrix_translate`
|
1571
|
-
- `draw_new_path`
|
1572
|
-
- `draw_new_text_layout`
|
1573
|
-
- `draw_path_add_rectangle`
|
1574
|
-
- `draw_path_arc_to`
|
1575
|
-
- `draw_path_bezier_to`
|
1576
|
-
- `draw_path_close_figure`
|
1577
|
-
- `draw_path_end`
|
1578
|
-
- `draw_path_line_to`
|
1579
|
-
- `draw_path_new_figure`
|
1580
|
-
- `draw_path_new_figure_with_arc`
|
1581
|
-
- `draw_restore`
|
1582
|
-
- `draw_save`
|
1583
|
-
- `draw_stroke`
|
1584
|
-
- `draw_text`
|
1585
|
-
- `draw_text_layout_extents`
|
1586
|
-
- `draw_transform`
|
1587
|
-
- `editable_combobox_append`
|
1588
|
-
- `editable_combobox_on_changed`
|
1589
|
-
- `editable_combobox_set_text`
|
1590
|
-
- `editable_combobox_text`
|
1591
|
-
- `entry_on_changed`
|
1592
|
-
- `entry_read_only`
|
1593
|
-
- `entry_set_read_only`
|
1594
|
-
- `entry_set_text`
|
1595
|
-
- `entry_text`
|
1596
|
-
- `ffi_lib`
|
1597
|
-
- `ffi_lib=`
|
1598
|
-
- `font_button_font`
|
1599
|
-
- `font_button_on_changed`
|
1600
|
-
- `form_append`
|
1601
|
-
- `form_delete`
|
1602
|
-
- `form_padded`
|
1603
|
-
- `form_set_padded`
|
1604
|
-
- `free_attribute`
|
1605
|
-
- `free_attributed_string`
|
1606
|
-
- `free_control`
|
1607
|
-
- `free_font_button_font`
|
1608
|
-
- `free_image`
|
1609
|
-
- `free_init_error`
|
1610
|
-
- `free_open_type_features`
|
1611
|
-
- `free_table_model`
|
1612
|
-
- `free_table_value`
|
1613
|
-
- `free_text`
|
1614
|
-
- `grid_append`
|
1615
|
-
- `grid_insert_at`
|
1616
|
-
- `grid_padded`
|
1617
|
-
- `grid_set_padded`
|
1618
|
-
- `group_margined`
|
1619
|
-
- `group_set_child`
|
1620
|
-
- `group_set_margined`
|
1621
|
-
- `group_set_title`
|
1622
|
-
- `group_title`
|
1623
|
-
- `image_append`
|
1624
|
-
- `init`
|
1625
|
-
- `label_set_text`
|
1626
|
-
- `label_text`
|
1627
|
-
- `main`
|
1628
|
-
- `main_step`
|
1629
|
-
- `main_steps`
|
1630
|
-
- `menu_append_about_item`
|
1631
|
-
- `menu_append_check_item`
|
1632
|
-
- `menu_append_item`
|
1633
|
-
- `menu_append_preferences_item`
|
1634
|
-
- `menu_append_quit_item`
|
1635
|
-
- `menu_append_separator`
|
1636
|
-
- `menu_item_checked`
|
1637
|
-
- `menu_item_disable`
|
1638
|
-
- `menu_item_enable`
|
1639
|
-
- `menu_item_on_clicked`
|
1640
|
-
- `menu_item_set_checked`
|
1641
|
-
- `msg_box`
|
1642
|
-
- `msg_box_error`
|
1643
|
-
- `multiline_entry_append`
|
1644
|
-
- `multiline_entry_on_changed`
|
1645
|
-
- `multiline_entry_read_only`
|
1646
|
-
- `multiline_entry_set_read_only`
|
1647
|
-
- `multiline_entry_set_text`
|
1648
|
-
- `multiline_entry_text`
|
1649
|
-
- `new_area`
|
1650
|
-
- `new_attributed_string`
|
1651
|
-
- `new_background_attribute`
|
1652
|
-
- `new_button`
|
1653
|
-
- `new_checkbox`
|
1654
|
-
- `new_color_attribute`
|
1655
|
-
- `new_color_button`
|
1656
|
-
- `new_combobox`
|
1657
|
-
- `new_date_picker`
|
1658
|
-
- `new_date_time_picker`
|
1659
|
-
- `new_editable_combobox`
|
1660
|
-
- `new_entry`
|
1661
|
-
- `new_family_attribute`
|
1662
|
-
- `new_features_attribute`
|
1663
|
-
- `new_font_button`
|
1664
|
-
- `new_form`
|
1665
|
-
- `new_grid`
|
1666
|
-
- `new_group`
|
1667
|
-
- `new_horizontal_box`
|
1668
|
-
- `new_horizontal_separator`
|
1669
|
-
- `new_image`
|
1670
|
-
- `new_italic_attribute`
|
1671
|
-
- `new_label`
|
1672
|
-
- `new_menu`
|
1673
|
-
- `new_multiline_entry`
|
1674
|
-
- `new_non_wrapping_multiline_entry`
|
1675
|
-
- `new_open_type_features`
|
1676
|
-
- `new_password_entry`
|
1677
|
-
- `new_progress_bar`
|
1678
|
-
- `new_radio_buttons`
|
1679
|
-
- `new_scrolling_area`
|
1680
|
-
- `new_search_entry`
|
1681
|
-
- `new_size_attribute`
|
1682
|
-
- `new_slider`
|
1683
|
-
- `new_spinbox`
|
1684
|
-
- `new_stretch_attribute`
|
1685
|
-
- `new_tab`
|
1686
|
-
- `new_table`
|
1687
|
-
- `new_table_model`
|
1688
|
-
- `new_table_value_color`
|
1689
|
-
- `new_table_value_image`
|
1690
|
-
- `new_table_value_int`
|
1691
|
-
- `new_table_value_string`
|
1692
|
-
- `new_time_picker`
|
1693
|
-
- `new_underline_attribute`
|
1694
|
-
- `new_underline_color_attribute`
|
1695
|
-
- `new_vertical_box`
|
1696
|
-
- `new_vertical_separator`
|
1697
|
-
- `new_weight_attribute`
|
1698
|
-
- `new_window`
|
1699
|
-
- `on_should_quit`
|
1700
|
-
- `open_file`
|
1701
|
-
- `open_type_features_add`
|
1702
|
-
- `open_type_features_clone`
|
1703
|
-
- `open_type_features_for_each`
|
1704
|
-
- `open_type_features_get`
|
1705
|
-
- `open_type_features_remove`
|
1706
|
-
- `progress_bar_set_value`
|
1707
|
-
- `progress_bar_value`
|
1708
|
-
- `queue_main`
|
1709
|
-
- `quit`
|
1710
|
-
- `radio_buttons_append`
|
1711
|
-
- `radio_buttons_on_selected`
|
1712
|
-
- `radio_buttons_selected`
|
1713
|
-
- `radio_buttons_set_selected`
|
1714
|
-
- `save_file`
|
1715
|
-
- `slider_on_changed`
|
1716
|
-
- `slider_set_value`
|
1717
|
-
- `slider_value`
|
1718
|
-
- `spinbox_on_changed`
|
1719
|
-
- `spinbox_set_value`
|
1720
|
-
- `spinbox_value`
|
1721
|
-
- `tab_append`
|
1722
|
-
- `tab_delete`
|
1723
|
-
- `tab_insert_at`
|
1724
|
-
- `tab_margined`
|
1725
|
-
- `tab_num_pages`
|
1726
|
-
- `tab_set_margined`
|
1727
|
-
- `table_append_button_column`
|
1728
|
-
- `table_append_checkbox_column`
|
1729
|
-
- `table_append_checkbox_text_column`
|
1730
|
-
- `table_append_image_column`
|
1731
|
-
- `table_append_image_text_column`
|
1732
|
-
- `table_append_progress_bar_column`
|
1733
|
-
- `table_append_text_column`
|
1734
|
-
- `table_model_row_changed`
|
1735
|
-
- `table_model_row_deleted`
|
1736
|
-
- `table_model_row_inserted`
|
1737
|
-
- `table_value_color`
|
1738
|
-
- `table_value_get_type`
|
1739
|
-
- `table_value_image`
|
1740
|
-
- `table_value_int`
|
1741
|
-
- `table_value_string`
|
1742
|
-
- `timer`
|
1743
|
-
- `uninit`
|
1744
|
-
- `user_bug_cannot_set_parent_on_toplevel`
|
1745
|
-
- `window_borderless`
|
1746
|
-
- `window_content_size`
|
1747
|
-
- `window_fullscreen`
|
1748
|
-
- `window_margined`
|
1749
|
-
- `window_on_closing`
|
1750
|
-
- `window_on_content_size_changed`
|
1751
|
-
- `window_set_borderless`
|
1752
|
-
- `window_set_child`
|
1753
|
-
- `window_set_content_size`
|
1754
|
-
- `window_set_fullscreen`
|
1755
|
-
- `window_set_margined`
|
1756
|
-
- `window_set_title`
|
1757
|
-
- `window_title`
|
1787
|
+
`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`
|
1758
1788
|
|
1759
1789
|
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):
|
1760
1790
|
- Check out [LibUI ffi.rb](https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb)
|
@@ -3063,7 +3093,44 @@ UI.main
|
|
3063
3093
|
UI.quit
|
3064
3094
|
```
|
3065
3095
|
|
3066
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3096
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3097
|
+
|
3098
|
+
```ruby
|
3099
|
+
# frozen_string_literal: true
|
3100
|
+
|
3101
|
+
# NOTE:
|
3102
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3103
|
+
|
3104
|
+
require 'glimmer-dsl-libui'
|
3105
|
+
|
3106
|
+
include Glimmer
|
3107
|
+
|
3108
|
+
IMAGE_ROWS = []
|
3109
|
+
|
3110
|
+
50.times do |i|
|
3111
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3112
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3113
|
+
IMAGE_ROWS << [url] # array of one column cell
|
3114
|
+
rescue StandardError => e
|
3115
|
+
warn url, e.message
|
3116
|
+
end
|
3117
|
+
|
3118
|
+
window('The Red Turtle', 310, 350, false) {
|
3119
|
+
horizontal_box {
|
3120
|
+
table {
|
3121
|
+
image_column('www.ghibli.jp/works/red-turtle')
|
3122
|
+
|
3123
|
+
cell_rows IMAGE_ROWS
|
3124
|
+
}
|
3125
|
+
}
|
3126
|
+
|
3127
|
+
on_closing do
|
3128
|
+
puts 'Bye Bye'
|
3129
|
+
end
|
3130
|
+
}.show
|
3131
|
+
```
|
3132
|
+
|
3133
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
3067
3134
|
|
3068
3135
|
```ruby
|
3069
3136
|
# NOTE:
|
@@ -3098,7 +3165,7 @@ window('The Red Turtle', 310, 350, false) {
|
|
3098
3165
|
}.show
|
3099
3166
|
```
|
3100
3167
|
|
3101
|
-
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3168
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (manual construction of `image` from `image_part`):
|
3102
3169
|
|
3103
3170
|
```ruby
|
3104
3171
|
# NOTE:
|
@@ -3166,7 +3233,44 @@ Mac | Windows | Linux
|
|
3166
3233
|
----|---------|------
|
3167
3234
|
![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)
|
3168
3235
|
|
3169
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3236
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (passing file url as image):
|
3237
|
+
|
3238
|
+
```ruby
|
3239
|
+
# frozen_string_literal: true
|
3240
|
+
|
3241
|
+
# NOTE:
|
3242
|
+
# This example displays images that can be freely downloaded from the Studio Ghibli website.
|
3243
|
+
|
3244
|
+
require 'glimmer-dsl-libui'
|
3245
|
+
|
3246
|
+
include Glimmer
|
3247
|
+
|
3248
|
+
IMAGE_ROWS = []
|
3249
|
+
|
3250
|
+
5.times do |i|
|
3251
|
+
url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
|
3252
|
+
puts "Processing Image: #{url}"; $stdout.flush # for Windows
|
3253
|
+
text = url.sub('https://www.ghibli.jp/gallery/thumb-redturtle', '').sub('.png', '')
|
3254
|
+
IMAGE_ROWS << [[url, text], [url, text]] # cell values are dual-element arrays
|
3255
|
+
rescue StandardError => e
|
3256
|
+
warn url, e.message
|
3257
|
+
end
|
3258
|
+
|
3259
|
+
window('The Red Turtle', 670, 350) {
|
3260
|
+
horizontal_box {
|
3261
|
+
table {
|
3262
|
+
image_text_column('image/number')
|
3263
|
+
image_text_column('image/number (editable)') {
|
3264
|
+
editable true
|
3265
|
+
}
|
3266
|
+
|
3267
|
+
cell_rows IMAGE_ROWS
|
3268
|
+
}
|
3269
|
+
}
|
3270
|
+
}.show
|
3271
|
+
```
|
3272
|
+
|
3273
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (automatic construction of `image`):
|
3170
3274
|
|
3171
3275
|
```ruby
|
3172
3276
|
# NOTE:
|
@@ -3268,7 +3372,70 @@ Mac | Windows | Linux
|
|
3268
3372
|
----|---------|------
|
3269
3373
|
![glimmer-dsl-libui-mac-basic-table-button.png](images/glimmer-dsl-libui-mac-basic-table-button.png) ![glimmer-dsl-libui-mac-basic-table-button-deleted.png](images/glimmer-dsl-libui-mac-basic-table-button-deleted.png) | ![glimmer-dsl-libui-windows-basic-table-button.png](images/glimmer-dsl-libui-windows-basic-table-button.png) ![glimmer-dsl-libui-windows-basic-table-button-deleted.png](images/glimmer-dsl-libui-windows-basic-table-button-deleted.png) | ![glimmer-dsl-libui-linux-basic-table-button.png](images/glimmer-dsl-libui-linux-basic-table-button.png) ![glimmer-dsl-libui-linux-basic-table-button-deleted.png](images/glimmer-dsl-libui-linux-basic-table-button-deleted.png)
|
3270
3374
|
|
3271
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3375
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
3376
|
+
|
3377
|
+
```ruby
|
3378
|
+
require 'glimmer-dsl-libui'
|
3379
|
+
|
3380
|
+
class BasicTableButton
|
3381
|
+
BasicAnimal = Struct.new(:name, :sound)
|
3382
|
+
|
3383
|
+
class Animal < BasicAnimal
|
3384
|
+
def action
|
3385
|
+
'delete'
|
3386
|
+
end
|
3387
|
+
end
|
3388
|
+
|
3389
|
+
include Glimmer
|
3390
|
+
|
3391
|
+
attr_accessor :animals
|
3392
|
+
|
3393
|
+
def initialize
|
3394
|
+
@animals = [
|
3395
|
+
Animal.new('cat', 'meow'),
|
3396
|
+
Animal.new('dog', 'woof'),
|
3397
|
+
Animal.new('chicken', 'cock-a-doodle-doo'),
|
3398
|
+
Animal.new('horse', 'neigh'),
|
3399
|
+
Animal.new('cow', 'moo'),
|
3400
|
+
]
|
3401
|
+
end
|
3402
|
+
|
3403
|
+
def launch
|
3404
|
+
window('Animal sounds', 400, 200) {
|
3405
|
+
horizontal_box {
|
3406
|
+
table {
|
3407
|
+
text_column('Animal')
|
3408
|
+
text_column('Description')
|
3409
|
+
button_column('Action') {
|
3410
|
+
on_clicked do |row|
|
3411
|
+
# Option 1: direct data deletion is the simpler solution
|
3412
|
+
# @animals.delete_at(row) # automatically deletes actual table row due to explicit data-binding
|
3413
|
+
|
3414
|
+
# Option 2: cloning only to demonstrate table row deletion upon explicit setting of animals attribute (cloning is not recommended beyond demonstrating this point)
|
3415
|
+
new_animals = @animals.clone
|
3416
|
+
new_animals.delete_at(row)
|
3417
|
+
self.animals = new_animals # automatically loses deleted table row due to explicit data-binding
|
3418
|
+
end
|
3419
|
+
}
|
3420
|
+
|
3421
|
+
|
3422
|
+
cell_rows <= [self, :animals, column_attributes: {'Animal' => :name, 'Description' => :sound}]
|
3423
|
+
|
3424
|
+
# explicit unidirectional data-binding of table cell_rows to self.animals
|
3425
|
+
on_changed do |row, type, row_data|
|
3426
|
+
puts "Row #{row} #{type}: #{row_data}"
|
3427
|
+
$stdout.flush
|
3428
|
+
end
|
3429
|
+
}
|
3430
|
+
}
|
3431
|
+
}.show
|
3432
|
+
end
|
3433
|
+
end
|
3434
|
+
|
3435
|
+
BasicTableButton.new.launch
|
3436
|
+
```
|
3437
|
+
|
3438
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with implicit [data-binding](#data-binding)):
|
3272
3439
|
|
3273
3440
|
```ruby
|
3274
3441
|
require 'glimmer-dsl-libui'
|
@@ -3477,16 +3644,126 @@ Mac | Windows | Linux
|
|
3477
3644
|
----|---------|------
|
3478
3645
|
![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)
|
3479
3646
|
|
3480
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3647
|
+
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):
|
3481
3648
|
|
3482
3649
|
```ruby
|
3483
|
-
|
3650
|
+
require 'glimmer-dsl-libui'
|
3651
|
+
|
3652
|
+
class BasicTableColor
|
3653
|
+
Animal = Struct.new(:name, :sound, :mammal)
|
3654
|
+
|
3655
|
+
class AnimalPresenter < Animal
|
3656
|
+
def name_color
|
3657
|
+
color = case name
|
3658
|
+
when 'cat'
|
3659
|
+
:red
|
3660
|
+
when 'dog'
|
3661
|
+
:yellow
|
3662
|
+
when 'chicken'
|
3663
|
+
:beige
|
3664
|
+
when 'horse'
|
3665
|
+
:purple
|
3666
|
+
when 'cow'
|
3667
|
+
:gray
|
3668
|
+
end
|
3669
|
+
[name, color]
|
3670
|
+
end
|
3671
|
+
|
3672
|
+
def sound_color
|
3673
|
+
color = case name
|
3674
|
+
when 'cat', 'chicken', 'cow'
|
3675
|
+
:blue
|
3676
|
+
when 'dog', 'horse'
|
3677
|
+
{r: 240, g: 32, b: 32}
|
3678
|
+
end
|
3679
|
+
[sound, color]
|
3680
|
+
end
|
3681
|
+
|
3682
|
+
def mammal_description_color
|
3683
|
+
color = case name
|
3684
|
+
when 'cat', 'dog', 'horse', 'cow'
|
3685
|
+
:green
|
3686
|
+
when 'chicken'
|
3687
|
+
:red
|
3688
|
+
end
|
3689
|
+
[mammal, 'mammal', color]
|
3690
|
+
end
|
3691
|
+
|
3692
|
+
def image_description_color
|
3693
|
+
color = case name
|
3694
|
+
when 'cat', 'dog', 'horse'
|
3695
|
+
:dark_blue
|
3696
|
+
when 'chicken'
|
3697
|
+
:beige
|
3698
|
+
when 'cow'
|
3699
|
+
:brown
|
3700
|
+
end
|
3701
|
+
[img, 'Glimmer', color]
|
3702
|
+
end
|
3703
|
+
|
3704
|
+
def img
|
3705
|
+
# scale image to 24x24 (can be passed as file path String only instead of Array to avoid scaling)
|
3706
|
+
[File.expand_path('../icons/glimmer.png', __dir__), 24, 24]
|
3707
|
+
end
|
3708
|
+
|
3709
|
+
def background_color
|
3710
|
+
case name
|
3711
|
+
when 'cat'
|
3712
|
+
{r: 255, g: 120, b: 0, a: 0.5}
|
3713
|
+
when 'dog'
|
3714
|
+
:skyblue
|
3715
|
+
when 'chicken'
|
3716
|
+
{r: 5, g: 120, b: 110}
|
3717
|
+
when 'horse'
|
3718
|
+
'#13a1fb'
|
3719
|
+
when 'cow'
|
3720
|
+
0x12ff02
|
3721
|
+
end
|
3722
|
+
end
|
3723
|
+
end
|
3724
|
+
|
3725
|
+
include Glimmer
|
3726
|
+
|
3727
|
+
attr_accessor :animals
|
3728
|
+
|
3729
|
+
def initialize
|
3730
|
+
@animals = [
|
3731
|
+
AnimalPresenter.new('cat', 'meow', true),
|
3732
|
+
AnimalPresenter.new('dog', 'woof', true),
|
3733
|
+
AnimalPresenter.new('chicken', 'cock-a-doodle-doo', false),
|
3734
|
+
AnimalPresenter.new('horse', 'neigh', true),
|
3735
|
+
AnimalPresenter.new('cow', 'moo', true),
|
3736
|
+
]
|
3737
|
+
end
|
3738
|
+
|
3739
|
+
def launch
|
3740
|
+
window('Animals', 500, 200) {
|
3741
|
+
horizontal_box {
|
3742
|
+
table {
|
3743
|
+
text_color_column('Animal')
|
3744
|
+
text_color_column('Sound')
|
3745
|
+
checkbox_text_color_column('Description')
|
3746
|
+
image_text_color_column('GUI')
|
3747
|
+
background_color_column # must always be the last column and always expects data-binding model attribute `background_color` when binding to Array of models
|
3748
|
+
|
3749
|
+
cell_rows <= [self, :animals, column_attributes: {'Animal' => :name_color, 'Sound' => :sound_color, 'Description' => :mammal_description_color, 'GUI' => :image_description_color}]
|
3750
|
+
}
|
3751
|
+
}
|
3752
|
+
}.show
|
3753
|
+
end
|
3754
|
+
end
|
3755
|
+
|
3756
|
+
BasicTableColor.new.launch
|
3757
|
+
```
|
3758
|
+
|
3759
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with implicit [data-binding](#data-binding) to raw data rows):
|
3484
3760
|
|
3761
|
+
```ruby
|
3485
3762
|
require 'glimmer-dsl-libui'
|
3486
3763
|
|
3487
3764
|
include Glimmer
|
3488
3765
|
|
3489
|
-
img =
|
3766
|
+
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)
|
3490
3767
|
|
3491
3768
|
data = [
|
3492
3769
|
[['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
|
@@ -3503,7 +3780,7 @@ window('Animals', 500, 200) {
|
|
3503
3780
|
text_color_column('Sound')
|
3504
3781
|
checkbox_text_color_column('Description')
|
3505
3782
|
image_text_color_column('GUI')
|
3506
|
-
background_color_column
|
3783
|
+
background_color_column # must be the last column
|
3507
3784
|
|
3508
3785
|
cell_rows data
|
3509
3786
|
}
|
@@ -3511,7 +3788,7 @@ window('Animals', 500, 200) {
|
|
3511
3788
|
}.show
|
3512
3789
|
```
|
3513
3790
|
|
3514
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
3791
|
+
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`):
|
3515
3792
|
|
3516
3793
|
```ruby
|
3517
3794
|
require 'glimmer-dsl-libui'
|
@@ -3545,7 +3822,7 @@ window('Animals', 500, 200) {
|
|
3545
3822
|
text_color_column('Sound')
|
3546
3823
|
checkbox_text_color_column('Description')
|
3547
3824
|
image_text_color_column('GUI')
|
3548
|
-
background_color_column
|
3825
|
+
background_color_column
|
3549
3826
|
|
3550
3827
|
cell_rows data
|
3551
3828
|
}
|
@@ -3687,9 +3964,9 @@ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/
|
|
3687
3964
|
ruby -r glimmer-dsl-libui -e "require 'examples/basic_scrolling_area'"
|
3688
3965
|
```
|
3689
3966
|
|
3690
|
-
Mac | Linux
|
3691
|
-
|
3692
|
-
![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)
|
3967
|
+
Mac | Windows | Linux
|
3968
|
+
----|---------|------
|
3969
|
+
![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)
|
3693
3970
|
|
3694
3971
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3695
3972
|
|
@@ -3776,6 +4053,8 @@ BasicScrollingArea.new.launch
|
|
3776
4053
|
|
3777
4054
|
#### Basic Image
|
3778
4055
|
|
4056
|
+
Please note the caveats of [Area Image](#area-image) **(Alpha Feature)** with regards to this example.
|
4057
|
+
|
3779
4058
|
[examples/basic_image.rb](examples/basic_image.rb)
|
3780
4059
|
|
3781
4060
|
Run with this command from the root of the project if you cloned the project:
|
@@ -5026,9 +5305,9 @@ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/
|
|
5026
5305
|
ruby -r glimmer-dsl-libui -e "require 'examples/button_counter'"
|
5027
5306
|
```
|
5028
5307
|
|
5029
|
-
Mac | Linux
|
5030
|
-
|
5031
|
-
![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)
|
5308
|
+
Mac | Windows | Linux
|
5309
|
+
----|---------|------
|
5310
|
+
![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)
|
5032
5311
|
|
5033
5312
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5034
5313
|
|
@@ -5687,9 +5966,74 @@ MAIN_WINDOW = window('Control Gallery', 600, 500) {
|
|
5687
5966
|
}
|
5688
5967
|
}
|
5689
5968
|
}
|
5690
|
-
}
|
5691
|
-
|
5692
|
-
MAIN_WINDOW.show
|
5969
|
+
}
|
5970
|
+
|
5971
|
+
MAIN_WINDOW.show
|
5972
|
+
```
|
5973
|
+
|
5974
|
+
#### CPU Percentage
|
5975
|
+
|
5976
|
+
This example shows CPU usage percentage second by second.
|
5977
|
+
|
5978
|
+
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.
|
5979
|
+
|
5980
|
+
[examples/cpu_percentage.rb](examples/cpu_percentage.rb)
|
5981
|
+
|
5982
|
+
Run with this command from the root of the project if you cloned the project:
|
5983
|
+
|
5984
|
+
```
|
5985
|
+
ruby -r './lib/glimmer-dsl-libui' examples/cpu_percentage.rb
|
5986
|
+
```
|
5987
|
+
|
5988
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
5989
|
+
|
5990
|
+
```
|
5991
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/cpu_percentage'"
|
5992
|
+
```
|
5993
|
+
|
5994
|
+
Mac | Windows | Linux
|
5995
|
+
----|---------|------
|
5996
|
+
![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)
|
5997
|
+
|
5998
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5999
|
+
|
6000
|
+
```ruby
|
6001
|
+
require 'glimmer-dsl-libui'
|
6002
|
+
require 'bigdecimal'
|
6003
|
+
|
6004
|
+
include Glimmer
|
6005
|
+
|
6006
|
+
data = [
|
6007
|
+
['CPU', '0%', 0],
|
6008
|
+
]
|
6009
|
+
|
6010
|
+
Glimmer::LibUI.timer(1) do
|
6011
|
+
cpu_percentage_value = nil
|
6012
|
+
if OS.windows?
|
6013
|
+
cpu_percentage_raw_value = `wmic cpu get loadpercentage`
|
6014
|
+
cpu_percentage_value = cpu_percentage_raw_value.split("\n")[2].to_i
|
6015
|
+
elsif OS.mac?
|
6016
|
+
cpu_percentage_value = `ps -A -o %cpu | awk '{s+=$1} END {print s}'`.to_i
|
6017
|
+
elsif OS.linux?
|
6018
|
+
stats = `top -n 1`
|
6019
|
+
idle_percentage = stats.split("\n")[2].match(/ni,.* (.*) .*id/)[1]
|
6020
|
+
cpu_percentage_value = (BigDecimal(100) - BigDecimal(idle_percentage)).to_i
|
6021
|
+
end
|
6022
|
+
data[0][1] = "#{cpu_percentage_value}%"
|
6023
|
+
data[0][2] = cpu_percentage_value
|
6024
|
+
end
|
6025
|
+
|
6026
|
+
window('CPU Percentage', 400, 200) {
|
6027
|
+
vertical_box {
|
6028
|
+
table {
|
6029
|
+
text_column('Name')
|
6030
|
+
text_column('Value')
|
6031
|
+
progress_bar_column('Percentage')
|
6032
|
+
|
6033
|
+
cell_rows data # implicit data-binding
|
6034
|
+
}
|
6035
|
+
}
|
6036
|
+
}.show
|
5693
6037
|
```
|
5694
6038
|
|
5695
6039
|
#### Custom Draw Text
|
@@ -6402,8 +6746,8 @@ window('Editable animal sounds', 300, 200) {
|
|
6402
6746
|
text_column('Animal')
|
6403
6747
|
text_column('Description')
|
6404
6748
|
|
6405
|
-
cell_rows data
|
6406
6749
|
editable true
|
6750
|
+
cell_rows data
|
6407
6751
|
|
6408
6752
|
on_changed do |row, type, row_data| # fires on all changes (even ones happening through data array)
|
6409
6753
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -6418,30 +6762,382 @@ window('Editable animal sounds', 300, 200) {
|
|
6418
6762
|
on_closing do
|
6419
6763
|
puts 'Bye Bye'
|
6420
6764
|
end
|
6421
|
-
}.show
|
6422
|
-
```
|
6423
|
-
|
6424
|
-
#### Form Table
|
6425
|
-
|
6426
|
-
[examples/form_table.rb](examples/form_table.rb)
|
6427
|
-
|
6428
|
-
Run with this command from the root of the project if you cloned the project:
|
6429
|
-
|
6430
|
-
```
|
6431
|
-
ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
|
6432
|
-
```
|
6433
|
-
|
6434
|
-
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6765
|
+
}.show
|
6766
|
+
```
|
6767
|
+
|
6768
|
+
#### Form Table
|
6769
|
+
|
6770
|
+
[examples/form_table.rb](examples/form_table.rb)
|
6771
|
+
|
6772
|
+
Run with this command from the root of the project if you cloned the project:
|
6773
|
+
|
6774
|
+
```
|
6775
|
+
ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
|
6776
|
+
```
|
6777
|
+
|
6778
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
6779
|
+
|
6780
|
+
```
|
6781
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
|
6782
|
+
```
|
6783
|
+
|
6784
|
+
Mac | Windows | Linux
|
6785
|
+
----|---------|------
|
6786
|
+
![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)
|
6787
|
+
|
6788
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
6789
|
+
|
6790
|
+
```ruby
|
6791
|
+
require 'glimmer-dsl-libui'
|
6792
|
+
|
6793
|
+
class FormTable
|
6794
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
6795
|
+
|
6796
|
+
include Glimmer
|
6797
|
+
|
6798
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
6799
|
+
|
6800
|
+
def initialize
|
6801
|
+
@contacts = [
|
6802
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
6803
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
6804
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
6805
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
6806
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
6807
|
+
]
|
6808
|
+
end
|
6809
|
+
|
6810
|
+
def launch
|
6811
|
+
window('Contacts', 600, 600) { |w|
|
6812
|
+
margined true
|
6813
|
+
|
6814
|
+
vertical_box {
|
6815
|
+
form {
|
6816
|
+
stretchy false
|
6817
|
+
|
6818
|
+
entry {
|
6819
|
+
label 'Name'
|
6820
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6821
|
+
}
|
6822
|
+
|
6823
|
+
entry {
|
6824
|
+
label 'Email'
|
6825
|
+
text <=> [self, :email]
|
6826
|
+
}
|
6827
|
+
|
6828
|
+
entry {
|
6829
|
+
label 'Phone'
|
6830
|
+
text <=> [self, :phone]
|
6831
|
+
}
|
6832
|
+
|
6833
|
+
entry {
|
6834
|
+
label 'City'
|
6835
|
+
text <=> [self, :city]
|
6836
|
+
}
|
6837
|
+
|
6838
|
+
entry {
|
6839
|
+
label 'State'
|
6840
|
+
text <=> [self, :state]
|
6841
|
+
}
|
6842
|
+
}
|
6843
|
+
|
6844
|
+
button('Save Contact') {
|
6845
|
+
stretchy false
|
6846
|
+
|
6847
|
+
on_clicked do
|
6848
|
+
new_row = [name, email, phone, city, state]
|
6849
|
+
if new_row.include?('')
|
6850
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6851
|
+
else
|
6852
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
|
6853
|
+
@unfiltered_contacts = @contacts.dup
|
6854
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
6855
|
+
self.email = ''
|
6856
|
+
self.phone = ''
|
6857
|
+
self.city = ''
|
6858
|
+
self.state = ''
|
6859
|
+
end
|
6860
|
+
end
|
6861
|
+
}
|
6862
|
+
|
6863
|
+
search_entry {
|
6864
|
+
stretchy false
|
6865
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
6866
|
+
text <=> [self, :filter_value,
|
6867
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6868
|
+
@unfiltered_contacts ||= @contacts.dup
|
6869
|
+
# Unfilter first to remove any previous filters
|
6870
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
6871
|
+
# Now, apply filter if entered
|
6872
|
+
unless filter_value.empty?
|
6873
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
6874
|
+
contact.members.any? do |attribute|
|
6875
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
6876
|
+
end
|
6877
|
+
end
|
6878
|
+
end
|
6879
|
+
}
|
6880
|
+
]
|
6881
|
+
}
|
6882
|
+
|
6883
|
+
table {
|
6884
|
+
text_column('Name')
|
6885
|
+
text_column('Email')
|
6886
|
+
text_column('Phone')
|
6887
|
+
text_column('City')
|
6888
|
+
text_column('State')
|
6889
|
+
|
6890
|
+
editable true
|
6891
|
+
cell_rows <=> [self, :contacts] # explicit data-binding to Model Array auto-inferring model attribute names from underscored table column names by convention
|
6892
|
+
|
6893
|
+
on_changed do |row, type, row_data|
|
6894
|
+
puts "Row #{row} #{type}: #{row_data}"
|
6895
|
+
end
|
6896
|
+
}
|
6897
|
+
}
|
6898
|
+
}.show
|
6899
|
+
end
|
6900
|
+
end
|
6901
|
+
|
6902
|
+
FormTable.new.launch
|
6903
|
+
```
|
6904
|
+
|
6905
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
6906
|
+
|
6907
|
+
```ruby
|
6908
|
+
require 'glimmer-dsl-libui'
|
6909
|
+
|
6910
|
+
class FormTable
|
6911
|
+
Contact = Struct.new(:name, :email, :phone, :city, :state)
|
6912
|
+
|
6913
|
+
include Glimmer
|
6914
|
+
|
6915
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
6916
|
+
|
6917
|
+
def initialize
|
6918
|
+
@contacts = [
|
6919
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
6920
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
6921
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
6922
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
6923
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
6924
|
+
]
|
6925
|
+
end
|
6926
|
+
|
6927
|
+
def launch
|
6928
|
+
window('Contacts', 600, 600) { |w|
|
6929
|
+
margined true
|
6930
|
+
|
6931
|
+
vertical_box {
|
6932
|
+
form {
|
6933
|
+
stretchy false
|
6934
|
+
|
6935
|
+
entry {
|
6936
|
+
label 'Name'
|
6937
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6938
|
+
}
|
6939
|
+
|
6940
|
+
entry {
|
6941
|
+
label 'Email'
|
6942
|
+
text <=> [self, :email]
|
6943
|
+
}
|
6944
|
+
|
6945
|
+
entry {
|
6946
|
+
label 'Phone'
|
6947
|
+
text <=> [self, :phone]
|
6948
|
+
}
|
6949
|
+
|
6950
|
+
entry {
|
6951
|
+
label 'City'
|
6952
|
+
text <=> [self, :city]
|
6953
|
+
}
|
6954
|
+
|
6955
|
+
entry {
|
6956
|
+
label 'State'
|
6957
|
+
text <=> [self, :state]
|
6958
|
+
}
|
6959
|
+
}
|
6960
|
+
|
6961
|
+
button('Save Contact') {
|
6962
|
+
stretchy false
|
6963
|
+
|
6964
|
+
on_clicked do
|
6965
|
+
new_row = [name, email, phone, city, state]
|
6966
|
+
if new_row.include?('')
|
6967
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6968
|
+
else
|
6969
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
6970
|
+
@unfiltered_contacts = @contacts.dup
|
6971
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
6972
|
+
self.email = ''
|
6973
|
+
self.phone = ''
|
6974
|
+
self.city = ''
|
6975
|
+
self.state = ''
|
6976
|
+
end
|
6977
|
+
end
|
6978
|
+
}
|
6979
|
+
|
6980
|
+
search_entry {
|
6981
|
+
stretchy false
|
6982
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
6983
|
+
text <=> [self, :filter_value,
|
6984
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6985
|
+
@unfiltered_contacts ||= @contacts.dup
|
6986
|
+
# Unfilter first to remove any previous filters
|
6987
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
6988
|
+
# Now, apply filter if entered
|
6989
|
+
unless filter_value.empty?
|
6990
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
6991
|
+
contact.members.any? do |attribute|
|
6992
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
6993
|
+
end
|
6994
|
+
end
|
6995
|
+
end
|
6996
|
+
}
|
6997
|
+
]
|
6998
|
+
}
|
6999
|
+
|
7000
|
+
table {
|
7001
|
+
text_column('Name')
|
7002
|
+
text_column('Email')
|
7003
|
+
text_column('Phone')
|
7004
|
+
text_column('City')
|
7005
|
+
text_column('State/Province')
|
7006
|
+
|
7007
|
+
editable true
|
7008
|
+
cell_rows <=> [self, :contacts, column_attributes: {'State/Province' => :state}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
|
7009
|
+
|
7010
|
+
on_changed do |row, type, row_data|
|
7011
|
+
puts "Row #{row} #{type}: #{row_data}"
|
7012
|
+
end
|
7013
|
+
}
|
7014
|
+
}
|
7015
|
+
}.show
|
7016
|
+
end
|
7017
|
+
end
|
7018
|
+
|
7019
|
+
FormTable.new.launch
|
7020
|
+
```
|
7021
|
+
|
7022
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
|
7023
|
+
|
7024
|
+
```ruby
|
7025
|
+
|
7026
|
+
require 'glimmer-dsl-libui'
|
7027
|
+
|
7028
|
+
class FormTable
|
7029
|
+
Contact = Struct.new(:full_name, :email_address, :phone_number, :city_or_town, :state_or_province)
|
7030
|
+
|
7031
|
+
include Glimmer
|
7032
|
+
|
7033
|
+
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
|
7034
|
+
|
7035
|
+
def initialize
|
7036
|
+
@contacts = [
|
7037
|
+
Contact.new('Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'),
|
7038
|
+
Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'),
|
7039
|
+
Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'),
|
7040
|
+
Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'),
|
7041
|
+
Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'),
|
7042
|
+
]
|
7043
|
+
end
|
7044
|
+
|
7045
|
+
def launch
|
7046
|
+
window('Contacts', 600, 600) { |w|
|
7047
|
+
margined true
|
7048
|
+
|
7049
|
+
vertical_box {
|
7050
|
+
form {
|
7051
|
+
stretchy false
|
7052
|
+
|
7053
|
+
entry {
|
7054
|
+
label 'Name'
|
7055
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
7056
|
+
}
|
7057
|
+
|
7058
|
+
entry {
|
7059
|
+
label 'Email'
|
7060
|
+
text <=> [self, :email]
|
7061
|
+
}
|
7062
|
+
|
7063
|
+
entry {
|
7064
|
+
label 'Phone'
|
7065
|
+
text <=> [self, :phone]
|
7066
|
+
}
|
7067
|
+
|
7068
|
+
entry {
|
7069
|
+
label 'City'
|
7070
|
+
text <=> [self, :city]
|
7071
|
+
}
|
7072
|
+
|
7073
|
+
entry {
|
7074
|
+
label 'State'
|
7075
|
+
text <=> [self, :state]
|
7076
|
+
}
|
7077
|
+
}
|
7078
|
+
|
7079
|
+
button('Save Contact') {
|
7080
|
+
stretchy false
|
7081
|
+
|
7082
|
+
on_clicked do
|
7083
|
+
new_row = [name, email, phone, city, state]
|
7084
|
+
if new_row.include?('')
|
7085
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
7086
|
+
else
|
7087
|
+
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
|
7088
|
+
@unfiltered_contacts = @contacts.dup
|
7089
|
+
self.name = '' # automatically clears name entry through explicit data-binding
|
7090
|
+
self.email = ''
|
7091
|
+
self.phone = ''
|
7092
|
+
self.city = ''
|
7093
|
+
self.state = ''
|
7094
|
+
end
|
7095
|
+
end
|
7096
|
+
}
|
7097
|
+
|
7098
|
+
search_entry {
|
7099
|
+
stretchy false
|
7100
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
7101
|
+
text <=> [self, :filter_value,
|
7102
|
+
after_write: ->(filter_value) { # execute after write to self.filter_value
|
7103
|
+
@unfiltered_contacts ||= @contacts.dup
|
7104
|
+
# Unfilter first to remove any previous filters
|
7105
|
+
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
|
7106
|
+
# Now, apply filter if entered
|
7107
|
+
unless filter_value.empty?
|
7108
|
+
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
|
7109
|
+
contact.members.any? do |attribute|
|
7110
|
+
contact[attribute].to_s.downcase.include?(filter_value.downcase)
|
7111
|
+
end
|
7112
|
+
end
|
7113
|
+
end
|
7114
|
+
}
|
7115
|
+
]
|
7116
|
+
}
|
7117
|
+
|
7118
|
+
table {
|
7119
|
+
text_column('Name')
|
7120
|
+
text_column('Email')
|
7121
|
+
text_column('Phone')
|
7122
|
+
text_column('City')
|
7123
|
+
text_column('State')
|
7124
|
+
|
7125
|
+
editable true
|
7126
|
+
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
|
7127
|
+
|
7128
|
+
on_changed do |row, type, row_data|
|
7129
|
+
puts "Row #{row} #{type}: #{row_data}"
|
7130
|
+
end
|
7131
|
+
}
|
7132
|
+
}
|
7133
|
+
}.show
|
7134
|
+
end
|
7135
|
+
end
|
6435
7136
|
|
7137
|
+
FormTable.new.launch
|
6436
7138
|
```
|
6437
|
-
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
|
6438
|
-
```
|
6439
|
-
|
6440
|
-
Mac | Windows | Linux
|
6441
|
-
----|---------|------
|
6442
|
-
![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)
|
6443
7139
|
|
6444
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
7140
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (with explicit [data-binding](#data-binding) to raw data):
|
6445
7141
|
|
6446
7142
|
```ruby
|
6447
7143
|
require 'glimmer-dsl-libui'
|
@@ -6449,15 +7145,15 @@ require 'glimmer-dsl-libui'
|
|
6449
7145
|
class FormTable
|
6450
7146
|
include Glimmer
|
6451
7147
|
|
6452
|
-
attr_accessor :name, :email, :phone, :city, :state, :filter_value
|
7148
|
+
attr_accessor :data, :name, :email, :phone, :city, :state, :filter_value
|
6453
7149
|
|
6454
7150
|
def initialize
|
6455
7151
|
@data = [
|
6456
|
-
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'
|
6457
|
-
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'
|
6458
|
-
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'
|
6459
|
-
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'
|
6460
|
-
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'
|
7152
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
7153
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
7154
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
7155
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
7156
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
6461
7157
|
]
|
6462
7158
|
end
|
6463
7159
|
|
@@ -6471,7 +7167,7 @@ class FormTable
|
|
6471
7167
|
|
6472
7168
|
entry {
|
6473
7169
|
label 'Name'
|
6474
|
-
text <=> [self, :name]
|
7170
|
+
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
|
6475
7171
|
}
|
6476
7172
|
|
6477
7173
|
entry {
|
@@ -6503,8 +7199,8 @@ class FormTable
|
|
6503
7199
|
if new_row.include?('')
|
6504
7200
|
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
6505
7201
|
else
|
6506
|
-
|
6507
|
-
@unfiltered_data =
|
7202
|
+
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
7203
|
+
@unfiltered_data = data.dup
|
6508
7204
|
self.name = '' # automatically clears name entry through explicit data-binding
|
6509
7205
|
self.email = ''
|
6510
7206
|
self.phone = ''
|
@@ -6516,14 +7212,15 @@ class FormTable
|
|
6516
7212
|
|
6517
7213
|
search_entry {
|
6518
7214
|
stretchy false
|
6519
|
-
|
7215
|
+
# bidirectional data-binding of text to self.filter_value with after_write option
|
7216
|
+
text <=> [self, :filter_value,
|
6520
7217
|
after_write: ->(filter_value) { # execute after write to self.filter_value
|
6521
|
-
@unfiltered_data ||=
|
7218
|
+
@unfiltered_data ||= data.dup
|
6522
7219
|
# Unfilter first to remove any previous filters
|
6523
|
-
|
7220
|
+
data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
6524
7221
|
# Now, apply filter if entered
|
6525
7222
|
unless filter_value.empty?
|
6526
|
-
|
7223
|
+
data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
6527
7224
|
row_data.any? do |cell|
|
6528
7225
|
cell.to_s.downcase.include?(filter_value.downcase)
|
6529
7226
|
end
|
@@ -6539,8 +7236,9 @@ class FormTable
|
|
6539
7236
|
text_column('Phone')
|
6540
7237
|
text_column('City')
|
6541
7238
|
text_column('State')
|
6542
|
-
|
6543
|
-
|
7239
|
+
|
7240
|
+
editable true
|
7241
|
+
cell_rows <=> [self, :data] # explicit data-binding to raw data Array of Arrays
|
6544
7242
|
|
6545
7243
|
on_changed do |row, type, row_data|
|
6546
7244
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -6554,7 +7252,7 @@ end
|
|
6554
7252
|
FormTable.new.launch
|
6555
7253
|
```
|
6556
7254
|
|
6557
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
|
7255
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 5 (with implicit [data-binding](#data-binding)):
|
6558
7256
|
|
6559
7257
|
```ruby
|
6560
7258
|
require 'glimmer-dsl-libui'
|
@@ -6562,11 +7260,11 @@ require 'glimmer-dsl-libui'
|
|
6562
7260
|
include Glimmer
|
6563
7261
|
|
6564
7262
|
data = [
|
6565
|
-
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'
|
6566
|
-
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'
|
6567
|
-
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'
|
6568
|
-
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'
|
6569
|
-
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'
|
7263
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'],
|
7264
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'],
|
7265
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'],
|
7266
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'],
|
7267
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
|
6570
7268
|
]
|
6571
7269
|
|
6572
7270
|
window('Contacts', 600, 600) { |w|
|
@@ -6642,7 +7340,8 @@ window('Contacts', 600, 600) { |w|
|
|
6642
7340
|
text_column('City')
|
6643
7341
|
text_column('State')
|
6644
7342
|
|
6645
|
-
|
7343
|
+
editable true
|
7344
|
+
cell_rows data # implicit data-binding to raw data Array of Arrays
|
6646
7345
|
|
6647
7346
|
on_changed do |row, type, row_data|
|
6648
7347
|
puts "Row #{row} #{type}: #{row_data}"
|
@@ -8178,7 +8877,7 @@ Mac | Windows | Linux
|
|
8178
8877
|
----|---------|------
|
8179
8878
|
![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)
|
8180
8879
|
|
8181
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
8880
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
8182
8881
|
|
8183
8882
|
```ruby
|
8184
8883
|
require 'glimmer-dsl-libui'
|
@@ -8195,6 +8894,7 @@ class Snake
|
|
8195
8894
|
@game = Model::Game.new
|
8196
8895
|
@grid = Presenter::Grid.new(@game)
|
8197
8896
|
@game.start
|
8897
|
+
@keypress_queue = []
|
8198
8898
|
create_gui
|
8199
8899
|
register_observers
|
8200
8900
|
end
|
@@ -8214,14 +8914,30 @@ class Snake
|
|
8214
8914
|
end
|
8215
8915
|
|
8216
8916
|
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
8217
|
-
|
8917
|
+
unless @game.over?
|
8918
|
+
process_queued_keypress
|
8919
|
+
@game.snake.move
|
8920
|
+
end
|
8921
|
+
end
|
8922
|
+
end
|
8923
|
+
|
8924
|
+
def process_queued_keypress
|
8925
|
+
# 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)
|
8926
|
+
key = @keypress_queue.shift
|
8927
|
+
case [@game.snake.head.orientation, key]
|
8928
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
8929
|
+
@game.snake.turn_right
|
8930
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
8931
|
+
@game.snake.turn_left
|
8932
|
+
else
|
8933
|
+
# No Op
|
8218
8934
|
end
|
8219
8935
|
end
|
8220
8936
|
|
8221
8937
|
def create_gui
|
8222
8938
|
@main_window = window {
|
8223
8939
|
# data-bind window title to game score, converting it to a title string on read from the model
|
8224
|
-
title <= [@game, :score, on_read: -> (score) {"
|
8940
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
8225
8941
|
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
8226
8942
|
resizable false
|
8227
8943
|
|
@@ -8239,15 +8955,109 @@ class Snake
|
|
8239
8955
|
}
|
8240
8956
|
|
8241
8957
|
on_key_up do |area_key_event|
|
8242
|
-
|
8243
|
-
|
8244
|
-
|
8245
|
-
|
8246
|
-
|
8247
|
-
|
8248
|
-
|
8249
|
-
|
8250
|
-
|
8958
|
+
@keypress_queue << area_key_event[:ext_key]
|
8959
|
+
end
|
8960
|
+
}
|
8961
|
+
end
|
8962
|
+
}
|
8963
|
+
end
|
8964
|
+
}
|
8965
|
+
}
|
8966
|
+
end
|
8967
|
+
end
|
8968
|
+
|
8969
|
+
Snake.new.launch
|
8970
|
+
```
|
8971
|
+
|
8972
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
8973
|
+
|
8974
|
+
```ruby
|
8975
|
+
require 'glimmer-dsl-libui'
|
8976
|
+
|
8977
|
+
require_relative 'snake/presenter/grid'
|
8978
|
+
|
8979
|
+
class Snake
|
8980
|
+
include Glimmer
|
8981
|
+
|
8982
|
+
CELL_SIZE = 15
|
8983
|
+
SNAKE_MOVE_DELAY = 0.1
|
8984
|
+
|
8985
|
+
def initialize
|
8986
|
+
@game = Model::Game.new
|
8987
|
+
@grid = Presenter::Grid.new(@game)
|
8988
|
+
@game.start
|
8989
|
+
@keypress_queue = []
|
8990
|
+
create_gui
|
8991
|
+
register_observers
|
8992
|
+
end
|
8993
|
+
|
8994
|
+
def launch
|
8995
|
+
@main_window.show
|
8996
|
+
end
|
8997
|
+
|
8998
|
+
def register_observers
|
8999
|
+
@game.height.times do |row|
|
9000
|
+
@game.width.times do |column|
|
9001
|
+
observe(@grid.cells[row][column], :color) do |new_color|
|
9002
|
+
@cell_grid[row][column].fill = new_color
|
9003
|
+
end
|
9004
|
+
end
|
9005
|
+
end
|
9006
|
+
|
9007
|
+
observe(@game, :over) do |game_over|
|
9008
|
+
Glimmer::LibUI.queue_main do
|
9009
|
+
if game_over
|
9010
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
9011
|
+
@game.start
|
9012
|
+
end
|
9013
|
+
end
|
9014
|
+
end
|
9015
|
+
|
9016
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
9017
|
+
unless @game.over?
|
9018
|
+
process_queued_keypress
|
9019
|
+
@game.snake.move
|
9020
|
+
end
|
9021
|
+
end
|
9022
|
+
end
|
9023
|
+
|
9024
|
+
def process_queued_keypress
|
9025
|
+
# 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)
|
9026
|
+
key = @keypress_queue.shift
|
9027
|
+
case [@game.snake.head.orientation, key]
|
9028
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
9029
|
+
@game.snake.turn_right
|
9030
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
9031
|
+
@game.snake.turn_left
|
9032
|
+
else
|
9033
|
+
# No Op
|
9034
|
+
end
|
9035
|
+
end
|
9036
|
+
|
9037
|
+
def create_gui
|
9038
|
+
@cell_grid = []
|
9039
|
+
@main_window = window {
|
9040
|
+
# data-bind window title to game score, converting it to a title string on read from the model
|
9041
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
9042
|
+
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
9043
|
+
resizable false
|
9044
|
+
|
9045
|
+
vertical_box {
|
9046
|
+
padded false
|
9047
|
+
|
9048
|
+
@game.height.times do |row|
|
9049
|
+
@cell_grid << []
|
9050
|
+
horizontal_box {
|
9051
|
+
padded false
|
9052
|
+
|
9053
|
+
@game.width.times do |column|
|
9054
|
+
area {
|
9055
|
+
@cell_grid.last << square(0, 0, CELL_SIZE) {
|
9056
|
+
fill Presenter::Cell::COLOR_CLEAR
|
9057
|
+
}
|
9058
|
+
|
9059
|
+
on_key_up do |area_key_event|
|
9060
|
+
@keypress_queue << area_key_event[:ext_key]
|
8251
9061
|
end
|
8252
9062
|
}
|
8253
9063
|
end
|
@@ -8676,7 +9486,7 @@ Mac | Windows | Linux
|
|
8676
9486
|
----|---------|------
|
8677
9487
|
![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)
|
8678
9488
|
|
8679
|
-
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
9489
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with [data-binding](#data-binding)):
|
8680
9490
|
|
8681
9491
|
```ruby
|
8682
9492
|
require 'glimmer-dsl-libui'
|
@@ -8722,6 +9532,7 @@ class TicTacToe
|
|
8722
9532
|
text(23, 19) {
|
8723
9533
|
string {
|
8724
9534
|
font family: 'Arial', size: OS.mac? ? 20 : 16
|
9535
|
+
# data-bind string property of area text attributed string to tic tac toe board cell sign
|
8725
9536
|
string <= [@tic_tac_toe_board[row + 1, column + 1], :sign] # board model is 1-based
|
8726
9537
|
}
|
8727
9538
|
}
|
@@ -8755,6 +9566,95 @@ end
|
|
8755
9566
|
TicTacToe.new.launch
|
8756
9567
|
```
|
8757
9568
|
|
9569
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (without [data-binding](#data-binding)):
|
9570
|
+
|
9571
|
+
```ruby
|
9572
|
+
|
9573
|
+
require 'glimmer-dsl-libui'
|
9574
|
+
|
9575
|
+
require_relative "tic_tac_toe/board"
|
9576
|
+
|
9577
|
+
class TicTacToe
|
9578
|
+
include Glimmer
|
9579
|
+
|
9580
|
+
def initialize
|
9581
|
+
@tic_tac_toe_board = Board.new
|
9582
|
+
end
|
9583
|
+
|
9584
|
+
def launch
|
9585
|
+
create_gui
|
9586
|
+
register_observers
|
9587
|
+
@main_window.show
|
9588
|
+
end
|
9589
|
+
|
9590
|
+
def register_observers
|
9591
|
+
observe(@tic_tac_toe_board, :game_status) do |game_status|
|
9592
|
+
display_win_message if game_status == Board::WIN
|
9593
|
+
display_draw_message if game_status == Board::DRAW
|
9594
|
+
end
|
9595
|
+
|
9596
|
+
3.times.map do |row|
|
9597
|
+
3.times.map do |column|
|
9598
|
+
observe(@tic_tac_toe_board[row + 1, column + 1], :sign) do |sign| # board model is 1-based
|
9599
|
+
@cells[row][column].string = sign
|
9600
|
+
end
|
9601
|
+
end
|
9602
|
+
end
|
9603
|
+
end
|
9604
|
+
|
9605
|
+
def create_gui
|
9606
|
+
@main_window = window('Tic-Tac-Toe', 180, 180) {
|
9607
|
+
resizable false
|
9608
|
+
|
9609
|
+
@cells = []
|
9610
|
+
vertical_box {
|
9611
|
+
padded false
|
9612
|
+
|
9613
|
+
3.times.map do |row|
|
9614
|
+
@cells << []
|
9615
|
+
horizontal_box {
|
9616
|
+
padded false
|
9617
|
+
|
9618
|
+
3.times.map do |column|
|
9619
|
+
area {
|
9620
|
+
square(0, 0, 60) {
|
9621
|
+
stroke :black, thickness: 2
|
9622
|
+
}
|
9623
|
+
text(23, 19) {
|
9624
|
+
@cells[row] << string('') {
|
9625
|
+
font family: 'Arial', size: OS.mac? ? 20 : 16
|
9626
|
+
}
|
9627
|
+
}
|
9628
|
+
on_mouse_up do
|
9629
|
+
@tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
|
9630
|
+
end
|
9631
|
+
}
|
9632
|
+
end
|
9633
|
+
}
|
9634
|
+
end
|
9635
|
+
}
|
9636
|
+
}
|
9637
|
+
end
|
9638
|
+
|
9639
|
+
def display_win_message
|
9640
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
9641
|
+
end
|
9642
|
+
|
9643
|
+
def display_draw_message
|
9644
|
+
display_game_over_message("Draw!")
|
9645
|
+
end
|
9646
|
+
|
9647
|
+
def display_game_over_message(message_text)
|
9648
|
+
Glimmer::LibUI.queue_main do
|
9649
|
+
msg_box('Game Over', message_text)
|
9650
|
+
@tic_tac_toe_board.reset!
|
9651
|
+
end
|
9652
|
+
end
|
9653
|
+
end
|
9654
|
+
|
9655
|
+
TicTacToe.new.launch
|
9656
|
+
```
|
9657
|
+
|
8758
9658
|
#### Timer
|
8759
9659
|
|
8760
9660
|
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).
|
@@ -9115,7 +10015,7 @@ These features have been planned or suggested. You might see them in a future ve
|
|
9115
10015
|
is fine, but please isolate to its own commit so I can cherry-pick
|
9116
10016
|
around it.
|
9117
10017
|
|
9118
|
-
Note that the latest development sometimes takes place in [development](https://github.com/AndyObtiva/glimmer-dsl-libui/tree/development) branch (
|
10018
|
+
Note that the latest development sometimes takes place in the [development](https://github.com/AndyObtiva/glimmer-dsl-libui/tree/development) branch (usually deleted once merged back to [master](https://github.com/AndyObtiva/glimmer-dsl-libui)).
|
9119
10019
|
|
9120
10020
|
## Contributors
|
9121
10021
|
|