glimmer-dsl-libui 0.4.12 → 0.4.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/README.md +111 -48
  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_button.rb +0 -1
  11. data/examples/cpu_percentage.rb +1 -1
  12. data/examples/editable_column_table.rb +5 -0
  13. data/examples/form_table.rb +10 -4
  14. data/examples/form_table2.rb +12 -6
  15. data/examples/form_table3.rb +9 -3
  16. data/examples/form_table4.rb +9 -3
  17. data/examples/form_table5.rb +9 -3
  18. data/examples/meta_example.rb +3 -1
  19. data/glimmer-dsl-libui.gemspec +0 -0
  20. data/icons/blank.png +0 -0
  21. data/lib/glimmer/libui/attributed_string.rb +17 -8
  22. data/lib/glimmer/libui/control_proxy/area_proxy.rb +17 -17
  23. data/lib/glimmer/libui/control_proxy/box.rb +1 -0
  24. data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +1 -29
  25. data/lib/glimmer/libui/control_proxy/form_proxy.rb +1 -0
  26. data/lib/glimmer/libui/control_proxy/image_proxy.rb +92 -10
  27. data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +18 -8
  28. data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +11 -2
  29. data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +2 -0
  30. data/lib/glimmer/libui/control_proxy/path_proxy.rb +2 -0
  31. data/lib/glimmer/libui/control_proxy/table_proxy.rb +13 -11
  32. data/lib/glimmer/libui/control_proxy/text_proxy.rb +2 -0
  33. data/lib/glimmer/libui/control_proxy/window_proxy.rb +34 -35
  34. data/lib/glimmer/libui/control_proxy.rb +45 -9
  35. data/lib/glimmer/libui/shape.rb +1 -0
  36. data/lib/glimmer/libui.rb +1 -0
  37. metadata +5 -4
@@ -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
@@ -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
- # 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.new('image', nil, img) if img.is_a?(Array)
215
- img = ControlProxy::ImageProxy.new('image', nil, [img]) if img.is_a?(String)
211
+ if OS.windows? && row == cell_rows.count
212
+ img = Glimmer::LibUI::ICON
213
+ else
214
+ img = expanded_cell_rows[row][column]
215
+ end
216
+ img = ControlProxy::ImageProxy.create('image', nil, img) if img.is_a?(Array)
217
+ img = ControlProxy::ImageProxy.create('image', nil, [img]) if img.is_a?(String)
216
218
  img = img.respond_to?(:libui) ? img.libui : img
217
219
  ::LibUI.new_table_value_image(img)
218
220
  when Column::CheckboxColumnProxy, Column::CheckboxTextColumnProxy, Column::CheckboxTextColorColumnProxy
@@ -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)
@@ -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
 
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.12
4
+ version: 0.4.16
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-06 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.1
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.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: os
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +309,7 @@ files:
309
309
  - examples/timer.rb
310
310
  - examples/timer2.rb
311
311
  - glimmer-dsl-libui.gemspec
312
+ - icons/blank.png
312
313
  - icons/glimmer.png
313
314
  - lib/glimmer-dsl-libui.rb
314
315
  - lib/glimmer/dsl/libui/bind_expression.rb