glimmer-dsl-libui 0.4.11 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +473 -57
  4. data/VERSION +1 -1
  5. data/examples/basic_image.rb +5 -3
  6. data/examples/basic_image2.rb +1 -3
  7. data/examples/basic_image3.rb +3 -3
  8. data/examples/basic_image4.rb +0 -3
  9. data/examples/basic_image5.rb +0 -2
  10. data/examples/basic_table_color.rb +104 -26
  11. data/examples/basic_table_color2.rb +2 -14
  12. data/examples/basic_table_color3.rb +37 -0
  13. data/examples/basic_table_image.rb +1 -1
  14. data/examples/basic_table_image2.rb +2 -14
  15. data/examples/basic_table_image3.rb +44 -0
  16. data/examples/basic_table_image_text.rb +1 -2
  17. data/examples/basic_table_image_text2.rb +2 -13
  18. data/examples/basic_table_image_text3.rb +44 -0
  19. data/examples/cpu_percentage.rb +1 -1
  20. data/examples/editable_column_table.rb +5 -0
  21. data/examples/form_table.rb +10 -4
  22. data/examples/form_table2.rb +12 -6
  23. data/examples/form_table3.rb +9 -3
  24. data/examples/form_table4.rb +9 -3
  25. data/examples/form_table5.rb +9 -3
  26. data/examples/meta_example.rb +3 -1
  27. data/glimmer-dsl-libui.gemspec +0 -0
  28. data/lib/glimmer/libui/attributed_string.rb +17 -8
  29. data/lib/glimmer/libui/control_proxy/area_proxy.rb +17 -17
  30. data/lib/glimmer/libui/control_proxy/box.rb +1 -0
  31. data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +4 -0
  32. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +1 -29
  33. data/lib/glimmer/libui/control_proxy/form_proxy.rb +1 -0
  34. data/lib/glimmer/libui/control_proxy/image_proxy.rb +92 -10
  35. data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +18 -8
  36. data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +11 -2
  37. data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +2 -0
  38. data/lib/glimmer/libui/control_proxy/path_proxy.rb +2 -0
  39. data/lib/glimmer/libui/control_proxy/table_proxy.rb +14 -12
  40. data/lib/glimmer/libui/control_proxy/text_proxy.rb +2 -0
  41. data/lib/glimmer/libui/control_proxy/window_proxy.rb +34 -35
  42. data/lib/glimmer/libui/control_proxy.rb +45 -9
  43. data/lib/glimmer/libui/shape.rb +1 -0
  44. data/lib/glimmer/libui.rb +2 -2
  45. metadata +5 -2
@@ -180,7 +180,9 @@ class MetaExample
180
180
  }
181
181
  button('Reset') {
182
182
  on_clicked do
183
- self.code_text = File.read(file_path_for(selected_example))
183
+ version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
184
+ example = "#{selected_example}#{version_number}"
185
+ self.code_text = File.read(file_path_for(example))
184
186
  end
185
187
  }
186
188
  }
Binary file
@@ -22,7 +22,6 @@
22
22
  require 'glimmer/libui/control_proxy'
23
23
  require 'glimmer/libui/control_proxy/area_proxy'
24
24
  require 'glimmer/libui/parent'
25
- require 'glimmer/libui/control_proxy/transformable'
26
25
  require 'glimmer/libui/data_bindable'
27
26
 
28
27
  module Glimmer
@@ -48,7 +47,7 @@ module Glimmer
48
47
  @string
49
48
  else
50
49
  @string = value
51
- redraw
50
+ request_auto_redraw
52
51
  end
53
52
  end
54
53
  alias string= string
@@ -59,7 +58,7 @@ module Glimmer
59
58
  @font
60
59
  else
61
60
  @font = value
62
- redraw
61
+ request_auto_redraw
63
62
  end
64
63
  end
65
64
  alias font= font
@@ -70,7 +69,7 @@ module Glimmer
70
69
  @color
71
70
  else
72
71
  @color = Glimmer::LibUI.interpret_color(value)
73
- redraw
72
+ request_auto_redraw
74
73
  end
75
74
  end
76
75
  alias color= color
@@ -81,7 +80,7 @@ module Glimmer
81
80
  @background
82
81
  else
83
82
  @background = Glimmer::LibUI.interpret_color(value)
84
- redraw
83
+ request_auto_redraw
85
84
  end
86
85
  end
87
86
  alias background= background
@@ -92,7 +91,7 @@ module Glimmer
92
91
  @underline
93
92
  else
94
93
  @underline = value
95
- redraw
94
+ request_auto_redraw
96
95
  end
97
96
  end
98
97
  alias underline= underline
@@ -103,7 +102,7 @@ module Glimmer
103
102
  @underline_color
104
103
  else
105
104
  @underline_color = value
106
- redraw
105
+ request_auto_redraw
107
106
  end
108
107
  end
109
108
  alias underline_color= underline_color
@@ -114,12 +113,21 @@ module Glimmer
114
113
  @open_type_features
115
114
  else
116
115
  @open_type_features = value
117
- redraw
116
+ request_auto_redraw
118
117
  end
119
118
  end
120
119
  alias open_type_features= open_type_features
121
120
  alias set_open_type_features open_type_features
122
121
 
122
+ def remove_open_type_features
123
+ return if @removing_open_type_features
124
+ @removing_open_type_features = true
125
+ @open_type_features&.destroy
126
+ @open_type_features = nil
127
+ request_auto_redraw
128
+ @removing_open_type_features = false
129
+ end
130
+
123
131
  def post_add_content(block = nil)
124
132
  block ||= @block
125
133
  block_result = block&.call
@@ -189,6 +197,7 @@ module Glimmer
189
197
  end
190
198
 
191
199
  def destroy
200
+ return if ControlProxy.main_window_proxy&.destroying?
192
201
  open_type_features.destroy unless open_type_features.nil?
193
202
  @parent_proxy&.children&.delete(self)
194
203
  end
@@ -36,9 +36,9 @@ module Glimmer
36
36
  attr_accessor :current_area_draw_params
37
37
  end
38
38
 
39
- LISTENERS = ['on_draw', 'on_mouse_event', 'on_mouse_move', 'on_mouse_down', 'on_mouse_up', 'on_mouse_drag_start', 'on_mouse_drag', 'on_mouse_drop', 'on_mouse_crossed', 'on_mouse_enter', 'on_mouse_exit', 'on_drag_broken', 'on_key_event', 'on_key_down', 'on_key_up']
39
+ CUSTOM_LISTENER_NAMES = ['on_draw', 'on_mouse_event', 'on_mouse_move', 'on_mouse_down', 'on_mouse_up', 'on_mouse_drag_start', 'on_mouse_drag', 'on_mouse_drop', 'on_mouse_crossed', 'on_mouse_enter', 'on_mouse_exit', 'on_drag_broken', 'on_key_event', 'on_key_down', 'on_key_up']
40
40
 
41
- LISTENER_ALIASES = {
41
+ CUSTOM_LISTENER_NAME_ALIASES = {
42
42
  on_drawn: 'on_draw',
43
43
  on_mouse_moved: 'on_mouse_move',
44
44
  on_mouse_drag_started: 'on_mouse_drag_start',
@@ -105,7 +105,7 @@ module Glimmer
105
105
 
106
106
  def draw(area_draw_params)
107
107
  children.dup.each {|child| child.draw(area_draw_params)}
108
- on_draw.each {|listener| listener.call(area_draw_params)}
108
+ notify_custom_listeners('on_draw', area_draw_params)
109
109
  end
110
110
 
111
111
  def redraw
@@ -156,37 +156,37 @@ module Glimmer
156
156
  @area_handler.MouseEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_mouse_event|
157
157
  area_mouse_event = ::LibUI::FFI::AreaMouseEvent.new(area_mouse_event)
158
158
  area_mouse_event = area_mouse_event_hash(area_mouse_event)
159
- on_mouse_event.each { |listener| listener.call(area_mouse_event)}
160
- on_mouse_move.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
159
+ notify_custom_listeners('on_mouse_event', area_mouse_event)
160
+ notify_custom_listeners('on_mouse_move', area_mouse_event) if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
161
161
  unless @last_area_mouse_event.nil?
162
- on_mouse_down.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
163
- on_mouse_up.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
164
- on_mouse_drag_start.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
165
- on_mouse_drag.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0
166
- on_mouse_drop.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
162
+ notify_custom_listeners('on_mouse_down', area_mouse_event) if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
163
+ notify_custom_listeners('on_mouse_up', area_mouse_event) if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
164
+ notify_custom_listeners('on_mouse_drag_start', area_mouse_event) if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
165
+ notify_custom_listeners('on_mouse_drag', area_mouse_event) if area_mouse_event[:held] > 0
166
+ notify_custom_listeners('on_mouse_drop', area_mouse_event) if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
167
167
  end
168
168
  @last_area_mouse_event = area_mouse_event
169
169
  end
170
170
  @area_handler.MouseCrossed = fiddle_closure_block_caller(0, [1, 1, 4]) do |_, _, left|
171
171
  left = Glimmer::LibUI.integer_to_boolean(left)
172
- on_mouse_crossed.each { |listener| listener.call(left) }
172
+ notify_custom_listeners('on_mouse_crossed', left)
173
173
  if left
174
- on_mouse_exit.each { |listener| listener.call(left) }
174
+ notify_custom_listeners('on_mouse_exit', left)
175
175
  else
176
- on_mouse_enter.each { |listener| listener.call(left) }
176
+ notify_custom_listeners('on_mouse_enter', left)
177
177
  end
178
178
  end
179
179
  @area_handler.DragBroken = fiddle_closure_block_caller(0, [1, 1]) do |_, _|
180
- on_drag_broken.each { |listener| listener.call }
180
+ notify_custom_listeners('on_drag_broken')
181
181
  end
182
182
  @area_handler.KeyEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_key_event|
183
183
  area_key_event = ::LibUI::FFI::AreaKeyEvent.new(area_key_event)
184
184
  area_key_event = area_key_event_hash(area_key_event)
185
- on_key_event.each { |listener| listener.call(area_key_event) }
185
+ notify_custom_listeners('on_key_event', area_key_event)
186
186
  if area_key_event[:up]
187
- on_key_up.each { |listener| listener.call(area_key_event) }
187
+ notify_custom_listeners('on_key_up', area_key_event)
188
188
  else
189
- on_key_down.each { |listener| listener.call(area_key_event) }
189
+ notify_custom_listeners('on_key_down', area_key_event)
190
190
  end
191
191
  end
192
192
  @listeners_installed = true
@@ -42,6 +42,7 @@ module Glimmer
42
42
  end
43
43
 
44
44
  def destroy_child(child)
45
+ child.deregister_all_custom_listeners
45
46
  ::LibUI.send("box_delete", @libui, children.index(child))
46
47
  ControlProxy.control_proxies.delete(child)
47
48
  end
@@ -31,6 +31,10 @@ module Glimmer
31
31
  # Follows the Proxy Design Pattern
32
32
  class BackgroundColorColumnProxy < ControlProxy
33
33
  include Column
34
+
35
+ def name
36
+ 'Background Color'
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -34,36 +34,8 @@ module Glimmer
34
34
  include Column
35
35
  include EnableableColumn
36
36
 
37
- def on_clicked(&block)
38
- # TODO consider generalizing into custom listeners and moving to ControlProxy
39
- @on_clicked_procs ||= []
40
- if block.nil?
41
- @on_clicked_procs
42
- else
43
- @on_clicked_procs << block
44
- block
45
- end
46
- end
47
-
48
- def can_handle_listener?(listener_name)
49
- listener_name == 'on_clicked' || super
50
- end
37
+ CUSTOM_LISTENER_NAMES = ['on_clicked']
51
38
 
52
- def handle_listener(listener_name, &listener)
53
- case listener_name
54
- when 'on_clicked'
55
- on_clicked(&listener)
56
- else
57
- super
58
- end
59
- end
60
-
61
- def notify_listeners(listener_name, *args)
62
- @on_clicked_procs&.each do |on_clicked_proc|
63
- on_clicked_proc.call(*args)
64
- end
65
- end
66
-
67
39
  private
68
40
 
69
41
  def build_control
@@ -39,6 +39,7 @@ module Glimmer
39
39
  end
40
40
 
41
41
  def destroy_child(child)
42
+ child.deregister_all_custom_listeners
42
43
  ::LibUI.send("form_delete", @libui, children.index(child))
43
44
  ControlProxy.control_proxies.delete(child)
44
45
  end
@@ -34,14 +34,31 @@ module Glimmer
34
34
  #
35
35
  # Follows the Proxy Design Pattern
36
36
  class ImageProxy < ControlProxy
37
+ class << self
38
+ # creates or returns existing instance for passed in arguments if parent is nil and block is nil
39
+ def create(keyword, parent, args, &block)
40
+ if parent.nil? && block.nil?
41
+ instances[args] ||= new(keyword, parent, args.dup, &block)
42
+ else
43
+ new(keyword, parent, args, &block)
44
+ end
45
+ end
46
+
47
+ def instances
48
+ @@instances = {} unless defined? @@instances
49
+ @@instances
50
+ end
51
+ end
52
+
37
53
  include Parent
38
54
  prepend Transformable
39
55
 
40
- attr_reader :data, :pixels, :shapes
56
+ attr_reader :data, :pixels, :shapes, :options
41
57
 
42
58
  def initialize(keyword, parent, args, &block)
43
59
  @keyword = keyword
44
60
  @parent_proxy = parent
61
+ @options = args.last.is_a?(Hash) ? args.pop : {}
45
62
  @args = args
46
63
  @block = block
47
64
  @enabled = true
@@ -76,11 +93,47 @@ module Glimmer
76
93
  alias file= file
77
94
  alias set_file file
78
95
 
96
+ def x(value = nil)
97
+ if value.nil?
98
+ @args.size > 3 ? @args[1] : (@options[:x] || 0)
99
+ else
100
+ if @args.size > 3
101
+ @args[1] = value
102
+ else
103
+ @options[:x] = value
104
+ end
105
+ if area_image? && @content_added
106
+ post_add_content
107
+ request_auto_redraw
108
+ end
109
+ end
110
+ end
111
+ alias x= x
112
+ alias set_x x
113
+
114
+ def y(value = nil)
115
+ if value.nil?
116
+ @args.size > 3 ? @args[2] : (@options[:y] || 0)
117
+ else
118
+ if @args.size > 3
119
+ @args[2] = value
120
+ else
121
+ @options[:y] = value
122
+ end
123
+ if area_image? && @content_added
124
+ post_add_content
125
+ request_auto_redraw
126
+ end
127
+ end
128
+ end
129
+ alias y= y
130
+ alias set_y y
131
+
79
132
  def width(value = nil)
80
133
  if value.nil?
81
- @args[1]
134
+ @args.size > 3 ? @args[3] : (@options[:width] || @args[1])
82
135
  else
83
- @args[1] = value
136
+ set_width_variable(value)
84
137
  if area_image? && @content_added
85
138
  post_add_content
86
139
  request_auto_redraw
@@ -92,9 +145,9 @@ module Glimmer
92
145
 
93
146
  def height(value = nil)
94
147
  if value.nil?
95
- @args[2]
148
+ @args.size > 3 ? @args[4] : (@options[:height] || @args[2])
96
149
  else
97
- @args[2] = value
150
+ set_height_variable(value)
98
151
  if area_image? && @content_added
99
152
  post_add_content
100
153
  request_auto_redraw
@@ -126,12 +179,34 @@ module Glimmer
126
179
  end
127
180
 
128
181
  def destroy
182
+ return if ControlProxy.main_window_proxy&.destroying?
183
+ deregister_all_custom_listeners
129
184
  @parent_proxy&.children&.delete(self)
130
185
  ControlProxy.control_proxies.delete(self)
131
186
  end
132
187
 
133
188
  private
134
189
 
190
+ def set_width_variable(value)
191
+ if @args.size > 3
192
+ @args[3] = value
193
+ elsif @options[:width]
194
+ @options[:width] = value
195
+ else
196
+ @args[1] = value
197
+ end
198
+ end
199
+
200
+ def set_height_variable(value)
201
+ if @args.size > 3
202
+ @args[4] = value
203
+ elsif @options[:height]
204
+ @options[:height] = value
205
+ else
206
+ @args[2] = value
207
+ end
208
+ end
209
+
135
210
  def build_control
136
211
  unless area_image? # image object
137
212
  if file
@@ -164,10 +239,15 @@ module Glimmer
164
239
  canvas = ChunkyPNG::Canvas.from_io(f)
165
240
  f.close
166
241
  end
167
- canvas.resample_nearest_neighbor!(width, height) if width && height
242
+ original_width = canvas.width
243
+ original_height = canvas.height
244
+ require 'bigdecimal'
245
+ calculated_width = ((BigDecimal(height)/BigDecimal(original_height))*original_width).to_i if height && !width
246
+ calculated_height = ((BigDecimal(width)/BigDecimal(original_width))*original_height).to_i if width && !height
247
+ canvas.resample_nearest_neighbor!(calculated_width || width, calculated_height || height) if width || height
168
248
  @data = canvas.to_rgba_stream
169
- @args[1] = canvas.width
170
- @args[2] = canvas.height
249
+ set_width_variable(canvas.width) unless width
250
+ set_height_variable(canvas.height) unless height
171
251
  [@data, width, height]
172
252
  end
173
253
 
@@ -187,6 +267,8 @@ module Glimmer
187
267
  @shapes = []
188
268
  original_pixels = @pixels.dup
189
269
  indexed_original_pixels = Hash[original_pixels.each_with_index.to_a]
270
+ x_offset = x
271
+ y_offset = y
190
272
  @pixels.each do |pixel|
191
273
  index = indexed_original_pixels[pixel]
192
274
  @rectangle_start_x ||= pixel[:x]
@@ -195,9 +277,9 @@ module Glimmer
195
277
  @rectangle_width += 1
196
278
  else
197
279
  if pixel[:x] > 0 && pixel[:color] == original_pixels[index - 1][:color]
198
- @shapes << {x: @rectangle_start_x, y: pixel[:y], width: @rectangle_width, height: 1, color: pixel[:color]}
280
+ @shapes << {x: x_offset + @rectangle_start_x, y: y_offset + pixel[:y], width: @rectangle_width, height: 1, color: pixel[:color]}
199
281
  else
200
- @shapes << {x: pixel[:x], y: pixel[:y], width: 1, height: 1, color: pixel[:color]}
282
+ @shapes << {x: x_offset + pixel[:x], y: y_offset + pixel[:y], width: 1, height: 1, color: pixel[:color]}
201
283
  end
202
284
  @rectangle_width = 1
203
285
  @rectangle_start_x = pixel[:x] == width - 1 ? 0 : pixel[:x] + 1
@@ -35,29 +35,39 @@ module Glimmer
35
35
 
36
36
  def handle_listener(listener_name, &listener)
37
37
  if listener_name == 'on_clicked'
38
- @default_behavior_listener = Proc.new do
39
- return_value = listener.call(self)
38
+ @on_clicked_listeners ||= []
39
+ @on_clicked_listeners << listener
40
+ @default_behavior_listener ||= Proc.new do
41
+ return_value = nil
42
+ @on_clicked_listeners.each do |l|
43
+ return_value = l.call(self)
44
+ break if return_value.is_a?(Numeric)
45
+ end
40
46
  if return_value.is_a?(Numeric)
41
47
  return_value
42
48
  else
43
49
  destroy
50
+ ControlProxy.main_window_proxy&.destroy
44
51
  ::LibUI.quit
45
52
  0
46
53
  end
54
+ end.tap do |default_behavior_listener|
55
+ ::LibUI.on_should_quit(&default_behavior_listener)
47
56
  end
48
- ::LibUI.on_should_quit(&@default_behavior_listener)
49
57
  end
50
58
  end
59
+
60
+ def destroy
61
+ @on_clicked_listeners&.clear
62
+ super
63
+ end
51
64
 
52
65
  private
53
66
 
54
67
  def build_control
55
68
  @libui = @parent_proxy.append_quit_item(*@args)
56
- handle_listener('on_clicked') do
57
- ControlProxy.main_window_proxy&.destroy
58
- ::LibUI.quit
59
- 0
60
- end
69
+ # setup default on_clicked listener if no on_clicked listeners are setup
70
+ handle_listener('on_clicked') {} if @on_clicked_listeners.nil? || @on_clicked_listeners.empty?
61
71
  end
62
72
  end
63
73
  end
@@ -33,15 +33,24 @@ module Glimmer
33
33
  include Parent
34
34
 
35
35
  def destroy
36
+ return if ControlProxy.main_window_proxy&.destroying?
37
+ return if @destroying
38
+ @destroying = true
39
+ deregister_all_custom_listeners
36
40
  ::LibUI.free_open_type_features(@libui)
37
- @parent_proxy&.children&.delete(self)
41
+ @parent_proxy&.remove_open_type_features
38
42
  ControlProxy.control_proxies.delete(self)
43
+ @destroying = false
39
44
  end
40
45
 
41
46
  def redraw
42
- @parent_proxy.redraw
47
+ @parent_proxy&.redraw
43
48
  end
44
49
 
50
+ def request_auto_redraw
51
+ @parent_proxy&.request_auto_redraw
52
+ end
53
+
45
54
  private
46
55
 
47
56
  def build_control
@@ -31,6 +31,8 @@ module Glimmer
31
31
  # Follows the Proxy Design Pattern
32
32
  class OpenTypeTagProxy < ControlProxy
33
33
  def destroy
34
+ return if ControlProxy.main_window_proxy&.destroying?
35
+ deregister_all_custom_listeners
34
36
  @parent_proxy&.children&.delete(self)
35
37
  ControlProxy.control_proxies.delete(self)
36
38
  end
@@ -140,6 +140,8 @@ module Glimmer
140
140
  end
141
141
 
142
142
  def destroy
143
+ return if ControlProxy.main_window_proxy&.destroying?
144
+ deregister_all_custom_listeners
143
145
  @parent_proxy&.children&.delete(self)
144
146
  ControlProxy.control_proxies.delete(self)
145
147
  end
@@ -36,7 +36,7 @@ module Glimmer
36
36
  class TableProxy < ControlProxy
37
37
  include Glimmer::FiddleConsumer
38
38
 
39
- LISTENERS = ['on_changed', 'on_edited']
39
+ CUSTOM_LISTENER_NAMES = ['on_changed', 'on_edited']
40
40
 
41
41
  attr_reader :model_handler, :model, :table_params, :columns, :column_attributes
42
42
 
@@ -91,18 +91,18 @@ module Glimmer
91
91
  if @cell_rows.size < @last_cell_rows.size && @last_cell_rows.include_all?(*@cell_rows)
92
92
  @last_cell_rows.array_diff_indexes(@cell_rows).reverse.each do |row|
93
93
  ::LibUI.table_model_row_deleted(model, row)
94
- on_changed.each {|listener| listener.call(row, :deleted, @last_cell_rows[row])}
94
+ notify_custom_listeners('on_changed', row, :deleted, @last_cell_rows[row])
95
95
  end
96
96
  elsif @cell_rows.size > @last_cell_rows.size && @cell_rows.include_all?(*@last_cell_rows)
97
97
  @cell_rows.array_diff_indexes(@last_cell_rows).each do |row|
98
98
  ::LibUI.table_model_row_inserted(model, row)
99
- on_changed.each {|listener| listener.call(row, :inserted, @cell_rows[row])}
99
+ notify_custom_listeners('on_changed', row, :inserted, @cell_rows[row])
100
100
  end
101
101
  else
102
102
  @cell_rows.each_with_index do |new_row_data, row|
103
103
  if new_row_data != @last_cell_rows[row]
104
104
  ::LibUI.table_model_row_changed(model, row)
105
- on_changed.each {|listener| listener.call(row, :changed, @cell_rows[row])}
105
+ notify_custom_listeners('on_changed', row, :changed, @cell_rows[row])
106
106
  end
107
107
  end
108
108
  end
@@ -145,7 +145,7 @@ module Glimmer
145
145
  @column_attributes = model_binding.binding_options[:column_attributes]
146
146
  else
147
147
  column_attribute_mapping = model_binding.binding_options[:column_attributes].is_a?(Hash) ? model_binding.binding_options[:column_attributes] : {}
148
- @column_attributes = columns.map(&:name).map {|column_name| column_attribute_mapping[column_name] || column_name.underscore}
148
+ @column_attributes = columns.select {|column| column.is_a?(Column)}.map(&:name).map {|column_name| column_attribute_mapping[column_name] || column_name.underscore}
149
149
  end
150
150
  model_attribute_observer = model_attribute_observer_registration = nil
151
151
  model_attribute_observer = Glimmer::DataBinding::Observer.proc do
@@ -208,11 +208,13 @@ module Glimmer
208
208
  when Column::TextColumnProxy, Column::ButtonColumnProxy, Column::TextColorColumnProxy, :text
209
209
  ::LibUI.new_table_value_string((expanded_cell_rows[row] && expanded_cell_rows[row][column]).to_s)
210
210
  when Column::ImageColumnProxy, Column::ImageTextColumnProxy, Column::ImageTextColorColumnProxy
211
- if OS.windows? && row == cell_rows.count
212
- ::LibUI.new_table_value_image((expanded_cell_rows[row - 1] && (expanded_cell_rows[row - 1][column].respond_to?(:libui) ? expanded_cell_rows[row - 1][column].libui : expanded_cell_rows[row - 1][column])))
213
- else
214
- ::LibUI.new_table_value_image((expanded_cell_rows[row] && (expanded_cell_rows[row][column].respond_to?(:libui) ? expanded_cell_rows[row][column].libui : expanded_cell_rows[row][column])))
215
- end
211
+ # TODO refactor to eliminate redundancy and share similar code
212
+ row = row - 1 if OS.windows? && row == cell_rows.count
213
+ img = expanded_cell_rows[row][column]
214
+ img = ControlProxy::ImageProxy.create('image', nil, img) if img.is_a?(Array)
215
+ img = ControlProxy::ImageProxy.create('image', nil, [img]) if img.is_a?(String)
216
+ img = img.respond_to?(:libui) ? img.libui : img
217
+ ::LibUI.new_table_value_image(img)
216
218
  when Column::CheckboxColumnProxy, Column::CheckboxTextColumnProxy, Column::CheckboxTextColorColumnProxy
217
219
  ::LibUI.new_table_value_int(((expanded_cell_rows[row] && (expanded_cell_rows[row][column] == 1 || expanded_cell_rows[row][column].to_s.strip.downcase == 'true' ? 1 : 0))) || 0)
218
220
  when Column::ProgressBarColumnProxy
@@ -268,7 +270,7 @@ module Glimmer
268
270
  @cell_rows[row].send(attribute)[1] = ::LibUI.table_value_string(val).to_s
269
271
  end
270
272
  when Column::ButtonColumnProxy
271
- @columns[column].notify_listeners(:on_clicked, row)
273
+ @columns[column].notify_custom_listeners('on_clicked', row)
272
274
  when Column::CheckboxColumnProxy
273
275
  column = @columns[column].index
274
276
  @cell_rows[row] ||= []
@@ -290,7 +292,7 @@ module Glimmer
290
292
  @cell_rows[row].send(attribute)[0] = ::LibUI.table_value_int(val).to_i == 1
291
293
  end
292
294
  end
293
- on_edited.each {|listener| listener.call(row, @cell_rows[row])}
295
+ notify_custom_listeners('on_edited', row, @cell_rows[row])
294
296
  end
295
297
 
296
298
  @model = ::LibUI.new_table_model(@model_handler)
@@ -60,6 +60,8 @@ module Glimmer
60
60
  end
61
61
 
62
62
  def destroy
63
+ return if ControlProxy.main_window_proxy&.destroying?
64
+ deregister_all_custom_listeners
63
65
  @parent_proxy&.children&.delete(self)
64
66
  ControlProxy.control_proxies.delete(self)
65
67
  end