glimmer-dsl-swt 4.18.5.1 → 4.18.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +15 -12
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +205 -24
- data/docs/reference/GLIMMER_SAMPLES.md +8 -0
- data/glimmer-dsl-swt.gemspec +8 -3
- data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
- data/lib/glimmer/swt/custom/drawable.rb +10 -2
- data/lib/glimmer/swt/custom/shape.rb +449 -54
- data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
- data/lib/glimmer/swt/custom/shape/cubic.rb +108 -0
- data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
- data/lib/glimmer/swt/custom/shape/image.rb +35 -9
- data/lib/glimmer/swt/custom/shape/line.rb +121 -4
- data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
- data/lib/glimmer/swt/custom/shape/path.rb +197 -0
- data/lib/glimmer/swt/custom/shape/path_segment.rb +86 -0
- data/lib/glimmer/swt/custom/shape/point.rb +42 -4
- data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
- data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
- data/lib/glimmer/swt/custom/shape/quad.rb +104 -0
- data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
- data/lib/glimmer/swt/custom/shape/text.rb +13 -3
- data/lib/glimmer/swt/dialog_proxy.rb +4 -0
- data/lib/glimmer/swt/proxy_properties.rb +1 -1
- data/lib/glimmer/swt/transform_proxy.rb +20 -4
- data/lib/glimmer/swt/widget_proxy.rb +17 -1
- 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/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 -23
- data/samples/hello/hello_canvas_animation.rb +2 -0
- data/samples/hello/hello_canvas_path.rb +223 -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 +7 -2
@@ -564,6 +564,10 @@ Hello, Canvas!
|
|
564
564
|
|
565
565
|
![Hello Canvas](/images/glimmer-hello-canvas.png)
|
566
566
|
|
567
|
+
Hello, Canvas! Moving Shapes and Nested Shapes via Drag'n'Drop
|
568
|
+
|
569
|
+
![Hello Canvas Moving Shapes](/images/glimmer-hello-canvas-moving-shapes.gif)
|
570
|
+
|
567
571
|
Hello, Canvas! with Moved Shapes (via Drag'n'Drop)
|
568
572
|
|
569
573
|
![Hello Canvas Moved Shapes](/images/glimmer-hello-canvas-moved-shapes.png)
|
@@ -580,6 +584,10 @@ Hello, Canvas! Colors Changed
|
|
580
584
|
|
581
585
|
![Hello Canvas Colors Changed](/images/glimmer-hello-canvas-colors-changed.png)
|
582
586
|
|
587
|
+
Hello, Canvas! Data-Binding (changing a `text` shape `string` via data-binding changes from another thread)
|
588
|
+
|
589
|
+
![Hello Canvas Data Binding](/images/glimmer-hello-canvas-data-binding.gif)
|
590
|
+
|
583
591
|
#### Hello, Canvas Animation!
|
584
592
|
|
585
593
|
This sample demonstrates the use of the `canvas` widget and [Animation DSL](#canvas-animation-dsl) in Glimmer.
|
data/glimmer-dsl-swt.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: glimmer-dsl-swt 4.18.
|
5
|
+
# stub: glimmer-dsl-swt 4.18.6.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer-dsl-swt".freeze
|
9
|
-
s.version = "4.18.
|
9
|
+
s.version = "4.18.6.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["AndyMaleh".freeze]
|
14
|
-
s.date = "2021-02-
|
14
|
+
s.date = "2021-02-28"
|
15
15
|
s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.executables = ["glimmer".freeze, "girb".freeze]
|
@@ -115,13 +115,17 @@ Gem::Specification.new do |s|
|
|
115
115
|
"lib/glimmer/swt/custom/radio_group.rb",
|
116
116
|
"lib/glimmer/swt/custom/shape.rb",
|
117
117
|
"lib/glimmer/swt/custom/shape/arc.rb",
|
118
|
+
"lib/glimmer/swt/custom/shape/cubic.rb",
|
118
119
|
"lib/glimmer/swt/custom/shape/focus.rb",
|
119
120
|
"lib/glimmer/swt/custom/shape/image.rb",
|
120
121
|
"lib/glimmer/swt/custom/shape/line.rb",
|
121
122
|
"lib/glimmer/swt/custom/shape/oval.rb",
|
123
|
+
"lib/glimmer/swt/custom/shape/path.rb",
|
124
|
+
"lib/glimmer/swt/custom/shape/path_segment.rb",
|
122
125
|
"lib/glimmer/swt/custom/shape/point.rb",
|
123
126
|
"lib/glimmer/swt/custom/shape/polygon.rb",
|
124
127
|
"lib/glimmer/swt/custom/shape/polyline.rb",
|
128
|
+
"lib/glimmer/swt/custom/shape/quad.rb",
|
125
129
|
"lib/glimmer/swt/custom/shape/rectangle.rb",
|
126
130
|
"lib/glimmer/swt/custom/shape/text.rb",
|
127
131
|
"lib/glimmer/swt/date_time_proxy.rb",
|
@@ -180,6 +184,7 @@ Gem::Specification.new do |s|
|
|
180
184
|
"samples/hello/hello_button.rb",
|
181
185
|
"samples/hello/hello_canvas.rb",
|
182
186
|
"samples/hello/hello_canvas_animation.rb",
|
187
|
+
"samples/hello/hello_canvas_path.rb",
|
183
188
|
"samples/hello/hello_canvas_transform.rb",
|
184
189
|
"samples/hello/hello_checkbox.rb",
|
185
190
|
"samples/hello/hello_checkbox_group.rb",
|
@@ -32,7 +32,7 @@ module Glimmer
|
|
32
32
|
include ParentExpression
|
33
33
|
|
34
34
|
def can_interpret?(parent, keyword, *args, &block)
|
35
|
-
parent.is_a?(Glimmer::SWT::Custom::Drawable) and
|
35
|
+
(parent.is_a?(Glimmer::SWT::Custom::Drawable) or parent.is_a?(Glimmer::SWT::Custom::Shape)) and
|
36
36
|
Glimmer::SWT::Custom::Shape.valid?(parent, keyword, *args, &block)
|
37
37
|
end
|
38
38
|
|
@@ -34,12 +34,20 @@ module Glimmer
|
|
34
34
|
@shapes ||= []
|
35
35
|
end
|
36
36
|
|
37
|
+
def expanded_shapes
|
38
|
+
@shapes.map do |shape|
|
39
|
+
[shape] + shape.expanded_shapes
|
40
|
+
end.flatten
|
41
|
+
end
|
42
|
+
|
37
43
|
def image_buffered_shapes
|
38
44
|
@image_buffered_shapes ||= []
|
39
45
|
end
|
40
46
|
|
47
|
+
# TODO add a method like shapes that specifies drawable_properties to be able to adjust properties like transform in between shapes
|
48
|
+
|
41
49
|
def shape_at_location(x, y)
|
42
|
-
|
50
|
+
expanded_shapes.reverse.detect {|shape| shape.include?(x, y)}
|
43
51
|
end
|
44
52
|
|
45
53
|
def add_shape(shape)
|
@@ -132,7 +140,7 @@ module Glimmer
|
|
132
140
|
@paint_listener_proxy = on_swt_paint(&shape_painter)
|
133
141
|
end
|
134
142
|
else
|
135
|
-
redraw if @finished_add_content && !is_disposed
|
143
|
+
redraw if respond_to?(:redraw) && @finished_add_content && !is_disposed
|
136
144
|
end
|
137
145
|
end
|
138
146
|
alias resetup_shape_painting setup_shape_painting
|
@@ -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
|
@@ -34,8 +62,6 @@ module Glimmer
|
|
34
62
|
class Shape
|
35
63
|
include Packages
|
36
64
|
include Properties
|
37
|
-
# TODO support textExtent sized shapes nested within text/string
|
38
|
-
# TODO support a Pattern DSL for methods that take Pattern arguments
|
39
65
|
|
40
66
|
class << self
|
41
67
|
def create(parent, keyword, *args, &property_block)
|
@@ -48,7 +74,8 @@ module Glimmer
|
|
48
74
|
end
|
49
75
|
|
50
76
|
def valid?(parent, keyword, *args, &block)
|
51
|
-
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)
|
52
79
|
end
|
53
80
|
|
54
81
|
def gc_instance_methods
|
@@ -100,15 +127,18 @@ module Glimmer
|
|
100
127
|
end
|
101
128
|
end
|
102
129
|
|
103
|
-
attr_reader :parent, :name, :args, :options
|
130
|
+
attr_reader :drawable, :parent, :name, :args, :options, :shapes
|
131
|
+
attr_accessor :extent
|
104
132
|
|
105
133
|
def initialize(parent, keyword, *args, &property_block)
|
106
134
|
@parent = parent
|
135
|
+
@drawable = @parent.is_a?(Drawable) ? @parent : @parent.drawable
|
107
136
|
@name = keyword
|
108
137
|
@options = self.class.arg_options(args, extract: true)
|
109
138
|
@method_name = self.class.method_name(keyword, @options)
|
110
139
|
@args = args
|
111
140
|
@properties = {}
|
141
|
+
@shapes = [] # nested shapes
|
112
142
|
@options.reject {|key, value| %w[fill gradient round].include?(key.to_s)}.each do |property, property_args|
|
113
143
|
@properties[property] = property_args
|
114
144
|
end
|
@@ -116,13 +146,20 @@ module Glimmer
|
|
116
146
|
post_add_content if property_block.nil?
|
117
147
|
end
|
118
148
|
|
149
|
+
def add_shape(shape)
|
150
|
+
@shapes << shape
|
151
|
+
calculated_args_changed_for_defaults!
|
152
|
+
end
|
153
|
+
|
119
154
|
def draw?
|
120
155
|
!fill?
|
121
156
|
end
|
157
|
+
alias drawn? draw?
|
122
158
|
|
123
159
|
def fill?
|
124
160
|
@options[:fill]
|
125
161
|
end
|
162
|
+
alias filled? fill?
|
126
163
|
|
127
164
|
def gradient?
|
128
165
|
@options[:gradient]
|
@@ -132,26 +169,68 @@ module Glimmer
|
|
132
169
|
@options[:round]
|
133
170
|
end
|
134
171
|
|
135
|
-
#
|
136
|
-
|
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
|
193
|
+
# some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
|
194
|
+
def contain?(x, y)
|
195
|
+
# assume a rectangular filled shape by default (works for several shapes like image, text, and focus)
|
196
|
+
x.between?(self.absolute_x, self.absolute_x + calculated_width) && y.between?(self.absolute_y, self.absolute_y + calculated_height)
|
197
|
+
end
|
198
|
+
|
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
|
201
|
+
# some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
|
137
202
|
def include?(x, y)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
else
|
146
|
-
false
|
147
|
-
end
|
203
|
+
# assume a rectangular shape by default
|
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
|
148
210
|
end
|
149
211
|
|
212
|
+
# moves by x delta and y delta. Subclasses must implement
|
213
|
+
# provdies a default implementation that assumes moving x and y is sufficient by default (not for polygons though, which must override)
|
150
214
|
def move_by(x_delta, y_delta)
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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)
|
233
|
+
drawable.redraw unless drawable.is_a?(ImageProxy)
|
155
234
|
end
|
156
235
|
end
|
157
236
|
|
@@ -164,23 +243,28 @@ module Glimmer
|
|
164
243
|
end
|
165
244
|
|
166
245
|
def post_add_content
|
167
|
-
|
246
|
+
# unless @content_added # TODO delete if no longer needed
|
168
247
|
amend_method_name_options_based_on_properties!
|
169
|
-
@
|
248
|
+
@drawable.setup_shape_painting unless @drawable.is_a?(ImageProxy)
|
170
249
|
@content_added = true
|
171
|
-
|
250
|
+
# end
|
172
251
|
end
|
173
252
|
|
174
253
|
def apply_property_arg_conversions(method_name, property, args)
|
175
254
|
args = args.dup
|
176
255
|
the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
|
256
|
+
return args if the_java_method.nil?
|
177
257
|
if the_java_method.parameter_types.first == Color.java_class && args.first.is_a?(RGB)
|
178
258
|
args[0] = [args[0].red, args[0].green, args[0].blue]
|
179
259
|
end
|
180
260
|
if ['setBackground', 'setForeground'].include?(method_name.to_s) && args.first.is_a?(Array)
|
181
261
|
args[0] = ColorProxy.new(args[0])
|
182
262
|
end
|
183
|
-
if
|
263
|
+
if method_name.to_s == 'setLineDash' && args.size > 1
|
264
|
+
args[0] = args.dup
|
265
|
+
args[1..-1] = []
|
266
|
+
end
|
267
|
+
if args.first.is_a?(Symbol) || args.first.is_a?(::String)
|
184
268
|
if the_java_method.parameter_types.first == Color.java_class
|
185
269
|
args[0] = ColorProxy.new(args[0])
|
186
270
|
end
|
@@ -201,11 +285,11 @@ module Glimmer
|
|
201
285
|
args[0] = args[0].swt_transform
|
202
286
|
end
|
203
287
|
if ['setBackgroundPattern', 'setForegroundPattern'].include?(method_name.to_s)
|
204
|
-
@
|
288
|
+
@drawable.requires_shape_disposal = true
|
205
289
|
args = args.first if args.first.is_a?(Array)
|
206
290
|
args.each_with_index do |arg, i|
|
207
291
|
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)
|
292
|
+
arg = ColorProxy.new(arg) if arg.is_a?(Symbol) || arg.is_a?(::String)
|
209
293
|
arg = arg.swt_color if arg.is_a?(ColorProxy)
|
210
294
|
args[i] = arg
|
211
295
|
end
|
@@ -229,7 +313,7 @@ module Glimmer
|
|
229
313
|
@args[1..-1] = []
|
230
314
|
end
|
231
315
|
if @name == 'image'
|
232
|
-
if @args.first.is_a?(String)
|
316
|
+
if @args.first.is_a?(::String)
|
233
317
|
@args[0] = ImageProxy.new(@args[0])
|
234
318
|
end
|
235
319
|
if @args.first.is_a?(ImageProxy)
|
@@ -240,7 +324,7 @@ module Glimmer
|
|
240
324
|
end
|
241
325
|
end
|
242
326
|
if @name == 'text'
|
243
|
-
if @args[3].is_a?(Symbol) || @args[3].is_a?(String)
|
327
|
+
if @args[3].is_a?(Symbol) || @args[3].is_a?(::String)
|
244
328
|
@args[3] = [@args[3]]
|
245
329
|
end
|
246
330
|
if @args[3].is_a?(Array)
|
@@ -253,19 +337,21 @@ module Glimmer
|
|
253
337
|
end
|
254
338
|
|
255
339
|
def apply_shape_arg_defaults!
|
340
|
+
self.x = :default if current_parameter_name?(:x) && x.nil?
|
341
|
+
self.y = :default if current_parameter_name?(:y) && y.nil?
|
342
|
+
self.dest_x = :default if current_parameter_name?(:dest_x) && dest_x.nil?
|
343
|
+
self.dest_y = :default if current_parameter_name?(:dest_y) && dest_y.nil?
|
344
|
+
self.width = :default if current_parameter_name?(:width) && width.nil?
|
345
|
+
self.height = :default if current_parameter_name?(:height) && height.nil?
|
256
346
|
if @name.include?('rectangle') && round? && @args.size.between?(4, 5)
|
257
347
|
(6 - @args.size).times {@args << 60}
|
258
348
|
elsif @name.include?('rectangle') && gradient? && @args.size == 4
|
259
|
-
|
260
|
-
elsif (@name.include?('text') || @name.include?('
|
261
|
-
|
349
|
+
set_attribute('vertical', true, redraw: false)
|
350
|
+
elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size < 4
|
351
|
+
set_attribute('is_transparent', true, redraw: false)
|
262
352
|
end
|
263
353
|
if @name.include?('image')
|
264
|
-
@
|
265
|
-
if @args.size == 1
|
266
|
-
@args[1] = 0
|
267
|
-
@args[2] = 0
|
268
|
-
end
|
354
|
+
@drawable.requires_shape_disposal = true
|
269
355
|
end
|
270
356
|
end
|
271
357
|
|
@@ -282,7 +368,7 @@ module Glimmer
|
|
282
368
|
|
283
369
|
def amend_method_name_options_based_on_properties!
|
284
370
|
return if @name == 'point'
|
285
|
-
if @name != 'text' && has_some_background? && !has_some_foreground?
|
371
|
+
if @name != 'text' && @name != 'string' && has_some_background? && !has_some_foreground?
|
286
372
|
@options[:fill] = true
|
287
373
|
elsif !has_some_background? && has_some_foreground?
|
288
374
|
@options[:fill] = false
|
@@ -301,6 +387,12 @@ module Glimmer
|
|
301
387
|
[]
|
302
388
|
end
|
303
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
|
+
|
304
396
|
def possible_parameter_names
|
305
397
|
parameter_names
|
306
398
|
end
|
@@ -309,8 +401,12 @@ module Glimmer
|
|
309
401
|
possible_parameter_names.map(&:to_s).include?(ruby_attribute_getter(attribute_name))
|
310
402
|
end
|
311
403
|
|
404
|
+
def current_parameter_name?(attribute_name)
|
405
|
+
parameter_names.include?(attribute_name.to_s.to_sym)
|
406
|
+
end
|
407
|
+
|
312
408
|
def parameter_index(attribute_name)
|
313
|
-
parameter_names.
|
409
|
+
parameter_names.index(attribute_name.to_s.to_sym)
|
314
410
|
end
|
315
411
|
|
316
412
|
def set_parameter_attribute(attribute_name, *args)
|
@@ -319,24 +415,44 @@ module Glimmer
|
|
319
415
|
|
320
416
|
def has_attribute?(attribute_name, *args)
|
321
417
|
self.class.gc_instance_methods.include?(attribute_setter(attribute_name)) or
|
322
|
-
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))
|
323
420
|
end
|
324
|
-
|
421
|
+
|
325
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?
|
326
428
|
if parameter_name?(attribute_name)
|
327
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)
|
328
432
|
else
|
329
433
|
@properties[ruby_attribute_getter(attribute_name)] = args
|
330
434
|
end
|
331
|
-
if @content_added &&
|
435
|
+
if @content_added && perform_redraw && !drawable.is_disposed
|
332
436
|
@calculated_paint_args = false
|
333
|
-
|
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)
|
334
447
|
end
|
335
448
|
end
|
336
449
|
|
337
450
|
def get_attribute(attribute_name)
|
338
451
|
if parameter_name?(attribute_name)
|
339
|
-
|
452
|
+
arg_index = parameter_index(attribute_name)
|
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)
|
340
456
|
else
|
341
457
|
@properties.symbolize_keys[attribute_name.to_s.to_sym]
|
342
458
|
end
|
@@ -353,7 +469,9 @@ module Glimmer
|
|
353
469
|
end
|
354
470
|
|
355
471
|
def respond_to?(method_name, *args, &block)
|
356
|
-
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)
|
357
475
|
true
|
358
476
|
else
|
359
477
|
super
|
@@ -382,6 +500,7 @@ module Glimmer
|
|
382
500
|
end
|
383
501
|
|
384
502
|
def dispose(dispose_images: true, dispose_patterns: true)
|
503
|
+
shapes.each { |shape| shape.is_a?(Shape::Path) && shape.dispose }
|
385
504
|
if dispose_patterns
|
386
505
|
@background_pattern&.dispose
|
387
506
|
@background_pattern = nil
|
@@ -394,21 +513,297 @@ module Glimmer
|
|
394
513
|
end
|
395
514
|
@parent.shapes.delete(self)
|
396
515
|
end
|
397
|
-
|
516
|
+
|
398
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
|
399
531
|
calculate_paint_args!
|
532
|
+
@original_properties_backup = {}
|
400
533
|
@properties.each do |property, args|
|
401
534
|
method_name = attribute_setter(property)
|
402
|
-
|
535
|
+
@original_properties_backup[method_name] = paint_event.gc.send(method_name.sub('set', 'get')) rescue nil
|
403
536
|
paint_event.gc.send(method_name, *args)
|
404
537
|
if property == 'transform' && args.first.is_a?(TransformProxy)
|
405
538
|
args.first.swt_transform.dispose
|
406
539
|
end
|
407
540
|
end
|
408
|
-
paint_event
|
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
|
409
551
|
rescue => e
|
410
|
-
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})"}
|
411
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)}"
|
412
807
|
end
|
413
808
|
|
414
809
|
def calculate_paint_args!
|
@@ -420,7 +815,7 @@ module Glimmer
|
|
420
815
|
if @properties[:foreground].is_a?(Array)
|
421
816
|
@properties[:foreground] = ColorProxy.new(@properties[:foreground], ensure_bounds: false)
|
422
817
|
end
|
423
|
-
if @properties[:foreground].is_a?(Symbol) || @properties[:foreground].is_a?(String)
|
818
|
+
if @properties[:foreground].is_a?(Symbol) || @properties[:foreground].is_a?(::String)
|
424
819
|
@properties[:foreground] = ColorProxy.new(@properties[:foreground], ensure_bounds: false)
|
425
820
|
end
|
426
821
|
if @properties[:foreground].is_a?(ColorProxy)
|
@@ -428,14 +823,14 @@ module Glimmer
|
|
428
823
|
end
|
429
824
|
end
|
430
825
|
else
|
431
|
-
@properties['background'] = [@
|
432
|
-
@properties['foreground'] = [@
|
826
|
+
@properties['background'] = [@drawable.background] if fill? && !has_some_background?
|
827
|
+
@properties['foreground'] = [@drawable.foreground] if @drawable.respond_to?(:foreground) && draw? && !has_some_foreground?
|
433
828
|
# TODO regarding alpha, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
|
434
829
|
@properties['alpha'] ||= [255]
|
435
|
-
@properties['font'] = [@
|
436
|
-
# TODO regarding transform, make sure to reset it to parent stored
|
830
|
+
@properties['font'] = [@drawable.font] if @drawable.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
|
831
|
+
# TODO regarding transform, make sure to reset it to parent stored transform once we allow setting shape properties on parents directly without shapes
|
437
832
|
# Also do that with all future-added properties
|
438
|
-
@properties['transform'] = [nil] if @
|
833
|
+
@properties['transform'] = [nil] if @drawable.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
|
439
834
|
@properties.each do |property, args|
|
440
835
|
method_name = attribute_setter(property)
|
441
836
|
converted_args = apply_property_arg_conversions(method_name, property, args)
|