glimmer-dsl-swt 4.18.5.2 → 4.18.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +8 -10
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +93 -16
  6. data/docs/reference/GLIMMER_SAMPLES.md +32 -0
  7. data/glimmer-dsl-swt.gemspec +9 -3
  8. data/lib/glimmer/swt/custom/drawable.rb +8 -7
  9. data/lib/glimmer/swt/custom/shape.rb +416 -37
  10. data/lib/glimmer/swt/custom/shape/arc.rb +22 -4
  11. data/lib/glimmer/swt/custom/shape/cubic.rb +117 -0
  12. data/lib/glimmer/swt/custom/shape/image.rb +19 -6
  13. data/lib/glimmer/swt/custom/shape/line.rb +119 -1
  14. data/lib/glimmer/swt/custom/shape/oval.rb +3 -3
  15. data/lib/glimmer/swt/custom/shape/path.rb +211 -0
  16. data/lib/glimmer/swt/custom/shape/path_segment.rb +111 -0
  17. data/lib/glimmer/swt/custom/shape/point.rb +40 -4
  18. data/lib/glimmer/swt/custom/shape/polygon.rb +93 -3
  19. data/lib/glimmer/swt/custom/shape/polyline.rb +76 -4
  20. data/lib/glimmer/swt/custom/shape/quad.rb +113 -0
  21. data/lib/glimmer/swt/custom/shape/rectangle.rb +7 -2
  22. data/lib/glimmer/swt/custom/shape/text.rb +2 -4
  23. data/lib/glimmer/swt/dialog_proxy.rb +4 -0
  24. data/lib/glimmer/swt/proxy_properties.rb +1 -1
  25. data/lib/glimmer/swt/widget_proxy.rb +16 -0
  26. data/samples/elaborate/contact_manager.rb +2 -0
  27. data/samples/elaborate/login.rb +2 -0
  28. data/samples/elaborate/mandelbrot_fractal.rb +2 -1
  29. data/samples/elaborate/meta_sample.rb +1 -0
  30. data/samples/elaborate/stock_ticker.rb +229 -0
  31. data/samples/elaborate/tetris.rb +2 -1
  32. data/samples/elaborate/tic_tac_toe.rb +2 -0
  33. data/samples/elaborate/user_profile.rb +10 -8
  34. data/samples/hello/hello_browser.rb +2 -0
  35. data/samples/hello/hello_button.rb +2 -0
  36. data/samples/hello/hello_canvas.rb +40 -21
  37. data/samples/hello/hello_canvas_animation.rb +2 -0
  38. data/samples/hello/hello_canvas_path.rb +66 -0
  39. data/samples/hello/hello_canvas_transform.rb +2 -0
  40. data/samples/hello/hello_checkbox.rb +2 -0
  41. data/samples/hello/hello_checkbox_group.rb +2 -0
  42. data/samples/hello/hello_code_text.rb +2 -0
  43. data/samples/hello/hello_color_dialog.rb +2 -0
  44. data/samples/hello/hello_combo.rb +2 -0
  45. data/samples/hello/hello_computed.rb +2 -0
  46. data/samples/hello/hello_cursor.rb +2 -0
  47. data/samples/hello/hello_custom_shell.rb +1 -0
  48. data/samples/hello/hello_custom_widget.rb +2 -0
  49. data/samples/hello/hello_date_time.rb +2 -0
  50. data/samples/hello/hello_dialog.rb +2 -0
  51. data/samples/hello/hello_directory_dialog.rb +2 -0
  52. data/samples/hello/hello_drag_and_drop.rb +5 -3
  53. data/samples/hello/hello_expand_bar.rb +2 -0
  54. data/samples/hello/hello_file_dialog.rb +2 -0
  55. data/samples/hello/hello_font_dialog.rb +2 -0
  56. data/samples/hello/hello_group.rb +2 -0
  57. data/samples/hello/hello_link.rb +2 -0
  58. data/samples/hello/hello_list_multi_selection.rb +2 -0
  59. data/samples/hello/hello_list_single_selection.rb +2 -0
  60. data/samples/hello/hello_menu_bar.rb +2 -0
  61. data/samples/hello/hello_message_box.rb +2 -0
  62. data/samples/hello/hello_pop_up_context_menu.rb +2 -0
  63. data/samples/hello/hello_progress_bar.rb +2 -0
  64. data/samples/hello/hello_radio.rb +2 -0
  65. data/samples/hello/hello_radio_group.rb +2 -0
  66. data/samples/hello/hello_sash_form.rb +2 -0
  67. data/samples/hello/hello_spinner.rb +2 -0
  68. data/samples/hello/hello_styled_text.rb +19 -17
  69. data/samples/hello/hello_tab.rb +2 -0
  70. data/samples/hello/hello_table.rb +2 -0
  71. data/samples/hello/hello_world.rb +2 -0
  72. metadata +8 -2
@@ -26,6 +26,34 @@ require 'glimmer/swt/color_proxy'
26
26
  require 'glimmer/swt/font_proxy'
27
27
  require 'glimmer/swt/transform_proxy'
28
28
 
29
+ class Java::OrgEclipseSwtGraphics::GC
30
+ def setLineDashOffset(value)
31
+ lineMiterLimit = getLineAttributes&.miterLimit || 999_999
32
+ setLineAttributes(Java::OrgEclipseSwtGraphics::LineAttributes.new(getLineWidth, getLineCap, getLineJoin, getLineStyle, getLineDash.map(&:to_f).to_java(:float), value, lineMiterLimit))
33
+ end
34
+ alias set_line_dash_offset setLineDashOffset
35
+ alias line_dash_offset= setLineDashOffset
36
+
37
+ def getLineDashOffset
38
+ getLineAttributes&.dashOffset
39
+ end
40
+ alias get_line_dash_offset getLineDashOffset
41
+ alias line_dash_offset getLineDashOffset
42
+
43
+ def setLineMiterLimit(value)
44
+ lineDashOffset = getLineAttributes&.dashOffset || 0
45
+ setLineAttributes(Java::OrgEclipseSwtGraphics::LineAttributes.new(getLineWidth, getLineCap, getLineJoin, getLineStyle, getLineDash.map(&:to_f).to_java(:float), lineDashOffset, value))
46
+ end
47
+ alias set_line_miter_limit setLineMiterLimit
48
+ alias line_miter_limit= setLineMiterLimit
49
+
50
+ def getLineMiterLimit
51
+ getLineAttributes&.miterLimit
52
+ end
53
+ alias get_line_miter_limit getLineMiterLimit
54
+ alias line_miter_limit getLineMiterLimit
55
+ end
56
+
29
57
  module Glimmer
30
58
  module SWT
31
59
  module Custom
@@ -46,7 +74,8 @@ module Glimmer
46
74
  end
47
75
 
48
76
  def valid?(parent, keyword, *args, &block)
49
- gc_instance_methods.include?(method_name(keyword, arg_options(args)))
77
+ gc_instance_methods.include?(method_name(keyword, arg_options(args))) ||
78
+ constants.include?(keyword.to_s.camelcase(:upper).to_sym)
50
79
  end
51
80
 
52
81
  def gc_instance_methods
@@ -99,6 +128,7 @@ module Glimmer
99
128
  end
100
129
 
101
130
  attr_reader :drawable, :parent, :name, :args, :options, :shapes
131
+ attr_accessor :extent
102
132
 
103
133
  def initialize(parent, keyword, *args, &property_block)
104
134
  @parent = parent
@@ -118,6 +148,7 @@ module Glimmer
118
148
 
119
149
  def add_shape(shape)
120
150
  @shapes << shape
151
+ calculated_args_changed_for_defaults!
121
152
  end
122
153
 
123
154
  def draw?
@@ -138,34 +169,67 @@ module Glimmer
138
169
  @options[:round]
139
170
  end
140
171
 
141
- # subclasses (like polygon) may override to indicate if a point x,y coordinates falls inside the shape
172
+ # The bounding box top-left x, y, width, height in absolute positioning
173
+ def bounds
174
+ org.eclipse.swt.graphics.Rectangle.new(absolute_x, absolute_y, calculated_width, calculated_height)
175
+ end
176
+
177
+ # The bounding box top-left x and y
178
+ def location
179
+ org.eclipse.swt.graphics.Point.new(bounds.x, bounds.y)
180
+ end
181
+
182
+ # The bounding box width and height (as a Point object with x being width and y being height)
183
+ def size
184
+ org.eclipse.swt.graphics.Point.new(calculated_width, calculated_height)
185
+ end
186
+
187
+ def extent
188
+ @extent || size
189
+ end
190
+
191
+ # Returns if shape contains a point
192
+ # Subclasses (like polygon) may override to indicate if a point x,y coordinates falls inside the shape
142
193
  # some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
143
194
  def contain?(x, y)
144
195
  # assume a rectangular filled shape by default (works for several shapes like image, text, and focus)
145
- if respond_to?(:x) && respond_to?(:y) && respond_to?(:width) && respond_to?(:height) && self.x && self.y && width && height
146
- x.between?(self.x, self.x + width) && y.between?(self.y, self.y + height)
147
- else
148
- false # subclasses must provide implementation
149
- end
196
+ x.between?(self.absolute_x, self.absolute_x + calculated_width) && y.between?(self.absolute_y, self.absolute_y + calculated_height)
150
197
  end
151
198
 
152
- # subclasses (like polygon) may override to indicate if a point x,y coordinates falls on the edge of a drawn shape or inside a filled shape
199
+ # Returns if shape includes a point. When the shape is filled, this is the same as contain. When the shape is drawn, it only returns true if the point lies on the edge (boundary/border)
200
+ # Subclasses (like polygon) may override to indicate if a point x,y coordinates falls on the edge of a drawn shape or inside a filled shape
153
201
  # some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
154
202
  def include?(x, y)
155
203
  # assume a rectangular shape by default
156
- if respond_to?(:x) && respond_to?(:y) && respond_to?(:width) && respond_to?(:height)
157
- contain?(x, y)
158
- else
159
- false # subclasses must provide implementation
160
- end
204
+ contain?(x, y)
205
+ end
206
+
207
+ # Indicates if a shape's x, y, width, height differ from its bounds calculation (e.g. arc / polygon)
208
+ def irregular?
209
+ false
161
210
  end
162
211
 
163
212
  # moves by x delta and y delta. Subclasses must implement
164
213
  # provdies a default implementation that assumes moving x and y is sufficient by default (not for polygons though, which must override)
165
214
  def move_by(x_delta, y_delta)
166
- if respond_to?(:x) && respond_to?(:y) && x && y
167
- self.x += x_delta
168
- self.y += y_delta
215
+ if respond_to?(:x) && respond_to?(:y) && respond_to?(:x=) && respond_to?(:y=)
216
+ if default_x?
217
+ self.default_x_delta += x_delta
218
+ else
219
+ self.x += x_delta
220
+ end
221
+ if default_y?
222
+ self.default_y_delta += y_delta
223
+ else
224
+ self.y += y_delta
225
+ end
226
+ end
227
+ end
228
+
229
+ def content(&block)
230
+ Glimmer::SWT::DisplayProxy.instance.auto_exec do
231
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShapeExpression.new, &block)
232
+ calculated_args_changed!(children: false)
169
233
  end
170
234
  end
171
235
 
@@ -178,8 +242,8 @@ module Glimmer
178
242
  end
179
243
 
180
244
  def post_add_content
181
- unless @content_added
182
- amend_method_name_options_based_on_properties!
245
+ amend_method_name_options_based_on_properties!
246
+ if !@content_added || @method_name != @original_method_name
183
247
  @drawable.setup_shape_painting unless @drawable.is_a?(ImageProxy)
184
248
  @content_added = true
185
249
  end
@@ -188,12 +252,17 @@ module Glimmer
188
252
  def apply_property_arg_conversions(method_name, property, args)
189
253
  args = args.dup
190
254
  the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
255
+ return args if the_java_method.nil?
191
256
  if the_java_method.parameter_types.first == Color.java_class && args.first.is_a?(RGB)
192
257
  args[0] = [args[0].red, args[0].green, args[0].blue]
193
258
  end
194
259
  if ['setBackground', 'setForeground'].include?(method_name.to_s) && args.first.is_a?(Array)
195
260
  args[0] = ColorProxy.new(args[0])
196
261
  end
262
+ if method_name.to_s == 'setLineDash' && args.size > 1
263
+ args[0] = args.dup
264
+ args[1..-1] = []
265
+ end
197
266
  if args.first.is_a?(Symbol) || args.first.is_a?(::String)
198
267
  if the_java_method.parameter_types.first == Color.java_class
199
268
  args[0] = ColorProxy.new(args[0])
@@ -267,19 +336,21 @@ module Glimmer
267
336
  end
268
337
 
269
338
  def apply_shape_arg_defaults!
339
+ self.x = :default if current_parameter_name?(:x) && x.nil?
340
+ self.y = :default if current_parameter_name?(:y) && y.nil?
341
+ self.dest_x = :default if current_parameter_name?(:dest_x) && dest_x.nil?
342
+ self.dest_y = :default if current_parameter_name?(:dest_y) && dest_y.nil?
343
+ self.width = :default if current_parameter_name?(:width) && width.nil?
344
+ self.height = :default if current_parameter_name?(:height) && height.nil?
270
345
  if @name.include?('rectangle') && round? && @args.size.between?(4, 5)
271
346
  (6 - @args.size).times {@args << 60}
272
347
  elsif @name.include?('rectangle') && gradient? && @args.size == 4
273
- @args << true # vertical is true by default
274
- elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size == 3
275
- @args << true # is_transparent is true by default
348
+ set_attribute('vertical', true, redraw: false)
349
+ elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size < 4
350
+ set_attribute('is_transparent', true, redraw: false)
276
351
  end
277
352
  if @name.include?('image')
278
353
  @drawable.requires_shape_disposal = true
279
- if @args.size == 1
280
- @args[1] = 0
281
- @args[2] = 0
282
- end
283
354
  end
284
355
  end
285
356
 
@@ -295,6 +366,7 @@ module Glimmer
295
366
  end
296
367
 
297
368
  def amend_method_name_options_based_on_properties!
369
+ @original_method_name = @method_name
298
370
  return if @name == 'point'
299
371
  if @name != 'text' && @name != 'string' && has_some_background? && !has_some_foreground?
300
372
  @options[:fill] = true
@@ -315,6 +387,12 @@ module Glimmer
315
387
  []
316
388
  end
317
389
 
390
+ # subclasses may override to specify location parameter names if different from x and y (e.g. all polygon points are location parameters)
391
+ # used in calculating movement changes
392
+ def location_parameter_names
393
+ [:x, :y]
394
+ end
395
+
318
396
  def possible_parameter_names
319
397
  parameter_names
320
398
  end
@@ -323,8 +401,12 @@ module Glimmer
323
401
  possible_parameter_names.map(&:to_s).include?(ruby_attribute_getter(attribute_name))
324
402
  end
325
403
 
404
+ def current_parameter_name?(attribute_name)
405
+ parameter_names.include?(attribute_name.to_s.to_sym)
406
+ end
407
+
326
408
  def parameter_index(attribute_name)
327
- parameter_names.map(&:to_s).index(attribute_name.to_s)
409
+ parameter_names.index(attribute_name.to_s.to_sym)
328
410
  end
329
411
 
330
412
  def set_parameter_attribute(attribute_name, *args)
@@ -333,18 +415,35 @@ module Glimmer
333
415
 
334
416
  def has_attribute?(attribute_name, *args)
335
417
  self.class.gc_instance_methods.include?(attribute_setter(attribute_name)) or
336
- parameter_name?(attribute_name)
418
+ parameter_name?(attribute_name) or
419
+ (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
337
420
  end
338
-
421
+
339
422
  def set_attribute(attribute_name, *args)
423
+ options = args.last if args.last.is_a?(Hash)
424
+ args.pop if !options.nil? && !options[:redraw].nil?
425
+ perform_redraw = @perform_redraw
426
+ perform_redraw = options[:redraw] if perform_redraw.nil? && !options.nil?
427
+ perform_redraw = true if perform_redraw.nil?
340
428
  if parameter_name?(attribute_name)
341
429
  set_parameter_attribute(attribute_name, *args)
430
+ elsif (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
431
+ self.send(ruby_attribute_setter(attribute_name), *args)
342
432
  else
343
433
  @properties[ruby_attribute_getter(attribute_name)] = args
344
434
  end
345
- if @content_added && !@drawable.is_disposed
435
+ if @content_added && perform_redraw && !drawable.is_disposed
346
436
  @calculated_paint_args = false
347
- @drawable.redraw
437
+ attribute_name = ruby_attribute_getter(attribute_name)
438
+ if location_parameter_names.map(&:to_s).include?(attribute_name)
439
+ @calculated_args = nil
440
+ parent.calculated_args_changed_for_defaults! if parent.is_a?(Shape)
441
+ end
442
+ if ['width', 'height'].include?(attribute_name)
443
+ calculated_args_changed_for_defaults!
444
+ end
445
+ # TODO consider redrawing an image proxy's gc in the future
446
+ drawable.redraw unless drawable.is_a?(ImageProxy)
348
447
  end
349
448
  end
350
449
 
@@ -352,6 +451,8 @@ module Glimmer
352
451
  if parameter_name?(attribute_name)
353
452
  arg_index = parameter_index(attribute_name)
354
453
  @args[arg_index] if arg_index
454
+ elsif (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
455
+ self.send(attribute_name)
355
456
  else
356
457
  @properties.symbolize_keys[attribute_name.to_s.to_sym]
357
458
  end
@@ -368,7 +469,9 @@ module Glimmer
368
469
  end
369
470
 
370
471
  def respond_to?(method_name, *args, &block)
371
- if has_attribute?(method_name)
472
+ options = args.last if args.last.is_a?(Hash)
473
+ super_invocation = options && options[:super]
474
+ if !super_invocation && has_attribute?(method_name)
372
475
  true
373
476
  else
374
477
  super
@@ -397,6 +500,7 @@ module Glimmer
397
500
  end
398
501
 
399
502
  def dispose(dispose_images: true, dispose_patterns: true)
503
+ shapes.each { |shape| shape.is_a?(Shape::Path) && shape.dispose }
400
504
  if dispose_patterns
401
505
  @background_pattern&.dispose
402
506
  @background_pattern = nil
@@ -409,22 +513,297 @@ module Glimmer
409
513
  end
410
514
  @parent.shapes.delete(self)
411
515
  end
412
-
516
+
413
517
  def paint(paint_event)
518
+ # pre-paint children an extra-time first when default width/height need to be calculated for defaults
519
+ paint_children(paint_event) if default_width? || default_height?
520
+ paint_self(paint_event)
521
+ # re-paint children from scratch in the special case of pre-calculating parent width/height to re-center within new parent dimensions
522
+ shapes.each(&:calculated_args_changed!) if default_width? || default_height?
523
+ paint_children(paint_event)
524
+ rescue => e
525
+ Glimmer::Config.logger.error {"Error encountered in painting shape (#{self.inspect}) with calculated args (#{@calculated_args}) and args (#{@args})"}
526
+ Glimmer::Config.logger.error {e.full_message}
527
+ end
528
+
529
+ def paint_self(paint_event)
530
+ @painting = true
414
531
  calculate_paint_args!
532
+ @original_properties_backup = {}
415
533
  @properties.each do |property, args|
416
534
  method_name = attribute_setter(property)
417
- # TODO consider optimization of not setting a background/foreground/font if it didn't change from last shape
535
+ @original_properties_backup[method_name] = paint_event.gc.send(method_name.sub('set', 'get')) rescue nil
418
536
  paint_event.gc.send(method_name, *args)
419
537
  if property == 'transform' && args.first.is_a?(TransformProxy)
420
538
  args.first.swt_transform.dispose
421
539
  end
422
540
  end
423
- self.extent = paint_event.gc.send("#{@name}Extent", *(([string, flags] if respond_to?(:flags)).compact)) if ['text', 'string'].include?(@name)
424
- paint_event.gc.send(@method_name, *@args)
541
+ ensure_extent(paint_event)
542
+ if !@calculated_args || parent_shape_absolute_location_changed?
543
+ @calculated_args = calculated_args
544
+ end
545
+ # paint unless parent's calculated args are not calculated yet, meaning it is about to get painted and trigger a paint on this child anyways
546
+ paint_event.gc.send(@method_name, *@calculated_args) unless parent.is_a?(Shape) && !parent.calculated_args?
547
+ @original_properties_backup.each do |method_name, value|
548
+ paint_event.gc.send(method_name, value)
549
+ end
550
+ @painting = false
425
551
  rescue => e
426
- Glimmer::Config.logger.error {"Error encountered in painting shape: #{self.inspect}"}
552
+ Glimmer::Config.logger.error {"Error encountered in painting shape (#{self.inspect}) with calculated args (#{@calculated_args}) and args (#{@args})"}
427
553
  Glimmer::Config.logger.error {e.full_message}
554
+ ensure
555
+ @painting = false
556
+ end
557
+
558
+ def paint_children(paint_event)
559
+ shapes.to_a.each do |shape|
560
+ shape.paint(paint_event)
561
+ end
562
+ end
563
+
564
+ def ensure_extent(paint_event)
565
+ old_extent = @extent
566
+ if ['text', 'string'].include?(@name)
567
+ extent_args = [string]
568
+ extent_flags = SWTProxy[:draw_transparent] if current_parameter_name?(:is_transparent) && is_transparent
569
+ extent_flags = flags if current_parameter_name?(:flags)
570
+ extent_args << extent_flags unless extent_flags.nil?
571
+ self.extent = paint_event.gc.send("#{@name}Extent", *extent_args)
572
+ end
573
+ if !@extent.nil? && (old_extent&.x != @extent&.x || old_extent&.y != @extent&.y)
574
+ calculated_args_changed!
575
+ parent.calculated_args_changed_for_defaults! if parent.is_a?(Shape)
576
+ end
577
+ end
578
+
579
+ def expanded_shapes
580
+ if shapes.to_a.any?
581
+ shapes.map do |shape|
582
+ [shape] + shape.expanded_shapes
583
+ end.flatten
584
+ else
585
+ []
586
+ end
587
+ end
588
+
589
+ def parent_shape_absolute_location_changed?
590
+ (parent.is_a?(Shape) && (parent.absolute_x != @parent_absolute_x || parent.absolute_y != @parent_absolute_y))
591
+ end
592
+
593
+ def calculated_args_changed!(children: true)
594
+ # TODO add a children: true option to enable setting to false to avoid recalculating children args
595
+ @calculated_args = nil
596
+ shapes.each(&:calculated_args_changed!) if children
597
+ end
598
+
599
+ def calculated_args_changed_for_defaults!
600
+ has_default_dimensions = default_width? || default_height?
601
+ parent_calculated_args_changed_for_defaults = has_default_dimensions
602
+ @calculated_args = nil if default_x? || default_y? || has_default_dimensions
603
+ if has_default_dimensions && parent.is_a?(Shape)
604
+ parent.calculated_args_changed_for_defaults!
605
+ elsif @content_added && !drawable.is_disposed
606
+ # TODO consider optimizing in the future if needed by ensuring one redraw for all parents in the hierarchy at the end instead of doing one per parent that needs it
607
+ drawable.redraw if !@painting && !drawable.is_a?(ImageProxy)
608
+ end
609
+ end
610
+
611
+ def calculated_args?
612
+ !!@calculated_args
613
+ end
614
+
615
+ # args translated to absolute coordinates
616
+ def calculated_args
617
+ return @args if !default_x? && !default_y? && !default_width? && !default_height? && parent.is_a?(Drawable)
618
+ # Note: Must set x and move_by because not all shapes have a real x and some must translate all their points with move_by
619
+ # TODO change that by setting a bounding box for all shapes with a calculated top-left x, y and
620
+ # a setter that does the moving inside them instead so that I could rely on absolute_x and absolute_y
621
+ # here to get the job done of calculating absolute args
622
+ @perform_redraw = false
623
+ original_x = nil
624
+ original_y = nil
625
+ original_width = nil
626
+ original_height = nil
627
+ if parent.is_a?(Shape)
628
+ @parent_absolute_x = parent.absolute_x
629
+ @parent_absolute_y = parent.absolute_y
630
+ end
631
+ if default_width?
632
+ original_width = width
633
+ self.width = default_width + default_width_delta
634
+ end
635
+ if default_height?
636
+ original_height = height
637
+ self.height = default_height + default_height_delta
638
+ end
639
+ if default_x?
640
+ original_x = x
641
+ self.x = default_x + default_x_delta
642
+ end
643
+ if default_y?
644
+ original_y = y
645
+ self.y = default_y + default_y_delta
646
+ end
647
+ if parent.is_a?(Shape)
648
+ move_by(@parent_absolute_x, @parent_absolute_y)
649
+ result_args = @args.clone
650
+ move_by(-1*@parent_absolute_x, -1*@parent_absolute_y)
651
+ else
652
+ result_args = @args.clone
653
+ end
654
+ if original_x
655
+ self.x = original_x
656
+ end
657
+ if original_y
658
+ self.y = original_y
659
+ end
660
+ if original_width
661
+ self.width = original_width
662
+ end
663
+ if original_height
664
+ self.height = original_height
665
+ end
666
+ @perform_redraw = true
667
+ result_args
668
+ end
669
+
670
+ def default_x?
671
+ current_parameter_name?(:x) and
672
+ (x.nil? || x.to_s == 'default' || (x.is_a?(Array) && x.first.to_s == 'default'))
673
+ end
674
+
675
+ def default_y?
676
+ current_parameter_name?(:y) and
677
+ (y.nil? || y.to_s == 'default' || (y.is_a?(Array) && y.first.to_s == 'default'))
678
+ end
679
+
680
+ def default_width?
681
+ return false unless current_parameter_name?(:width)
682
+ width = self.width
683
+ (width.nil? || width == :default || width == 'default' || (width.is_a?(Array) && (width.first.to_s == :default || width.first.to_s == 'default')))
684
+ end
685
+
686
+ def default_height?
687
+ return false unless current_parameter_name?(:height)
688
+ height = self.height
689
+ (height.nil? || height == :default || height == 'default' || (height.is_a?(Array) && (height.first.to_s == :default || height.first.to_s == 'default')))
690
+ end
691
+
692
+ def default_x
693
+ result = ((parent.size.x - size.x) / 2)
694
+ result += parent.bounds.x - parent.absolute_x if parent.is_a?(Shape) && parent.irregular?
695
+ result
696
+ end
697
+
698
+ def default_y
699
+ result = ((parent.size.y - size.y) / 2)
700
+ result += parent.bounds.y - parent.absolute_y if parent.is_a?(Shape) && parent.irregular?
701
+ result
702
+ end
703
+
704
+ def default_width
705
+ # TODO consider caching
706
+ x_ends = shapes.map do |shape|
707
+ shape_width = shape.calculated_width.to_f
708
+ shape_x = shape.default_x? ? 0 : shape.x.to_f
709
+ shape_x + shape_width
710
+ end
711
+ x_ends.max.to_f
712
+ end
713
+
714
+ def default_height
715
+ # TODO consider caching
716
+ y_ends = shapes.map do |shape|
717
+ shape_height = shape.calculated_height.to_f
718
+ shape_y = shape.default_y? ? 0 : shape.y.to_f
719
+ shape_y + shape_height
720
+ end
721
+ y_ends.max.to_f
722
+ end
723
+
724
+ def calculated_width
725
+ default_width? ? (default_width + default_width_delta) : width
726
+ end
727
+
728
+ def calculated_height
729
+ default_height? ? (default_height + default_height_delta) : height
730
+ end
731
+
732
+ def default_x_delta
733
+ return 0 unless default_x? && x.is_a?(Array)
734
+ x[1].to_f
735
+ end
736
+
737
+ def default_y_delta
738
+ return 0 unless default_y? && y.is_a?(Array)
739
+ y[1].to_f
740
+ end
741
+
742
+ def default_width_delta
743
+ return 0 unless default_width? && width.is_a?(Array)
744
+ width[1].to_f
745
+ end
746
+
747
+ def default_height_delta
748
+ return 0 unless default_height? && height.is_a?(Array)
749
+ height[1].to_f
750
+ end
751
+
752
+ def default_x_delta=(delta)
753
+ return unless default_x?
754
+ self.x = [:default, delta]
755
+ end
756
+
757
+ def default_y_delta=(delta)
758
+ return unless default_y?
759
+ self.y = [:default, delta]
760
+ end
761
+
762
+ def default_width_delta=(delta)
763
+ return unless default_width?
764
+ self.width = [:default, delta]
765
+ end
766
+
767
+ def default_height_delta=(delta)
768
+ return unless default_height?
769
+ self.height = [:default, delta]
770
+ end
771
+
772
+ def calculated_x
773
+ result = default_x? ? default_x : self.x
774
+ result += default_x_delta
775
+ result
776
+ end
777
+
778
+ def calculated_y
779
+ result = default_y? ? default_y : self.y
780
+ result += default_y_delta
781
+ result
782
+ end
783
+
784
+ def absolute_x
785
+ x = calculated_x
786
+ if parent.is_a?(Shape)
787
+ parent.absolute_x + x
788
+ else
789
+ x
790
+ end
791
+ end
792
+
793
+ def absolute_y
794
+ y = calculated_y
795
+ if parent.is_a?(Shape)
796
+ parent.absolute_y + y
797
+ else
798
+ y
799
+ end
800
+ end
801
+
802
+ # Overriding inspect to avoid printing very long shape hierarchies
803
+ def inspect
804
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)} args=#{@args.inspect}, properties=#{@properties.inspect}}>"
805
+ rescue => e
806
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)}"
428
807
  end
429
808
 
430
809
  def calculate_paint_args!
@@ -449,7 +828,7 @@ module Glimmer
449
828
  # TODO regarding alpha, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
450
829
  @properties['alpha'] ||= [255]
451
830
  @properties['font'] = [@drawable.font] if @drawable.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
452
- # TODO regarding transform, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
831
+ # TODO regarding transform, make sure to reset it to parent stored transform once we allow setting shape properties on parents directly without shapes
453
832
  # Also do that with all future-added properties
454
833
  @properties['transform'] = [nil] if @drawable.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
455
834
  @properties.each do |property, args|