glimmer-dsl-libui 0.7.1 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
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