glimmer-dsl-swt 4.18.5.1 → 4.18.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +15 -12
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +205 -24
  6. data/docs/reference/GLIMMER_SAMPLES.md +8 -0
  7. data/glimmer-dsl-swt.gemspec +8 -3
  8. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  9. data/lib/glimmer/swt/custom/drawable.rb +10 -2
  10. data/lib/glimmer/swt/custom/shape.rb +449 -54
  11. data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
  12. data/lib/glimmer/swt/custom/shape/cubic.rb +108 -0
  13. data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
  14. data/lib/glimmer/swt/custom/shape/image.rb +35 -9
  15. data/lib/glimmer/swt/custom/shape/line.rb +121 -4
  16. data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
  17. data/lib/glimmer/swt/custom/shape/path.rb +197 -0
  18. data/lib/glimmer/swt/custom/shape/path_segment.rb +86 -0
  19. data/lib/glimmer/swt/custom/shape/point.rb +42 -4
  20. data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
  21. data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
  22. data/lib/glimmer/swt/custom/shape/quad.rb +104 -0
  23. data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
  24. data/lib/glimmer/swt/custom/shape/text.rb +13 -3
  25. data/lib/glimmer/swt/dialog_proxy.rb +4 -0
  26. data/lib/glimmer/swt/proxy_properties.rb +1 -1
  27. data/lib/glimmer/swt/transform_proxy.rb +20 -4
  28. data/lib/glimmer/swt/widget_proxy.rb +17 -1
  29. data/samples/elaborate/contact_manager.rb +2 -0
  30. data/samples/elaborate/login.rb +2 -0
  31. data/samples/elaborate/mandelbrot_fractal.rb +2 -1
  32. data/samples/elaborate/meta_sample.rb +1 -0
  33. data/samples/elaborate/tetris.rb +2 -1
  34. data/samples/elaborate/tic_tac_toe.rb +2 -0
  35. data/samples/elaborate/user_profile.rb +10 -8
  36. data/samples/hello/hello_browser.rb +2 -0
  37. data/samples/hello/hello_button.rb +2 -0
  38. data/samples/hello/hello_canvas.rb +40 -23
  39. data/samples/hello/hello_canvas_animation.rb +2 -0
  40. data/samples/hello/hello_canvas_path.rb +223 -0
  41. data/samples/hello/hello_canvas_transform.rb +2 -0
  42. data/samples/hello/hello_checkbox.rb +2 -0
  43. data/samples/hello/hello_checkbox_group.rb +2 -0
  44. data/samples/hello/hello_code_text.rb +2 -0
  45. data/samples/hello/hello_color_dialog.rb +2 -0
  46. data/samples/hello/hello_combo.rb +2 -0
  47. data/samples/hello/hello_computed.rb +2 -0
  48. data/samples/hello/hello_cursor.rb +2 -0
  49. data/samples/hello/hello_custom_shell.rb +1 -0
  50. data/samples/hello/hello_custom_widget.rb +2 -0
  51. data/samples/hello/hello_date_time.rb +2 -0
  52. data/samples/hello/hello_dialog.rb +2 -0
  53. data/samples/hello/hello_directory_dialog.rb +2 -0
  54. data/samples/hello/hello_drag_and_drop.rb +5 -3
  55. data/samples/hello/hello_expand_bar.rb +2 -0
  56. data/samples/hello/hello_file_dialog.rb +2 -0
  57. data/samples/hello/hello_font_dialog.rb +2 -0
  58. data/samples/hello/hello_group.rb +2 -0
  59. data/samples/hello/hello_link.rb +2 -0
  60. data/samples/hello/hello_list_multi_selection.rb +2 -0
  61. data/samples/hello/hello_list_single_selection.rb +2 -0
  62. data/samples/hello/hello_menu_bar.rb +2 -0
  63. data/samples/hello/hello_message_box.rb +2 -0
  64. data/samples/hello/hello_pop_up_context_menu.rb +2 -0
  65. data/samples/hello/hello_progress_bar.rb +2 -0
  66. data/samples/hello/hello_radio.rb +2 -0
  67. data/samples/hello/hello_radio_group.rb +2 -0
  68. data/samples/hello/hello_sash_form.rb +2 -0
  69. data/samples/hello/hello_spinner.rb +2 -0
  70. data/samples/hello/hello_styled_text.rb +19 -17
  71. data/samples/hello/hello_tab.rb +2 -0
  72. data/samples/hello/hello_table.rb +2 -0
  73. data/samples/hello/hello_world.rb +2 -0
  74. metadata +7 -2
@@ -36,6 +36,41 @@ module Glimmer
36
36
  def parameter_names
37
37
  [:x, :y, :width, :height, :start_angle, :arc_angle]
38
38
  end
39
+
40
+ def bounds
41
+ shape_bounds = geometry.getBounds2D
42
+ org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
43
+ end
44
+
45
+ def size
46
+ shape_bounds = geometry.getBounds2D
47
+ org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
48
+ end
49
+
50
+ def geometry
51
+ java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, calculated_width, calculated_height, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
52
+ end
53
+
54
+ # checks if shape contains the point denoted by x and y
55
+ def contain?(x, y)
56
+ geometry.contains(x, y)
57
+ end
58
+
59
+ def include?(x, y)
60
+ if filled?
61
+ contain?(x, y)
62
+ else
63
+ # give it some fuzz to allow a larger region around the drawn oval to accept including a point (helps with mouse clickability on a shape)
64
+ outer_shape_geometry = java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, calculated_width + 3, calculated_height + 3, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
65
+ inner_shape_geometry = java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, calculated_width - 3, calculated_height - 3, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
66
+ outer_shape_geometry.contains(x, y) && !inner_shape_geometry.contains(x, y)
67
+ end
68
+ end
69
+
70
+ def irregular?
71
+ true
72
+ end
73
+
39
74
  end
40
75
  end
41
76
  end
@@ -0,0 +1,108 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swt/custom/shape'
23
+ require 'glimmer/swt/custom/shape/path_segment'
24
+ require 'glimmer/swt/swt_proxy'
25
+ require 'glimmer/swt/display_proxy'
26
+ require 'glimmer/swt/color_proxy'
27
+ require 'glimmer/swt/font_proxy'
28
+ require 'glimmer/swt/transform_proxy'
29
+
30
+ module Glimmer
31
+ module SWT
32
+ module Custom
33
+ # Represents a shape (graphics) to be drawn on a control/widget/canvas/display
34
+ # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
35
+ class Shape
36
+ class Cubic < Path
37
+ def parameter_names
38
+ [:point_array]
39
+ end
40
+
41
+ def geometry
42
+ if @point_array != @geometry_point_array
43
+ @geometry_point_array = @point_array
44
+ @geometry = Java::JavaAwtGeom::Path2D::Double.new
45
+ @geometry.send(path_segment_geometry_method_name, *path_segment_geometry_args)
46
+ end
47
+ @geometry
48
+ end
49
+
50
+ def contain?(x, y)
51
+ include?(x, y, filled: true)
52
+ end
53
+
54
+ # checks if drawn or filled rectangle includes the point denoted by x and y (if drawn, it only returns true if point lies on the edge)
55
+ def include?(x, y, filled: nil)
56
+ filled = filled? if filled.nil?
57
+ makeshift_gc = org.eclipse.swt.graphics.GC.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
58
+ swt_path = org.eclipse.swt.graphics.Path.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
59
+ the_path_segment_args = path_segment_args.dup
60
+ if previous_point_connected?
61
+ the_previous_path_segment = previous_path_segment
62
+ swt_path.moveTo(the_previous_path_segment.x, the_previous_path_segment.y)
63
+ else
64
+ swt_path.moveTo(the_path_segment_args.shift, the_path_segment_args.shift)
65
+ end
66
+ swt_path.curveTo(*the_path_segment_args)
67
+ swt_path.contains(x.to_f, y.to_f, makeshift_gc, !filled)
68
+ ensure
69
+ swt_path.dispose
70
+ end
71
+
72
+ def move_by(x_delta, y_delta)
73
+ the_point_array = @args.compact
74
+ the_point_array = the_point_array.first if the_point_array.first.is_a?(Array)
75
+ self.point_array = the_point_array.each_with_index.map {|coordinate, i| i.even? ? coordinate + x_delta : coordinate + y_delta}
76
+ end
77
+
78
+ def path_segment_method_name
79
+ 'cubicTo'
80
+ end
81
+
82
+ def path_segment_args
83
+ # TODO make args auto-infer control points if previous_point_connected is true or if there is only a point_array with 1 point
84
+ @args.to_a
85
+ end
86
+
87
+ def path_segment_geometry_method_name
88
+ 'curveTo'
89
+ end
90
+
91
+ def previous_point_connected?
92
+ @args.compact.count <= 6 && !first_path_segment?
93
+ end
94
+
95
+ def eql?(other)
96
+ point_array == (other && other.respond_to?(:point_array) && other.point_array)
97
+ end
98
+ alias == eql?
99
+
100
+ def hash
101
+ point_array.hash
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -29,9 +29,9 @@ require 'glimmer/swt/transform_proxy'
29
29
  module Glimmer
30
30
  module SWT
31
31
  module Custom
32
- # Represents a shape (graphics) to be drawn on a control/widget/canvas/display
33
- # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
34
32
  class Shape
33
+ # Represents a focus shape to be drawn on a control/widget/canvas/display
34
+ # Helps highlight focus on another selected shape
35
35
  class Focus < Shape
36
36
  def parameter_names
37
37
  [:x, :y, :width, :height]
@@ -62,20 +62,46 @@ module Glimmer
62
62
  end
63
63
  end
64
64
 
65
- def include?(x, y)
66
- self_x = dest_x || self.x
67
- self_y = dest_y || self.y
68
- width = dest_width || image.bounds.width
69
- height = dest_height || image.bounds.height
70
- x.between?(self_x, self_x + width) && y.between?(self_y, self_y + height)
65
+ def x
66
+ dest_x || get_attribute('x')
71
67
  end
72
-
68
+
69
+ def y
70
+ dest_y || get_attribute('y')
71
+ end
72
+
73
+ def width
74
+ dest_width || image.bounds.width
75
+ end
76
+
77
+ def height
78
+ dest_height || image.bounds.height
79
+ end
80
+
81
+ def default_x?
82
+ super ||
83
+ current_parameter_name?(:dest_x) && (dest_x.nil? || dest_x.to_s == 'default')
84
+ end
85
+
86
+ def default_y?
87
+ super ||
88
+ current_parameter_name?(:dest_y) && (dest_y.nil? || dest_y.to_s == 'default')
89
+ end
90
+
73
91
  def move_by(x_delta, y_delta)
74
- if dest_x
92
+ if default_x?
93
+ self.default_x_delta += x_delta
94
+ elsif dest_x
75
95
  self.dest_x += x_delta
76
- self.dest_y += y_delta
77
96
  else
78
97
  self.x += x_delta
98
+ end
99
+
100
+ if default_y?
101
+ self.default_y_delta += y_delta
102
+ elsif dest_y
103
+ self.dest_y += y_delta
104
+ else
79
105
  self.y += y_delta
80
106
  end
81
107
  end
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/swt/custom/shape'
23
+ require 'glimmer/swt/custom/shape/path_segment'
23
24
  require 'glimmer/swt/swt_proxy'
24
25
  require 'glimmer/swt/display_proxy'
25
26
  require 'glimmer/swt/color_proxy'
@@ -33,17 +34,98 @@ module Glimmer
33
34
  # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
34
35
  class Shape
35
36
  class Line < Shape
37
+ include PathSegment
38
+
39
+ class << self
40
+ def include?(x1, y1, x2, y2, x, y)
41
+ distance1 = Math.sqrt((x - x1)**2 + (y - y1)**2)
42
+ distance2 = Math.sqrt((x2 - x)**2 + (y2 - y)**2)
43
+ distance = Math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
44
+ (distance1 + distance2).to_i == distance.to_i
45
+ end
46
+ end
47
+
36
48
  def parameter_names
37
49
  [:x1, :y1, :x2, :y2]
38
50
  end
39
51
 
52
+ def location_parameter_names
53
+ parameter_names
54
+ end
55
+
56
+ def bounds
57
+ shape_bounds = geometry.getBounds2D
58
+ org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
59
+ end
60
+
61
+ def size
62
+ shape_bounds = geometry.getBounds2D
63
+ org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
64
+ end
65
+
66
+ def geometry
67
+ java.awt.geom.Line2D::Double.new(absolute_x1, absolute_y1, absolute_x2, absolute_y2)
68
+ end
69
+
70
+ # Logical x coordinate relative to parent
71
+ def x
72
+ x_value = bounds.x
73
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
74
+ x_value
75
+ end
76
+
77
+ # Logical y coordinate relative to parent
78
+ def y
79
+ y_value = bounds.y
80
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
81
+ y_value
82
+ end
83
+
84
+ def width
85
+ size.x
86
+ end
87
+
88
+ def height
89
+ size.y
90
+ end
91
+
92
+ def absolute_x1
93
+ if parent.is_a?(Shape)
94
+ parent.absolute_x + x1
95
+ else
96
+ x1
97
+ end
98
+ end
99
+
100
+ def absolute_y1
101
+ if parent.is_a?(Shape)
102
+ parent.absolute_y + y1
103
+ else
104
+ y1
105
+ end
106
+ end
107
+
108
+ def absolute_x2
109
+ if parent.is_a?(Shape)
110
+ parent.absolute_x + x2.to_f
111
+ else
112
+ x2
113
+ end
114
+ end
115
+
116
+ def absolute_y2
117
+ if parent.is_a?(Shape)
118
+ parent.absolute_y + y2.to_f
119
+ else
120
+ y2
121
+ end
122
+ end
123
+
40
124
  def include?(x, y)
41
125
  # TODO must account for line width
42
- distance1 = Math.sqrt((x - x1)**2 + (y - y1)**2)
43
- distance2 = Math.sqrt((x2 - x)**2 + (y2 - y)**2)
44
- distance = Math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
45
- (distance1 + distance2).to_i == distance.to_i
126
+ Line.include?(absolute_x1, absolute_y1, absolute_x2, absolute_y2, x, y)
46
127
  end
128
+ alias contain? include?
47
129
 
48
130
  def move_by(x_delta, y_delta)
49
131
  self.x1 += x_delta
@@ -51,6 +133,41 @@ module Glimmer
51
133
  self.x2 += x_delta
52
134
  self.y2 += y_delta
53
135
  end
136
+
137
+ def irregular?
138
+ true
139
+ end
140
+
141
+ def path_segment_method_name
142
+ 'lineTo'
143
+ end
144
+
145
+ def path_segment_args
146
+ # TODO make args auto-infer first point if previous_point_connected is true or if there is only x1,y1 or x2,y2 (but not both), or if there is an x, y, or if there is a point_array with 1 point
147
+ @args
148
+ end
149
+
150
+ def path_segment_geometry_args
151
+ # TODO make args auto-infer first point if previous_point_connected is true or if there is only x1,y1 or x2,y2 (but not both), or if there is an x, y, or if there is a point_array with 1 point
152
+ @args[0..1]
153
+ end
154
+
155
+ def previous_point_connected?
156
+ @args.compact.count == 2 && !first_path_segment?
157
+ end
158
+
159
+ def eql?(other)
160
+ x1 == (other && other.respond_to?(:x1) && other.x1) &&
161
+ y1 == (other && other.respond_to?(:y1) && other.y1) &&
162
+ x2 == (other && other.respond_to?(:x2) && other.x2) &&
163
+ y2 == (other && other.respond_to?(:y2) && other.y2)
164
+ end
165
+ alias == eql?
166
+
167
+ def hash
168
+ [x1, y1, x2, y2].hash
169
+ end
170
+
54
171
  end
55
172
  end
56
173
  end
@@ -36,6 +36,24 @@ module Glimmer
36
36
  def parameter_names
37
37
  [:x, :y, :width, :height]
38
38
  end
39
+
40
+ # checks if shape contains the point denoted by x and y
41
+ def contain?(x, y)
42
+ shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x, self.absolute_y, calculated_width, calculated_height)
43
+ shape_geometry.contains(x, y)
44
+ end
45
+
46
+ # checks if drawn or filled oval includes the point denoted by x and y (if drawn, it only returns true if point lies on the edge)
47
+ def include?(x, y)
48
+ if filled?
49
+ contain?(x, y)
50
+ else
51
+ # give it some fuzz to allow a larger region around the drawn oval to accept including a point (helps with mouse clickability on a shape)
52
+ outer_shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x - 3, self.absolute_y - 3, calculated_width + 6, calculated_height + 6)
53
+ inner_shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x + 3, self.absolute_y + 3, calculated_width - 6, calculated_height - 6)
54
+ outer_shape_geometry.contains(x, y) && !inner_shape_geometry.contains(x, y)
55
+ end
56
+ end
39
57
  end
40
58
  end
41
59
  end
@@ -0,0 +1,197 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swt/custom/shape'
23
+ require 'glimmer/swt/custom/shape/path_segment'
24
+ require 'glimmer/swt/swt_proxy'
25
+ require 'glimmer/swt/display_proxy'
26
+ require 'glimmer/swt/color_proxy'
27
+ require 'glimmer/swt/font_proxy'
28
+ require 'glimmer/swt/display_proxy'
29
+
30
+ module Glimmer
31
+ module SWT
32
+ module Custom
33
+ # Represents a path to be drawn on a control/widget/canvas/display
34
+ # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
35
+ class Shape
36
+ class Path < Shape
37
+ include PathSegment # a path may behave as a path segment in another path
38
+
39
+ attr_accessor :flatness, :closed
40
+ attr_reader :swt_path, :path_segments
41
+
42
+ def initialize(parent, keyword, *args, &property_block)
43
+ super
44
+ @path_segments = []
45
+ @uncalculated_path_segments = []
46
+ end
47
+
48
+ def parameter_names
49
+ [:swt_path]
50
+ end
51
+
52
+ def add_shape(shape)
53
+ if shape.is_a?(PathSegment)
54
+ @path_segments << shape
55
+ @uncalculated_path_segments << shape
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def contain?(x, y)
62
+ makeshift_gc = org.eclipse.swt.graphics.GC.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
63
+ @swt_path.contains(x.to_f, y.to_f, makeshift_gc, false)
64
+ end
65
+
66
+ def contain?(x, y)
67
+ include?(x, y, filled: true)
68
+ end
69
+
70
+ # checks if drawn or filled rectangle includes the point denoted by x and y (if drawn, it only returns true if point lies on the edge)
71
+ def include?(x, y, filled: nil)
72
+ filled = filled? if filled.nil?
73
+ makeshift_gc = org.eclipse.swt.graphics.GC.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
74
+ @swt_path.contains(x.to_f, y.to_f, makeshift_gc, !filled)
75
+ end
76
+
77
+ def irregular?
78
+ true
79
+ end
80
+
81
+ def post_dispose_content(path_segment)
82
+ @path_segments.delete(path_segment)
83
+ @uncalculated_path_segments = @path_segments.dup
84
+ dispose
85
+ end
86
+
87
+ def dispose
88
+ @swt_path&.dispose
89
+ @swt_path = nil
90
+ @args = []
91
+ calculated_args_changed!(children: false)
92
+ super
93
+ end
94
+
95
+ def calculated_args_changed!(children: true)
96
+ super
97
+ end
98
+
99
+ def calculated_args
100
+ @swt_path ||= org.eclipse.swt.graphics.Path.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
101
+ # TODO recreate @swt_path only if one of the children get disposed (must notify parent on dispose)
102
+ @args = [@swt_path]
103
+ @uncalculated_path_segments.dup.each do |path_segment|
104
+ path_segment.add_to_swt_path(@swt_path)
105
+ @uncalculated_path_segments.delete(path_segment)
106
+ end
107
+ super
108
+ rescue => e
109
+ Glimmer::Config.logger.error {e.full_message}
110
+ end
111
+
112
+ def move_by(x_delta, y_delta)
113
+ @path_segments.each {|path_segment| path_segment.move_by(x_delta, y_delta)}
114
+ end
115
+
116
+ def bounds
117
+ if @path_segments != @bounds_path_segments
118
+ @bounds_path_segments = @path_segments
119
+ shape_bounds = geometry.getBounds2D
120
+ @bounds = org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
121
+ end
122
+ @bounds
123
+ end
124
+
125
+ def size
126
+ if @path_segments != @size_path_segments
127
+ @size_path_segments = @path_segments
128
+ shape_bounds = geometry.getBounds2D
129
+ @size = org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
130
+ end
131
+ @size
132
+ end
133
+
134
+ # Logical x coordinate relative to parent
135
+ def x
136
+ x_value = bounds.x
137
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
138
+ x_value
139
+ end
140
+
141
+ # Logical y coordinate relative to parent
142
+ def y
143
+ y_value = bounds.y
144
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
145
+ y_value
146
+ end
147
+
148
+ def width
149
+ size.x
150
+ end
151
+
152
+ def height
153
+ size.y
154
+ end
155
+
156
+ def geometry
157
+ if @path_segments != @geometry_path_segments
158
+ @geometry_path_segments = @path_segments
159
+ @geometry = Java::JavaAwtGeom::Path2D::Double.new
160
+ @path_segments.each do |path_segment|
161
+ @geometry.send(path_segment.path_segment_geometry_method_name, *path_segment.path_segment_geometry_args)
162
+ end
163
+ end
164
+ @geometry
165
+ end
166
+
167
+ def path_segment_method_name
168
+ 'addPath'
169
+ end
170
+
171
+ def path_segment_args
172
+ @args
173
+ end
174
+
175
+ def path_segment_geometry_method_name
176
+ 'append'
177
+ end
178
+
179
+ def path_segment_geometry_args
180
+ # TODO consider supporting connected true instead of false (2nd arg)
181
+ [geometry, false]
182
+ end
183
+
184
+ def eql?(other)
185
+ geometry.equals(other && other.respond_to?(:geometry) && other.geometry)
186
+ end
187
+ alias == eql?
188
+
189
+ def hash
190
+ geometry.hashCode
191
+ end
192
+
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end