glimmer-dsl-libui 0.4.13 → 0.4.17

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +102 -47
  4. data/VERSION +1 -1
  5. data/bin/girb +0 -0
  6. data/examples/basic_image.rb +5 -3
  7. data/examples/basic_image2.rb +1 -3
  8. data/examples/basic_image3.rb +3 -3
  9. data/examples/basic_image4.rb +0 -3
  10. data/examples/basic_image5.rb +0 -2
  11. data/examples/basic_table_button.rb +0 -1
  12. data/examples/cpu_percentage.rb +1 -1
  13. data/examples/editable_column_table.rb +5 -0
  14. data/examples/form_table.rb +10 -4
  15. data/examples/form_table2.rb +12 -6
  16. data/examples/form_table3.rb +9 -3
  17. data/examples/form_table4.rb +9 -3
  18. data/examples/form_table5.rb +9 -3
  19. data/examples/meta_example.rb +3 -1
  20. data/glimmer-dsl-libui.gemspec +0 -0
  21. data/icons/blank.png +0 -0
  22. data/lib/glimmer/libui/attributed_string.rb +17 -8
  23. data/lib/glimmer/libui/control_proxy/area_proxy.rb +17 -17
  24. data/lib/glimmer/libui/control_proxy/box.rb +1 -0
  25. data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +6 -0
  26. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +6 -28
  27. data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +6 -0
  28. data/lib/glimmer/libui/control_proxy/column/checkbox_text_color_column_proxy.rb +6 -0
  29. data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +6 -0
  30. data/lib/glimmer/libui/control_proxy/column/image_column_proxy.rb +6 -0
  31. data/lib/glimmer/libui/control_proxy/column/image_text_color_column_proxy.rb +6 -0
  32. data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +6 -0
  33. data/lib/glimmer/libui/control_proxy/column/progress_bar_column_proxy.rb +6 -0
  34. data/lib/glimmer/libui/control_proxy/column/text_color_column_proxy.rb +6 -0
  35. data/lib/glimmer/libui/control_proxy/column/text_column_proxy.rb +6 -0
  36. data/lib/glimmer/libui/control_proxy/column.rb +7 -0
  37. data/lib/glimmer/libui/control_proxy/form_proxy.rb +1 -0
  38. data/lib/glimmer/libui/control_proxy/image_proxy.rb +77 -10
  39. data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +18 -8
  40. data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +11 -2
  41. data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +2 -0
  42. data/lib/glimmer/libui/control_proxy/path_proxy.rb +2 -0
  43. data/lib/glimmer/libui/control_proxy/table_proxy.rb +25 -14
  44. data/lib/glimmer/libui/control_proxy/text_proxy.rb +2 -0
  45. data/lib/glimmer/libui/control_proxy/window_proxy.rb +34 -35
  46. data/lib/glimmer/libui/control_proxy.rb +45 -9
  47. data/lib/glimmer/libui/shape.rb +1 -0
  48. data/lib/glimmer/libui.rb +1 -0
  49. data/lib/glimmer-dsl-libui.rb +6 -0
  50. metadata +20 -5
@@ -52,12 +52,14 @@ module Glimmer
52
52
 
53
53
  include Parent
54
54
  prepend Transformable
55
+ include Equalizer.new(:options, :data)
55
56
 
56
- attr_reader :data, :pixels, :shapes
57
+ attr_reader :data, :pixels, :shapes, :options
57
58
 
58
59
  def initialize(keyword, parent, args, &block)
59
60
  @keyword = keyword
60
61
  @parent_proxy = parent
62
+ @options = args.last.is_a?(Hash) ? args.pop : {}
61
63
  @args = args
62
64
  @block = block
63
65
  @enabled = true
@@ -92,11 +94,47 @@ module Glimmer
92
94
  alias file= file
93
95
  alias set_file file
94
96
 
97
+ def x(value = nil)
98
+ if value.nil?
99
+ @args.size > 3 ? @args[1] : (@options[:x] || 0)
100
+ else
101
+ if @args.size > 3
102
+ @args[1] = value
103
+ else
104
+ @options[:x] = value
105
+ end
106
+ if area_image? && @content_added
107
+ post_add_content
108
+ request_auto_redraw
109
+ end
110
+ end
111
+ end
112
+ alias x= x
113
+ alias set_x x
114
+
115
+ def y(value = nil)
116
+ if value.nil?
117
+ @args.size > 3 ? @args[2] : (@options[:y] || 0)
118
+ else
119
+ if @args.size > 3
120
+ @args[2] = value
121
+ else
122
+ @options[:y] = value
123
+ end
124
+ if area_image? && @content_added
125
+ post_add_content
126
+ request_auto_redraw
127
+ end
128
+ end
129
+ end
130
+ alias y= y
131
+ alias set_y y
132
+
95
133
  def width(value = nil)
96
134
  if value.nil?
97
- @args[1]
135
+ @args.size > 3 ? @args[3] : (@options[:width] || @args[1])
98
136
  else
99
- @args[1] = value
137
+ set_width_variable(value)
100
138
  if area_image? && @content_added
101
139
  post_add_content
102
140
  request_auto_redraw
@@ -108,9 +146,9 @@ module Glimmer
108
146
 
109
147
  def height(value = nil)
110
148
  if value.nil?
111
- @args[2]
149
+ @args.size > 3 ? @args[4] : (@options[:height] || @args[2])
112
150
  else
113
- @args[2] = value
151
+ set_height_variable(value)
114
152
  if area_image? && @content_added
115
153
  post_add_content
116
154
  request_auto_redraw
@@ -142,12 +180,34 @@ module Glimmer
142
180
  end
143
181
 
144
182
  def destroy
183
+ return if ControlProxy.main_window_proxy&.destroying?
184
+ deregister_all_custom_listeners
145
185
  @parent_proxy&.children&.delete(self)
146
186
  ControlProxy.control_proxies.delete(self)
147
187
  end
148
188
 
149
189
  private
150
190
 
191
+ def set_width_variable(value)
192
+ if @args.size > 3
193
+ @args[3] = value
194
+ elsif @options[:width]
195
+ @options[:width] = value
196
+ else
197
+ @args[1] = value
198
+ end
199
+ end
200
+
201
+ def set_height_variable(value)
202
+ if @args.size > 3
203
+ @args[4] = value
204
+ elsif @options[:height]
205
+ @options[:height] = value
206
+ else
207
+ @args[2] = value
208
+ end
209
+ end
210
+
151
211
  def build_control
152
212
  unless area_image? # image object
153
213
  if file
@@ -180,10 +240,15 @@ module Glimmer
180
240
  canvas = ChunkyPNG::Canvas.from_io(f)
181
241
  f.close
182
242
  end
183
- canvas.resample_nearest_neighbor!(width, height) if width && height
243
+ original_width = canvas.width
244
+ original_height = canvas.height
245
+ require 'bigdecimal'
246
+ calculated_width = ((BigDecimal(height)/BigDecimal(original_height))*original_width).to_i if height && !width
247
+ calculated_height = ((BigDecimal(width)/BigDecimal(original_width))*original_height).to_i if width && !height
248
+ canvas.resample_nearest_neighbor!(calculated_width || width, calculated_height || height) if width || height
184
249
  @data = canvas.to_rgba_stream
185
- @args[1] = canvas.width
186
- @args[2] = canvas.height
250
+ set_width_variable(canvas.width) unless width
251
+ set_height_variable(canvas.height) unless height
187
252
  [@data, width, height]
188
253
  end
189
254
 
@@ -203,6 +268,8 @@ module Glimmer
203
268
  @shapes = []
204
269
  original_pixels = @pixels.dup
205
270
  indexed_original_pixels = Hash[original_pixels.each_with_index.to_a]
271
+ x_offset = x
272
+ y_offset = y
206
273
  @pixels.each do |pixel|
207
274
  index = indexed_original_pixels[pixel]
208
275
  @rectangle_start_x ||= pixel[:x]
@@ -211,9 +278,9 @@ module Glimmer
211
278
  @rectangle_width += 1
212
279
  else
213
280
  if pixel[:x] > 0 && pixel[:color] == original_pixels[index - 1][:color]
214
- @shapes << {x: @rectangle_start_x, y: pixel[:y], width: @rectangle_width, height: 1, color: pixel[:color]}
281
+ @shapes << {x: x_offset + @rectangle_start_x, y: y_offset + pixel[:y], width: @rectangle_width, height: 1, color: pixel[:color]}
215
282
  else
216
- @shapes << {x: pixel[:x], y: pixel[:y], width: 1, height: 1, color: pixel[:color]}
283
+ @shapes << {x: x_offset + pixel[:x], y: y_offset + pixel[:y], width: 1, height: 1, color: pixel[:color]}
217
284
  end
218
285
  @rectangle_width = 1
219
286
  @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
 
@@ -90,26 +90,26 @@ module Glimmer
90
90
  @cell_rows_observer ||= Glimmer::DataBinding::Observer.proc do |new_cell_rows|
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
- ::LibUI.table_model_row_deleted(model, row)
94
- on_changed.each {|listener| listener.call(row, :deleted, @last_cell_rows[row])}
93
+ ::LibUI.table_model_row_deleted(model, row) if model && 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
- ::LibUI.table_model_row_inserted(model, row)
99
- on_changed.each {|listener| listener.call(row, :inserted, @cell_rows[row])}
98
+ ::LibUI.table_model_row_inserted(model, row) if model && 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
- ::LibUI.table_model_row_changed(model, row)
105
- on_changed.each {|listener| listener.call(row, :changed, @cell_rows[row])}
104
+ ::LibUI.table_model_row_changed(model, row) if model && row
105
+ notify_custom_listeners('on_changed', row, :changed, @cell_rows[row])
106
106
  end
107
107
  end
108
108
  end
109
109
  @last_last_cell_rows = array_deep_clone(@last_cell_rows)
110
110
  @last_cell_rows = array_deep_clone(@cell_rows)
111
111
  end.tap do |cell_rows_observer|
112
- cell_rows_observer.observe(self, :cell_rows, recursive: true)
112
+ cell_rows_observer.observe(self, :cell_rows, recursive: true, ignore_frozen: true)
113
113
  end
114
114
  end
115
115
  @cell_rows
@@ -153,7 +153,7 @@ module Glimmer
153
153
  new_value = new_value.to_a if new_value.is_a?(Enumerator)
154
154
  if model_binding.binding_options[:column_attributes] || (!new_value.empty? && !new_value.first.is_a?(Array))
155
155
  @model_attribute_array_observer_registration&.deregister
156
- @model_attribute_array_observer_registration = model_attribute_observer.observe(new_value, @column_attributes)
156
+ @model_attribute_array_observer_registration = model_attribute_observer.observe(new_value, @column_attributes, ignore_frozen: true)
157
157
  model_attribute_observer.add_dependent(model_attribute_observer_registration => @model_attribute_array_observer_registration)
158
158
  end
159
159
  # TODO look if multiple notifications are happening as a result of observing array and observing model binding
@@ -208,9 +208,11 @@ 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
- # 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]
211
+ if OS.windows? && row == cell_rows.count
212
+ img = Glimmer::LibUI::ICON
213
+ else
214
+ img = expanded_cell_rows[row][column]
215
+ end
214
216
  img = ControlProxy::ImageProxy.create('image', nil, img) if img.is_a?(Array)
215
217
  img = ControlProxy::ImageProxy.create('image', nil, [img]) if img.is_a?(String)
216
218
  img = img.respond_to?(:libui) ? img.libui : img
@@ -270,7 +272,7 @@ module Glimmer
270
272
  @cell_rows[row].send(attribute)[1] = ::LibUI.table_value_string(val).to_s
271
273
  end
272
274
  when Column::ButtonColumnProxy
273
- @columns[column].notify_listeners(:on_clicked, row)
275
+ @columns[column].notify_custom_listeners('on_clicked', row)
274
276
  when Column::CheckboxColumnProxy
275
277
  column = @columns[column].index
276
278
  @cell_rows[row] ||= []
@@ -292,7 +294,7 @@ module Glimmer
292
294
  @cell_rows[row].send(attribute)[0] = ::LibUI.table_value_int(val).to_i == 1
293
295
  end
294
296
  end
295
- on_edited.each {|listener| listener.call(row, @cell_rows[row])}
297
+ notify_custom_listeners('on_edited', row, @cell_rows[row])
296
298
  end
297
299
 
298
300
  @model = ::LibUI.new_table_model(@model_handler)
@@ -308,6 +310,15 @@ module Glimmer
308
310
  @libui.tap do
309
311
  @columns.each {|column| column.respond_to?(:build_control, true) && column.send(:build_control) }
310
312
  end
313
+
314
+ if !@applied_windows_fix && OS.windows?
315
+ @applied_windows_fix = true
316
+ new_row = @columns&.select {|column| column.is_a?(Column)}&.map {|column| column.class.default_value}
317
+ if new_row
318
+ @cell_rows << new_row
319
+ @cell_rows.pop
320
+ end
321
+ end
311
322
  end
312
323
 
313
324
  def next_column_index
@@ -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
@@ -29,6 +29,10 @@ module Glimmer
29
29
  #
30
30
  # Follows the Proxy Design Pattern
31
31
  class WindowProxy < ControlProxy
32
+ CUSTOM_LISTENER_NAMES = ['on_destroy']
33
+ CUSTOM_LISTENER_NAME_ALIASES = {
34
+ on_destroyed: 'on_destroy',
35
+ }
32
36
  DEFAULT_TITLE = ''
33
37
  DEFAULT_WIDTH = 190
34
38
  DEFAULT_HEIGHT = 150
@@ -44,22 +48,20 @@ module Glimmer
44
48
  end
45
49
 
46
50
  def destroy
51
+ return if @destroying
52
+ @destroying = true
53
+ @on_closing_listeners&.clear
47
54
  super
48
55
  ControlProxy.image_proxies.each { |image_proxy| ::LibUI.free_image(image_proxy.libui) unless image_proxy.area_image? }
49
- @on_destroy_procs&.each { |on_destroy_proc| on_destroy_proc.call(self)}
56
+ notify_custom_listeners('on_destroy', self)
57
+ deregister_custom_listeners('on_destroy')
58
+ @destroying = false
50
59
  end
51
60
 
52
- def on_destroy(&block)
53
- # TODO look into a way to generalize this logic for multiple listeners
54
- @on_destroy_procs ||= []
55
- if block.nil?
56
- @on_destroy_procs
57
- else
58
- @on_destroy_procs << block
59
- block
60
- end
61
+ def destroying?
62
+ @destroying
61
63
  end
62
-
64
+
63
65
  def show
64
66
  super
65
67
  unless @shown_at_least_once
@@ -69,29 +71,29 @@ module Glimmer
69
71
  end
70
72
  end
71
73
 
72
- def can_handle_listener?(listener_name)
73
- listener_name == 'on_destroy' || super
74
- end
75
-
76
74
  def handle_listener(listener_name, &listener)
77
75
  case listener_name
78
- when 'on_destroy'
79
- on_destroy(&listener)
80
- else
81
- default_behavior_listener = nil
82
- if listener_name == 'on_closing'
83
- default_behavior_listener = Proc.new do
84
- return_value = listener.call(self)
85
- if return_value.is_a?(Numeric)
86
- return_value
87
- else
88
- destroy
89
- ::LibUI.quit
90
- 0
91
- end
76
+ when 'on_closing'
77
+ @on_closing_listeners ||= []
78
+ @on_closing_listeners << listener
79
+ @default_behavior_listener ||= Proc.new do
80
+ return_value = nil
81
+ @on_closing_listeners.each do |l|
82
+ return_value = l.call(self)
83
+ break if return_value.is_a?(Numeric)
84
+ end
85
+ if return_value.is_a?(Numeric)
86
+ return_value
87
+ else
88
+ destroy
89
+ ::LibUI.quit
90
+ 0
92
91
  end
92
+ end.tap do |default_behavior_listener|
93
+ super(listener_name, &default_behavior_listener)
93
94
  end
94
- super(listener_name, &(default_behavior_listener || listener))
95
+ else
96
+ super
95
97
  end
96
98
  end
97
99
 
@@ -168,11 +170,8 @@ module Glimmer
168
170
  @height = construction_args[2]
169
171
  @libui = ControlProxy.new_control(@keyword, construction_args)
170
172
  @libui.tap do
171
- handle_listener('on_closing') do
172
- destroy
173
- ::LibUI.quit
174
- 0
175
- end
173
+ # setup default on_closing listener if no on_closing listeners are setup
174
+ handle_listener('on_closing') {} if @on_closing_listeners.nil? || @on_closing_listeners.empty?
176
175
  end
177
176
  end
178
177
  end
@@ -169,31 +169,49 @@ module Glimmer
169
169
  def handle_listener(listener_name, &listener)
170
170
  safe_listener = Proc.new { listener.call(self) }
171
171
  if ::LibUI.respond_to?("#{libui_api_keyword}_#{listener_name}")
172
- ::LibUI.send("#{libui_api_keyword}_#{listener_name}", @libui, &safe_listener)
172
+ if listeners[listener_name].nil?
173
+ ::LibUI.send("#{libui_api_keyword}_#{listener_name}", @libui) do
174
+ listeners_for(listener_name).map { |listener| listener.call }.last
175
+ end
176
+ end
177
+ listeners_for(listener_name) << safe_listener
173
178
  elsif ::LibUI.respond_to?("control_#{listener_name}")
174
- ::LibUI.send("control_#{listener_name}", @libui, &safe_listener)
179
+ if listeners[listener_name].nil?
180
+ ::LibUI.send("control_#{listener_name}", @libui) do
181
+ listeners_for(listener_name).map { |listener| listener.call }.last
182
+ end
183
+ end
184
+ listeners_for(listener_name) << safe_listener
175
185
  elsif has_custom_listener?(listener_name)
176
186
  handle_custom_listener(listener_name, &listener)
177
187
  end
178
188
  end
179
189
 
190
+ def listeners
191
+ @listeners ||= {}
192
+ end
193
+
194
+ def listeners_for(listener_name)
195
+ listeners[listener_name] ||= []
196
+ end
197
+
180
198
  def has_custom_listener?(listener_name)
181
199
  listener_name = listener_name.to_s
182
- custom_listeners.include?(listener_name) || custom_listener_aliases.stringify_keys.keys.include?(listener_name)
200
+ custom_listener_names.include?(listener_name) || custom_listener_name_aliases.stringify_keys.keys.include?(listener_name)
183
201
  end
184
202
 
185
- def custom_listeners
186
- self.class.constants.include?(:LISTENERS) ? self.class::LISTENERS : []
203
+ def custom_listener_names
204
+ self.class.constants.include?(:CUSTOM_LISTENER_NAMES) ? self.class::CUSTOM_LISTENER_NAMES : []
187
205
  end
188
206
 
189
- def custom_listener_aliases
190
- self.class.constants.include?(:LISTENER_ALIASES) ? self.class::LISTENER_ALIASES : {}
207
+ def custom_listener_name_aliases
208
+ self.class.constants.include?(:CUSTOM_LISTENER_NAME_ALIASES) ? self.class::CUSTOM_LISTENER_NAME_ALIASES : {}
191
209
  end
192
210
 
193
211
  def handle_custom_listener(listener_name, &listener)
194
212
  listener_name = listener_name.to_s
195
- listener_name = custom_listener_aliases.stringify_keys[listener_name] || listener_name
196
- instance_variable_name = "@#{listener_name}_procs"
213
+ listener_name = custom_listener_name_aliases.stringify_keys[listener_name] || listener_name
214
+ instance_variable_name = "@#{listener_name}_procs" # TODO ensure clearing custom listeners on destroy of a control
197
215
  instance_variable_set(instance_variable_name, []) if instance_variable_get(instance_variable_name).nil?
198
216
  if listener.nil?
199
217
  instance_variable_get(instance_variable_name)
@@ -203,6 +221,21 @@ module Glimmer
203
221
  end
204
222
  end
205
223
 
224
+ def notify_custom_listeners(listener_name, *args)
225
+ handle_custom_listener(listener_name).each do |listener|
226
+ listener.call(*args)
227
+ end
228
+ end
229
+
230
+ def deregister_custom_listeners(listener_name)
231
+ handle_custom_listener(listener_name).clear
232
+ end
233
+
234
+ # deregisters all custom listeners except on_destroy, which can only be deregistered after destruction of a control, using deregister_custom_listeners
235
+ def deregister_all_custom_listeners
236
+ (custom_listener_names - ['on_destroy']).each { |listener_name| deregister_custom_listeners(listener_name) }
237
+ end
238
+
206
239
  def respond_to?(method_name, *args, &block)
207
240
  respond_to_libui?(method_name, *args, &block) ||
208
241
  (
@@ -289,6 +322,8 @@ module Glimmer
289
322
  end
290
323
 
291
324
  def destroy
325
+ # TODO exclude menus from this initial return
326
+ return if !is_a?(ControlProxy::WindowProxy) && ControlProxy.main_window_proxy&.destroying?
292
327
  data_binding_model_attribute_observer_registrations.each(&:deregister)
293
328
  if parent_proxy.nil?
294
329
  default_destroy
@@ -302,6 +337,7 @@ module Glimmer
302
337
  end
303
338
 
304
339
  def default_destroy
340
+ deregister_all_custom_listeners
305
341
  send_to_libui('destroy')
306
342
  ControlProxy.control_proxies.delete(self)
307
343
  end
@@ -116,6 +116,7 @@ module Glimmer
116
116
  end
117
117
 
118
118
  def destroy
119
+ return if ControlProxy.main_window_proxy&.destroying?
119
120
  @parent.children.delete(self)
120
121
  end
121
122
 
data/lib/glimmer/libui.rb CHANGED
@@ -23,6 +23,7 @@ require 'glimmer/fiddle_consumer'
23
23
 
24
24
  module Glimmer
25
25
  module LibUI
26
+ ICON = File.expand_path('../../icons/blank.png', __dir__)
26
27
  class << self
27
28
  include Glimmer::FiddleConsumer
28
29
 
@@ -28,6 +28,7 @@ require 'glimmer'
28
28
  # require 'super_module'
29
29
  require 'color'
30
30
  require 'os'
31
+ require 'equalizer'
31
32
  require 'array_include_methods'
32
33
  require 'facets/hash/stringify_keys'
33
34
  require 'facets/string/underscore'
@@ -46,3 +47,8 @@ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
46
47
  end
47
48
 
48
49
  ::LibUI.init
50
+ # begin
51
+ # PutsDebuggerer.printer = lambda { |m| puts m; $stdout.flush}
52
+ # rescue
53
+ ## No Op if puts_debuggerer is not loaded
54
+ # 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.4.13
4
+ version: 0.4.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-03 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.5.0
19
+ version: 2.5.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.5.0
26
+ version: 2.5.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: os
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: 1.4.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: equalizer
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '='
94
+ - !ruby/object:Gem::Version
95
+ version: 0.0.11
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 0.0.11
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: juwelier
91
105
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +323,7 @@ files:
309
323
  - examples/timer.rb
310
324
  - examples/timer2.rb
311
325
  - glimmer-dsl-libui.gemspec
326
+ - icons/blank.png
312
327
  - icons/glimmer.png
313
328
  - lib/glimmer-dsl-libui.rb
314
329
  - lib/glimmer/dsl/libui/bind_expression.rb
@@ -433,7 +448,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
433
448
  - !ruby/object:Gem::Version
434
449
  version: '0'
435
450
  requirements: []
436
- rubygems_version: 3.2.31
451
+ rubygems_version: 3.2.22
437
452
  signing_key:
438
453
  specification_version: 4
439
454
  summary: Glimmer DSL for LibUI