glimmer-dsl-swt 4.18.5.3 → 4.18.5.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acf07c3a7c6f534f4082330369a0bacac2593675506da814ec68e70446ec02b9
4
- data.tar.gz: ff2983c28283b30b4f7f9e6bdf9cc0bad3768331014ef281ff5397726851b39d
3
+ metadata.gz: 495c8eacce66f3b425a8f1603eea5051f5b776f0cb8e8550419382079c58e85e
4
+ data.tar.gz: 7e922de5ff80a2e85facee8a36444fe70bd6a9e25a65416aeebec4bfabd10749
5
5
  SHA512:
6
- metadata.gz: d89da48eb352e555e861032de5b5fee9c1e1ad3e7796c920e354b61b5fb1e2522fa1eafd89e363259ee9c3961ab4207a51ea483ef670e072c869fb1671fecccb
7
- data.tar.gz: d267615568ac7e20ef8b5778df77cfe36f3de061ab9dd5c4e227b2ef08d5323a27bc6742f07728a84b0760a11f64bdad822c4468f1cf24049ac536919816548e
6
+ metadata.gz: 5ace8433246247b3210cced98a70bb45cfdc978808b632ad322b5c995a7b0e868fc7df9c6ed23293fd5845e50257696617ad9a85ad9e7a0f0b697aea55901cfc
7
+ data.tar.gz: 58c632f794d07225737d101b68300db72c41b90778320765971e29539242d48260512db44c77ed99fb1aa9307056d24364a5bb57e400b3a0aab49c41ac8babb4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ### 4.18.5.4
4
+
5
+ - Support passing width, height as :default (or nil or not passed in if they are the last args) in all shapes that include other shapes to indicate they are calculated automatically from nested shapes, text/string extent, or otherwise defaulting to 0, 0
6
+ - Support [:default, width_delta], [:default, height_delta] attributes for width and height, which add/subtract from defaults used for shape
7
+ - Switch from use of `:default` with x_delta/y_delta to passing `[:default, x_delta]` or `[:default, y_delta]` (e.g. `image(file, [:default, -30], :default)` for x = default - 30 and y = default + 0)
8
+ - Support a bounding box for all shapes, implementing `#bounds` (x, y, width, and height) and `#size` (width, height) for the ones that don't receive as parameters (like polygon)
9
+
3
10
  ### 4.18.5.3
4
11
 
5
12
  - Support nesting shapes within shapes, with relative positioning (meaning x, y coordinates are assumed relative to parent's x, y in nested shapes)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.5.3
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.5.4
2
2
  ## JRuby Desktop Development GUI Framework
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
4
4
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
@@ -8,7 +8,7 @@
8
8
 
9
9
  **[Contributors Wanted! (Submit a Glimmer App Sample to Get Started)](#contributing)**
10
10
 
11
- [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer) is a native-GUI cross-platform desktop development library written in [JRuby](https://www.jruby.org/), an OS-threaded faster JVM version of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://github.com/AndyObtiva/glimmer)'s main innovation is a declarative [Ruby DSL](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#glimmer-dsl-syntax) that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [Glimmer](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#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](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#widgets), but it also supports drawing Canvas Graphics like [Shapes](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-shape-dsl) and [Animations](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-animation-dsl). To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](docs/reference/GLIMMER_COMMAND.md#scaffolding) options for [Apps](#in-production), [Gems](docs/reference/GLIMMER_COMMAND.md#custom-shell-gem), and [Custom Widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#custom-widgets). [Glimmer](https://rubygems.org/gems/glimmer) also includes native-executable [packaging](docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos) + [App Store](https://developer.apple.com/macos/distribution/), MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows), and [Gem Packaged Shell Scripts](docs/reference/GLIMMER_COMMAND.md#packaging) on [Linux](https://www.linux.org/).
11
+ [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for SWT is a native-GUI cross-platform desktop development library written in [JRuby](https://www.jruby.org/), an OS-threaded faster JVM version of [Ruby](https://www.ruby-lang.org/en/). [Glimmer](https://github.com/AndyObtiva/glimmer)'s main innovation is a declarative [Ruby DSL](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#glimmer-dsl-syntax) that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust [Eclipse SWT library](https://www.eclipse.org/swt/). [Glimmer](https://rubygems.org/gems/glimmer) additionally innovates by having built-in [data-binding](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#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](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#widgets), but it also supports drawing Canvas Graphics like [Shapes](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-shape-dsl) and [Animations](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#canvas-animation-dsl). To get started quickly, [Glimmer](https://rubygems.org/gems/glimmer) offers [scaffolding](docs/reference/GLIMMER_COMMAND.md#scaffolding) options for [Apps](#in-production), [Gems](docs/reference/GLIMMER_COMMAND.md#custom-shell-gem), and [Custom Widgets](docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#custom-widgets). [Glimmer](https://rubygems.org/gems/glimmer) also includes native-executable [packaging](docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in [Ruby](https://www.ruby-lang.org/en/) as truly native DMG/PKG/APP files on the [Mac](https://www.apple.com/ca/macos) + [App Store](https://developer.apple.com/macos/distribution/), MSI/EXE files on [Windows](https://www.microsoft.com/en-ca/windows), and [Gem Packaged Shell Scripts](docs/reference/GLIMMER_COMMAND.md#packaging) on [Linux](https://www.linux.org/).
12
12
 
13
13
  [Glimmer receives two updates per month](https://rubygems.org/gems/glimmer-dsl-swt/versions). You can trust [Glimmer](https://rubygems.org/gems/glimmer) with your Ruby desktop GUI development needs. Please make [Glimmer](https://rubygems.org/gems/glimmer) even better by providing feedback and [contributing](#contributing) when possible.
14
14
 
@@ -342,7 +342,7 @@ jgem install glimmer-dsl-swt
342
342
 
343
343
  Or this command if you want a specific version:
344
344
  ```
345
- jgem install glimmer-dsl-swt -v 4.18.5.3
345
+ jgem install glimmer-dsl-swt -v 4.18.5.4
346
346
  ```
347
347
 
348
348
  `jgem` is JRuby's version of `gem` command.
@@ -360,7 +360,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
360
360
 
361
361
  Add the following to `Gemfile`:
362
362
  ```
363
- gem 'glimmer-dsl-swt', '~> 4.18.5.3'
363
+ gem 'glimmer-dsl-swt', '~> 4.18.5.4'
364
364
  ```
365
365
 
366
366
  And, then run:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.18.5.3
1
+ 4.18.5.4
@@ -36,6 +36,7 @@ This guide should help you get started with Glimmer DSL for SWT. For more advanc
36
36
  - [Layouts](#layouts)
37
37
  - [Layout Data](#layout-data)
38
38
  - [Canvas Shape DSL](#canvas-shape-dsl)
39
+ - [Shapes inside a Shape](#shapes-inside-a-shape)
39
40
  - [Shapes inside a Widget](#shapes-inside-a-widget)
40
41
  - [Shapes inside an Image](#shapes-inside-an-image)
41
42
  - [Canvas Shape API](#canvas-shape-api)
@@ -1403,7 +1404,7 @@ Shape keywords and their args (including defaults) are listed below (they basica
1403
1404
  - `rectangle(x, y, width, height, arcWidth = 60, arcHeight = 60, fill: false, round: true)` round rectangle, which can be optionally filled, and takes optional extra round angle arguments
1404
1405
  - `rectangle(x, y, width, height, vertical = true, fill: true, gradient: true)` gradient rectangle, which is always filled, and takes an optional extra argument to specify true for vertical gradient (default) and false for horizontal gradient
1405
1406
  - `text(string, x, y, is_transparent = true)` text with optional is_transparent to indicate if background is transparent (default is true)
1406
- - `text(string, x, y, flags)` text with optional flags (flag format is `swt(comma_separated_flags)` where flags can be :draw_delimiter (i.e. new lines), :draw_tab, :draw_mnemonic, and :draw_transparent as explained in [GC API](https://help.eclipse.org/2020-12/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html))
1407
+ - `text(string, x, y, flags)` text with optional flags (flag format is `swt(comma_separated_flags)` where flags can be `:draw_delimiter` (i.e. new lines), `:draw_tab`, `:draw_mnemonic`, and `:draw_transparent` as explained in [GC API](https://help.eclipse.org/2020-12/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html))
1407
1408
 
1408
1409
  Shape keywords that can be filled with color can take a keyword argument `fill: true`. Defaults to false when not specified unless background is set with no foreground (or foreground is set with no background), in which case a smart default is applied.
1409
1410
  Smart defaults can be applied to automatically infer `gradient: true` (rectangle with both foreground and background) and `round: true` (rectangle with more than 4 args, the extra args are numeric) as well.
@@ -1460,7 +1461,7 @@ shell {
1460
1461
  font height: 25, style: :bold
1461
1462
  }
1462
1463
  rectangle(200, 80, 108, 36) {
1463
- foreground :black
1464
+ foreground rgb(0, 0, 0)
1464
1465
  line_width 3
1465
1466
  }
1466
1467
  image(image_object, 70, 50)
@@ -1506,7 +1507,7 @@ shell {
1506
1507
  font height: 25, style: :bold
1507
1508
  }
1508
1509
  rectangle(200, 80, 108, 36) {
1509
- foreground :black
1510
+ foreground rgb(0, 0, 0)
1510
1511
  line_width 3
1511
1512
  }
1512
1513
  image(image_object, 70, 50)
@@ -1541,7 +1542,7 @@ shell {
1541
1542
  }
1542
1543
  rectangle {
1543
1544
  x 50
1544
- x 20
1545
+ y 20
1545
1546
  width 300
1546
1547
  height 150
1547
1548
  arc_width 30
@@ -1596,23 +1597,26 @@ shell {
1596
1597
  minimum_size 320, 400
1597
1598
 
1598
1599
  canvas {
1599
- background :yellow
1600
+ background :dark_yellow
1600
1601
 
1601
1602
  on_paint_control { |paint_event|
1602
1603
  gc = paint_event.gc
1603
- gc.background = color(:red).swt_color
1604
- gc.fill_rectangle(0, 0, 220, 400)
1605
1604
 
1606
- gc.background = color(:magenta).swt_color
1607
- gc.fill_roundRectangle(50, 20, 300, 150, 30, 50)
1605
+ gc.background = color(:dark_red).swt_color
1606
+ gc.fill_rectangle(0, 0, 220, 400)
1608
1607
 
1609
- gc.background = color(:dark_magenta).swt_color
1610
- gc.fill_gradientRectangle(150, 200, 100, 70, true)
1608
+ gc.background = color(:yellow).swt_color
1609
+ gc.fill_round_rectangle(50, 20, 300, 150, 30, 50)
1611
1610
 
1612
- gc.foreground = color(:dark_blue).swt_color
1613
- gc.draw_rectangle(200, 80, 108, 36)
1611
+ gc.background = color(:dark_red).swt_color
1612
+ gc.foreground = color(:yellow).swt_color
1613
+ gc.fill_gradient_rectangle(150, 200, 100, 70, true)
1614
1614
 
1615
+ gc.font = font(height: 25, style: :bold).swt_font
1615
1616
  gc.foreground = color(:black).swt_color
1617
+ gc.draw_text('Glimmer', 208, 83, true)
1618
+
1619
+ gc.foreground = rgb(0, 0, 0).swt_color
1616
1620
  gc.line_width = 3
1617
1621
  gc.draw_rectangle(200, 80, 108, 36)
1618
1622
 
@@ -1762,6 +1766,8 @@ They are implemented with the help of the highly robust Java built-in shape geom
1762
1766
  - `Shape#contain?(x, y)` : indicates if shape contains x, y point
1763
1767
  - `Shape#include?(x, y)` : indicates if shape includes x, y point on the edge if drawn or inside if filled (include uses contain for filled shapes)
1764
1768
  - `Shape#move_by(x_delta, y_delta)` : moves shape object at x, y location
1769
+ - `Shape#size` : calculated size for shape bounding box (e.g. a polygon with an irregular shape will have its bounding box width and height calculated)
1770
+ - `Shape#bounds` : calculated bounds (x, y, width, height) for shape bounding box (e.g. a polygon with an irregular shape will have its bounding box top-left x, y, width and height calculated)
1765
1771
 
1766
1772
  Check [Hello, Canvas!](GLIMMER_SAMPLES.md#hello-canvas) for an example.
1767
1773
 
@@ -580,6 +580,10 @@ Hello, Canvas! Colors Changed
580
580
 
581
581
  ![Hello Canvas Colors Changed](/images/glimmer-hello-canvas-colors-changed.png)
582
582
 
583
+ Hello, Canvas! Data-Binding (changing a `text` shape `string` via data-binding changes from another thread)
584
+
585
+ ![Hello Canvas Data Binding](/images/glimmer-hello-canvas-data-binding.gif)
586
+
583
587
  #### Hello, Canvas Animation!
584
588
 
585
589
  This sample demonstrates the use of the `canvas` widget and [Animation DSL](#canvas-animation-dsl) in Glimmer.
@@ -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.3 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.5.4 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.5.3"
9
+ s.version = "4.18.5.4"
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-25"
14
+ s.date = "2021-02-26"
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]
@@ -99,7 +99,7 @@ module Glimmer
99
99
  end
100
100
 
101
101
  attr_reader :drawable, :parent, :name, :args, :options, :shapes
102
- attr_accessor :x_delta, :y_delta
102
+ attr_accessor :extent
103
103
 
104
104
  def initialize(parent, keyword, *args, &property_block)
105
105
  @parent = parent
@@ -110,8 +110,6 @@ module Glimmer
110
110
  @args = args
111
111
  @properties = {}
112
112
  @shapes = [] # nested shapes
113
- @x_delta = 0
114
- @y_delta = 0
115
113
  @options.reject {|key, value| %w[fill gradient round].include?(key.to_s)}.each do |property, property_args|
116
114
  @properties[property] = property_args
117
115
  end
@@ -121,6 +119,7 @@ module Glimmer
121
119
 
122
120
  def add_shape(shape)
123
121
  @shapes << shape
122
+ calculated_args_changed_for_default_size!
124
123
  end
125
124
 
126
125
  def draw?
@@ -141,26 +140,34 @@ module Glimmer
141
140
  @options[:round]
142
141
  end
143
142
 
144
- # subclasses (like polygon) may override to indicate if a point x,y coordinates falls inside the shape
143
+ # The bounding box top-left x, y, width, height in absolute positioning
144
+ def bounds
145
+ org.eclipse.swt.graphics.Rectangle.new(absolute_x, absolute_y, calculated_width, calculated_height)
146
+ end
147
+
148
+ # The bounding box width and height (as a Point object with x being width and y being height)
149
+ def size
150
+ org.eclipse.swt.graphics.Point.new(calculated_width, calculated_height)
151
+ end
152
+
153
+ def extent
154
+ @extent || size
155
+ end
156
+
157
+ # Returns if shape contains a point
158
+ # Subclasses (like polygon) may override to indicate if a point x,y coordinates falls inside the shape
145
159
  # some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
146
160
  def contain?(x, y)
147
161
  # assume a rectangular filled shape by default (works for several shapes like image, text, and focus)
148
- if respond_to?(:x) && respond_to?(:y) && respond_to?(:width) && respond_to?(:height) && self.x && self.y && width && height
149
- x.between?(self.absolute_x, self.absolute_x + width) && y.between?(self.absolute_y, self.absolute_y + height)
150
- else
151
- false # subclasses must provide implementation
152
- end
162
+ x.between?(self.absolute_x, self.absolute_x + calculated_width) && y.between?(self.absolute_y, self.absolute_y + calculated_height)
153
163
  end
154
164
 
155
- # 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
165
+ # 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)
166
+ # 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
156
167
  # some shapes may choose to provide a fuzz factor to make usage of this method for mouse clicking more user friendly
157
168
  def include?(x, y)
158
169
  # assume a rectangular shape by default
159
- if respond_to?(:x) && respond_to?(:y) && respond_to?(:width) && respond_to?(:height)
160
- contain?(x, y)
161
- else
162
- false # subclasses must provide implementation
163
- end
170
+ contain?(x, y)
164
171
  end
165
172
 
166
173
  # moves by x delta and y delta. Subclasses must implement
@@ -168,12 +175,12 @@ module Glimmer
168
175
  def move_by(x_delta, y_delta)
169
176
  if respond_to?(:x) && respond_to?(:y) && respond_to?(:x=) && respond_to?(:y=)
170
177
  if default_x?
171
- self.x_delta += x_delta
178
+ self.default_x_delta += x_delta
172
179
  else
173
180
  self.x += x_delta
174
181
  end
175
182
  if default_y?
176
- self.y_delta += y_delta
183
+ self.default_y_delta += y_delta
177
184
  else
178
185
  self.y += y_delta
179
186
  end
@@ -278,20 +285,22 @@ module Glimmer
278
285
  end
279
286
 
280
287
  def apply_shape_arg_defaults!
288
+ self.x = :default if current_parameter_name?(:x) && x.nil?
289
+ self.y = :default if current_parameter_name?(:y) && y.nil?
290
+ self.dest_x = :default if current_parameter_name?(:dest_x) && dest_x.nil?
291
+ self.dest_y = :default if current_parameter_name?(:dest_y) && dest_y.nil?
292
+ self.width = :default if current_parameter_name?(:width) && width.nil?
293
+ self.height = :default if current_parameter_name?(:height) && height.nil?
281
294
  if @name.include?('rectangle') && round? && @args.size.between?(4, 5)
282
295
  (6 - @args.size).times {@args << 60}
283
296
  elsif @name.include?('rectangle') && gradient? && @args.size == 4
284
- @args << true # vertical is true by default
285
- elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size == 3
286
- @args << true # is_transparent is true by default
297
+ set_attribute('vertical', true, redraw: false)
298
+ elsif (@name.include?('text') || @name.include?('string')) && !@properties.keys.map(&:to_s).include?('background') && @args.size < 4
299
+ set_attribute('is_transparent', true, redraw: false)
287
300
  end
288
301
  if @name.include?('image')
289
302
  @drawable.requires_shape_disposal = true
290
303
  end
291
- self.x = :default if current_parameter_name?(:x) && x.nil?
292
- self.y = :default if current_parameter_name?(:y) && y.nil?
293
- self.dest_x = :default if current_parameter_name?(:dest_x) && dest_x.nil?
294
- self.dest_y = :default if current_parameter_name?(:dest_y) && dest_y.nil?
295
304
  end
296
305
 
297
306
  # Tolerates shape extra args added by user by mistake
@@ -341,11 +350,11 @@ module Glimmer
341
350
  end
342
351
 
343
352
  def current_parameter_name?(attribute_name)
344
- parameter_names.map(&:to_s).include?(ruby_attribute_getter(attribute_name))
353
+ parameter_names.include?(attribute_name.to_s.to_sym)
345
354
  end
346
355
 
347
356
  def parameter_index(attribute_name)
348
- parameter_names.map(&:to_s).index(attribute_name.to_s)
357
+ parameter_names.index(attribute_name.to_s.to_sym)
349
358
  end
350
359
 
351
360
  def set_parameter_attribute(attribute_name, *args)
@@ -357,9 +366,10 @@ module Glimmer
357
366
  parameter_name?(attribute_name) or
358
367
  (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
359
368
  end
360
-
369
+
361
370
  def set_attribute(attribute_name, *args)
362
371
  options = args.last if args.last.is_a?(Hash)
372
+ args.pop if !options.nil? && !options[:redraw].nil?
363
373
  perform_redraw = @perform_redraw
364
374
  perform_redraw = options[:redraw] if perform_redraw.nil? && !options.nil?
365
375
  perform_redraw = true if perform_redraw.nil?
@@ -373,8 +383,10 @@ module Glimmer
373
383
  if @content_added && perform_redraw && !drawable.is_disposed
374
384
  @calculated_paint_args = false
375
385
  attribute_name = ruby_attribute_getter(attribute_name)
376
- @calculated_absolute_args = false if (location_parameter_names.map(&:to_s) + ['x_delta', 'y_delta']).include?(attribute_name)
377
-
386
+ @calculated_args = nil if location_parameter_names.map(&:to_s).include?(attribute_name)
387
+ if ['width', 'height'].include?(attribute_name)
388
+ calculated_args_changed_for_default_size!
389
+ end
378
390
  # TODO consider redrawing an image proxy's gc in the future
379
391
  drawable.redraw unless drawable.is_a?(ImageProxy)
380
392
  end
@@ -447,6 +459,17 @@ module Glimmer
447
459
  end
448
460
 
449
461
  def paint(paint_event)
462
+ paint_children(paint_event) if default_width? || default_height?
463
+ paint_self(paint_event)
464
+ shapes.each(&:calculated_args_changed!) if default_width? || default_height?
465
+ paint_children(paint_event)
466
+ rescue => e
467
+ Glimmer::Config.logger.error {"Error encountered in painting shape (#{self.inspect}) with calculated args (#{@calculated_args}) and args (#{@args})"}
468
+ Glimmer::Config.logger.error {e.full_message}
469
+ end
470
+
471
+ def paint_self(paint_event)
472
+ @painting = true
450
473
  calculate_paint_args!
451
474
  @properties.each do |property, args|
452
475
  method_name = attribute_setter(property)
@@ -456,16 +479,18 @@ module Glimmer
456
479
  args.first.swt_transform.dispose
457
480
  end
458
481
  end
459
- self.extent = paint_event.gc.send("#{@name}Extent", *(([string, flags] if respond_to?(:flags)).compact)) if ['text', 'string'].include?(@name)
460
- if !@calculated_absolute_args || parent_shape_absolute_location_changed?
461
- @absolute_args = absolute_args
462
- @calculated_absolute_args = true
482
+ ensure_extent(paint_event)
483
+ if !@calculated_args || parent_shape_absolute_location_changed?
484
+ @calculated_args = calculated_args
463
485
  end
464
- paint_event.gc.send(@method_name, *@absolute_args)
465
- paint_children(paint_event)
486
+ # 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
487
+ paint_event.gc.send(@method_name, *@calculated_args) unless parent.is_a?(Shape) && !parent.calculated_args?
488
+ @painting = false
466
489
  rescue => e
467
- Glimmer::Config.logger.error {"Error encountered in painting shape: #{self.inspect}"}
490
+ Glimmer::Config.logger.error {"Error encountered in painting shape (#{self.inspect}) with calculated args (#{@calculated_args}) and args (#{@args})"}
468
491
  Glimmer::Config.logger.error {e.full_message}
492
+ ensure
493
+ @painting = false
469
494
  end
470
495
 
471
496
  def paint_children(paint_event)
@@ -474,6 +499,20 @@ module Glimmer
474
499
  end
475
500
  end
476
501
 
502
+ def ensure_extent(paint_event)
503
+ old_extent = @extent
504
+ if ['text', 'string'].include?(@name)
505
+ extent_args = [string]
506
+ extent_flags = SWTProxy[:draw_transparent] if current_parameter_name?(:is_transparent) && is_transparent
507
+ extent_flags = flags if current_parameter_name?(:flags)
508
+ extent_args << extent_flags unless extent_flags.nil?
509
+ self.extent = paint_event.gc.send("#{@name}Extent", *extent_args)
510
+ end
511
+ if !@extent.nil? && (old_extent&.x != @extent&.x || old_extent&.y != @extent&.y)
512
+ parent.calculated_args_changed_for_default_size! if parent.is_a?(Shape)
513
+ end
514
+ end
515
+
477
516
  def expanded_shapes
478
517
  if shapes.to_a.any?
479
518
  shapes.map do |shape|
@@ -487,69 +526,198 @@ module Glimmer
487
526
  def parent_shape_absolute_location_changed?
488
527
  (parent.is_a?(Shape) && (parent.absolute_x != @parent_absolute_x || parent.absolute_y != @parent_absolute_y))
489
528
  end
529
+
530
+ def calculated_args_changed!
531
+ # TODO add a children: true option to enable setting to false to avoid recalculating children args
532
+ @calculated_args = nil
533
+ shapes.each(&:calculated_args_changed!)
534
+ end
535
+
536
+ def calculated_args_changed_for_default_size!
537
+ @calculated_args = nil if default_width? || default_height?
538
+ if parent.is_a?(Shape)
539
+ parent.calculated_args_changed_for_default_size!
540
+ elsif @content_added && !drawable.is_disposed
541
+ # 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
542
+ drawable.redraw if !@painting && !drawable.is_a?(ImageProxy)
543
+ end
544
+ end
545
+
546
+ def calculated_args?
547
+ !!@calculated_args
548
+ end
490
549
 
491
550
  # args translated to absolute coordinates
492
- def absolute_args
493
- return @args if !default_x? && !default_y? && @x_delta == 0 && @y_delta == 0 && parent.is_a?(Drawable)
551
+ def calculated_args
552
+ return @args if !default_x? && !default_y? && !default_width? && !default_height? && parent.is_a?(Drawable)
553
+ # 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
554
+ # TODO change that by setting a bounding box for all shapes with a calculated top-left x, y and
555
+ # a setter that does the moving inside them instead so that I could rely on absolute_x and absolute_y
556
+ # here to get the job done of calculating absolute args
494
557
  @perform_redraw = false
495
558
  original_x = nil
496
559
  original_y = nil
560
+ original_width = nil
561
+ original_height = nil
562
+ if default_width?
563
+ original_width = width
564
+ self.width = default_width + default_width_delta
565
+ end
566
+ if default_height?
567
+ original_height = height
568
+ self.height = default_height + default_height_delta
569
+ end
497
570
  if default_x?
498
571
  original_x = x
499
- self.x = default_x
572
+ self.x = default_x + default_x_delta
500
573
  end
501
574
  if default_y?
502
575
  original_y = y
503
- self.y = default_y
576
+ self.y = default_y + default_y_delta
504
577
  end
505
- move_by(@x_delta, @y_delta)
506
578
  if parent.is_a?(Shape)
507
579
  @parent_absolute_x = parent.absolute_x
508
580
  @parent_absolute_y = parent.absolute_y
509
581
  move_by(parent.absolute_x, parent.absolute_y)
510
- calculated_absolute_args = @args.clone
582
+ result_args = @args.clone
511
583
  move_by(-1*parent.absolute_x, -1*parent.absolute_y)
512
584
  else
513
- calculated_absolute_args = @args.clone
585
+ result_args = @args.clone
514
586
  end
515
- move_by(-1*@x_delta, -1*@y_delta)
516
587
  if original_x
517
588
  self.x = original_x
518
589
  end
519
590
  if original_y
520
591
  self.y = original_y
521
592
  end
593
+ if original_width
594
+ self.width = original_width
595
+ end
596
+ if original_height
597
+ self.height = original_height
598
+ end
522
599
  @perform_redraw = true
523
- calculated_absolute_args
600
+ result_args
524
601
  end
525
602
 
526
603
  def default_x?
527
- current_parameter_name?('x') && (x.nil? || x.to_s == 'default')
604
+ current_parameter_name?(:x) and
605
+ (x.nil? || x.to_s == 'default' || (x.is_a?(Array) && x.first.to_s == 'default'))
528
606
  end
529
607
 
530
608
  def default_y?
531
- current_parameter_name?('y') && (y.nil? || y.to_s == 'default')
609
+ current_parameter_name?(:y) and
610
+ (y.nil? || y.to_s == 'default' || (y.is_a?(Array) && y.first.to_s == 'default'))
611
+ end
612
+
613
+ def default_width?
614
+ return false unless current_parameter_name?(:width)
615
+ width = self.width
616
+ (width.nil? || width == :default || width == 'default' || (width.is_a?(Array) && (width.first.to_s == :default || width.first.to_s == 'default')))
617
+ end
618
+
619
+ def default_height?
620
+ return false unless current_parameter_name?(:height)
621
+ height = self.height
622
+ (height.nil? || height == :default || height == 'default' || (height.is_a?(Array) && (height.first.to_s == :default || height.first.to_s == 'default')))
532
623
  end
533
624
 
534
625
  def default_x
535
- if respond_to?(:width) && width && parent.respond_to?(:width) && parent.width
536
- (parent.width - width) / 2
537
- else
538
- 0
539
- end
626
+ result = ((parent.size.x - size.x) / 2)
627
+ result += parent.bounds.x - parent.absolute_x if parent.is_a?(Shape)
628
+ result
540
629
  end
541
630
 
542
631
  def default_y
543
- if respond_to?(:height) && height && parent.respond_to?(:height) && parent.height
544
- (parent.height - height) / 2
545
- else
546
- 0
632
+ result = ((parent.size.y - size.y) / 2)
633
+ result += parent.bounds.y - parent.absolute_y if parent.is_a?(Shape)
634
+ result
635
+ end
636
+
637
+ def default_width
638
+ x_start_end_pairs = shapes.map do |shape|
639
+ shape_x = shape.default_x? ? 0 : shape.x.to_f
640
+ shape_width = shape.calculated_width.to_f
641
+ [shape_x, shape_x + shape_width]
547
642
  end
643
+ min_x = x_start_end_pairs.map(&:first).min.to_f
644
+ max_x = x_start_end_pairs.map(&:last).max.to_f
645
+ max_x - min_x
646
+ end
647
+
648
+ def default_height
649
+ y_start_end_pairs = shapes.map do |shape|
650
+ shape_y = shape.default_y? ? 0 : shape.y.to_f
651
+ shape_height = shape.calculated_height.to_f
652
+ [shape_y, shape_y + shape_height]
653
+ end
654
+ min_y = y_start_end_pairs.map(&:first).min.to_f
655
+ max_y = y_start_end_pairs.map(&:last).max.to_f
656
+ max_y - min_y
657
+ end
658
+
659
+ def calculated_width
660
+ default_width? ? default_width : width
661
+ end
662
+
663
+ def calculated_height
664
+ default_height? ? default_height : height
665
+ end
666
+
667
+ def default_x_delta
668
+ return 0 unless default_x? && x.is_a?(Array)
669
+ x[1].to_f
670
+ end
671
+
672
+ def default_y_delta
673
+ return 0 unless default_y? && y.is_a?(Array)
674
+ y[1].to_f
675
+ end
676
+
677
+ def default_width_delta
678
+ return 0 unless default_width? && width.is_a?(Array)
679
+ width[1].to_f
680
+ end
681
+
682
+ def default_height_delta
683
+ return 0 unless default_height? && height.is_a?(Array)
684
+ height[1].to_f
685
+ end
686
+
687
+ def default_x_delta=(delta)
688
+ return unless default_x?
689
+ self.x = [:default, delta]
690
+ end
691
+
692
+ def default_y_delta=(delta)
693
+ return unless default_y?
694
+ self.y = [:default, delta]
695
+ end
696
+
697
+ def default_width_delta=(delta)
698
+ return unless default_width?
699
+ self.width = [:default, delta]
700
+ end
701
+
702
+ def default_height_delta=(delta)
703
+ return unless default_height?
704
+ self.height = [:default, delta]
705
+ end
706
+
707
+ def calculated_x
708
+ result = default_x? ? default_x : self.x
709
+ result += default_x_delta
710
+ result
711
+ end
712
+
713
+ def calculated_y
714
+ result = default_y? ? default_y : self.y
715
+ result += default_y_delta
716
+ result
548
717
  end
549
718
 
550
719
  def absolute_x
551
- x = default_x? ? default_x : self.x
552
- x += @x_delta
720
+ x = calculated_x
553
721
  if parent.is_a?(Shape)
554
722
  parent.absolute_x + x
555
723
  else
@@ -558,8 +726,7 @@ module Glimmer
558
726
  end
559
727
 
560
728
  def absolute_y
561
- y = default_y? ? default_y : self.y
562
- y += @y_delta
729
+ y = calculated_y
563
730
  if parent.is_a?(Shape)
564
731
  parent.absolute_y + y
565
732
  else
@@ -567,6 +734,13 @@ module Glimmer
567
734
  end
568
735
  end
569
736
 
737
+ # Overriding inspect to avoid printing very long shape hierarchies
738
+ def inspect
739
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)} args=#{@args.inspect}, properties=#{@properties.inspect}}>"
740
+ rescue => e
741
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)}"
742
+ end
743
+
570
744
  def calculate_paint_args!
571
745
  unless @calculated_paint_args
572
746
  if @name == 'pixel'
@@ -37,10 +37,23 @@ module Glimmer
37
37
  [:x, :y, :width, :height, :start_angle, :arc_angle]
38
38
  end
39
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
+
40
54
  # checks if shape contains the point denoted by x and y
41
55
  def contain?(x, y)
42
- shape_geometry = java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, width, height, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
43
- shape_geometry.contains(x, y)
56
+ geometry.contains(x, y)
44
57
  end
45
58
 
46
59
  def include?(x, y)
@@ -48,8 +61,8 @@ module Glimmer
48
61
  contain?(x, y)
49
62
  else
50
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)
51
- outer_shape_geometry = java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, width + 3, height + 3, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
52
- inner_shape_geometry = java.awt.geom.Arc2D::Double.new(self.absolute_x, self.absolute_y, width - 3, height - 3, start_angle, arc_angle, java.awt.geom.Arc2D::PIE)
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)
53
66
  outer_shape_geometry.contains(x, y) && !inner_shape_geometry.contains(x, y)
54
67
  end
55
68
  end
@@ -80,17 +80,17 @@ module Glimmer
80
80
 
81
81
  def default_x?
82
82
  super ||
83
- current_parameter_name?('dest_x') && (dest_x.nil? || dest_x.to_s == 'default')
83
+ current_parameter_name?(:dest_x) && (dest_x.nil? || dest_x.to_s == 'default')
84
84
  end
85
85
 
86
86
  def default_y?
87
87
  super ||
88
- current_parameter_name?('dest_y') && (dest_y.nil? || dest_y.to_s == 'default')
88
+ current_parameter_name?(:dest_y) && (dest_y.nil? || dest_y.to_s == 'default')
89
89
  end
90
90
 
91
91
  def move_by(x_delta, y_delta)
92
92
  if default_x?
93
- self.x_delta += x_delta
93
+ self.default_x_delta += x_delta
94
94
  elsif dest_x
95
95
  self.dest_x += x_delta
96
96
  else
@@ -98,7 +98,7 @@ module Glimmer
98
98
  end
99
99
 
100
100
  if default_y?
101
- self.y_delta += y_delta
101
+ self.default_y_delta += y_delta
102
102
  elsif dest_y
103
103
  self.dest_y += y_delta
104
104
  else
@@ -50,14 +50,40 @@ module Glimmer
50
50
  parameter_names
51
51
  end
52
52
 
53
- # Logical x coordinate. Always assumes the first point in the line to be the x coordinate.
53
+ def bounds
54
+ shape_bounds = geometry.getBounds2D
55
+ org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
56
+ end
57
+
58
+ def size
59
+ shape_bounds = geometry.getBounds2D
60
+ org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
61
+ end
62
+
63
+ def geometry
64
+ java.awt.geom.Line2D::Double.new(absolute_x1, absolute_y1, absolute_x2, absolute_y2)
65
+ end
66
+
67
+ # Logical x coordinate relative to parent
54
68
  def x
55
- x1
69
+ x_value = bounds.x
70
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
71
+ x_value
56
72
  end
57
73
 
58
- # Logical y coordinate. Always assumes the first point in the line to be the y coordinate.
74
+ # Logical y coordinate relative to parent
59
75
  def y
60
- y1
76
+ y_value = bounds.y
77
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
78
+ y_value
79
+ end
80
+
81
+ def width
82
+ bounds.width
83
+ end
84
+
85
+ def height
86
+ bounds.height
61
87
  end
62
88
 
63
89
  def absolute_x1
@@ -39,7 +39,7 @@ module Glimmer
39
39
 
40
40
  # checks if shape contains the point denoted by x and y
41
41
  def contain?(x, y)
42
- shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x, self.absolute_y, width, height)
42
+ shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x, self.absolute_y, calculated_width, calculated_height)
43
43
  shape_geometry.contains(x, y)
44
44
  end
45
45
 
@@ -49,8 +49,8 @@ module Glimmer
49
49
  contain?(x, y)
50
50
  else
51
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, width + 6, height + 6)
53
- inner_shape_geometry = java.awt.geom.Ellipse2D::Double.new(self.absolute_x + 3, self.absolute_y + 3, width - 6, height - 6)
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
54
  outer_shape_geometry.contains(x, y) && !inner_shape_geometry.contains(x, y)
55
55
  end
56
56
  end
@@ -37,6 +37,14 @@ module Glimmer
37
37
  [:x, :y]
38
38
  end
39
39
 
40
+ def width
41
+ 1
42
+ end
43
+
44
+ def height
45
+ 1
46
+ end
47
+
40
48
  def include?(x, y)
41
49
  # give it some fuzz (helps makes mouse clicking easier)
42
50
  x.to_i.between?(self.absolute_x.to_i - 2, self.absolute_x.to_i + 2) && y.to_i.between?(self.absolute_y.to_i - 2, self.absolute_y.to_i + 2)
@@ -62,16 +62,6 @@ module Glimmer
62
62
  x_array.zip(y_array)
63
63
  end
64
64
 
65
- # Logical x coordinate. Always assumes the first point in the polygon to be the x coordinate.
66
- def x
67
- x_array.first
68
- end
69
-
70
- # Logical y coordinate. Always assumes the first point in the polygon to be the y coordinate.
71
- def y
72
- y_array.first
73
- end
74
-
75
65
  def absolute_point_array
76
66
  if parent.is_a?(Shape)
77
67
  point_array.each_with_index.map do |coordinate, i|
@@ -98,9 +88,59 @@ module Glimmer
98
88
  absolute_x_array.zip(absolute_y_array)
99
89
  end
100
90
 
91
+ def bounds
92
+ the_point_array = point_array
93
+ if the_point_array != @bounds_point_array
94
+ @bounds_point_array = point_array
95
+ shape_bounds = geometry.getBounds2D
96
+ @bounds = org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
97
+ end
98
+ @bounds
99
+ end
100
+
101
+ def size
102
+ the_point_array = point_array
103
+ if the_point_array != @size_point_array
104
+ @size_point_array = point_array
105
+ shape_bounds = geometry.getBounds2D
106
+ @size = org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
107
+ end
108
+ @size
109
+ end
110
+
111
+ def geometry
112
+ the_point_array = point_array
113
+ if the_point_array != @geometry_point_array
114
+ @geometry_point_array = point_array
115
+ @geometry = java.awt.Polygon.new(absolute_x_array.to_java(:int), absolute_y_array.to_java(:int), point_count)
116
+ end
117
+ @geometry
118
+ end
119
+
120
+ # Logical x coordinate relative to parent
121
+ def x
122
+ x_value = bounds.x
123
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
124
+ x_value
125
+ end
126
+
127
+ # Logical y coordinate relative to parent
128
+ def y
129
+ y_value = bounds.y
130
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
131
+ y_value
132
+ end
133
+
134
+ def width
135
+ bounds.width
136
+ end
137
+
138
+ def height
139
+ bounds.height
140
+ end
141
+
101
142
  def include?(x, y)
102
- shape_geometry = java.awt.Polygon.new(absolute_x_array.to_java(:int), absolute_y_array.to_java(:int), point_count)
103
- shape_geometry.contains(x, y)
143
+ geometry.contains(x, y)
104
144
  end
105
145
  alias contain? include? # TODO make include do an outer/inner check of edge detection only
106
146
 
@@ -62,16 +62,6 @@ module Glimmer
62
62
  x_array.zip(y_array)
63
63
  end
64
64
 
65
- # Logical x coordinate. Always assumes the first point in the polyline to be the x coordinate.
66
- def x
67
- x_array.first
68
- end
69
-
70
- # Logical y coordinate. Always assumes the first point in the polyline to be the y coordinate.
71
- def y
72
- y_array.first
73
- end
74
-
75
65
  def absolute_point_array
76
66
  if parent.is_a?(Shape)
77
67
  point_array.each_with_index.map do |coordinate, i|
@@ -98,6 +88,42 @@ module Glimmer
98
88
  absolute_x_array.zip(absolute_y_array)
99
89
  end
100
90
 
91
+ def bounds
92
+ shape_bounds = geometry.getBounds2D
93
+ org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
94
+ end
95
+
96
+ def size
97
+ shape_bounds = geometry.getBounds2D
98
+ org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
99
+ end
100
+
101
+ def geometry
102
+ java.awt.Polygon.new(absolute_x_array.to_java(:int), absolute_y_array.to_java(:int), point_count)
103
+ end
104
+
105
+ # Logical x coordinate relative to parent
106
+ def x
107
+ x_value = bounds.x
108
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
109
+ x_value
110
+ end
111
+
112
+ # Logical y coordinate relative to parent
113
+ def y
114
+ y_value = bounds.y
115
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
116
+ y_value
117
+ end
118
+
119
+ def width
120
+ bounds.width
121
+ end
122
+
123
+ def height
124
+ bounds.height
125
+ end
126
+
101
127
  def include?(x, y)
102
128
  comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
103
129
  comparison_lines.pop # ignore last pair since you don't want to compare last point with first point
@@ -34,6 +34,7 @@ module Glimmer
34
34
  class Shape
35
35
  class Rectangle < Shape
36
36
  def parameter_names
37
+ # TODO consider optimizing just like text where it is set upon updating attribute and here you just return a variable
37
38
  if @args.to_a.size >= 6
38
39
  rectangle_round_parameter_names
39
40
  elsif @args.to_a.size == 5
@@ -81,11 +82,11 @@ module Glimmer
81
82
  end
82
83
 
83
84
  def point_xy_array
84
- [[x, y], [x + width, y], [x + width, y + height], [x, y + height]]
85
+ [[x, y], [x + calculated_width, y], [x + calculated_width, y + calculated_height], [x, y + calculated_height]]
85
86
  end
86
87
 
87
88
  def absolute_point_xy_array
88
- [[absolute_x, absolute_y], [absolute_x + width, absolute_y], [absolute_x + width, absolute_y + height], [absolute_x, absolute_y + height]]
89
+ [[absolute_x, absolute_y], [absolute_x + calculated_width, absolute_y], [absolute_x + calculated_width, absolute_y + calculated_height], [absolute_x, absolute_y + calculated_height]]
89
90
  end
90
91
 
91
92
  # 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)
@@ -33,8 +33,6 @@ module Glimmer
33
33
  # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
34
34
  class Shape
35
35
  class Text < Shape
36
- attr_accessor :extent
37
-
38
36
  def parameter_names
39
37
  @parameter_names || text_parameter_names
40
38
  end
@@ -69,11 +67,11 @@ module Glimmer
69
67
  end
70
68
 
71
69
  def width
72
- extent&.x
70
+ @extent&.x
73
71
  end
74
72
 
75
73
  def height
76
- extent&.y
74
+ @extent&.y
77
75
  end
78
76
 
79
77
  end
@@ -25,9 +25,20 @@ class HelloCanvas
25
25
  include Glimmer::UI::CustomShell
26
26
 
27
27
  attr_accessor :selected_shape
28
+ attr_accessor :artist
28
29
 
29
30
  before_body {
30
31
  @image_object = image(File.expand_path('../../icons/scaffold_app.png', __dir__), width: 50)
32
+ @artist = ''
33
+ }
34
+
35
+ after_body {
36
+ Thread.new {
37
+ 'Picasso'.chars.each do |character|
38
+ sleep(1)
39
+ self.artist += character
40
+ end
41
+ }
31
42
  }
32
43
 
33
44
  body {
@@ -38,10 +49,36 @@ class HelloCanvas
38
49
  @canvas = canvas {
39
50
  background :yellow
40
51
  rectangle(0, 0, 220, 400) {
41
- background :red
52
+ background rgb(255, 0, 0)
42
53
  }
43
54
  rectangle(50, 20, 300, 150, 30, 50) {
44
55
  background :magenta
56
+ rectangle([:default, -70], :default, :default, [:default, 1]) {
57
+ foreground :cyan
58
+ text {
59
+ x :default, 1
60
+ # y is assumed to be the default (centered within parent)
61
+ string bind(self, :artist)
62
+ background :yellow
63
+ foreground :dark_magenta
64
+ font name: 'Courier', height: 30
65
+ }
66
+ }
67
+ rectangle(155, 30) { # width and height are assumed to be the default (calculated from children)
68
+ foreground :yellow
69
+ 3.times { |n|
70
+ line(45, 70 + n*10, 65 + n*10, 30 + n*10) {
71
+ foreground :yellow
72
+ }
73
+ }
74
+ 10.times {|n|
75
+ point(15 + n*5, 50 + n*5) {
76
+ foreground :yellow
77
+ }
78
+ }
79
+ polyline(45, 60, 55, 20, 65, 60, 85, 80, 45, 60)
80
+ image(@image_object, 0, 5)
81
+ }
45
82
  }
46
83
  rectangle(150, 200, 100, 70, true) {
47
84
  background :dark_magenta
@@ -51,26 +88,6 @@ class HelloCanvas
51
88
  background :magenta
52
89
  foreground :dark_blue
53
90
  }
54
- rectangle(205, 50, 88, 96) {
55
- foreground :yellow
56
- 3.times { |n|
57
- line(45, 70 + n*10, 65 + n*10, 30 + n*10) {
58
- foreground :yellow
59
- }
60
- }
61
- 10.times {|n|
62
- point(15 + n*5, 50 + n*5) {
63
- foreground :yellow
64
- }
65
- }
66
- polyline(45, 60, 55, 20, 65, 60, 85, 80, 45, 60)
67
- image(@image_object, 0, 5)
68
- }
69
- text('Picasso', 60, 80) {
70
- background :yellow
71
- foreground :dark_magenta
72
- font name: 'Courier', height: 30
73
- }
74
91
  oval(110, 310, 100, 100) {
75
92
  # patterns provide a differnet way to make gradients
76
93
  background_pattern 0, 0, 105, 0, :yellow, rgb(128, 138, 248)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.5.3
4
+ version: 4.18.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-25 00:00:00.000000000 Z
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement