glimmer-dsl-swt 4.18.4.8 → 4.18.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -0
  3. data/README.md +24 -11
  4. data/VERSION +1 -1
  5. data/bin/glimmer +3 -3
  6. data/docs/reference/GLIMMER_CONFIGURATION.md +7 -3
  7. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +353 -145
  8. data/docs/reference/GLIMMER_SAMPLES.md +207 -41
  9. data/glimmer-dsl-swt.gemspec +33 -15
  10. data/lib/ext/glimmer/config.rb +3 -7
  11. data/lib/glimmer/data_binding/list_selection_binding.rb +13 -7
  12. data/lib/glimmer/data_binding/table_items_binding.rb +22 -17
  13. data/lib/glimmer/data_binding/tree_items_binding.rb +19 -15
  14. data/lib/glimmer/data_binding/widget_binding.rb +13 -15
  15. data/lib/glimmer/dsl/swt/{file_dialog_expression.rb → auto_exec_expression.rb} +6 -18
  16. data/lib/glimmer/dsl/swt/checkbox_group_selection_data_binding_expression.rb +9 -6
  17. data/lib/glimmer/dsl/swt/color_expression.rb +1 -1
  18. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +16 -14
  19. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +4 -1
  20. data/lib/glimmer/dsl/swt/data_binding_expression.rb +2 -2
  21. data/lib/glimmer/dsl/swt/dialog_expression.rb +18 -9
  22. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  23. data/lib/glimmer/dsl/swt/exec_expression.rb +1 -1
  24. data/lib/glimmer/dsl/swt/font_expression.rb +1 -1
  25. data/lib/glimmer/dsl/swt/image_expression.rb +18 -3
  26. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +11 -8
  27. data/lib/glimmer/dsl/swt/pixel_expression.rb +1 -1
  28. data/lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb +9 -5
  29. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  30. data/lib/glimmer/dsl/swt/shell_expression.rb +5 -2
  31. data/lib/glimmer/dsl/swt/widget_expression.rb +8 -4
  32. data/lib/glimmer/launcher.rb +3 -0
  33. data/lib/glimmer/rake_task/scaffold.rb +3 -0
  34. data/lib/glimmer/swt/color_proxy.rb +1 -1
  35. data/lib/glimmer/swt/custom/code_text.rb +33 -11
  36. data/lib/glimmer/swt/custom/drawable.rb +50 -2
  37. data/lib/glimmer/swt/custom/radio_group.rb +2 -1
  38. data/lib/glimmer/swt/custom/shape.rb +166 -34
  39. data/lib/glimmer/{dsl/swt/directory_dialog_expression.rb → swt/custom/shape/arc.rb} +15 -20
  40. data/lib/glimmer/swt/custom/shape/focus.rb +43 -0
  41. data/lib/glimmer/swt/custom/shape/image.rb +86 -0
  42. data/lib/glimmer/swt/custom/shape/line.rb +58 -0
  43. data/lib/glimmer/swt/custom/shape/oval.rb +43 -0
  44. data/lib/glimmer/swt/custom/shape/point.rb +52 -0
  45. data/lib/glimmer/swt/custom/shape/polygon.rb +73 -0
  46. data/lib/glimmer/swt/custom/shape/polyline.rb +73 -0
  47. data/lib/glimmer/swt/custom/shape/rectangle.rb +87 -0
  48. data/lib/glimmer/swt/custom/shape/text.rb +73 -0
  49. data/lib/glimmer/swt/date_time_proxy.rb +9 -3
  50. data/lib/glimmer/swt/dialog_proxy.rb +92 -0
  51. data/lib/glimmer/swt/display_proxy.rb +62 -2
  52. data/lib/glimmer/swt/expand_item_proxy.rb +18 -12
  53. data/lib/glimmer/swt/font_proxy.rb +13 -7
  54. data/lib/glimmer/swt/image_proxy.rb +16 -5
  55. data/lib/glimmer/swt/layout_data_proxy.rb +21 -15
  56. data/lib/glimmer/swt/layout_proxy.rb +19 -15
  57. data/lib/glimmer/swt/menu_proxy.rb +2 -2
  58. data/lib/glimmer/swt/message_box_proxy.rb +21 -7
  59. data/lib/glimmer/swt/properties.rb +3 -0
  60. data/lib/glimmer/swt/proxy_properties.rb +145 -0
  61. data/lib/glimmer/swt/scrolled_composite_proxy.rb +20 -7
  62. data/lib/glimmer/swt/shell_proxy.rb +96 -80
  63. data/lib/glimmer/swt/swt_proxy.rb +17 -0
  64. data/lib/glimmer/swt/tab_item_proxy.rb +6 -3
  65. data/lib/glimmer/swt/table_proxy.rb +32 -11
  66. data/lib/glimmer/swt/transform_proxy.rb +26 -38
  67. data/lib/glimmer/swt/tree_proxy.rb +11 -16
  68. data/lib/glimmer/swt/widget_listener_proxy.rb +6 -2
  69. data/lib/glimmer/swt/widget_proxy.rb +194 -137
  70. data/lib/glimmer/ui.rb +5 -0
  71. data/lib/glimmer/ui/custom_shell.rb +13 -7
  72. data/lib/glimmer/ui/custom_widget.rb +4 -5
  73. data/samples/elaborate/contact_manager.rb +7 -7
  74. data/samples/elaborate/login.rb +25 -21
  75. data/samples/elaborate/mandelbrot_fractal.rb +346 -39
  76. data/samples/elaborate/meta_sample.rb +1 -1
  77. data/samples/elaborate/tetris.rb +1 -0
  78. data/samples/elaborate/tic_tac_toe.rb +16 -14
  79. data/samples/elaborate/tic_tac_toe/board.rb +5 -5
  80. data/samples/elaborate/tic_tac_toe/cell.rb +5 -5
  81. data/samples/hello/hello_button.rb +7 -7
  82. data/samples/hello/hello_canvas.rb +145 -41
  83. data/samples/hello/hello_checkbox.rb +16 -14
  84. data/samples/hello/hello_checkbox_group.rb +11 -9
  85. data/samples/hello/hello_color_dialog.rb +66 -0
  86. data/samples/hello/hello_combo.rb +14 -12
  87. data/samples/hello/hello_computed.rb +7 -7
  88. data/samples/hello/hello_cursor.rb +58 -0
  89. data/samples/hello/hello_custom_shell.rb +17 -21
  90. data/samples/hello/hello_custom_widget.rb +4 -6
  91. data/samples/hello/hello_date_time.rb +14 -12
  92. data/samples/hello/hello_directory_dialog.rb +7 -7
  93. data/samples/hello/hello_expand_bar.rb +8 -8
  94. data/samples/hello/hello_file_dialog.rb +7 -7
  95. data/samples/hello/hello_font_dialog.rb +82 -0
  96. data/samples/hello/hello_group.rb +18 -16
  97. data/samples/hello/hello_list_multi_selection.rb +13 -11
  98. data/samples/hello/hello_list_single_selection.rb +13 -11
  99. data/samples/hello/hello_progress_bar.rb +125 -0
  100. data/samples/hello/hello_radio.rb +18 -16
  101. data/samples/hello/hello_radio_group.rb +14 -12
  102. data/samples/hello/hello_spinner.rb +7 -7
  103. data/samples/hello/hello_tab.rb +5 -5
  104. data/samples/hello/hello_table.rb +10 -5
  105. data/samples/hello/hello_tree.rb +485 -0
  106. metadata +30 -23
  107. data/lib/glimmer/swt/directory_dialog_proxy.rb +0 -65
  108. data/lib/glimmer/swt/file_dialog_proxy.rb +0 -66
@@ -33,7 +33,7 @@ module Glimmer
33
33
  include_package 'org.eclipse.swt.graphics'
34
34
 
35
35
  class << self
36
- def flyweight(*args)
36
+ def create(*args)
37
37
  flyweight_color_proxies[args] ||= new(*args)
38
38
  end
39
39
 
@@ -64,6 +64,18 @@ module Glimmer
64
64
  respond_to?(method_name)
65
65
  end
66
66
 
67
+ def can_handle_observation_request?(observation_request)
68
+ @styled_text_proxy.can_handle_observation_request?(observation_request)
69
+ rescue
70
+ super
71
+ end
72
+
73
+ def handle_observation_request(observation_request, &block)
74
+ @styled_text_proxy.handle_observation_request(observation_request, &block)
75
+ rescue
76
+ super
77
+ end
78
+
67
79
  def root_block=(block)
68
80
  body_root.content(&block)
69
81
  end
@@ -124,13 +136,13 @@ module Glimmer
124
136
  editable false
125
137
  caret nil
126
138
  on_focus_gained {
127
- @styled_text_proxy&.swt_widget.setFocus
139
+ @styled_text_proxy&.setFocus
128
140
  }
129
141
  on_key_pressed {
130
- @styled_text_proxy&.swt_widget.setFocus
142
+ @styled_text_proxy&.setFocus
131
143
  }
132
144
  on_mouse_up {
133
- @styled_text_proxy&.swt_widget.setFocus
145
+ @styled_text_proxy&.setFocus
134
146
  }
135
147
  }
136
148
 
@@ -153,19 +165,29 @@ module Glimmer
153
165
  top_margin 5
154
166
  right_margin 5
155
167
  bottom_margin 5
168
+ tabs 2
156
169
 
157
170
  if default_behavior
158
171
  on_key_pressed { |event|
159
172
  character = event.keyCode.chr rescue nil
160
173
  case [event.stateMask, character]
161
174
  when [(OS.mac? ? swt(:command) : swt(:ctrl)), 'a']
162
- @styled_text_proxy.swt_widget.selectAll
175
+ @styled_text_proxy.selectAll
163
176
  when [(swt(:ctrl) if OS.mac?), 'a']
164
177
  jump_to_beginning_of_line
165
178
  when [(swt(:ctrl) if OS.mac?), 'e']
166
179
  jump_to_end_of_line
167
180
  end
168
181
  }
182
+ on_verify_text { |verify_event|
183
+ if verify_event.text == "\n"
184
+ line_index = verify_event.widget.get_line_at_offset(verify_event.widget.get_caret_offset)
185
+ line = verify_event.widget.get_line(line_index)
186
+ line_indent = line.match(/^([ ]*)/)[1].to_s.size
187
+ verify_event.text += ' '*line_indent
188
+ verify_event.text += ' '*2 if line.strip.end_with?('{') || line.strip.match(/do([ ]*[|][^|]*[|])?$/) || line.start_with?('class') || line.start_with?('module') || line.strip.start_with?('def')
189
+ end
190
+ }
169
191
  end
170
192
 
171
193
  on_modify_text { |event|
@@ -241,17 +263,17 @@ module Glimmer
241
263
  end
242
264
 
243
265
  def jump_to_beginning_of_line
244
- current_line_index = @styled_text_proxy.swt_widget.getLineAtOffset(@styled_text_proxy.swt_widget.getCaretOffset)
245
- beginning_of_current_line_offset = @styled_text_proxy.swt_widget.getOffsetAtLine(current_line_index)
246
- @styled_text_proxy.swt_widget.setSelection(beginning_of_current_line_offset, beginning_of_current_line_offset)
266
+ current_line_index = @styled_text_proxy.getLineAtOffset(@styled_text_proxy.getCaretOffset)
267
+ beginning_of_current_line_offset = @styled_text_proxy.getOffsetAtLine(current_line_index)
268
+ @styled_text_proxy.setSelection(beginning_of_current_line_offset, beginning_of_current_line_offset)
247
269
  end
248
270
 
249
271
  def jump_to_end_of_line
250
- current_line_index = @styled_text_proxy.swt_widget.getLineAtOffset(@styled_text_proxy.swt_widget.getCaretOffset)
251
- current_line = @styled_text_proxy.swt_widget.getLine(current_line_index)
252
- beginning_of_current_line_offset = @styled_text_proxy.swt_widget.getOffsetAtLine(current_line_index)
272
+ current_line_index = @styled_text_proxy.getLineAtOffset(@styled_text_proxy.getCaretOffset)
273
+ current_line = @styled_text_proxy.getLine(current_line_index)
274
+ beginning_of_current_line_offset = @styled_text_proxy.getOffsetAtLine(current_line_index)
253
275
  new_offset = beginning_of_current_line_offset + current_line.size
254
- @styled_text_proxy.swt_widget.setSelection(new_offset, new_offset)
276
+ @styled_text_proxy.setSelection(new_offset, new_offset)
255
277
  end
256
278
  end
257
279
  end
@@ -38,6 +38,10 @@ module Glimmer
38
38
  @image_buffered_shapes ||= []
39
39
  end
40
40
 
41
+ def shape_at_location(x, y)
42
+ shapes.reverse.detect {|shape| shape.include?(x, y)}
43
+ end
44
+
41
45
  def add_shape(shape)
42
46
  if !@image_double_buffered || shape.args.first == @image_proxy_buffer
43
47
  shapes << shape
@@ -46,9 +50,53 @@ module Glimmer
46
50
  end
47
51
  end
48
52
 
49
- def clear_shapes
53
+ def clear_shapes(dispose_images: true, dispose_patterns: true)
50
54
  # Optimize further by having a collection of disposable_shapes independent of shapes, which is much smaller and only has shapes that require disposal (shapes with patterns or image)
51
- shapes.dup.each(&:dispose) if requires_shape_disposal?
55
+ shapes.dup.each {|s| s.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns) } if requires_shape_disposal?
56
+ end
57
+
58
+ def paint_pixel_by_pixel(width = nil, height = nil, &each_pixel_color)
59
+ if @image_double_buffered
60
+ work = lambda do |paint_event|
61
+ width ||= swt_drawable.bounds.width
62
+ height ||= swt_drawable.bounds.height
63
+ @image_proxy_buffer ||= ImageProxy.create_pixel_by_pixel(width, height, &each_pixel_color)
64
+ @image_proxy_buffer.shape(self).paint(paint_event)
65
+ end
66
+ else
67
+ work = lambda do |paint_event_or_image|
68
+ the_gc = paint_event_or_image.gc
69
+ current_foreground = nil
70
+ width ||= swt_drawable.bounds.width
71
+ height ||= swt_drawable.bounds.height
72
+ height.times do |y|
73
+ width.times do |x|
74
+ new_foreground = each_pixel_color.call(x, y)
75
+ new_foreground = Glimmer::SWT::ColorProxy.create(new_foreground, ensure_bounds: false) unless new_foreground.is_a?(ColorProxy) || new_foreground.is_a?(Color)
76
+ new_foreground = new_foreground.swt_color if new_foreground.is_a?(Glimmer::SWT::ColorProxy)
77
+ the_gc.foreground = current_foreground = new_foreground unless new_foreground == current_foreground
78
+ the_gc.draw_point x, y
79
+ end
80
+ end
81
+ end
82
+ end
83
+ if respond_to?(:gc)
84
+ work.call(self)
85
+ else
86
+ on_swt_paint(&work)
87
+ end
88
+ end
89
+
90
+ def swt_drawable
91
+ swt_drawable = nil
92
+ if respond_to?(:swt_image)
93
+ swt_drawable = swt_image
94
+ elsif respond_to?(:swt_display)
95
+ swt_drawable = swt_display
96
+ elsif respond_to?(:swt_widget)
97
+ swt_drawable = swt_widget
98
+ end
99
+ swt_drawable
52
100
  end
53
101
 
54
102
  def deregister_shape_painting
@@ -73,7 +73,8 @@ module Glimmer
73
73
  end
74
74
 
75
75
  def can_handle_observation_request?(observation_request)
76
- radios.first&.can_handle_observation_request?(observation_request) || super(observation_request)
76
+ radios.first&.can_handle_observation_request?(observation_request) or
77
+ super(observation_request)
77
78
  end
78
79
 
79
80
  def handle_observation_request(observation_request, &block)
@@ -38,6 +38,15 @@ module Glimmer
38
38
  # TODO support a Pattern DSL for methods that take Pattern arguments
39
39
 
40
40
  class << self
41
+ def create(parent, keyword, *args, &property_block)
42
+ potential_shape_class_name = keyword.to_s.camelcase(:upper).to_sym
43
+ if constants.include?(potential_shape_class_name)
44
+ const_get(potential_shape_class_name).new(parent, keyword, *args, &property_block)
45
+ else
46
+ new(parent, keyword, *args, &property_block)
47
+ end
48
+ end
49
+
41
50
  def valid?(parent, keyword, *args, &block)
42
51
  gc_instance_methods.include?(method_name(keyword, arg_options(args)))
43
52
  end
@@ -79,15 +88,15 @@ module Glimmer
79
88
  end
80
89
 
81
90
  def pattern(*args)
82
- found_pattern = flyweigh_patterns[args]
91
+ found_pattern = flyweight_patterns[args]
83
92
  if found_pattern.nil? || found_pattern.is_disposed
84
- found_pattern = flyweigh_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
93
+ found_pattern = flyweight_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
85
94
  end
86
95
  found_pattern
87
96
  end
88
97
 
89
- def flyweigh_patterns
90
- @flyweigh_patterns ||= {}
98
+ def flyweight_patterns
99
+ @flyweight_patterns ||= {}
91
100
  end
92
101
  end
93
102
 
@@ -123,6 +132,29 @@ module Glimmer
123
132
  @options[:round]
124
133
  end
125
134
 
135
+ # subclasses (like polygon) may override to indicate if a point x,y coordinates fall inside the shape
136
+ # has a default implementation for rectangle and oval
137
+ def include?(x, y)
138
+ case @name
139
+ when 'rectangle', 'oval', 'arc'
140
+ self_x = self.x
141
+ self_y = self.y
142
+ width = self.width
143
+ height = self.height
144
+ x.between?(self_x, self_x + width) && y.between?(self_y, self_y + height)
145
+ else
146
+ false
147
+ end
148
+ end
149
+
150
+ def move_by(x_delta, y_delta)
151
+ case @name
152
+ when 'rectangle', 'oval', 'arc'
153
+ self.x += x_delta
154
+ self.y += y_delta
155
+ end
156
+ end
157
+
126
158
  def has_some_background?
127
159
  @properties.keys.map(&:to_s).include?('background') || @properties.keys.map(&:to_s).include?('background_pattern')
128
160
  end
@@ -142,6 +174,9 @@ module Glimmer
142
174
  def apply_property_arg_conversions(method_name, property, args)
143
175
  args = args.dup
144
176
  the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
177
+ if the_java_method.parameter_types.first == Color.java_class && args.first.is_a?(RGB)
178
+ args[0] = [args[0].red, args[0].green, args[0].blue]
179
+ end
145
180
  if ['setBackground', 'setForeground'].include?(method_name.to_s) && args.first.is_a?(Array)
146
181
  args[0] = ColorProxy.new(args[0])
147
182
  end
@@ -156,7 +191,7 @@ module Glimmer
156
191
  if args.first.is_a?(ColorProxy)
157
192
  args[0] = args[0].swt_color
158
193
  end
159
- if args.first.is_a?(Hash) && the_java_method.parameter_types.first == Font.java_class
194
+ if (args.first.is_a?(Hash) || args.first.is_a?(FontData)) && the_java_method.parameter_types.first == Font.java_class
160
195
  args[0] = FontProxy.new(args[0])
161
196
  end
162
197
  if args.first.is_a?(FontProxy)
@@ -167,15 +202,22 @@ module Glimmer
167
202
  end
168
203
  if ['setBackgroundPattern', 'setForegroundPattern'].include?(method_name.to_s)
169
204
  @parent.requires_shape_disposal = true
205
+ args = args.first if args.first.is_a?(Array)
170
206
  args.each_with_index do |arg, i|
171
- if arg.is_a?(Symbol) || arg.is_a?(String)
172
- args[i] = ColorProxy.new(arg).swt_color
173
- elsif arg.is_a?(ColorProxy)
174
- args[i] = arg.swt_color
175
- end
207
+ arg = ColorProxy.new(arg.red, arg.green, arg.blue) if arg.is_a?(RGB)
208
+ arg = ColorProxy.new(arg) if arg.is_a?(Symbol) || arg.is_a?(String)
209
+ arg = arg.swt_color if arg.is_a?(ColorProxy)
210
+ args[i] = arg
176
211
  end
177
- new_args = [DisplayProxy.instance.swt_display] + args
178
- args[0] = pattern(*new_args, type: method_name.to_s.match(/set(.+)Pattern/)[1])
212
+ @pattern_args ||= {}
213
+ pattern_type = method_name.to_s.match(/set(.+)Pattern/)[1]
214
+ if args.first.is_a?(Pattern)
215
+ new_args = @pattern_args[pattern_type]
216
+ else
217
+ new_args = args.first.is_a?(Display) ? args : ([DisplayProxy.instance.swt_display] + args)
218
+ @pattern_args[pattern_type] = new_args.dup
219
+ end
220
+ args[0] = pattern(*new_args, type: pattern_type)
179
221
  args[1..-1] = []
180
222
  end
181
223
  args
@@ -186,6 +228,28 @@ module Glimmer
186
228
  @args[0] = @args.dup
187
229
  @args[1..-1] = []
188
230
  end
231
+ if @name == 'image'
232
+ if @args.first.is_a?(String)
233
+ @args[0] = ImageProxy.new(@args[0])
234
+ end
235
+ if @args.first.is_a?(ImageProxy)
236
+ @image = @args[0] = @args[0].swt_image
237
+ end
238
+ if @args.first.nil?
239
+ @image = nil
240
+ end
241
+ end
242
+ if @name == 'text'
243
+ if @args[3].is_a?(Symbol) || @args[3].is_a?(String)
244
+ @args[3] = [@args[3]]
245
+ end
246
+ if @args[3].is_a?(Array)
247
+ if @args[3].size == 1 && @args[3].first.is_a?(Array)
248
+ @args[3] = @args[3].first
249
+ end
250
+ @args[3] = SWTProxy[*@args[3]]
251
+ end
252
+ end
189
253
  end
190
254
 
191
255
  def apply_shape_arg_defaults!
@@ -202,12 +266,6 @@ module Glimmer
202
266
  @args[1] = 0
203
267
  @args[2] = 0
204
268
  end
205
- if @args.first.is_a?(String)
206
- @args[0] = ImageProxy.new(@args[0])
207
- end
208
- if @args.first.is_a?(ImageProxy)
209
- @image = @args[0] = @args[0].swt_image
210
- end
211
269
  end
212
270
  end
213
271
 
@@ -217,14 +275,14 @@ module Glimmer
217
275
  the_java_method_arg_count = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.select do |m|
218
276
  m.name == @method_name.camelcase(:lower)
219
277
  end.map(&:parameter_types).map(&:size).max
220
- if @args.size > the_java_method_arg_count
278
+ if the_java_method_arg_count && @args.to_a.size > the_java_method_arg_count
221
279
  @args[the_java_method_arg_count..-1] = []
222
280
  end
223
281
  end
224
282
 
225
283
  def amend_method_name_options_based_on_properties!
226
284
  return if @name == 'point'
227
- if has_some_background? && !has_some_foreground?
285
+ if @name != 'text' && has_some_background? && !has_some_foreground?
228
286
  @options[:fill] = true
229
287
  elsif !has_some_background? && has_some_foreground?
230
288
  @options[:fill] = false
@@ -237,13 +295,39 @@ module Glimmer
237
295
  end
238
296
  @method_name = self.class.method_name(@name, @options)
239
297
  end
240
-
298
+
299
+ # parameter names for arguments to pass to SWT GC.xyz method for rendering shape (e.g. draw_image(image, x, y) yields :image, :x, :y parameter names)
300
+ def parameter_names
301
+ []
302
+ end
303
+
304
+ def possible_parameter_names
305
+ parameter_names
306
+ end
307
+
308
+ def parameter_name?(attribute_name)
309
+ possible_parameter_names.map(&:to_s).include?(ruby_attribute_getter(attribute_name))
310
+ end
311
+
312
+ def parameter_index(attribute_name)
313
+ parameter_names.map(&:to_s).index(attribute_name.to_s)
314
+ end
315
+
316
+ def set_parameter_attribute(attribute_name, *args)
317
+ @args[parameter_index(ruby_attribute_getter(attribute_name))] = args.size == 1 ? args.first : args
318
+ end
319
+
241
320
  def has_attribute?(attribute_name, *args)
242
- self.class.gc_instance_methods.include?(attribute_setter(attribute_name))
321
+ self.class.gc_instance_methods.include?(attribute_setter(attribute_name)) or
322
+ parameter_name?(attribute_name)
243
323
  end
244
324
 
245
325
  def set_attribute(attribute_name, *args)
246
- @properties[attribute_name] = args
326
+ if parameter_name?(attribute_name)
327
+ set_parameter_attribute(attribute_name, *args)
328
+ else
329
+ @properties[ruby_attribute_getter(attribute_name)] = args
330
+ end
247
331
  if @content_added && !@parent.is_disposed
248
332
  @calculated_paint_args = false
249
333
  @parent.redraw
@@ -251,28 +335,66 @@ module Glimmer
251
335
  end
252
336
 
253
337
  def get_attribute(attribute_name)
254
- @properties.symbolize_keys[attribute_name.to_s.to_sym]
338
+ if parameter_name?(attribute_name)
339
+ @args[parameter_index(attribute_name)]
340
+ else
341
+ @properties.symbolize_keys[attribute_name.to_s.to_sym]
342
+ end
343
+ end
344
+
345
+ def method_missing(method_name, *args, &block)
346
+ if method_name.to_s.end_with?('=')
347
+ set_attribute(method_name, *args)
348
+ elsif has_attribute?(method_name)
349
+ get_attribute(method_name)
350
+ else
351
+ super
352
+ end
353
+ end
354
+
355
+ def respond_to?(method_name, *args, &block)
356
+ if has_attribute?(method_name)
357
+ true
358
+ else
359
+ super
360
+ end
255
361
  end
256
362
 
257
363
  def pattern(*args, type: nil)
258
364
  instance_variable_name = "@#{type}_pattern"
259
365
  the_pattern = instance_variable_get(instance_variable_name)
260
- if the_pattern.nil?
366
+ if the_pattern.nil? || the_pattern.is_disposed
261
367
  the_pattern = self.class.pattern(*args)
262
368
  end
263
369
  the_pattern
264
370
  end
265
371
 
266
- def dispose
267
- @background_pattern&.dispose
268
- @background_pattern = nil
269
- @foreground_pattern&.dispose
270
- @foreground_pattern = nil
271
- @image&.dispose
272
- @image = nil
273
- @parent.shapes.delete(self)
372
+ def pattern_args(type: nil)
373
+ @pattern_args && @pattern_args[type.to_s.capitalize]
374
+ end
375
+
376
+ def background_pattern_args
377
+ pattern_args(type: 'background')
274
378
  end
275
379
 
380
+ def foreground_pattern_args
381
+ pattern_args(type: 'foreground')
382
+ end
383
+
384
+ def dispose(dispose_images: true, dispose_patterns: true)
385
+ if dispose_patterns
386
+ @background_pattern&.dispose
387
+ @background_pattern = nil
388
+ @foreground_pattern&.dispose
389
+ @foreground_pattern = nil
390
+ end
391
+ if dispose_images
392
+ @image&.dispose
393
+ @image = nil
394
+ end
395
+ @parent.shapes.delete(self)
396
+ end
397
+
276
398
  def paint(paint_event)
277
399
  calculate_paint_args!
278
400
  @properties.each do |property, args|
@@ -284,11 +406,15 @@ module Glimmer
284
406
  end
285
407
  end
286
408
  paint_event.gc.send(@method_name, *@args)
409
+ rescue => e
410
+ Glimmer::Config.logger.error {"Error encountered in painting shape: #{self.inspect}"}
411
+ Glimmer::Config.logger.error {e.full_message}
287
412
  end
288
413
 
289
414
  def calculate_paint_args!
290
415
  unless @calculated_paint_args
291
- if @name == 'point'
416
+ if @name == 'pixel'
417
+ @name = 'point'
292
418
  # optimized performance calculation for pixel points
293
419
  if !@properties[:foreground].is_a?(Color)
294
420
  if @properties[:foreground].is_a?(Array)
@@ -304,7 +430,11 @@ module Glimmer
304
430
  else
305
431
  @properties['background'] = [@parent.background] if fill? && !has_some_background?
306
432
  @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
433
+ # TODO regarding alpha, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
434
+ @properties['alpha'] ||= [255]
307
435
  @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
436
+ # TODO regarding transform, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
437
+ # Also do that with all future-added properties
308
438
  @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
309
439
  @properties.each do |property, args|
310
440
  method_name = attribute_setter(property)
@@ -326,3 +456,5 @@ module Glimmer
326
456
  end
327
457
 
328
458
  end
459
+
460
+ Dir[File.expand_path(File.join(__dir__, 'shape', '**', '*.rb'))].each {|shape_file| require(shape_file)}