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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/README.md +8 -10
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +93 -16
- data/docs/reference/GLIMMER_SAMPLES.md +32 -0
- data/glimmer-dsl-swt.gemspec +9 -3
- data/lib/glimmer/swt/custom/drawable.rb +8 -7
- data/lib/glimmer/swt/custom/shape.rb +416 -37
- data/lib/glimmer/swt/custom/shape/arc.rb +22 -4
- data/lib/glimmer/swt/custom/shape/cubic.rb +117 -0
- data/lib/glimmer/swt/custom/shape/image.rb +19 -6
- data/lib/glimmer/swt/custom/shape/line.rb +119 -1
- data/lib/glimmer/swt/custom/shape/oval.rb +3 -3
- data/lib/glimmer/swt/custom/shape/path.rb +211 -0
- data/lib/glimmer/swt/custom/shape/path_segment.rb +111 -0
- data/lib/glimmer/swt/custom/shape/point.rb +40 -4
- data/lib/glimmer/swt/custom/shape/polygon.rb +93 -3
- data/lib/glimmer/swt/custom/shape/polyline.rb +76 -4
- data/lib/glimmer/swt/custom/shape/quad.rb +113 -0
- data/lib/glimmer/swt/custom/shape/rectangle.rb +7 -2
- data/lib/glimmer/swt/custom/shape/text.rb +2 -4
- data/lib/glimmer/swt/dialog_proxy.rb +4 -0
- data/lib/glimmer/swt/proxy_properties.rb +1 -1
- data/lib/glimmer/swt/widget_proxy.rb +16 -0
- data/samples/elaborate/contact_manager.rb +2 -0
- data/samples/elaborate/login.rb +2 -0
- data/samples/elaborate/mandelbrot_fractal.rb +2 -1
- data/samples/elaborate/meta_sample.rb +1 -0
- data/samples/elaborate/stock_ticker.rb +229 -0
- data/samples/elaborate/tetris.rb +2 -1
- data/samples/elaborate/tic_tac_toe.rb +2 -0
- data/samples/elaborate/user_profile.rb +10 -8
- data/samples/hello/hello_browser.rb +2 -0
- data/samples/hello/hello_button.rb +2 -0
- data/samples/hello/hello_canvas.rb +40 -21
- data/samples/hello/hello_canvas_animation.rb +2 -0
- data/samples/hello/hello_canvas_path.rb +66 -0
- data/samples/hello/hello_canvas_transform.rb +2 -0
- data/samples/hello/hello_checkbox.rb +2 -0
- data/samples/hello/hello_checkbox_group.rb +2 -0
- data/samples/hello/hello_code_text.rb +2 -0
- data/samples/hello/hello_color_dialog.rb +2 -0
- data/samples/hello/hello_combo.rb +2 -0
- data/samples/hello/hello_computed.rb +2 -0
- data/samples/hello/hello_cursor.rb +2 -0
- data/samples/hello/hello_custom_shell.rb +1 -0
- data/samples/hello/hello_custom_widget.rb +2 -0
- data/samples/hello/hello_date_time.rb +2 -0
- data/samples/hello/hello_dialog.rb +2 -0
- data/samples/hello/hello_directory_dialog.rb +2 -0
- data/samples/hello/hello_drag_and_drop.rb +5 -3
- data/samples/hello/hello_expand_bar.rb +2 -0
- data/samples/hello/hello_file_dialog.rb +2 -0
- data/samples/hello/hello_font_dialog.rb +2 -0
- data/samples/hello/hello_group.rb +2 -0
- data/samples/hello/hello_link.rb +2 -0
- data/samples/hello/hello_list_multi_selection.rb +2 -0
- data/samples/hello/hello_list_single_selection.rb +2 -0
- data/samples/hello/hello_menu_bar.rb +2 -0
- data/samples/hello/hello_message_box.rb +2 -0
- data/samples/hello/hello_pop_up_context_menu.rb +2 -0
- data/samples/hello/hello_progress_bar.rb +2 -0
- data/samples/hello/hello_radio.rb +2 -0
- data/samples/hello/hello_radio_group.rb +2 -0
- data/samples/hello/hello_sash_form.rb +2 -0
- data/samples/hello/hello_spinner.rb +2 -0
- data/samples/hello/hello_styled_text.rb +19 -17
- data/samples/hello/hello_tab.rb +2 -0
- data/samples/hello/hello_table.rb +2 -0
- data/samples/hello/hello_world.rb +2 -0
- 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
|
-
#
|
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
|
-
|
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
|
-
#
|
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
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
168
|
-
|
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
|
-
|
182
|
-
|
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
|
-
|
274
|
-
elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size
|
275
|
-
|
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.
|
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 &&
|
435
|
+
if @content_added && perform_redraw && !drawable.is_disposed
|
346
436
|
@calculated_paint_args = false
|
347
|
-
|
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
|
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
|
-
|
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
|
-
|
424
|
-
|
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
|
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
|
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|
|