glimmer-dsl-libui 0.7.3 → 0.7.5
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +27 -6
- data/VERSION +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md +8 -2
- data/examples/basic_table_selection.rb +163 -152
- data/examples/basic_table_selection2.rb +12 -9
- data/examples/basic_table_selection3.rb +307 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/control_proxy/column.rb +6 -0
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +80 -7
- data/lib/glimmer/libui/custom_control/refined_table.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec43caceca7a5693e9a98278af76787a03cdfa7e259b4eafc221456f2388f1cf
|
|
4
|
+
data.tar.gz: 72e7b5b20c6d07ab1160d1e83c7564dea41181b538b71d73d54acb41e839f503
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b829f991b9fa34fb2ba186a022a950e45e65d13e81019ad53829b2c57b13aa7a16c10304207c6cc734015a4a5a3b44885070da15832f92f655603e925623396e
|
|
7
|
+
data.tar.gz: c00a6b5c543039dc64c68f5e2e3cccfad74f7b511ba6fb40aa3482e9468ea49de995dc0edb8cc924082c2cce456923a47e5d9bc406b2866be8999f6309b31925
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 0.7.5
|
|
4
|
+
|
|
5
|
+
- Fix [issue 46](https://github.com/AndyObtiva/glimmer-dsl-libui/issues/46) (GTK Error rendering table with zero initial elements), which happens when explicitly data-binding table cell_rows to an empty array
|
|
6
|
+
|
|
7
|
+
## 0.7.4
|
|
8
|
+
|
|
9
|
+
- `table` `sortable` property (default: `true`) to enable automatic table sorting support when `cell_rows` is an `Array` (does not sort if `cell_rows` is a lazy enumerable)
|
|
10
|
+
- Fix issue with not auto-checking checkboxes for zero-or-many table selection in `examples/basic_table_selection2.rb`
|
|
11
|
+
- Rename `examples/basic_table_selection.rb` to `examples/basic_table_selection3.rb` and add new `examples/basic_table_selection.rb` with automated `table` selection via `sortable` property (default: `true`)
|
|
12
|
+
- Disable automatic sorting by default in `refined_table` (set its `table` `sortable` property to `false`) since it does not sort over the entire collection, yet the visible collection only
|
|
13
|
+
- Disable `sortable` sorting for `table` `button_column` since it does not make sense for it
|
|
14
|
+
|
|
3
15
|
## 0.7.3
|
|
4
16
|
|
|
5
17
|
- `table` `selection` data-binding support
|
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
|
+
# [<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.5
|
|
2
2
|
## Prerequisite-Free Ruby Desktop Development GUI Library
|
|
3
3
|
### The Quickest Way From Zero To GUI
|
|
4
4
|
[](http://badge.fury.io/rb/glimmer-dsl-libui)
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
[**(Ruby Rogues Podcast Interview - Desktop Apps in Ruby ft. Andy)**](https://andymaleh.blogspot.com/2022/05/ruby-rogues-podcast-interview-desktop.html)
|
|
12
12
|
|
|
13
|
-
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/
|
|
13
|
+
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/libui-ng/libui-ng) is a prerequisite-free [MRI Ruby](https://www.ruby-lang.org) desktop development GUI (Graphical User Interface) library. No need to pre-install any prerequisites. Just install the [gem](https://rubygems.org/gems/glimmer-dsl-libui) and have platform-independent native GUI that just works!
|
|
14
14
|
|
|
15
15
|
Mac | Windows | Linux
|
|
16
16
|
----|---------|------
|
|
17
17
|
 |  | 
|
|
18
18
|
|
|
19
|
-
[LibUI](https://github.com/
|
|
19
|
+
[LibUI](https://github.com/libui-ng/libui-ng) is a relatively new C GUI library that renders native controls on every platform (similar to [SWT](https://www.eclipse.org/swt/), but without the heavy weight of the [Java Virtual Machine](https://www.java.com/en/)).
|
|
20
20
|
|
|
21
|
-
The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) as opposed to [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) or [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than mid-alpha [libui
|
|
21
|
+
The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) as opposed to [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) or [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than mid-alpha [libui](https://github.com/libui-ng/libui-ng) as GUI toolkits. Still, if there is only a need to build a small simple application, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) could be a good convenient choice due to having zero prerequisites (beyond Ruby and the dependencies included in the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui)). Also, just like [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk), its apps start instantly and have a small memory footprint. [LibUI](https://github.com/kojix2/LibUI) is a promising new GUI toolkit that might prove quite worthy in the future.
|
|
22
22
|
|
|
23
23
|
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
|
|
24
24
|
- [Declarative DSL syntax](#glimmer-gui-dsl-concepts) that visually maps to the GUI control hierarchy
|
|
@@ -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.
|
|
547
|
+
gem 'glimmer-dsl-libui', '~> 0.7.5'
|
|
548
548
|
```
|
|
549
549
|
|
|
550
550
|
Test that installation worked by running the [Meta-Example](#examples):
|
|
@@ -824,7 +824,7 @@ There are additional useful `Glimmer::LibUI` operations that are not found in `L
|
|
|
824
824
|
|
|
825
825
|
The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Keywords](#supported-keywords)):
|
|
826
826
|
- `background_color_column`: expects color cell values
|
|
827
|
-
- `button_column`: expects `String` cell values
|
|
827
|
+
- `button_column`: expects `String` cell values and a nested `on_clicked` listener that gets triggerd when a button is clicked
|
|
828
828
|
- `checkbox_column`: expects Boolean cell values
|
|
829
829
|
- `checkbox_text_column`: expects dual-element `Array` of Boolean and `String` cell values
|
|
830
830
|
- `checkbox_text_color_column`: expects triple-element `Array` of Boolean, `String`, and color cell values
|
|
@@ -842,6 +842,27 @@ Note that the `cell_rows` property declaration results in "implicit data-binding
|
|
|
842
842
|
- Inserting cell rows: Calling `Array#<<`, `Array#push`, `Array#prepend`, or any insertion/addition `Array` method automatically inserts rows in actual `table` control
|
|
843
843
|
- Changing cell rows: Calling `Array#[]=`, `Array#map!`, or any update `Array` method automatically updates rows in actual `table` control
|
|
844
844
|
|
|
845
|
+
More details about table data-binding can be found in [examples/basic_table.rb](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-table) or other `table` [basic examples](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md) and [advanced examples](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md).
|
|
846
|
+
|
|
847
|
+
The `table` control supports table selection and table sorting automatically as smart defaults, which can also be configured if needed as per the options below.
|
|
848
|
+
|
|
849
|
+
There are other properties that `table` supports:
|
|
850
|
+
- `selection_mode` (`Symbol`) [default: `:zero_or_one`]: sets selection mode to `:one`, `:zero_or_one`, `:zero_or_many`, or `:none`
|
|
851
|
+
- `selection` (`Integer` or `Array` of `Integer`s): a single `Integer` row index for `:one` and `:zero_or_one` selection modes, or an `Array` of `Integer` row indexes if selection mode is `:zero_or_many`
|
|
852
|
+
- `header_visible` (Boolean): shows or hides column headers
|
|
853
|
+
- `sortable` (Boolean) [default: `true`]: enables automatic table sorting support
|
|
854
|
+
- `on_changed {|row, type, row_data| ...}`: triggered upon a change to a row that happens outside the table in the model
|
|
855
|
+
- `on_edited {|row, row_data| ...}`: triggered upon a change to a row that happens in the table GUI through editing.
|
|
856
|
+
- `on_row_clicked {|table, row| }`: triggered upon clicking a table row
|
|
857
|
+
- `on_row_double_clicked {|table, row| }`: triggered upon double-clicking a table row
|
|
858
|
+
- `on_selection_changed {|table, selection, added_selection, removed_selection| }`: triggered upon selecting a table row
|
|
859
|
+
|
|
860
|
+
To handle `table` sorting manually, the following can be set inside a table column:
|
|
861
|
+
- `sort_indicator` (`Symbol`): sets sort indicator to ascending or descending with the value being `:ascending`, `:descending`, `:asc`, `:desc`, `:a`, or `:d`
|
|
862
|
+
- `on_clicked` (`Proc`): this listener is triggered when a table column is clicked
|
|
863
|
+
|
|
864
|
+
More details about table selection and table sorting can be found in [examples/basic_table_selection.rb](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-table-selection).
|
|
865
|
+
|
|
845
866
|
([explicit data-binding](#data-binding) supports everything available with implicit data-binding too)
|
|
846
867
|
|
|
847
868
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.7.
|
|
1
|
+
0.7.5
|
|
@@ -1506,6 +1506,8 @@ Mac | Windows | Linux
|
|
|
1506
1506
|
|
|
1507
1507
|
## Basic Table Selection
|
|
1508
1508
|
|
|
1509
|
+
[examples/basic_table_selection.rb](/examples/basic_table_selection.rb)
|
|
1510
|
+
|
|
1509
1511
|
Run with this command from the root of the project if you cloned the project:
|
|
1510
1512
|
|
|
1511
1513
|
```
|
|
@@ -1524,14 +1526,18 @@ ruby -r glimmer-dsl-libui -e "require 'examples/basic_table_selection'"
|
|
|
1524
1526
|

|
|
1525
1527
|

|
|
1526
1528
|
|
|
1527
|
-
Version 1 (
|
|
1529
|
+
Version 1 (automatic sorting and data-binding):
|
|
1528
1530
|
|
|
1529
1531
|
[examples/basic_table_selection.rb](/examples/basic_table_selection.rb)
|
|
1530
1532
|
|
|
1531
|
-
Version 2 (
|
|
1533
|
+
Version 2 (custom sorting and data-binding):
|
|
1532
1534
|
|
|
1533
1535
|
[examples/basic_table_selection2.rb](/examples/basic_table_selection2.rb)
|
|
1534
1536
|
|
|
1537
|
+
Version 3 (custom sorting without data-binding):
|
|
1538
|
+
|
|
1539
|
+
[examples/basic_table_selection3.rb](/examples/basic_table_selection3.rb)
|
|
1540
|
+
|
|
1535
1541
|
## Basic Area
|
|
1536
1542
|
|
|
1537
1543
|
[examples/basic_area.rb](/examples/basic_area.rb)
|
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
require 'glimmer-dsl-libui'
|
|
2
2
|
|
|
3
3
|
class BasicTableSelection
|
|
4
|
+
TableColumnPresenter = Struct.new(:name,
|
|
5
|
+
:column,
|
|
6
|
+
:table_presenter,
|
|
7
|
+
keyword_init: true)
|
|
8
|
+
|
|
9
|
+
TablePresenter = Struct.new(:data,
|
|
10
|
+
:column_names,
|
|
11
|
+
:selection_mode,
|
|
12
|
+
:selection,
|
|
13
|
+
:header_visible,
|
|
14
|
+
:sortable,
|
|
15
|
+
keyword_init: true) do
|
|
16
|
+
def selection_items
|
|
17
|
+
data.size.times.map { |row| "Row #{row} Selection" }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def toggle_header_visible
|
|
21
|
+
self.header_visible = !(header_visible.nil? || header_visible)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def toggle_sortable
|
|
25
|
+
self.sortable = !(sortable.nil? || sortable)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def column_presenters
|
|
29
|
+
@column_presenters ||= column_names.each_with_index.map do |column_name, column|
|
|
30
|
+
TableColumnPresenter.new(name: column_name, column: column, table_presenter: self)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def selected_row
|
|
35
|
+
selection && data[selection]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def selected_rows
|
|
39
|
+
selection && selection.is_a?(Array) && selection.map { |row| data[row] }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
4
43
|
include Glimmer::LibUI::Application
|
|
5
44
|
|
|
6
45
|
before_body do
|
|
@@ -11,10 +50,38 @@ class BasicTableSelection
|
|
|
11
50
|
%w[horse neigh],
|
|
12
51
|
%w[cow moo]
|
|
13
52
|
]
|
|
14
|
-
@
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
53
|
+
@one_table_presenter = TablePresenter.new(
|
|
54
|
+
data: data.dup,
|
|
55
|
+
column_names: ['Name', 'Description'],
|
|
56
|
+
selection_mode: :one, # other values are :zero_or_many , :zero_or_one, :none (default is :zero_or_one if not specified)
|
|
57
|
+
selection: 2, # initial selection row index (could be nil too or just left off, defaulting to 0)
|
|
58
|
+
header_visible: nil, # defaults to true
|
|
59
|
+
sortable: nil, # defaults to true
|
|
60
|
+
)
|
|
61
|
+
@zero_or_one_table_presenter = TablePresenter.new(
|
|
62
|
+
data: data.dup,
|
|
63
|
+
column_names: ['Name', 'Description'],
|
|
64
|
+
selection_mode: :zero_or_one, # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
|
|
65
|
+
selection: nil, # initial selection row index (could be an integer too or just left off, defaulting to nil)
|
|
66
|
+
header_visible: nil, # defaults to true
|
|
67
|
+
sortable: nil, # defaults to true
|
|
68
|
+
)
|
|
69
|
+
@zero_or_many_table_presenter = TablePresenter.new(
|
|
70
|
+
data: data.dup,
|
|
71
|
+
column_names: ['Name', 'Description'],
|
|
72
|
+
selection_mode: :zero_or_many, # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
|
|
73
|
+
selection: [0, 2, 4], # initial selection row index (could be an integer too or just left off, defaulting to nil)
|
|
74
|
+
header_visible: nil, # defaults to true
|
|
75
|
+
sortable: nil, # defaults to true
|
|
76
|
+
)
|
|
77
|
+
@none_table_presenter = TablePresenter.new(
|
|
78
|
+
data: data.dup,
|
|
79
|
+
column_names: ['Name', 'Description'],
|
|
80
|
+
selection_mode: :none, # other values are :zero_or_many , :zero_or_one, :one (default is :zero_or_one if not specified)
|
|
81
|
+
selection: nil, # defaults to nil
|
|
82
|
+
header_visible: nil, # defaults to true
|
|
83
|
+
sortable: nil, # defaults to true
|
|
84
|
+
)
|
|
18
85
|
end
|
|
19
86
|
|
|
20
87
|
body {
|
|
@@ -26,42 +93,37 @@ class BasicTableSelection
|
|
|
26
93
|
stretchy false
|
|
27
94
|
|
|
28
95
|
@one_table_selection_radio_buttons = radio_buttons {
|
|
29
|
-
items @
|
|
30
|
-
|
|
31
|
-
on_selected do |rb|
|
|
32
|
-
@one_table.selection = [rb.selected]
|
|
33
|
-
end
|
|
96
|
+
items @one_table_presenter.selection_items
|
|
97
|
+
selected <=> [@one_table_presenter, :selection]
|
|
34
98
|
}
|
|
35
99
|
}
|
|
36
|
-
|
|
37
|
-
|
|
100
|
+
|
|
101
|
+
horizontal_box {
|
|
38
102
|
stretchy false
|
|
39
103
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@one_table = table {
|
|
46
|
-
text_column('Animal') {
|
|
47
|
-
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
48
|
-
|
|
49
|
-
on_clicked do |tc, column|
|
|
50
|
-
sort_one_table_column(tc, column)
|
|
104
|
+
button('Toggle Table Header Visibility') {
|
|
105
|
+
on_clicked do
|
|
106
|
+
@one_table_presenter.toggle_header_visible
|
|
51
107
|
end
|
|
52
108
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sort_one_table_column(tc, column)
|
|
109
|
+
|
|
110
|
+
button('Toggle Table Sortability') {
|
|
111
|
+
on_clicked do
|
|
112
|
+
@one_table_presenter.toggle_sortable # toggles sortable attribute to false or true
|
|
58
113
|
end
|
|
59
114
|
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@one_table = table {
|
|
118
|
+
@one_table_presenter.column_presenters.each do |column_presenter|
|
|
119
|
+
text_column(column_presenter.name)
|
|
120
|
+
end
|
|
60
121
|
|
|
61
|
-
cell_rows @
|
|
62
|
-
selection_mode
|
|
63
|
-
selection
|
|
64
|
-
|
|
122
|
+
cell_rows @one_table_presenter.data
|
|
123
|
+
selection_mode <= [@one_table_presenter, :selection_mode]
|
|
124
|
+
selection <=> [@one_table_presenter, :selection]
|
|
125
|
+
header_visible <= [@one_table_presenter, :header_visible]
|
|
126
|
+
sortable <= [@one_table_presenter, :sortable]
|
|
65
127
|
|
|
66
128
|
on_row_clicked do |t, row|
|
|
67
129
|
puts "Row Clicked: #{row}"
|
|
@@ -77,54 +139,48 @@ class BasicTableSelection
|
|
|
77
139
|
puts "Selection Changed: #{selection.inspect}"
|
|
78
140
|
puts "Added Selection: #{added_selection.inspect}"
|
|
79
141
|
puts "Removed Selection: #{removed_selection.inspect}"
|
|
80
|
-
@one_table_selection_radio_buttons.selected = selection
|
|
81
142
|
end
|
|
82
143
|
}
|
|
83
144
|
}
|
|
84
145
|
}
|
|
85
|
-
|
|
146
|
+
|
|
86
147
|
tab_item('Zero-Or-One') {
|
|
87
148
|
vertical_box {
|
|
88
149
|
vertical_box {
|
|
89
150
|
stretchy false
|
|
90
151
|
|
|
91
152
|
@zero_or_one_table_selection_radio_buttons = radio_buttons {
|
|
92
|
-
items @
|
|
93
|
-
|
|
94
|
-
on_selected do |rb|
|
|
95
|
-
@zero_or_one_table.selection = [rb.selected]
|
|
96
|
-
end
|
|
153
|
+
items @zero_or_one_table_presenter.selection_items
|
|
154
|
+
selected <=> [@zero_or_one_table_presenter, :selection]
|
|
97
155
|
}
|
|
98
156
|
}
|
|
99
157
|
|
|
100
|
-
|
|
158
|
+
horizontal_box {
|
|
101
159
|
stretchy false
|
|
102
160
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@zero_or_one_table = table {
|
|
109
|
-
text_column('Animal') {
|
|
110
|
-
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
111
|
-
|
|
112
|
-
on_clicked do |tc, column|
|
|
113
|
-
sort_zero_or_one_table_column(tc, column)
|
|
161
|
+
button('Toggle Table Header Visibility') {
|
|
162
|
+
on_clicked do
|
|
163
|
+
@zero_or_one_table_presenter.toggle_header_visible
|
|
114
164
|
end
|
|
115
165
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
sort_zero_or_one_table_column(tc, column)
|
|
166
|
+
|
|
167
|
+
button('Toggle Table Sortability') {
|
|
168
|
+
on_clicked do
|
|
169
|
+
@zero_or_one_table_presenter.toggle_sortable # toggles sortable attribute to false or true
|
|
121
170
|
end
|
|
122
171
|
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@zero_or_one_table = table {
|
|
175
|
+
@zero_or_one_table_presenter.column_presenters.each do |column_presenter|
|
|
176
|
+
text_column(column_presenter.name)
|
|
177
|
+
end
|
|
123
178
|
|
|
124
|
-
cell_rows @
|
|
125
|
-
selection_mode
|
|
126
|
-
|
|
127
|
-
|
|
179
|
+
cell_rows @zero_or_one_table_presenter.data
|
|
180
|
+
selection_mode <= [@zero_or_one_table_presenter, :selection_mode]
|
|
181
|
+
selection <=> [@zero_or_one_table_presenter, :selection]
|
|
182
|
+
header_visible <= [@zero_or_one_table_presenter, :header_visible]
|
|
183
|
+
sortable <= [@zero_or_one_table_presenter, :sortable]
|
|
128
184
|
|
|
129
185
|
on_row_clicked do |t, row|
|
|
130
186
|
puts "Row Clicked: #{row}"
|
|
@@ -140,7 +196,6 @@ class BasicTableSelection
|
|
|
140
196
|
puts "Selection Changed: #{selection.inspect}"
|
|
141
197
|
puts "Added Selection: #{added_selection.inspect}"
|
|
142
198
|
puts "Removed Selection: #{removed_selection.inspect}"
|
|
143
|
-
@zero_or_one_table_selection_radio_buttons.selected = selection
|
|
144
199
|
end
|
|
145
200
|
}
|
|
146
201
|
}
|
|
@@ -151,49 +206,46 @@ class BasicTableSelection
|
|
|
151
206
|
vertical_box {
|
|
152
207
|
stretchy false
|
|
153
208
|
|
|
154
|
-
@zero_or_many_table_selection_checkboxes = @
|
|
209
|
+
@zero_or_many_table_selection_checkboxes = @zero_or_many_table_presenter.data.size.times.map do |row|
|
|
155
210
|
checkbox("Row #{row} Selection") {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
end
|
|
211
|
+
checked <=> [@zero_or_many_table_presenter, :selection,
|
|
212
|
+
on_read: ->(selection_rows) {selection_rows.to_a.include?(row)},
|
|
213
|
+
on_write: ->(checked_value) {
|
|
214
|
+
checked_value ?
|
|
215
|
+
(@zero_or_many_table_presenter.selection.to_a + [row]).uniq :
|
|
216
|
+
@zero_or_many_table_presenter.selection.to_a.reject {|v| v == row }
|
|
217
|
+
},
|
|
218
|
+
]
|
|
165
219
|
}
|
|
166
220
|
end
|
|
167
221
|
}
|
|
168
222
|
|
|
169
|
-
|
|
223
|
+
horizontal_box {
|
|
170
224
|
stretchy false
|
|
171
225
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
@zero_or_many_table = table {
|
|
178
|
-
text_column('Animal') {
|
|
179
|
-
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
180
|
-
|
|
181
|
-
on_clicked do |tc, column|
|
|
182
|
-
sort_zero_or_many_table_column(tc, column)
|
|
226
|
+
button('Toggle Table Header Visibility') {
|
|
227
|
+
on_clicked do
|
|
228
|
+
@zero_or_many_table_presenter.toggle_header_visible
|
|
183
229
|
end
|
|
184
230
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
sort_zero_or_many_table_column(tc, column)
|
|
231
|
+
|
|
232
|
+
button('Toggle Table Sortability') {
|
|
233
|
+
on_clicked do
|
|
234
|
+
@zero_or_many_table_presenter.toggle_sortable # toggles sortable attribute to false or true
|
|
190
235
|
end
|
|
191
236
|
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@zero_or_many_table = table {
|
|
240
|
+
@zero_or_many_table_presenter.column_presenters.each do |column_presenter|
|
|
241
|
+
text_column(column_presenter.name)
|
|
242
|
+
end
|
|
192
243
|
|
|
193
|
-
cell_rows @
|
|
194
|
-
selection_mode
|
|
195
|
-
selection
|
|
196
|
-
|
|
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
|
+
sortable <= [@zero_or_many_table_presenter, :sortable]
|
|
197
249
|
|
|
198
250
|
on_row_clicked do |t, row|
|
|
199
251
|
puts "Row Clicked: #{row}"
|
|
@@ -209,46 +261,39 @@ class BasicTableSelection
|
|
|
209
261
|
puts "Selection Changed: #{selection.inspect}"
|
|
210
262
|
puts "Added Selection: #{added_selection.inspect}"
|
|
211
263
|
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
|
|
217
|
-
end
|
|
218
264
|
end
|
|
219
265
|
}
|
|
220
266
|
}
|
|
221
267
|
}
|
|
222
|
-
|
|
268
|
+
|
|
223
269
|
tab_item('None') {
|
|
224
270
|
vertical_box {
|
|
225
|
-
|
|
271
|
+
horizontal_box {
|
|
226
272
|
stretchy false
|
|
227
273
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
@none_table = table {
|
|
234
|
-
text_column('Animal') {
|
|
235
|
-
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
236
|
-
|
|
237
|
-
on_clicked do |tc, column|
|
|
238
|
-
sort_none_table_column(tc, column)
|
|
274
|
+
button('Toggle Table Header Visibility') {
|
|
275
|
+
on_clicked do
|
|
276
|
+
@none_table_presenter.toggle_header_visible
|
|
239
277
|
end
|
|
240
278
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
sort_none_table_column(tc, column)
|
|
279
|
+
|
|
280
|
+
button('Toggle Table Sortability') {
|
|
281
|
+
on_clicked do
|
|
282
|
+
@none_table_presenter.toggle_sortable # toggles sortable attribute to false or true
|
|
246
283
|
end
|
|
247
284
|
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@none_table = table {
|
|
288
|
+
@none_table_presenter.column_presenters.each do |column_presenter|
|
|
289
|
+
text_column(column_presenter.name)
|
|
290
|
+
end
|
|
248
291
|
|
|
249
|
-
cell_rows @
|
|
250
|
-
selection_mode
|
|
251
|
-
|
|
292
|
+
cell_rows @none_table_presenter.data
|
|
293
|
+
selection_mode <= [@none_table_presenter, :selection_mode]
|
|
294
|
+
selection <=> [@none_table_presenter, :selection]
|
|
295
|
+
header_visible <= [@none_table_presenter, :header_visible]
|
|
296
|
+
sortable <= [@none_table_presenter, :sortable]
|
|
252
297
|
|
|
253
298
|
on_row_clicked do |t, row|
|
|
254
299
|
puts "Row Clicked: #{row}"
|
|
@@ -264,40 +309,6 @@ class BasicTableSelection
|
|
|
264
309
|
}
|
|
265
310
|
}
|
|
266
311
|
}
|
|
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
|
|
301
312
|
end
|
|
302
313
|
|
|
303
314
|
BasicTableSelection.launch
|
|
@@ -126,6 +126,7 @@ class BasicTableSelection
|
|
|
126
126
|
selection_mode <= [@one_table_presenter, :selection_mode]
|
|
127
127
|
selection <=> [@one_table_presenter, :selection]
|
|
128
128
|
header_visible <= [@one_table_presenter, :header_visible]
|
|
129
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
129
130
|
|
|
130
131
|
on_row_clicked do |t, row|
|
|
131
132
|
puts "Row Clicked: #{row}"
|
|
@@ -181,6 +182,7 @@ class BasicTableSelection
|
|
|
181
182
|
selection_mode <= [@zero_or_one_table_presenter, :selection_mode]
|
|
182
183
|
selection <=> [@zero_or_one_table_presenter, :selection]
|
|
183
184
|
header_visible <= [@zero_or_one_table_presenter, :header_visible]
|
|
185
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
184
186
|
|
|
185
187
|
on_row_clicked do |t, row|
|
|
186
188
|
puts "Row Clicked: #{row}"
|
|
@@ -208,15 +210,14 @@ class BasicTableSelection
|
|
|
208
210
|
|
|
209
211
|
@zero_or_many_table_selection_checkboxes = @zero_or_many_table_presenter.data.size.times.map do |row|
|
|
210
212
|
checkbox("Row #{row} Selection") {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
end
|
|
213
|
+
checked <=> [@zero_or_many_table_presenter, :selection,
|
|
214
|
+
on_read: ->(selection_rows) {selection_rows.to_a.include?(row)},
|
|
215
|
+
on_write: ->(checked_value) {
|
|
216
|
+
checked_value ?
|
|
217
|
+
(@zero_or_many_table_presenter.selection.to_a + [row]).uniq :
|
|
218
|
+
@zero_or_many_table_presenter.selection.to_a.reject {|v| v == row }
|
|
219
|
+
},
|
|
220
|
+
]
|
|
220
221
|
}
|
|
221
222
|
end
|
|
222
223
|
}
|
|
@@ -245,6 +246,7 @@ class BasicTableSelection
|
|
|
245
246
|
selection_mode <= [@zero_or_many_table_presenter, :selection_mode]
|
|
246
247
|
selection <=> [@zero_or_many_table_presenter, :selection]
|
|
247
248
|
header_visible <= [@zero_or_many_table_presenter, :header_visible]
|
|
249
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
248
250
|
|
|
249
251
|
on_row_clicked do |t, row|
|
|
250
252
|
puts "Row Clicked: #{row}"
|
|
@@ -291,6 +293,7 @@ class BasicTableSelection
|
|
|
291
293
|
selection_mode <= [@none_table_presenter, :selection_mode]
|
|
292
294
|
selection <=> [@none_table_presenter, :selection]
|
|
293
295
|
header_visible <= [@none_table_presenter, :header_visible]
|
|
296
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
294
297
|
|
|
295
298
|
on_row_clicked do |t, row|
|
|
296
299
|
puts "Row Clicked: #{row}"
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
require 'glimmer-dsl-libui'
|
|
2
|
+
|
|
3
|
+
class BasicTableSelection
|
|
4
|
+
include Glimmer::LibUI::Application
|
|
5
|
+
|
|
6
|
+
before_body do
|
|
7
|
+
data = [
|
|
8
|
+
%w[cat meow],
|
|
9
|
+
%w[dog woof],
|
|
10
|
+
%w[chicken cock-a-doodle-doo],
|
|
11
|
+
%w[horse neigh],
|
|
12
|
+
%w[cow moo]
|
|
13
|
+
]
|
|
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
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
window('Basic Table Selection', 400, 300) {
|
|
22
|
+
tab {
|
|
23
|
+
tab_item('One') {
|
|
24
|
+
vertical_box {
|
|
25
|
+
vertical_box {
|
|
26
|
+
stretchy false
|
|
27
|
+
|
|
28
|
+
@one_table_selection_radio_buttons = radio_buttons {
|
|
29
|
+
items @one_table_data.size.times.map { |row| "Row #{row} Selection" }
|
|
30
|
+
|
|
31
|
+
on_selected do |rb|
|
|
32
|
+
@one_table.selection = [rb.selected]
|
|
33
|
+
end
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
button('Toggle Table Header Visibility') {
|
|
38
|
+
stretchy false
|
|
39
|
+
|
|
40
|
+
on_clicked do
|
|
41
|
+
@one_table.header_visible = !@one_table.header_visible
|
|
42
|
+
end
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@one_table = table {
|
|
46
|
+
text_column('Animal') {
|
|
47
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
48
|
+
|
|
49
|
+
on_clicked do |tc, column|
|
|
50
|
+
sort_one_table_column(tc, column)
|
|
51
|
+
end
|
|
52
|
+
}
|
|
53
|
+
text_column('Description') {
|
|
54
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
55
|
+
|
|
56
|
+
on_clicked do |tc, column|
|
|
57
|
+
sort_one_table_column(tc, column)
|
|
58
|
+
end
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
cell_rows @one_table_data
|
|
62
|
+
selection_mode :one # other values are :zero_or_many , :zero_or_one, :none (default is :zero_or_one if not specified)
|
|
63
|
+
selection 2 # initial selection row index (could be nil too or just left off, defaulting to 0)
|
|
64
|
+
# header_visible true # default
|
|
65
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
66
|
+
|
|
67
|
+
on_row_clicked do |t, row|
|
|
68
|
+
puts "Row Clicked: #{row}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
on_row_double_clicked do |t, row|
|
|
72
|
+
puts "Row Double Clicked: #{row}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
on_selection_changed do |t, selection, added_selection, removed_selection|
|
|
76
|
+
# selection is an array or nil if selection mode is zero_or_many
|
|
77
|
+
# otherwise, selection is a single index integer or nil when not selected
|
|
78
|
+
puts "Selection Changed: #{selection.inspect}"
|
|
79
|
+
puts "Added Selection: #{added_selection.inspect}"
|
|
80
|
+
puts "Removed Selection: #{removed_selection.inspect}"
|
|
81
|
+
@one_table_selection_radio_buttons.selected = selection
|
|
82
|
+
end
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
tab_item('Zero-Or-One') {
|
|
88
|
+
vertical_box {
|
|
89
|
+
vertical_box {
|
|
90
|
+
stretchy false
|
|
91
|
+
|
|
92
|
+
@zero_or_one_table_selection_radio_buttons = radio_buttons {
|
|
93
|
+
items @zero_or_one_table_data.size.times.map { |row| "Row #{row} Selection" }
|
|
94
|
+
|
|
95
|
+
on_selected do |rb|
|
|
96
|
+
@zero_or_one_table.selection = [rb.selected]
|
|
97
|
+
end
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
button('Toggle Table Header Visibility') {
|
|
102
|
+
stretchy false
|
|
103
|
+
|
|
104
|
+
on_clicked do
|
|
105
|
+
@zero_or_one_table.header_visible = !@zero_or_one_table.header_visible
|
|
106
|
+
end
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@zero_or_one_table = table {
|
|
110
|
+
text_column('Animal') {
|
|
111
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
112
|
+
|
|
113
|
+
on_clicked do |tc, column|
|
|
114
|
+
sort_zero_or_one_table_column(tc, column)
|
|
115
|
+
end
|
|
116
|
+
}
|
|
117
|
+
text_column('Description') {
|
|
118
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
119
|
+
|
|
120
|
+
on_clicked do |tc, column|
|
|
121
|
+
sort_zero_or_one_table_column(tc, column)
|
|
122
|
+
end
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
cell_rows @zero_or_one_table_data
|
|
126
|
+
selection_mode :zero_or_one # other values are :zero_or_many , :one, :none (default is :zero_or_one if not specified)
|
|
127
|
+
# selection 0 # initial selection row index (could be nil too or just left off)
|
|
128
|
+
# header_visible true # default
|
|
129
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
130
|
+
|
|
131
|
+
on_row_clicked do |t, row|
|
|
132
|
+
puts "Row Clicked: #{row}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
on_row_double_clicked do |t, row|
|
|
136
|
+
puts "Row Double Clicked: #{row}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
on_selection_changed do |t, selection, added_selection, removed_selection|
|
|
140
|
+
# selection is an array or nil if selection mode is zero_or_many
|
|
141
|
+
# otherwise, selection is a single index integer or nil when not selected
|
|
142
|
+
puts "Selection Changed: #{selection.inspect}"
|
|
143
|
+
puts "Added Selection: #{added_selection.inspect}"
|
|
144
|
+
puts "Removed Selection: #{removed_selection.inspect}"
|
|
145
|
+
@zero_or_one_table_selection_radio_buttons.selected = selection
|
|
146
|
+
end
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
tab_item('Zero-Or-Many') {
|
|
152
|
+
vertical_box {
|
|
153
|
+
vertical_box {
|
|
154
|
+
stretchy false
|
|
155
|
+
|
|
156
|
+
@zero_or_many_table_selection_checkboxes = @zero_or_many_table_data.size.times.map do |row|
|
|
157
|
+
checkbox("Row #{row} Selection") {
|
|
158
|
+
on_toggled do |c|
|
|
159
|
+
table_selection = @zero_or_many_table.selection.to_a
|
|
160
|
+
if c.checked?
|
|
161
|
+
table_selection << row unless table_selection.include?(row)
|
|
162
|
+
else
|
|
163
|
+
table_selection.delete(row) if table_selection.include?(row)
|
|
164
|
+
end
|
|
165
|
+
@zero_or_many_table.selection = table_selection
|
|
166
|
+
end
|
|
167
|
+
}
|
|
168
|
+
end
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
button('Toggle Table Header Visibility') {
|
|
172
|
+
stretchy false
|
|
173
|
+
|
|
174
|
+
on_clicked do
|
|
175
|
+
@zero_or_many_table.header_visible = !@zero_or_many_table.header_visible
|
|
176
|
+
end
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@zero_or_many_table = table {
|
|
180
|
+
text_column('Animal') {
|
|
181
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
182
|
+
|
|
183
|
+
on_clicked do |tc, column|
|
|
184
|
+
sort_zero_or_many_table_column(tc, column)
|
|
185
|
+
end
|
|
186
|
+
}
|
|
187
|
+
text_column('Description') {
|
|
188
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
189
|
+
|
|
190
|
+
on_clicked do |tc, column|
|
|
191
|
+
sort_zero_or_many_table_column(tc, column)
|
|
192
|
+
end
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
cell_rows @zero_or_many_table_data
|
|
196
|
+
selection_mode :zero_or_many # other values are :none , :zero_or_one , and :one (default is :zero_or_one if not specified)
|
|
197
|
+
selection 0, 2, 4 # initial selection row indexes (could be empty array too or just left off)
|
|
198
|
+
# header_visible true # default
|
|
199
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
200
|
+
|
|
201
|
+
on_row_clicked do |t, row|
|
|
202
|
+
puts "Row Clicked: #{row}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
on_row_double_clicked do |t, row|
|
|
206
|
+
puts "Row Double Clicked: #{row}"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
on_selection_changed do |t, selection, added_selection, removed_selection|
|
|
210
|
+
# selection is an array or nil if selection mode is zero_or_many
|
|
211
|
+
# otherwise, selection is a single index integer or nil when not selected
|
|
212
|
+
puts "Selection Changed: #{selection.inspect}"
|
|
213
|
+
puts "Added Selection: #{added_selection.inspect}"
|
|
214
|
+
puts "Removed Selection: #{removed_selection.inspect}"
|
|
215
|
+
removed_selection&.each do |selected_row|
|
|
216
|
+
@zero_or_many_table_selection_checkboxes[selected_row].checked = false
|
|
217
|
+
end
|
|
218
|
+
added_selection&.each do |selected_row|
|
|
219
|
+
@zero_or_many_table_selection_checkboxes[selected_row].checked = true
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
tab_item('None') {
|
|
227
|
+
vertical_box {
|
|
228
|
+
button('Toggle Table Header Visibility') {
|
|
229
|
+
stretchy false
|
|
230
|
+
|
|
231
|
+
on_clicked do
|
|
232
|
+
@none_table.header_visible = !@none_table.header_visible
|
|
233
|
+
end
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@none_table = table {
|
|
237
|
+
text_column('Animal') {
|
|
238
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
239
|
+
|
|
240
|
+
on_clicked do |tc, column|
|
|
241
|
+
sort_none_table_column(tc, column)
|
|
242
|
+
end
|
|
243
|
+
}
|
|
244
|
+
text_column('Description') {
|
|
245
|
+
# sort_indicator :descending # (optional) can be :ascending, :descending, or nil (default)
|
|
246
|
+
|
|
247
|
+
on_clicked do |tc, column|
|
|
248
|
+
sort_none_table_column(tc, column)
|
|
249
|
+
end
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
cell_rows @none_table_data
|
|
253
|
+
selection_mode :none # other values are :zero_or_many , :zero_or_one, :one (default is :zero_or_one if not specified)
|
|
254
|
+
# header_visible true # default
|
|
255
|
+
sortable false # disable default sorting behavior to demonstrate manual sorting
|
|
256
|
+
|
|
257
|
+
on_row_clicked do |t, row|
|
|
258
|
+
puts "Row Clicked: #{row}"
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
on_row_double_clicked do |t, row|
|
|
262
|
+
puts "Row Double Clicked: #{row}"
|
|
263
|
+
end
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
def sort_one_table_column(tc, column)
|
|
273
|
+
puts "Clicked column #{column}: #{tc.name}"
|
|
274
|
+
selected_row = @one_table.selection && @one_table_data[@one_table.selection]
|
|
275
|
+
tc.toggle_sort_indicator
|
|
276
|
+
@one_table_data.sort_by! { |row_data| row_data[column] }
|
|
277
|
+
@one_table_data.reverse! if tc.sort_indicator == :descending
|
|
278
|
+
@one_table.selection = @one_table_data.index(selected_row)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def sort_zero_or_one_table_column(tc, column)
|
|
282
|
+
puts "Clicked column #{column}: #{tc.name}"
|
|
283
|
+
selected_row = @zero_or_one_table.selection && @zero_or_one_table_data[@zero_or_one_table.selection]
|
|
284
|
+
tc.toggle_sort_indicator
|
|
285
|
+
@zero_or_one_table_data.sort_by! { |row_data| row_data[column] }
|
|
286
|
+
@zero_or_one_table_data.reverse! if tc.sort_indicator == :descending
|
|
287
|
+
@zero_or_one_table.selection = @zero_or_one_table_data.index(selected_row)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def sort_zero_or_many_table_column(tc, column)
|
|
291
|
+
puts "Clicked column #{column}: #{tc.name}"
|
|
292
|
+
selected_rows = @zero_or_many_table.selection&.map { |row| @zero_or_many_table_data[row] }
|
|
293
|
+
tc.toggle_sort_indicator
|
|
294
|
+
@zero_or_many_table_data.sort_by! { |row_data| row_data[column] }
|
|
295
|
+
@zero_or_many_table_data.reverse! if tc.sort_indicator == :descending
|
|
296
|
+
@zero_or_many_table.selection = selected_rows&.map {|row_data| @zero_or_many_table_data.index(row_data) }
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def sort_none_table_column(tc, column)
|
|
300
|
+
puts "Clicked column #{column}: #{tc.name}"
|
|
301
|
+
tc.toggle_sort_indicator
|
|
302
|
+
@none_table_data.sort_by! { |row_data| row_data[column] }
|
|
303
|
+
@none_table_data.reverse! if tc.sort_indicator == :descending
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
BasicTableSelection.launch
|
data/glimmer-dsl-libui.gemspec
CHANGED
|
Binary file
|
|
@@ -101,6 +101,12 @@ module Glimmer
|
|
|
101
101
|
|
|
102
102
|
def handle_listener(listener_name, &listener)
|
|
103
103
|
column_listeners_for(listener_name) << listener
|
|
104
|
+
# TODO fix this by adding a `on_button_clicked` listener in the future to separate it from `on_clicked` on the column header
|
|
105
|
+
begin
|
|
106
|
+
super # attempt to handle listener natively if this column supports it (button_column)
|
|
107
|
+
rescue => e
|
|
108
|
+
# No Op
|
|
109
|
+
end
|
|
104
110
|
end
|
|
105
111
|
|
|
106
112
|
def column_listeners
|
|
@@ -37,6 +37,28 @@ module Glimmer
|
|
|
37
37
|
include Glimmer::FiddleConsumer
|
|
38
38
|
|
|
39
39
|
CUSTOM_LISTENER_NAMES = ['on_changed', 'on_edited']
|
|
40
|
+
DEFAULT_COLUMN_SORT_BLOCK = lambda do |table_cell_row, column, table_proxy|
|
|
41
|
+
if table_cell_row.is_a?(Array)
|
|
42
|
+
value = table_cell_row[column]
|
|
43
|
+
else
|
|
44
|
+
attribute = table_proxy.column_attributes[column]
|
|
45
|
+
value = table_cell_row.send(attribute)
|
|
46
|
+
end
|
|
47
|
+
if value.is_a?(Array)
|
|
48
|
+
# This is needed to not crash on sorting an unsortable array
|
|
49
|
+
value = value.map do |element|
|
|
50
|
+
case element
|
|
51
|
+
when true
|
|
52
|
+
1
|
|
53
|
+
when false
|
|
54
|
+
0
|
|
55
|
+
else
|
|
56
|
+
element
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
value
|
|
61
|
+
end
|
|
40
62
|
|
|
41
63
|
attr_reader :model_handler, :model, :table_params, :columns
|
|
42
64
|
|
|
@@ -66,6 +88,7 @@ module Glimmer
|
|
|
66
88
|
configure_selection
|
|
67
89
|
configure_header_visible
|
|
68
90
|
configure_column_sort_indicators
|
|
91
|
+
configure_sorting
|
|
69
92
|
end
|
|
70
93
|
|
|
71
94
|
def post_initialize_child(child)
|
|
@@ -183,6 +206,7 @@ module Glimmer
|
|
|
183
206
|
result = ::LibUI.table_header_visible(@libui)
|
|
184
207
|
LibUI.integer_to_boolean(result)
|
|
185
208
|
end
|
|
209
|
+
alias header_visible? header_visible
|
|
186
210
|
|
|
187
211
|
def header_visible=(value)
|
|
188
212
|
@header_visible = value
|
|
@@ -194,6 +218,17 @@ module Glimmer
|
|
|
194
218
|
end
|
|
195
219
|
alias set_header_visible header_visible=
|
|
196
220
|
|
|
221
|
+
def sortable
|
|
222
|
+
@sortable = true if @sortable.nil?
|
|
223
|
+
@sortable
|
|
224
|
+
end
|
|
225
|
+
alias sortable? sortable
|
|
226
|
+
|
|
227
|
+
def sortable=(value)
|
|
228
|
+
@sortable = value
|
|
229
|
+
end
|
|
230
|
+
alias set_sortable sortable=
|
|
231
|
+
|
|
197
232
|
def column_attributes
|
|
198
233
|
@column_attributes ||= columns.select {|column| column.is_a?(Column)}.map(&:name).map(&:underscore)
|
|
199
234
|
end
|
|
@@ -599,6 +634,7 @@ module Glimmer
|
|
|
599
634
|
end
|
|
600
635
|
end
|
|
601
636
|
@cell_rows_observer_registration = @cell_rows_observer.observe(self, :cell_rows, recursive: true, ignore_frozen: true, attribute_writer_type: [:attribute=, :set_attribute])
|
|
637
|
+
@cell_rows_observer.call
|
|
602
638
|
end
|
|
603
639
|
|
|
604
640
|
def apply_windows_fix
|
|
@@ -625,16 +661,14 @@ module Glimmer
|
|
|
625
661
|
def register_column_listeners
|
|
626
662
|
# register accumulated column listeners after table content is closed
|
|
627
663
|
return if @columns.nil? || @columns.empty?
|
|
628
|
-
if @columns.any? {|column| column.is_a?(Column)
|
|
664
|
+
if @columns.any? {|column| column.is_a?(Column)}
|
|
629
665
|
::LibUI.table_header_on_clicked(@libui) do |_, column_index|
|
|
630
666
|
actual_columns = @columns.select {|column| column.is_a?(Column)}
|
|
631
667
|
column = actual_columns[column_index]
|
|
632
|
-
if column.is_a?(Column)
|
|
668
|
+
if column.is_a?(Column) && !column.is_a?(Column::ButtonColumnProxy)
|
|
633
669
|
column_listeners = column.column_listeners_for('on_clicked')
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
column_listener.call(column, column_index)
|
|
637
|
-
end
|
|
670
|
+
column_listeners.each do |column_listener|
|
|
671
|
+
column_listener.call(column, column_index)
|
|
638
672
|
end
|
|
639
673
|
end
|
|
640
674
|
end
|
|
@@ -654,8 +688,47 @@ module Glimmer
|
|
|
654
688
|
end
|
|
655
689
|
|
|
656
690
|
def configure_column_sort_indicators
|
|
657
|
-
column_proxies.each
|
|
691
|
+
column_proxies.each(&:configure_sort_indicator)
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
def configure_sorting
|
|
695
|
+
if sortable?
|
|
696
|
+
columns.each do |column_object|
|
|
697
|
+
next unless column_object.is_a?(Column) && !column_object.is_a?(Column::ButtonColumnProxy)
|
|
698
|
+
column_object.on_clicked do |column_proxy, column|
|
|
699
|
+
sort_by_column(column_proxy, column)
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
def sort_by_column(column_proxy, column)
|
|
706
|
+
return unless sortable? && cell_rows.is_a?(Array)
|
|
707
|
+
old_selection = backup_selection
|
|
708
|
+
column_proxy.toggle_sort_indicator
|
|
709
|
+
cell_rows.sort_by! {|table_cell_row| DEFAULT_COLUMN_SORT_BLOCK.call(table_cell_row, column, self) }
|
|
710
|
+
cell_rows.reverse! if column_proxy.sort_indicator == :descending
|
|
711
|
+
restore_selection(old_selection)
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def backup_selection
|
|
715
|
+
if selection_mode == ::LibUI::TableSelectionModeZeroOrMany
|
|
716
|
+
selected_rows = selection&.map { |row| cell_rows[row] }
|
|
717
|
+
else
|
|
718
|
+
selected_row = selection && cell_rows[selection]
|
|
719
|
+
end
|
|
658
720
|
end
|
|
721
|
+
|
|
722
|
+
def restore_selection(old_selection)
|
|
723
|
+
if selection_mode == ::LibUI::TableSelectionModeZeroOrMany
|
|
724
|
+
selected_rows = old_selection
|
|
725
|
+
self.selection = selected_rows&.map {|row_data| cell_rows.index(row_data) }
|
|
726
|
+
else
|
|
727
|
+
selected_row = old_selection
|
|
728
|
+
self.selection = cell_rows.index(selected_row)
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
659
732
|
end
|
|
660
733
|
end
|
|
661
734
|
end
|
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.
|
|
4
|
+
version: 0.7.5
|
|
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-
|
|
11
|
+
date: 2023-04-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: glimmer
|
|
@@ -358,6 +358,7 @@ files:
|
|
|
358
358
|
- examples/basic_table_progress_bar.rb
|
|
359
359
|
- examples/basic_table_selection.rb
|
|
360
360
|
- examples/basic_table_selection2.rb
|
|
361
|
+
- examples/basic_table_selection3.rb
|
|
361
362
|
- examples/basic_transform.rb
|
|
362
363
|
- examples/basic_transform2.rb
|
|
363
364
|
- examples/basic_window.rb
|