glimmer-dsl-libui 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26461689045ba139f45bc8b50392f77a261c4f3ade65ed9f64da188086d0f2e5
4
- data.tar.gz: a8745528d47f04cff8c6d65d03e7d732dc06ab3b35dbea6d754253a5eddcd543
3
+ metadata.gz: 1c1ff2eeecd4520bb427d6a2ca0abb85ea41f5b3b92d859253b59c9574c6c899
4
+ data.tar.gz: 907fa263dc715be72bf022258da6cb58aaef70e2d647ee17c29f9eda942547e5
5
5
  SHA512:
6
- metadata.gz: 286be15f2b3df417ee6c7e904508d186353118a74547a87d0eef1d79670d7d4b405a803b3ba7c86c96d0665fbf7e8673f846aad55b2ce71f45b478ce05a904f7
7
- data.tar.gz: 93e2451a94d4ec59c04a20dd6cd6cd34c3b8efb00d19d40cba7cbe6ef5c57efb0e0c689ea122d884fb0873dc7fcd50b3d68c032b0c712b9581e66303b8148257
6
+ metadata.gz: 2f8cd302076fc5e5cdced272facbd12c9af556cc0c5d1c2a3cdd271676316c80f302b496613334db749c67a8ecff2ca88bb50b3157583bce693ea7a9f77b277b
7
+ data.tar.gz: f5062b028e2c4ca0eb1e804842d7940f43c4bfb8d1212b9075a0ca223c71f9730bb36c83345029e4d4eaee30d6056851621e4726d619c7f5209c0b08bde9f74d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.7.3
4
+
5
+ - `table` `selection` data-binding support
6
+ - `table` column `sort_indicator` data-binding support
7
+ - New `examples/basic_table_selection2.rb` that uses `selection`, `selection_mode`, `header_visible`, and `sort_indicator` data-binding support
8
+
9
+ ## 0.7.2
10
+
11
+ - `table` `on_selection_changed` listener arguments now provide extra arguments of `selection`, `added_selection`, `removed_selection` after first argument (`table`)
12
+ - Update `examples/basic_table_selection.rb` to use new `on_selection_changed` arguments of `selection`, `added_selection`, and `removed_selection`
13
+
3
14
  ## 0.7.1
4
15
 
5
16
  - `table` column `on_clicked` listener (can be nested under `text_column`, `text_color_column`, `button_column`, `checkbox_column`, `checkbox_text_color_column`, `image_column`, `image_text_color_column`, `image_text_column`, and `progress_bar_column`)
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.7.1
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.7.3
2
2
  ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  ### The Quickest Way From Zero To GUI
4
4
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
@@ -544,7 +544,7 @@ gem install glimmer-dsl-libui
544
544
  Or install via Bundler `Gemfile`:
545
545
 
546
546
  ```ruby
547
- gem 'glimmer-dsl-libui', '~> 0.7.1'
547
+ gem 'glimmer-dsl-libui', '~> 0.7.3'
548
548
  ```
549
549
 
550
550
  Test that installation worked by running the [Meta-Example](#examples):
@@ -736,7 +736,7 @@ Keyword(Args) | Properties | Listeners
736
736
  `string(string = '')` | `font`, `color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `background` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `underline`, `underline_color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `open_type_features`, `string` (`String`) | None
737
737
  `tab` | `margined` (Boolean), `num_pages` (`Integer`) | None
738
738
  `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
739
- `table` | `cell_rows` (`Array` (rows) of `Arrays` (row columns) of cell values (e.g. `String` values for `text_column` cells or `Array` of `image`/`String` for `image_text_column`)), `editable` as Boolean, `selection_mode` (`:zero_or_many` , `:none` , `:zero_or_one` , or `:one`), `selection` (`Integer` for row index or `Array` of multiple row indexes), `header_visible` (Boolean) | `on_changed {|row, type, row_data| ...}`, `on_edited {|row, row_data| ...}`, `on_row_clicked {|table, row| }`, `on_row_double_clicked {|table, row| }`, and `on_selection_changed {|table| }`
739
+ `table` | `cell_rows` (`Array` (rows) of `Arrays` (row columns) of cell values (e.g. `String` values for `text_column` cells or `Array` of `image`/`String` for `image_text_column`)), `editable` as Boolean, `selection_mode` (`:zero_or_many` , `:none` , `:zero_or_one` , or `:one`), `selection` (`Integer` for row index or `Array` of multiple row indexes), `header_visible` (Boolean) | `on_changed {|row, type, row_data| ...}`, `on_edited {|row, row_data| ...}`, `on_row_clicked {|table, row| }`, `on_row_double_clicked {|table, row| }`, and `on_selection_changed {|table, selection, added_selection, removed_selection| }`
740
740
  `text(x = 0 as Numeric, y = 0 as Numeric, width = area_width as Numeric)` | `align`, `default_font` | None
741
741
  `text_column(name as String)` | `editable` (Boolean), `sort_indicator` (`:ascending` [alias: `:asc`, `:a`], `:descending` [alias: `:desc`, `:d`], or `nil`) | `on_clicked {|tc, column_index| }`
742
742
  `text_color_column(name as String)` | `editable` (Boolean) | None
@@ -1976,7 +1976,8 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
1976
1976
  - `search_entry`: `text`
1977
1977
  - `slider`: `value`
1978
1978
  - `spinbox`: `value`
1979
- - `table`: `cell_rows` (explicit data-binding by using `<=>` and [implicit data-binding](#table-api) by assigning value directly)
1979
+ - `table`: `cell_rows`, `selection`
1980
+ - `table` columns (e.g. `text_column`): `sort_indicator`
1980
1981
  - `time_picker`: `time`
1981
1982
 
1982
1983
  Example of bidirectional data-binding:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.1
1
+ 0.7.3
@@ -1506,8 +1506,6 @@ Mac | Windows | Linux
1506
1506
 
1507
1507
  ## Basic Table Selection
1508
1508
 
1509
- [examples/basic_table_selection.rb](/examples/basic_table_selection.rb)
1510
-
1511
1509
  Run with this command from the root of the project if you cloned the project:
1512
1510
 
1513
1511
  ```
@@ -1521,6 +1519,18 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_table_selection'"
1521
1519
  ```
1522
1520
 
1523
1521
  ![glimmer-dsl-libui-mac-basic-table-selection-one.png](/images/glimmer-dsl-libui-mac-basic-table-selection-one.png)
1522
+ ![glimmer-dsl-libui-mac-basic-table-selection-zero-or-one.png](/images/glimmer-dsl-libui-mac-basic-table-selection-zero-or-one.png)
1523
+ ![glimmer-dsl-libui-mac-basic-table-selection-zero-or-many.png](/images/glimmer-dsl-libui-mac-basic-table-selection-zero-or-many.png)
1524
+ ![glimmer-dsl-libui-mac-basic-table-selection-none.png](/images/glimmer-dsl-libui-mac-basic-table-selection-none.png)
1525
+ ![glimmer-dsl-libui-mac-basic-table-selection-header-not-visible.png](/images/glimmer-dsl-libui-mac-basic-table-selection-header-not-visible.png)
1526
+
1527
+ Version 1 (without data-binding):
1528
+
1529
+ [examples/basic_table_selection.rb](/examples/basic_table_selection.rb)
1530
+
1531
+ Version 2 (with data-binding):
1532
+
1533
+ [examples/basic_table_selection2.rb](/examples/basic_table_selection2.rb)
1524
1534
 
1525
1535
  ## Basic Area
1526
1536
 
@@ -4,16 +4,17 @@ class BasicTableSelection
4
4
  include Glimmer::LibUI::Application
5
5
 
6
6
  before_body do
7
- @one_data = [
7
+ data = [
8
8
  %w[cat meow],
9
9
  %w[dog woof],
10
10
  %w[chicken cock-a-doodle-doo],
11
11
  %w[horse neigh],
12
12
  %w[cow moo]
13
13
  ]
14
- @zero_or_one_data = @one_data.dup
15
- @zero_or_many_data = @one_data.dup
16
- @none_data = @one_data.dup
14
+ @one_table_data = data.dup
15
+ @zero_or_one_table_data = data.dup
16
+ @zero_or_many_table_data = data.dup
17
+ @none_table_data = data.dup
17
18
  end
18
19
 
19
20
  body {
@@ -24,8 +25,8 @@ class BasicTableSelection
24
25
  vertical_box {
25
26
  stretchy false
26
27
 
27
- @one_radio_buttons = radio_buttons {
28
- items @one_data.size.times.map { |row| "Row #{row} Selection" }
28
+ @one_table_selection_radio_buttons = radio_buttons {
29
+ items @one_table_data.size.times.map { |row| "Row #{row} Selection" }
29
30
 
30
31
  on_selected do |rb|
31
32
  @one_table.selection = [rb.selected]
@@ -43,31 +44,21 @@ class BasicTableSelection
43
44
 
44
45
  @one_table = table {
45
46
  text_column('Animal') {
46
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
47
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
47
48
 
48
49
  on_clicked do |tc, column|
49
- puts "Clicked column #{column}: #{tc.name}"
50
- selected_row = @one_table.selection && @one_data[@one_table.selection]
51
- tc.toggle_sort_indicator
52
- @one_data.sort_by! { |row_data| row_data[column] }
53
- @one_data.reverse! if tc.sort_indicator == :descending
54
- @one_table.selection = @one_data.index(selected_row)
50
+ sort_one_table_column(tc, column)
55
51
  end
56
52
  }
57
53
  text_column('Description') {
58
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
54
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
59
55
 
60
56
  on_clicked do |tc, column|
61
- puts "Clicked column #{column}: #{tc.name}"
62
- selected_row = @one_table.selection && @one_data[@one_table.selection]
63
- tc.toggle_sort_indicator
64
- @one_data.sort_by! { |row_data| row_data[column] }
65
- @one_data.reverse! if tc.sort_indicator == :descending
66
- @one_table.selection = @one_data.index(selected_row)
57
+ sort_one_table_column(tc, column)
67
58
  end
68
59
  }
69
60
 
70
- cell_rows @one_data
61
+ cell_rows @one_table_data
71
62
  selection_mode :one # other values are :zero_or_many , :zero_or_one, :none (default is :zero_or_one if not specified)
72
63
  selection 2 # initial selection row index (could be nil too or just left off, defaulting to 0)
73
64
  # header_visible true # default
@@ -80,11 +71,13 @@ class BasicTableSelection
80
71
  puts "Row Double Clicked: #{row}"
81
72
  end
82
73
 
83
- on_selection_changed do |t|
74
+ on_selection_changed do |t, selection, added_selection, removed_selection|
84
75
  # selection is an array or nil if selection mode is zero_or_many
85
76
  # otherwise, selection is a single index integer or nil when not selected
86
- puts "Selection Changed: #{t.selection.inspect}"
87
- @one_radio_buttons.selected = t.selection
77
+ puts "Selection Changed: #{selection.inspect}"
78
+ puts "Added Selection: #{added_selection.inspect}"
79
+ puts "Removed Selection: #{removed_selection.inspect}"
80
+ @one_table_selection_radio_buttons.selected = selection
88
81
  end
89
82
  }
90
83
  }
@@ -95,8 +88,8 @@ class BasicTableSelection
95
88
  vertical_box {
96
89
  stretchy false
97
90
 
98
- @zero_or_one_radio_buttons = radio_buttons {
99
- items @zero_or_one_data.size.times.map { |row| "Row #{row} Selection" }
91
+ @zero_or_one_table_selection_radio_buttons = radio_buttons {
92
+ items @zero_or_one_table_data.size.times.map { |row| "Row #{row} Selection" }
100
93
 
101
94
  on_selected do |rb|
102
95
  @zero_or_one_table.selection = [rb.selected]
@@ -114,31 +107,21 @@ class BasicTableSelection
114
107
 
115
108
  @zero_or_one_table = table {
116
109
  text_column('Animal') {
117
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
110
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
118
111
 
119
112
  on_clicked do |tc, column|
120
- puts "Clicked column #{column}: #{tc.name}"
121
- selected_row = @zero_or_one_table.selection && @zero_or_one_data[@zero_or_one_table.selection]
122
- tc.toggle_sort_indicator
123
- @zero_or_one_data.sort_by! { |row_data| row_data[column] }
124
- @zero_or_one_data.reverse! if tc.sort_indicator == :descending
125
- @zero_or_one_table.selection = @zero_or_one_data.index(selected_row)
113
+ sort_zero_or_one_table_column(tc, column)
126
114
  end
127
115
  }
128
116
  text_column('Description') {
129
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
117
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
130
118
 
131
119
  on_clicked do |tc, column|
132
- puts "Clicked column #{column}: #{tc.name}"
133
- selected_row = @zero_or_one_table.selection && @zero_or_one_data[@zero_or_one_table.selection]
134
- tc.toggle_sort_indicator
135
- @zero_or_one_data.sort_by! { |row_data| row_data[column] }
136
- @zero_or_one_data.reverse! if tc.sort_indicator == :descending
137
- @zero_or_one_table.selection = @zero_or_one_data.index(selected_row)
120
+ sort_zero_or_one_table_column(tc, column)
138
121
  end
139
122
  }
140
123
 
141
- cell_rows @zero_or_one_data
124
+ cell_rows @zero_or_one_table_data
142
125
  selection_mode :zero_or_one # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
143
126
  # selection 0 # initial selection row index (could be nil too or just left off)
144
127
  # header_visible true # default
@@ -151,11 +134,13 @@ class BasicTableSelection
151
134
  puts "Row Double Clicked: #{row}"
152
135
  end
153
136
 
154
- on_selection_changed do |t|
137
+ on_selection_changed do |t, selection, added_selection, removed_selection|
155
138
  # selection is an array or nil if selection mode is zero_or_many
156
139
  # otherwise, selection is a single index integer or nil when not selected
157
- puts "Selection Changed: #{t.selection.inspect}"
158
- @zero_or_one_radio_buttons.selected = t.selection
140
+ puts "Selection Changed: #{selection.inspect}"
141
+ puts "Added Selection: #{added_selection.inspect}"
142
+ puts "Removed Selection: #{removed_selection.inspect}"
143
+ @zero_or_one_table_selection_radio_buttons.selected = selection
159
144
  end
160
145
  }
161
146
  }
@@ -166,7 +151,7 @@ class BasicTableSelection
166
151
  vertical_box {
167
152
  stretchy false
168
153
 
169
- @zero_or_many_checkboxes = @zero_or_many_data.size.times.map do |row|
154
+ @zero_or_many_table_selection_checkboxes = @zero_or_many_table_data.size.times.map do |row|
170
155
  checkbox("Row #{row} Selection") {
171
156
  on_toggled do |c|
172
157
  table_selection = @zero_or_many_table.selection.to_a
@@ -191,31 +176,21 @@ class BasicTableSelection
191
176
 
192
177
  @zero_or_many_table = table {
193
178
  text_column('Animal') {
194
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
179
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
195
180
 
196
181
  on_clicked do |tc, column|
197
- puts "Clicked column #{column}: #{tc.name}"
198
- selected_rows = @zero_or_many_table.selection&.map { |row| @zero_or_many_data[row] }
199
- tc.toggle_sort_indicator
200
- @zero_or_many_data.sort_by! { |row_data| row_data[column] }
201
- @zero_or_many_data.reverse! if tc.sort_indicator == :descending
202
- @zero_or_many_table.selection = selected_rows&.map {|row_data| @zero_or_many_data.index(row_data) }
182
+ sort_zero_or_many_table_column(tc, column)
203
183
  end
204
184
  }
205
185
  text_column('Description') {
206
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
186
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
207
187
 
208
188
  on_clicked do |tc, column|
209
- puts "Clicked column #{column}: #{tc.name}"
210
- selected_rows = @zero_or_many_table.selection&.map { |row| @zero_or_many_data[row] }
211
- tc.toggle_sort_indicator
212
- @zero_or_many_data.sort_by! { |row_data| row_data[column] }
213
- @zero_or_many_data.reverse! if tc.sort_indicator == :descending
214
- @zero_or_many_table.selection = selected_rows&.map {|row_data| @zero_or_many_data.index(row_data) }
189
+ sort_zero_or_many_table_column(tc, column)
215
190
  end
216
191
  }
217
192
 
218
- cell_rows @zero_or_many_data
193
+ cell_rows @zero_or_many_table_data
219
194
  selection_mode :zero_or_many # other values are :none , :zero_or_one , and :one (default is :zero_or_one if not specified)
220
195
  selection 0, 2, 4 # initial selection row indexes (could be empty array too or just left off)
221
196
  # header_visible true # default
@@ -228,13 +203,17 @@ class BasicTableSelection
228
203
  puts "Row Double Clicked: #{row}"
229
204
  end
230
205
 
231
- on_selection_changed do |t|
206
+ on_selection_changed do |t, selection, added_selection, removed_selection|
232
207
  # selection is an array or nil if selection mode is zero_or_many
233
208
  # otherwise, selection is a single index integer or nil when not selected
234
- puts "Selection Changed: #{t.selection.inspect}"
235
- @zero_or_many_checkboxes.each { |cb| cb.checked = false }
236
- t.selection&.each do |selected_row|
237
- @zero_or_many_checkboxes[selected_row].checked = true
209
+ puts "Selection Changed: #{selection.inspect}"
210
+ puts "Added Selection: #{added_selection.inspect}"
211
+ puts "Removed Selection: #{removed_selection.inspect}"
212
+ removed_selection&.each do |selected_row|
213
+ @zero_or_many_table_selection_checkboxes[selected_row].checked = false
214
+ end
215
+ added_selection&.each do |selected_row|
216
+ @zero_or_many_table_selection_checkboxes[selected_row].checked = true
238
217
  end
239
218
  end
240
219
  }
@@ -253,31 +232,21 @@ class BasicTableSelection
253
232
 
254
233
  @none_table = table {
255
234
  text_column('Animal') {
256
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
235
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
257
236
 
258
237
  on_clicked do |tc, column|
259
- puts "Clicked column #{column}: #{tc.name}"
260
- selected_row = @none_table.selection && @none_data[@none_table.selection]
261
- tc.toggle_sort_indicator
262
- @none_data.sort_by! { |row_data| row_data[column] }
263
- @none_data.reverse! if tc.sort_indicator == :descending
264
- @none_table.selection = @none_data.index(selected_row)
238
+ sort_none_table_column(tc, column)
265
239
  end
266
240
  }
267
241
  text_column('Description') {
268
- # sort_indicator :descending # can be :ascending, :descending, or nil (default)
242
+ # sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
269
243
 
270
244
  on_clicked do |tc, column|
271
- puts "Clicked column #{column}: #{tc.name}"
272
- selected_row = @none_table.selection && @none_data[@none_table.selection]
273
- tc.toggle_sort_indicator
274
- @none_data.sort_by! { |row_data| row_data[column] }
275
- @none_data.reverse! if tc.sort_indicator == :descending
276
- @none_table.selection = @none_data.index(selected_row)
245
+ sort_none_table_column(tc, column)
277
246
  end
278
247
  }
279
248
 
280
- cell_rows @none_data
249
+ cell_rows @none_table_data
281
250
  selection_mode :none # other values are :zero_or_many , :zero_or_one, :one (default is :zero_or_one if not specified)
282
251
  # header_visible true # default
283
252
 
@@ -288,12 +257,6 @@ class BasicTableSelection
288
257
  on_row_double_clicked do |t, row|
289
258
  puts "Row Double Clicked: #{row}"
290
259
  end
291
-
292
- on_selection_changed do |t|
293
- # selection is an array or nil if selection mode is zero_or_many
294
- # otherwise, selection is a single index integer or nil when not selected
295
- puts "Selection Changed: #{t.selection.inspect}"
296
- end
297
260
  }
298
261
  }
299
262
  }
@@ -301,6 +264,40 @@ class BasicTableSelection
301
264
  }
302
265
  }
303
266
  }
267
+
268
+ def sort_one_table_column(tc, column)
269
+ puts "Clicked column #{column}: #{tc.name}"
270
+ selected_row = @one_table.selection && @one_table_data[@one_table.selection]
271
+ tc.toggle_sort_indicator
272
+ @one_table_data.sort_by! { |row_data| row_data[column] }
273
+ @one_table_data.reverse! if tc.sort_indicator == :descending
274
+ @one_table.selection = @one_table_data.index(selected_row)
275
+ end
276
+
277
+ def sort_zero_or_one_table_column(tc, column)
278
+ puts "Clicked column #{column}: #{tc.name}"
279
+ selected_row = @zero_or_one_table.selection && @zero_or_one_table_data[@zero_or_one_table.selection]
280
+ tc.toggle_sort_indicator
281
+ @zero_or_one_table_data.sort_by! { |row_data| row_data[column] }
282
+ @zero_or_one_table_data.reverse! if tc.sort_indicator == :descending
283
+ @zero_or_one_table.selection = @zero_or_one_table_data.index(selected_row)
284
+ end
285
+
286
+ def sort_zero_or_many_table_column(tc, column)
287
+ puts "Clicked column #{column}: #{tc.name}"
288
+ selected_rows = @zero_or_many_table.selection&.map { |row| @zero_or_many_table_data[row] }
289
+ tc.toggle_sort_indicator
290
+ @zero_or_many_table_data.sort_by! { |row_data| row_data[column] }
291
+ @zero_or_many_table_data.reverse! if tc.sort_indicator == :descending
292
+ @zero_or_many_table.selection = selected_rows&.map {|row_data| @zero_or_many_table_data.index(row_data) }
293
+ end
294
+
295
+ def sort_none_table_column(tc, column)
296
+ puts "Clicked column #{column}: #{tc.name}"
297
+ tc.toggle_sort_indicator
298
+ @none_table_data.sort_by! { |row_data| row_data[column] }
299
+ @none_table_data.reverse! if tc.sort_indicator == :descending
300
+ end
304
301
  end
305
302
 
306
303
  BasicTableSelection.launch
@@ -0,0 +1,311 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class BasicTableSelection
4
+ TableColumnPresenter = Struct.new(:name,
5
+ :column,
6
+ :sort_indicator,
7
+ :table_presenter,
8
+ keyword_init: true) do
9
+ def toggle_sort_indicator
10
+ self.sort_indicator = self.sort_indicator != :ascending ? :ascending : :descending
11
+ end
12
+
13
+ def sort
14
+ selected_data = table_presenter.selection_mode == :zero_or_many ? table_presenter.selected_rows : table_presenter.selected_row
15
+ toggle_sort_indicator
16
+ table_presenter.data.sort_by! { |row_data| row_data[column] }
17
+ table_presenter.data.reverse! if sort_indicator == :descending
18
+ table_presenter.selection = table_presenter.selection_mode == :zero_or_many ? selected_data&.map { |selected_row| table_presenter.data.index(selected_row) } : table_presenter.data.index(selected_data)
19
+ end
20
+ end
21
+
22
+ TablePresenter = Struct.new(:data,
23
+ :column_names,
24
+ :selection_mode,
25
+ :selection,
26
+ :header_visible,
27
+ keyword_init: true) do
28
+ def selection_items
29
+ data.size.times.map { |row| "Row #{row} Selection" }
30
+ end
31
+
32
+ def toggle_header_visible
33
+ self.header_visible = !(header_visible.nil? || header_visible)
34
+ end
35
+
36
+ def column_presenters
37
+ @column_presenters ||= column_names.each_with_index.map do |column_name, column|
38
+ TableColumnPresenter.new(name: column_name, column: column, table_presenter: self)
39
+ end
40
+ end
41
+
42
+ def selected_row
43
+ selection && data[selection]
44
+ end
45
+
46
+ def selected_rows
47
+ selection && selection.is_a?(Array) && selection.map { |row| data[row] }
48
+ end
49
+ end
50
+
51
+ include Glimmer::LibUI::Application
52
+
53
+ before_body do
54
+ data = [
55
+ %w[cat meow],
56
+ %w[dog woof],
57
+ %w[chicken cock-a-doodle-doo],
58
+ %w[horse neigh],
59
+ %w[cow moo]
60
+ ]
61
+ @one_table_presenter = TablePresenter.new(
62
+ data: data.dup,
63
+ column_names: ['Name', 'Description'],
64
+ selection_mode: :one, # other values are :zero_or_many , :zero_or_one, :none (default is :zero_or_one if not specified)
65
+ selection: 2, # initial selection row index (could be nil too or just left off, defaulting to 0)
66
+ header_visible: nil, # defaults to true
67
+ )
68
+ @zero_or_one_table_presenter = TablePresenter.new(
69
+ data: data.dup,
70
+ column_names: ['Name', 'Description'],
71
+ selection_mode: :zero_or_one, # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
72
+ selection: nil, # initial selection row index (could be an integer too or just left off, defaulting to nil)
73
+ header_visible: nil, # defaults to true
74
+ )
75
+ @zero_or_many_table_presenter = TablePresenter.new(
76
+ data: data.dup,
77
+ column_names: ['Name', 'Description'],
78
+ selection_mode: :zero_or_many, # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
79
+ selection: [0, 2, 4], # initial selection row index (could be an integer too or just left off, defaulting to nil)
80
+ header_visible: nil, # defaults to true
81
+ )
82
+ @none_table_presenter = TablePresenter.new(
83
+ data: data.dup,
84
+ column_names: ['Name', 'Description'],
85
+ selection_mode: :none, # other values are :zero_or_many , :zero_or_one, :one (default is :zero_or_one if not specified)
86
+ selection: nil, # defaults to nil
87
+ header_visible: nil, # defaults to true
88
+ )
89
+ end
90
+
91
+ body {
92
+ window('Basic Table Selection', 400, 300) {
93
+ tab {
94
+ tab_item('One') {
95
+ vertical_box {
96
+ vertical_box {
97
+ stretchy false
98
+
99
+ @one_table_selection_radio_buttons = radio_buttons {
100
+ items @one_table_presenter.selection_items
101
+ selected <=> [@one_table_presenter, :selection]
102
+ }
103
+ }
104
+
105
+ button('Toggle Table Header Visibility') {
106
+ stretchy false
107
+
108
+ on_clicked do
109
+ @one_table_presenter.toggle_header_visible
110
+ end
111
+ }
112
+
113
+ @one_table = table {
114
+ @one_table_presenter.column_presenters.each do |column_presenter|
115
+ text_column(column_presenter.name) {
116
+ sort_indicator <=> [column_presenter, :sort_indicator]
117
+
118
+ on_clicked do |tc, column|
119
+ puts "Clicked column #{column}: #{tc.name}"
120
+ column_presenter.sort
121
+ end
122
+ }
123
+ end
124
+
125
+ cell_rows @one_table_presenter.data
126
+ selection_mode <= [@one_table_presenter, :selection_mode]
127
+ selection <=> [@one_table_presenter, :selection]
128
+ header_visible <= [@one_table_presenter, :header_visible]
129
+
130
+ on_row_clicked do |t, row|
131
+ puts "Row Clicked: #{row}"
132
+ end
133
+
134
+ on_row_double_clicked do |t, row|
135
+ puts "Row Double Clicked: #{row}"
136
+ end
137
+
138
+ on_selection_changed do |t, selection, added_selection, removed_selection|
139
+ # selection is an array or nil if selection mode is zero_or_many
140
+ # otherwise, selection is a single index integer or nil when not selected
141
+ puts "Selection Changed: #{selection.inspect}"
142
+ puts "Added Selection: #{added_selection.inspect}"
143
+ puts "Removed Selection: #{removed_selection.inspect}"
144
+ end
145
+ }
146
+ }
147
+ }
148
+
149
+ tab_item('Zero-Or-One') {
150
+ vertical_box {
151
+ vertical_box {
152
+ stretchy false
153
+
154
+ @zero_or_one_table_selection_radio_buttons = radio_buttons {
155
+ items @zero_or_one_table_presenter.selection_items
156
+ selected <=> [@zero_or_one_table_presenter, :selection]
157
+ }
158
+ }
159
+
160
+ button('Toggle Table Header Visibility') {
161
+ stretchy false
162
+
163
+ on_clicked do
164
+ @zero_or_one_table_presenter.toggle_header_visible
165
+ end
166
+ }
167
+
168
+ @zero_or_one_table = table {
169
+ @zero_or_one_table_presenter.column_presenters.each do |column_presenter|
170
+ text_column(column_presenter.name) {
171
+ sort_indicator <=> [column_presenter, :sort_indicator]
172
+
173
+ on_clicked do |tc, column|
174
+ puts "Clicked column #{column}: #{tc.name}"
175
+ column_presenter.sort
176
+ end
177
+ }
178
+ end
179
+
180
+ cell_rows @zero_or_one_table_presenter.data
181
+ selection_mode <= [@zero_or_one_table_presenter, :selection_mode]
182
+ selection <=> [@zero_or_one_table_presenter, :selection]
183
+ header_visible <= [@zero_or_one_table_presenter, :header_visible]
184
+
185
+ on_row_clicked do |t, row|
186
+ puts "Row Clicked: #{row}"
187
+ end
188
+
189
+ on_row_double_clicked do |t, row|
190
+ puts "Row Double Clicked: #{row}"
191
+ end
192
+
193
+ on_selection_changed do |t, selection, added_selection, removed_selection|
194
+ # selection is an array or nil if selection mode is zero_or_many
195
+ # otherwise, selection is a single index integer or nil when not selected
196
+ puts "Selection Changed: #{selection.inspect}"
197
+ puts "Added Selection: #{added_selection.inspect}"
198
+ puts "Removed Selection: #{removed_selection.inspect}"
199
+ end
200
+ }
201
+ }
202
+ }
203
+
204
+ tab_item('Zero-Or-Many') {
205
+ vertical_box {
206
+ vertical_box {
207
+ stretchy false
208
+
209
+ @zero_or_many_table_selection_checkboxes = @zero_or_many_table_presenter.data.size.times.map do |row|
210
+ checkbox("Row #{row} Selection") {
211
+ on_toggled do |c|
212
+ table_selection = @zero_or_many_table_presenter.selection.to_a
213
+ if c.checked?
214
+ table_selection << row unless table_selection.include?(row)
215
+ else
216
+ table_selection.delete(row) if table_selection.include?(row)
217
+ end
218
+ @zero_or_many_table_presenter.selection = table_selection
219
+ end
220
+ }
221
+ end
222
+ }
223
+
224
+ button('Toggle Table Header Visibility') {
225
+ stretchy false
226
+
227
+ on_clicked do
228
+ @zero_or_many_table_presenter.toggle_header_visible
229
+ end
230
+ }
231
+
232
+ @zero_or_many_table = table {
233
+ @zero_or_many_table_presenter.column_presenters.each do |column_presenter|
234
+ text_column(column_presenter.name) {
235
+ sort_indicator <=> [column_presenter, :sort_indicator]
236
+
237
+ on_clicked do |tc, column|
238
+ puts "Clicked column #{column}: #{tc.name}"
239
+ column_presenter.sort
240
+ end
241
+ }
242
+ end
243
+
244
+ cell_rows @zero_or_many_table_presenter.data
245
+ selection_mode <= [@zero_or_many_table_presenter, :selection_mode]
246
+ selection <=> [@zero_or_many_table_presenter, :selection]
247
+ header_visible <= [@zero_or_many_table_presenter, :header_visible]
248
+
249
+ on_row_clicked do |t, row|
250
+ puts "Row Clicked: #{row}"
251
+ end
252
+
253
+ on_row_double_clicked do |t, row|
254
+ puts "Row Double Clicked: #{row}"
255
+ end
256
+
257
+ on_selection_changed do |t, selection, added_selection, removed_selection|
258
+ # selection is an array or nil if selection mode is zero_or_many
259
+ # otherwise, selection is a single index integer or nil when not selected
260
+ puts "Selection Changed: #{selection.inspect}"
261
+ puts "Added Selection: #{added_selection.inspect}"
262
+ puts "Removed Selection: #{removed_selection.inspect}"
263
+ end
264
+ }
265
+ }
266
+ }
267
+
268
+ tab_item('None') {
269
+ vertical_box {
270
+ button('Toggle Table Header Visibility') {
271
+ stretchy false
272
+
273
+ on_clicked do
274
+ @none_table_presenter.toggle_header_visible
275
+ end
276
+ }
277
+
278
+ @none_table = table {
279
+ @none_table_presenter.column_presenters.each do |column_presenter|
280
+ text_column(column_presenter.name) {
281
+ sort_indicator <=> [column_presenter, :sort_indicator]
282
+
283
+ on_clicked do |tc, column|
284
+ puts "Clicked column #{column}: #{tc.name}"
285
+ column_presenter.sort
286
+ end
287
+ }
288
+ end
289
+
290
+ cell_rows @none_table_presenter.data
291
+ selection_mode <= [@none_table_presenter, :selection_mode]
292
+ selection <=> [@none_table_presenter, :selection]
293
+ header_visible <= [@none_table_presenter, :header_visible]
294
+
295
+ on_row_clicked do |t, row|
296
+ puts "Row Clicked: #{row}"
297
+ end
298
+
299
+ on_row_double_clicked do |t, row|
300
+ puts "Row Double Clicked: #{row}"
301
+ end
302
+ }
303
+ }
304
+ }
305
+
306
+ }
307
+ }
308
+ }
309
+ end
310
+
311
+ BasicTableSelection.launch
Binary file
@@ -85,6 +85,15 @@ module Glimmer
85
85
  self.sort_indicator = value
86
86
  end
87
87
  end
88
+
89
+ def data_bind_write(property, model_binding)
90
+ case property
91
+ when 'sort_indicator'
92
+ Glimmer::DataBinding::Observer.proc do
93
+ model_binding.call(sort_indicator)
94
+ end.observe(self, :sort_indicator)
95
+ end
96
+ end
88
97
 
89
98
  def can_handle_listener?(listener_name)
90
99
  listener_name == 'on_clicked'
@@ -164,11 +164,11 @@ module Glimmer
164
164
  value = value.first if value.size == 1
165
165
  @selection = value
166
166
  return @selection if !@content_added
167
- return if value.nil?
167
+ return if @selection.nil?
168
168
 
169
169
  ts = ::LibUI::FFI::TableSelection.malloc
170
- ts.NumRows = value.is_a?(Array) ? value.size : 1
171
- ts.Rows = [value].flatten.pack('i*')
170
+ ts.NumRows = @selection.is_a?(Array) ? @selection.size : 1
171
+ ts.Rows = [@selection].flatten.pack('i*')
172
172
  super(ts)
173
173
  # TODO figure out why ensure block is not working (perhaps libui auto-frees that resource upon setting selection)
174
174
  # Delete following code if not needed.
@@ -224,7 +224,12 @@ module Glimmer
224
224
  end
225
225
 
226
226
  def data_bind_write(property, model_binding)
227
- handle_listener('on_edited') { model_binding.call(cell_rows) } if property == 'cell_rows'
227
+ case property
228
+ when 'cell_rows'
229
+ handle_listener('on_edited') { model_binding.call(cell_rows) }
230
+ when 'selection'
231
+ handle_listener('on_selection_changed') { model_binding.call(selection) }
232
+ end
228
233
  end
229
234
 
230
235
  def array_deep_dup(array_or_object)
@@ -248,9 +253,18 @@ module Glimmer
248
253
  end
249
254
 
250
255
  def handle_listener(listener_name, &listener)
251
- # if content has been added, then you can register listeners immediately (without accumulation
252
- if CUSTOM_LISTENER_NAMES.include?(listener_name.to_s) || @content_added
253
- super
256
+ # if content has been added, then you can register listeners immediately (without accumulation)
257
+ if CUSTOM_LISTENER_NAMES.include?(listener_name) || @content_added
258
+ actual_listener = listener
259
+ case listener_name
260
+ when 'on_selection_changed'
261
+ actual_listener = Proc.new do |myself, *args|
262
+ added_selection = selection.is_a?(Array) ? (selection - @old_selection.to_a) : selection
263
+ removed_selection = selection.is_a?(Array) ? (@old_selection.to_a - selection) : @old_selection
264
+ listener.call(myself, selection, added_selection, removed_selection)
265
+ end
266
+ end
267
+ super(listener_name, &actual_listener)
254
268
  else
255
269
  # if content is not added yet, then accumulate listeners to register later when table content is closed
256
270
  @table_listeners ||= []
@@ -603,6 +617,9 @@ module Glimmer
603
617
  @table_listeners&.each do |listener_name, listener|
604
618
  handle_listener(listener_name, &listener)
605
619
  end
620
+ handle_listener('on_selection_changed') do |myself, selection, added_selection, removed_selection|
621
+ @old_selection = selection
622
+ end
606
623
  end
607
624
 
608
625
  def register_column_listeners
@@ -167,6 +167,7 @@ module Glimmer
167
167
  end
168
168
 
169
169
  def handle_listener(listener_name, &listener)
170
+ # replace first listener argument (control libui pointer) with actual Ruby libui object
170
171
  safe_listener = Proc.new { |*args| listener.call(self, *args[1..-1]) }
171
172
  if ::LibUI.respond_to?("#{libui_api_keyword}_#{listener_name}")
172
173
  if listeners[listener_name].nil?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-libui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-12 00:00:00.000000000 Z
11
+ date: 2023-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -357,6 +357,7 @@ files:
357
357
  - examples/basic_table_image_text3.rb
358
358
  - examples/basic_table_progress_bar.rb
359
359
  - examples/basic_table_selection.rb
360
+ - examples/basic_table_selection2.rb
360
361
  - examples/basic_transform.rb
361
362
  - examples/basic_transform2.rb
362
363
  - examples/basic_window.rb