glimmer-dsl-libui 0.6.0.pre.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/LICENSE.txt +1 -1
- data/README.md +3 -5
- data/VERSION +1 -1
- data/bin/girb_runner.rb +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md +0 -56
- data/examples/basic_table_checkbox.rb +13 -1
- data/examples/basic_table_checkbox_text.rb +13 -1
- data/examples/tetris/model/block.rb +1 -1
- data/examples/tetris/model/game.rb +1 -1
- data/examples/tetris/model/past_game.rb +1 -1
- data/examples/tetris/model/tetromino.rb +1 -1
- data/examples/tetris.rb +1 -1
- data/examples/tic_tac_toe/board.rb +1 -1
- data/examples/tic_tac_toe/cell.rb +1 -1
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/bind_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/control_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/custom_control_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/data_binding_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/dsl.rb +1 -1
- data/lib/glimmer/dsl/libui/file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/listener_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/observe_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/open_file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/open_folder_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/operation_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/property_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/save_file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/shape_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/shine_data_binding_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/string_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/tab_item_expression.rb +1 -1
- data/lib/glimmer/fiddle_consumer.rb +1 -1
- data/lib/glimmer/libui/attributed_string.rb +1 -1
- data/lib/glimmer/libui/control_proxy/area_proxy/scrolling_area_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box/horizontal_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box/vertical_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box.rb +1 -1
- data/lib/glimmer/libui/control_proxy/button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/checkbox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/progress_bar_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/date_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/time_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/dual_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/editable_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/enableable_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy/password_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy/search_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/form_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/grid_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/group_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/image_part_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/image_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/label_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/matrix_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/about_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/preferences_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/separator_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box/msg_box_error_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box/msg_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box.rb +1 -1
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy/non_wrapping_multiline_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/tab_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +243 -98
- data/lib/glimmer/libui/control_proxy/text_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/transformable.rb +1 -1
- data/lib/glimmer/libui/control_proxy/triple_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy.rb +1 -1
- data/lib/glimmer/libui/custom_control/code_area.rb +1 -1
- data/lib/glimmer/libui/custom_control/refined_table.rb +2 -2
- data/lib/glimmer/libui/custom_control.rb +1 -1
- data/lib/glimmer/libui/custom_window.rb +1 -1
- data/lib/glimmer/libui/data_bindable.rb +1 -1
- data/lib/glimmer/libui/parent.rb +1 -1
- data/lib/glimmer/libui/shape/arc.rb +1 -1
- data/lib/glimmer/libui/shape/bezier.rb +1 -1
- data/lib/glimmer/libui/shape/circle.rb +1 -1
- data/lib/glimmer/libui/shape/figure.rb +1 -1
- data/lib/glimmer/libui/shape/line.rb +1 -1
- data/lib/glimmer/libui/shape/polybezier.rb +1 -1
- data/lib/glimmer/libui/shape/polygon.rb +1 -1
- data/lib/glimmer/libui/shape/polyline.rb +1 -1
- data/lib/glimmer/libui/shape/rectangle.rb +1 -1
- data/lib/glimmer/libui/shape/square.rb +1 -1
- data/lib/glimmer/libui/shape.rb +1 -1
- data/lib/glimmer/libui.rb +1 -1
- data/lib/glimmer-dsl-libui.rb +1 -1
- metadata +5 -5
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2021-
|
1
|
+
# Copyright (c) 2021-2023 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -48,7 +48,7 @@ module Glimmer
|
|
48
48
|
@enabled = true
|
49
49
|
@columns = []
|
50
50
|
@cell_rows = []
|
51
|
-
@last_cell_rows =
|
51
|
+
@last_cell_rows = nil
|
52
52
|
register_cell_rows_observer
|
53
53
|
window_proxy.on_destroy do
|
54
54
|
# the following unless condition is an exceptional condition stumbled upon that fails freeing the table model
|
@@ -88,7 +88,12 @@ module Glimmer
|
|
88
88
|
else
|
89
89
|
if !rows.equal?(@cell_rows)
|
90
90
|
@cell_rows = rows
|
91
|
-
|
91
|
+
# TODO instead of clearing cached cell rows, consider amending cached cell rows for better performance (to avoid regenerating them)
|
92
|
+
clear_cached_cell_rows
|
93
|
+
if @cell_rows.is_a?(Enumerator)
|
94
|
+
@cell_rows.rewind
|
95
|
+
@future_last_cell_rows = array_deep_dup(@cell_rows) # must be done after rewinding
|
96
|
+
end
|
92
97
|
end
|
93
98
|
@cell_rows
|
94
99
|
end
|
@@ -96,20 +101,21 @@ module Glimmer
|
|
96
101
|
alias cell_rows= cell_rows
|
97
102
|
alias set_cell_rows cell_rows
|
98
103
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
@expanded_cell_rows = expand(@expanded_cell_rows_dependency_cell_rows)
|
104
|
-
end
|
105
|
-
@expanded_cell_rows
|
104
|
+
def expand_cell_rows(cell_rows = nil)
|
105
|
+
cell_rows ||= self.cell_rows
|
106
|
+
cell_rows ||= []
|
107
|
+
cell_rows.map { |cell_row| expand_cell_row(cell_row) }
|
106
108
|
end
|
109
|
+
alias expanded_cell_rows expand_cell_rows
|
107
110
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
def expand_cell_row(cell_row)
|
112
|
+
return cell_row if cell_row.nil?
|
113
|
+
cell_row = expand_cell_row_from_model(cell_row) if !cell_row.is_a?(Array) && @column_attributes&.any?
|
114
|
+
cell_row.flatten(1)
|
115
|
+
end
|
116
|
+
|
117
|
+
def expand_cell_row_from_model(cell_row)
|
118
|
+
@column_attributes.to_a.map {|attribute| cell_row.send(attribute) }
|
113
119
|
end
|
114
120
|
|
115
121
|
def editable(value = nil)
|
@@ -133,14 +139,14 @@ module Glimmer
|
|
133
139
|
model_attribute_observer = model_attribute_observer_registration = nil
|
134
140
|
model_attribute_observer = Glimmer::DataBinding::Observer.proc do
|
135
141
|
new_value = model_binding.evaluate_property
|
136
|
-
new_value = new_value.to_a if new_value.is_a?(Enumerator)
|
137
142
|
if model_binding.binding_options[:column_attributes] || (!new_value.nil? && (!new_value.is_a?(String) || !new_value.empty?) && (!new_value.is_a?(Array) || !new_value.first.is_a?(Array)))
|
138
143
|
@model_attribute_array_observer_registration&.deregister
|
139
144
|
@model_attribute_array_observer_registration = model_attribute_observer.observe(new_value, @column_attributes, ignore_frozen: true, attribute_writer_type: [:attribute=, :set_attribute])
|
140
145
|
model_attribute_observer.add_dependent(model_attribute_observer_registration => @model_attribute_array_observer_registration)
|
141
146
|
end
|
142
147
|
# TODO look if multiple notifications are happening as a result of observing array and observing model binding
|
143
|
-
|
148
|
+
last_cell_rows = @last_cell_rows || [] # initialize with empty array of first time loading table (only time when @last_cell_rows is nil)
|
149
|
+
send("#{property}=", new_value) unless last_cell_rows == new_value
|
144
150
|
end
|
145
151
|
model_attribute_observer_registration = model_attribute_observer.observe(model_binding, attribute_writer_type: [:attribute=, :set_attribute])
|
146
152
|
model_attribute_observer.call # initial update
|
@@ -149,22 +155,127 @@ module Glimmer
|
|
149
155
|
end
|
150
156
|
|
151
157
|
def data_bind_write(property, model_binding)
|
152
|
-
# TODO ensure writing is happening to models if rows are not arrays
|
153
158
|
handle_listener('on_edited') { model_binding.call(cell_rows) } if property == 'cell_rows'
|
154
159
|
end
|
155
160
|
|
156
|
-
def
|
161
|
+
def array_deep_dup(array_or_object)
|
157
162
|
if array_or_object.is_a?(Array)
|
158
163
|
array_or_object.map do |element|
|
159
|
-
|
164
|
+
array_deep_dup(element)
|
160
165
|
end
|
161
166
|
else
|
162
|
-
array_or_object.
|
167
|
+
array_or_object.dup
|
163
168
|
end
|
164
169
|
end
|
165
170
|
|
171
|
+
def compound_column_index_for(expanded_column_index)
|
172
|
+
compound_column = @columns.find { |compound_column| compound_column.respond_to?(:column_index) && compound_column.column_index == expanded_column_index }
|
173
|
+
compound_columns = @columns.select { |compound_column| compound_column.is_a?(Column) }
|
174
|
+
compound_columns.index(compound_column)
|
175
|
+
end
|
176
|
+
|
166
177
|
private
|
167
178
|
|
179
|
+
# returns table cell for row and column (expanded)
|
180
|
+
def expanded_cell_for(row, column)
|
181
|
+
cell_row = expanded_cell_row_for(row)
|
182
|
+
cell = cell_row && cell_row[column]
|
183
|
+
end
|
184
|
+
|
185
|
+
def expanded_cell_row_for(row)
|
186
|
+
expand_cell_row(cell_row_for(row))
|
187
|
+
end
|
188
|
+
|
189
|
+
def cell_row_for(row)
|
190
|
+
@cached_cell_rows ||= []
|
191
|
+
if @cached_cell_rows[row].nil?
|
192
|
+
cell_rows = self.cell_rows || []
|
193
|
+
if cell_rows.is_a?(Enumerator)
|
194
|
+
@cached_cell_rows_size ||= @cached_cell_rows.size
|
195
|
+
@cached_cell_rows_enumerator_index ||= 0
|
196
|
+
# TODO consider handling size being nil and needing to force Enumerator count instead
|
197
|
+
while @cached_cell_rows_enumerator_index <= row
|
198
|
+
begin
|
199
|
+
@cached_cell_rows << cell_rows.next
|
200
|
+
@cached_cell_rows_enumerator_index += 1
|
201
|
+
rescue StopIteration => e
|
202
|
+
break
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
@cached_cell_rows = cell_rows
|
207
|
+
end
|
208
|
+
end
|
209
|
+
@cached_cell_rows[row]
|
210
|
+
end
|
211
|
+
|
212
|
+
def last_cell_row_for(row)
|
213
|
+
# TODO refactor to share code with cell_row_for
|
214
|
+
@cached_last_cell_rows ||= []
|
215
|
+
if @cached_last_cell_rows[row].nil?
|
216
|
+
last_cell_rows = @last_cell_rows || []
|
217
|
+
if last_cell_rows.is_a?(Enumerator)
|
218
|
+
@cached_last_cell_rows_size ||= @cached_last_cell_rows.size
|
219
|
+
@cached_last_cell_rows_enumerator_index ||= 0
|
220
|
+
# TODO consider handling size being nil and needing to force Enumerator count instead
|
221
|
+
while @cached_last_cell_rows_enumerator_index <= row
|
222
|
+
begin
|
223
|
+
@cached_last_cell_rows << last_cell_rows.next
|
224
|
+
@cached_last_cell_rows_enumerator_index += 1
|
225
|
+
rescue StopIteration => e
|
226
|
+
break
|
227
|
+
end
|
228
|
+
end
|
229
|
+
else
|
230
|
+
@cached_last_cell_rows = last_cell_rows
|
231
|
+
end
|
232
|
+
end
|
233
|
+
@cached_last_cell_rows[row]
|
234
|
+
end
|
235
|
+
|
236
|
+
def last_last_cell_row_for(row)
|
237
|
+
# TODO refactor to share code with cell_row_for
|
238
|
+
@cached_last_last_cell_rows ||= []
|
239
|
+
if @cached_last_last_cell_rows[row].nil?
|
240
|
+
last_last_cell_rows = @last_last_cell_rows || []
|
241
|
+
if last_last_cell_rows.is_a?(Enumerator)
|
242
|
+
@cached_last_last_cell_rows_size ||= @cached_last_last_cell_rows.size
|
243
|
+
@cached_last_last_cell_rows_enumerator_index ||= 0
|
244
|
+
# TODO consider handling size being nil and needing to force Enumerator count instead
|
245
|
+
while @cached_last_last_cell_rows_enumerator_index <= row
|
246
|
+
begin
|
247
|
+
@cached_last_last_cell_rows << last_last_cell_rows.next
|
248
|
+
@cached_last_last_cell_rows_enumerator_index += 1
|
249
|
+
rescue StopIteration => e
|
250
|
+
break
|
251
|
+
end
|
252
|
+
end
|
253
|
+
else
|
254
|
+
@cached_last_last_cell_rows = last_last_cell_rows
|
255
|
+
end
|
256
|
+
end
|
257
|
+
@cached_last_last_cell_rows[row]
|
258
|
+
end
|
259
|
+
|
260
|
+
def dup_last_cell_rows
|
261
|
+
return (@last_cell_rows = nil) if @cell_rows.nil?
|
262
|
+
# using future last cell rows guarantees that Enumerator is rewound
|
263
|
+
@last_cell_rows = @future_last_cell_rows || array_deep_dup(@cell_rows)
|
264
|
+
@future_last_last_cell_rows = array_deep_dup(@last_cell_rows)
|
265
|
+
@future_last_cell_rows = nil
|
266
|
+
clear_cached_last_cell_rows
|
267
|
+
@last_cell_rows
|
268
|
+
end
|
269
|
+
|
270
|
+
def dup_last_last_cell_rows
|
271
|
+
return (@last_last_cell_rows = nil) if @last_cell_rows.nil?
|
272
|
+
# using future last cell rows guarantees that Enumerator is rewound
|
273
|
+
@last_last_cell_rows = @future_last_last_cell_rows || array_deep_dup(@last_cell_rows)
|
274
|
+
@future_last_last_cell_rows = nil
|
275
|
+
clear_cached_last_last_cell_rows
|
276
|
+
@last_last_cell_rows
|
277
|
+
end
|
278
|
+
|
168
279
|
def build_control
|
169
280
|
@model_handler = ::LibUI::FFI::TableModelHandler.malloc
|
170
281
|
@model_handler.NumColumns = fiddle_closure_block_caller(4) { @columns.map {|c| c.is_a?(DualColumn) ? 2 : (c.is_a?(TripleColumn) ? 3 : 1)}.sum }
|
@@ -183,102 +294,106 @@ module Glimmer
|
|
183
294
|
end
|
184
295
|
@model_handler.NumRows = fiddle_closure_block_caller(4) do
|
185
296
|
# Note: there is a double-delete bug in Windows when performing table_model_row_deleted, which requires pre-adding and extra empty row
|
186
|
-
cell_rows.
|
297
|
+
cell_rows.size + (OS.windows? ? 1 : 0)
|
298
|
+
# TODO consider handling case of Enumerator not having size, but having count that needs to be forced instead
|
187
299
|
end
|
188
300
|
@model_handler.CellValue = fiddle_closure_block_caller(1, [1, 1, 4, 4]) do |_, _, row, column|
|
189
|
-
|
301
|
+
cell_rows = self.cell_rows || []
|
302
|
+
the_cell = expanded_cell_for(row, column)
|
190
303
|
case @columns[column]
|
191
304
|
when Column::TextColumnProxy, Column::ButtonColumnProxy, Column::TextColorColumnProxy, :text
|
192
|
-
::LibUI.new_table_value_string((
|
305
|
+
::LibUI.new_table_value_string((the_cell).to_s)
|
193
306
|
when Column::ImageColumnProxy, Column::ImageTextColumnProxy, Column::ImageTextColorColumnProxy
|
194
|
-
if OS.windows? && row == cell_rows.
|
307
|
+
if OS.windows? && row == cell_rows.size
|
195
308
|
img = Glimmer::LibUI::ICON
|
196
309
|
else
|
197
|
-
img =
|
310
|
+
img = the_cell
|
198
311
|
end
|
199
312
|
img = ControlProxy::ImageProxy.create('image', nil, img) if img.is_a?(Array)
|
200
313
|
img = ControlProxy::ImageProxy.create('image', nil, [img]) if img.is_a?(String)
|
201
314
|
img = img.respond_to?(:libui) ? img.libui : img
|
202
315
|
::LibUI.new_table_value_image(img)
|
203
316
|
when Column::CheckboxColumnProxy, Column::CheckboxTextColumnProxy, Column::CheckboxTextColorColumnProxy
|
204
|
-
::LibUI.new_table_value_int(((
|
317
|
+
::LibUI.new_table_value_int(((the_cell == 1 || the_cell.to_s.strip.downcase == 'true' ? 1 : 0)) || 0)
|
205
318
|
when Column::ProgressBarColumnProxy
|
206
|
-
value = (
|
207
|
-
|
208
|
-
|
319
|
+
value = (the_cell).to_i
|
320
|
+
expanded_last_last_cell_row = expand_cell_row(last_last_cell_row_for(row))
|
321
|
+
# TODO consider only caching old value when displayed in CellValue before, but otherwise not worrying about it (if row was hiding, this fix shouldn't be needed on Windows)
|
322
|
+
old_value = (expanded_last_last_cell_row && expanded_last_last_cell_row[column]).to_i
|
209
323
|
if OS.windows? && old_value == -1 && value >= 0
|
210
324
|
Glimmer::Config.logger.error('Switching a progress bar value from -1 to a positive value is not supported on Windows')
|
211
|
-
|
325
|
+
cell_row = cell_row_for(row)
|
326
|
+
if cell_row.is_a?(Array)
|
327
|
+
cell_row[compound_column_index_for(column)] = -1
|
328
|
+
else
|
329
|
+
attribute = @column_attributes[column]
|
330
|
+
cell_row.send("#{attribute}=", -1)
|
331
|
+
end
|
212
332
|
::LibUI.new_table_value_int(old_value)
|
213
333
|
else
|
214
|
-
::LibUI.new_table_value_int((
|
334
|
+
::LibUI.new_table_value_int((the_cell).to_i)
|
215
335
|
end
|
216
336
|
when Column::BackgroundColorColumnProxy
|
217
|
-
background_color = Glimmer::LibUI.interpret_color(
|
337
|
+
background_color = Glimmer::LibUI.interpret_color(the_cell) || {r: 255, g: 255, b: 255}
|
218
338
|
::LibUI.new_table_value_color(background_color[:r] / 255.0, background_color[:g] / 255.0, background_color[:b] / 255.0, background_color[:a] || 1.0)
|
219
339
|
when :color
|
220
|
-
color = Glimmer::LibUI.interpret_color(
|
340
|
+
color = Glimmer::LibUI.interpret_color(the_cell) || {r: 0, g: 0, b: 0}
|
221
341
|
::LibUI.new_table_value_color(color[:r] / 255.0, color[:g] / 255.0, color[:b] / 255.0, color[:a] || 1.0)
|
222
342
|
end
|
223
343
|
end
|
224
344
|
@model_handler.SetCellValue = fiddle_closure_block_caller(0, [1, 1, 4, 4, 1]) do |_, _, row, column, val|
|
345
|
+
table_cell_row = cell_row_for(row)
|
225
346
|
case @columns[column]
|
226
347
|
when Column::TextColumnProxy
|
227
348
|
column = @columns[column].index
|
228
|
-
|
229
|
-
|
230
|
-
@cell_rows[row][column] = ::LibUI.table_value_string(val).to_s
|
349
|
+
if table_cell_row.is_a?(Array)
|
350
|
+
table_cell_row[column] = ::LibUI.table_value_string(val).to_s
|
231
351
|
else
|
232
352
|
attribute = @column_attributes[column]
|
233
|
-
|
353
|
+
table_cell_row.send("#{attribute}=", ::LibUI.table_value_string(val).to_s)
|
234
354
|
end
|
235
355
|
when Column::TextColorColumnProxy
|
236
356
|
column = @columns[column].index
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
@cell_rows[row][column][0] = ::LibUI.table_value_string(val).to_s
|
357
|
+
if table_cell_row.is_a?(Array)
|
358
|
+
table_cell_row[column] ||= []
|
359
|
+
table_cell_row[column][0] = ::LibUI.table_value_string(val).to_s
|
241
360
|
else
|
242
361
|
attribute = @column_attributes[column]
|
243
|
-
|
244
|
-
|
362
|
+
table_cell_row.send("#{attribute}=", []) unless table_cell_row.send(attribute)
|
363
|
+
table_cell_row.send(attribute)[0] = ::LibUI.table_value_string(val).to_s
|
245
364
|
end
|
246
365
|
when :text
|
247
366
|
column = @columns[column - 1].index
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
@cell_rows[row][column][1] = ::LibUI.table_value_string(val).to_s
|
367
|
+
if table_cell_row.is_a?(Array)
|
368
|
+
table_cell_row[column] ||= []
|
369
|
+
table_cell_row[column][1] = ::LibUI.table_value_string(val).to_s
|
252
370
|
else
|
253
371
|
attribute = @column_attributes[column]
|
254
|
-
|
255
|
-
|
372
|
+
table_cell_row.send("#{attribute}=", []) unless table_cell_row.send(attribute)
|
373
|
+
table_cell_row.send(attribute)[1] = ::LibUI.table_value_string(val).to_s
|
256
374
|
end
|
257
375
|
when Column::ButtonColumnProxy
|
258
376
|
@columns[column].notify_custom_listeners('on_clicked', row)
|
259
377
|
when Column::CheckboxColumnProxy
|
260
378
|
column = @columns[column].index
|
261
|
-
|
262
|
-
|
263
|
-
@cell_rows[row][column] = ::LibUI.table_value_int(val).to_i == 1
|
379
|
+
if table_cell_row.is_a?(Array)
|
380
|
+
table_cell_row[column] = ::LibUI.table_value_int(val).to_i == 1
|
264
381
|
else
|
265
382
|
attribute = @column_attributes[column]
|
266
|
-
|
383
|
+
table_cell_row.send("#{attribute}=", ::LibUI.table_value_int(val).to_i == 1)
|
267
384
|
end
|
268
385
|
when Column::CheckboxTextColumnProxy
|
269
386
|
column = @columns[column].index
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
@cell_rows[row][column][0] = ::LibUI.table_value_int(val).to_i == 1
|
387
|
+
if table_cell_row.is_a?(Array)
|
388
|
+
table_cell_row[column] ||= []
|
389
|
+
table_cell_row[column][0] = ::LibUI.table_value_int(val).to_i == 1
|
274
390
|
else
|
275
391
|
attribute = @column_attributes[column]
|
276
|
-
|
277
|
-
|
392
|
+
table_cell_row.send("#{attribute}=", []) unless table_cell_row.send(attribute)
|
393
|
+
table_cell_row.send(attribute)[0] = ::LibUI.table_value_int(val).to_i == 1
|
278
394
|
end
|
279
395
|
end
|
280
|
-
|
281
|
-
notify_custom_listeners('on_edited', row, @cell_rows[row])
|
396
|
+
notify_custom_listeners('on_edited', row, table_cell_row)
|
282
397
|
end
|
283
398
|
|
284
399
|
@model = ::LibUI.new_table_model(@model_handler)
|
@@ -301,6 +416,24 @@ module Glimmer
|
|
301
416
|
end
|
302
417
|
end
|
303
418
|
|
419
|
+
def clear_cached_cell_rows
|
420
|
+
@cached_cell_rows = nil
|
421
|
+
@cached_cell_rows_size = nil
|
422
|
+
@cached_cell_rows_enumerator_index = nil
|
423
|
+
end
|
424
|
+
|
425
|
+
def clear_cached_last_cell_rows
|
426
|
+
@cached_last_cell_rows = nil
|
427
|
+
@cached_last_cell_rows_size = nil
|
428
|
+
@cached_last_cell_rows_enumerator_index = nil
|
429
|
+
end
|
430
|
+
|
431
|
+
def clear_cached_last_last_cell_rows
|
432
|
+
@cached_last_last_cell_rows = nil
|
433
|
+
@cached_last_last_cell_rows_size = nil
|
434
|
+
@cached_last_last_cell_rows_enumerator_index = nil
|
435
|
+
end
|
436
|
+
|
304
437
|
def next_column_index
|
305
438
|
@next_column_index ||= -1
|
306
439
|
@next_column_index += 1
|
@@ -308,49 +441,60 @@ module Glimmer
|
|
308
441
|
|
309
442
|
def register_cell_rows_observer
|
310
443
|
@cell_rows_observer = Glimmer::DataBinding::Observer.proc do |new_cell_rows|
|
311
|
-
if
|
312
|
-
@
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
444
|
+
if !@last_cell_rows.nil? # not initial load of table
|
445
|
+
if @cell_rows.size < @last_cell_rows.size
|
446
|
+
# TODO avoid inefficient delete/change notifications by only updating cells that need updates (only cells that have been displayed in CellValue)
|
447
|
+
# instead of updating everything
|
448
|
+
@last_cell_rows.each_with_index do |old_row_data, row|
|
449
|
+
new_row_data = cell_row_for(row)
|
450
|
+
if old_row_data != new_row_data && model
|
451
|
+
::LibUI.table_model_row_changed(model, row)
|
452
|
+
notify_custom_listeners('on_changed', row, :changed, new_row_data)
|
453
|
+
end
|
317
454
|
end
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
455
|
+
count_of_cells_to_delete = @last_cell_rows.size - @cell_rows.size
|
456
|
+
count_of_cells_to_delete.times do |n|
|
457
|
+
row = @last_cell_rows.size - n - 1
|
458
|
+
if model
|
459
|
+
::LibUI.table_model_row_deleted(model, row)
|
460
|
+
notify_custom_listeners('on_changed', row, :deleted, last_cell_row_for(row))
|
461
|
+
end
|
325
462
|
end
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
notify_custom_listeners('on_changed', row, :inserted, @cell_rows[row])
|
463
|
+
elsif @cell_rows.size > @last_cell_rows.size
|
464
|
+
(@cell_rows.size - @last_cell_rows.size).times do |n|
|
465
|
+
row = @last_cell_rows.size + n
|
466
|
+
if model
|
467
|
+
::LibUI.table_model_row_inserted(model, row)
|
468
|
+
notify_custom_listeners('on_changed', row, :inserted, cell_row_for(row))
|
469
|
+
end
|
334
470
|
end
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
471
|
+
# TODO avoid inefficient insert/change notifications by only updating cells that need updates (only cells that have been displayed in CellValue)
|
472
|
+
# instead of updating everything
|
473
|
+
@cell_rows.each_with_index do |new_row_data, row|
|
474
|
+
if new_row_data != last_cell_row_for(row) && model
|
475
|
+
::LibUI.table_model_row_changed(model, row)
|
476
|
+
notify_custom_listeners('on_changed', row, :changed, new_row_data)
|
477
|
+
end
|
341
478
|
end
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
notify_custom_listeners('on_changed', row, :changed, @cell_rows[row])
|
479
|
+
elsif @cell_rows != @last_cell_rows
|
480
|
+
@cell_rows.each_with_index do |new_row_data, row|
|
481
|
+
if new_row_data != last_cell_row_for(row) && model
|
482
|
+
::LibUI.table_model_row_changed(model, row)
|
483
|
+
notify_custom_listeners('on_changed', row, :changed, new_row_data)
|
484
|
+
end
|
349
485
|
end
|
350
486
|
end
|
351
487
|
end
|
352
|
-
|
353
|
-
|
488
|
+
# TODO look into performance implications of deep cloning an entire array,
|
489
|
+
# which wastes time looping through all elements even if we are displaying about
|
490
|
+
# 20 of them only at the moment, thus preventing lazy loading from happening
|
491
|
+
# Consider alternatively caching rows per index when needed instead
|
492
|
+
# This seems to add about a full second to certain apps, especially when using enumerators
|
493
|
+
# to avoid loading everything at once
|
494
|
+
|
495
|
+
dup_last_last_cell_rows if OS.windows?
|
496
|
+
dup_last_cell_rows
|
497
|
+
|
354
498
|
if !@applied_windows_fix_on_first_cell_rows_update && OS.windows?
|
355
499
|
@applied_windows_fix_on_first_cell_rows_update = true
|
356
500
|
apply_windows_fix
|
@@ -360,6 +504,7 @@ module Glimmer
|
|
360
504
|
end
|
361
505
|
|
362
506
|
def apply_windows_fix
|
507
|
+
# TODO will this require that @cell_rows_observer is called with queue_main too to avoid issue with multiple immediate model updates breaking this?
|
363
508
|
Glimmer::LibUI.queue_main do
|
364
509
|
new_row = @columns&.select {|column| column.is_a?(Column)}&.map {|column| column.class.default_value}
|
365
510
|
if new_row
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2021-
|
1
|
+
# Copyright (c) 2021-2023 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -216,7 +216,7 @@ module Glimmer
|
|
216
216
|
if !@filtered_model_array_stack.key?(filter_query)
|
217
217
|
table_column_names = @table_proxy.columns.map(&:name)
|
218
218
|
@filtered_model_array_stack[filter_query] = model_array.dup.filter do |model|
|
219
|
-
row_values = @table_proxy.
|
219
|
+
row_values = @table_proxy.expand_cell_row(model).map(&:to_s)
|
220
220
|
row_hash = Hash[table_column_names.zip(row_values)]
|
221
221
|
filter.call(row_hash, filter_query)
|
222
222
|
end
|
data/lib/glimmer/libui/parent.rb
CHANGED