glimmer-dsl-swt 4.18.5.0 → 4.18.5.5

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +16 -11
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +179 -33
  6. data/docs/reference/GLIMMER_SAMPLES.md +58 -0
  7. data/glimmer-dsl-swt.gemspec +7 -7
  8. data/lib/glimmer/data_binding/widget_binding.rb +4 -1
  9. data/lib/glimmer/dsl/swt/dialog_expression.rb +18 -9
  10. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  11. data/lib/glimmer/dsl/swt/font_expression.rb +1 -1
  12. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  13. data/lib/glimmer/dsl/swt/shell_expression.rb +1 -1
  14. data/lib/glimmer/swt/custom/drawable.rb +10 -2
  15. data/lib/glimmer/swt/custom/shape.rb +458 -58
  16. data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
  17. data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
  18. data/lib/glimmer/swt/custom/shape/image.rb +35 -9
  19. data/lib/glimmer/swt/custom/shape/line.rb +88 -4
  20. data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
  21. data/lib/glimmer/swt/custom/shape/point.rb +10 -5
  22. data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
  23. data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
  24. data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
  25. data/lib/glimmer/swt/custom/shape/text.rb +13 -3
  26. data/lib/glimmer/swt/{directory_dialog_proxy.rb → dialog_proxy.rb} +36 -7
  27. data/lib/glimmer/swt/font_proxy.rb +12 -6
  28. data/lib/glimmer/swt/message_box_proxy.rb +1 -0
  29. data/lib/glimmer/swt/properties.rb +3 -0
  30. data/lib/glimmer/swt/proxy_properties.rb +145 -0
  31. data/lib/glimmer/swt/transform_proxy.rb +39 -35
  32. data/lib/glimmer/swt/widget_proxy.rb +32 -60
  33. data/samples/elaborate/contact_manager.rb +2 -0
  34. data/samples/elaborate/login.rb +2 -0
  35. data/samples/elaborate/mandelbrot_fractal.rb +1 -0
  36. data/samples/elaborate/meta_sample.rb +1 -0
  37. data/samples/elaborate/tetris.rb +2 -1
  38. data/samples/elaborate/tic_tac_toe.rb +2 -0
  39. data/samples/elaborate/user_profile.rb +10 -8
  40. data/samples/hello/hello_browser.rb +2 -0
  41. data/samples/hello/hello_button.rb +2 -0
  42. data/samples/hello/hello_canvas.rb +157 -77
  43. data/samples/hello/hello_canvas_animation.rb +2 -0
  44. data/samples/hello/hello_canvas_transform.rb +2 -0
  45. data/samples/hello/hello_checkbox.rb +2 -0
  46. data/samples/hello/hello_checkbox_group.rb +2 -0
  47. data/samples/hello/hello_code_text.rb +2 -0
  48. data/{lib/glimmer/dsl/swt/directory_dialog_expression.rb → samples/hello/hello_color_dialog.rb} +44 -24
  49. data/samples/hello/hello_combo.rb +2 -0
  50. data/samples/hello/hello_computed.rb +2 -0
  51. data/samples/hello/hello_cursor.rb +2 -0
  52. data/samples/hello/hello_custom_shell.rb +1 -0
  53. data/samples/hello/hello_custom_widget.rb +2 -0
  54. data/samples/hello/hello_date_time.rb +2 -0
  55. data/samples/hello/hello_dialog.rb +2 -0
  56. data/samples/hello/hello_directory_dialog.rb +2 -0
  57. data/samples/hello/hello_drag_and_drop.rb +5 -3
  58. data/samples/hello/hello_expand_bar.rb +2 -0
  59. data/samples/hello/hello_file_dialog.rb +2 -0
  60. data/samples/hello/hello_font_dialog.rb +84 -0
  61. data/samples/hello/hello_group.rb +2 -0
  62. data/samples/hello/hello_link.rb +2 -0
  63. data/samples/hello/hello_list_multi_selection.rb +2 -0
  64. data/samples/hello/hello_list_single_selection.rb +2 -0
  65. data/samples/hello/hello_menu_bar.rb +2 -0
  66. data/samples/hello/hello_message_box.rb +2 -0
  67. data/samples/hello/hello_pop_up_context_menu.rb +2 -0
  68. data/samples/hello/hello_progress_bar.rb +2 -0
  69. data/samples/hello/hello_radio.rb +2 -0
  70. data/samples/hello/hello_radio_group.rb +2 -0
  71. data/samples/hello/hello_sash_form.rb +2 -0
  72. data/samples/hello/hello_spinner.rb +2 -0
  73. data/samples/hello/hello_styled_text.rb +19 -17
  74. data/samples/hello/hello_tab.rb +2 -0
  75. data/samples/hello/hello_table.rb +2 -0
  76. data/samples/hello/hello_world.rb +2 -0
  77. metadata +6 -6
  78. data/lib/glimmer/dsl/swt/file_dialog_expression.rb +0 -48
  79. data/lib/glimmer/swt/file_dialog_proxy.rb +0 -68
@@ -26,7 +26,7 @@ require 'glimmer/swt/swt_proxy'
26
26
  require 'glimmer/swt/display_proxy'
27
27
  require 'glimmer/swt/dnd_proxy'
28
28
  require 'glimmer/swt/image_proxy'
29
- require 'glimmer/swt/properties'
29
+ require 'glimmer/swt/proxy_properties'
30
30
  require 'glimmer/swt/custom/drawable'
31
31
 
32
32
  # TODO refactor to make file smaller and extract sub-widget-proxies out of this
@@ -44,13 +44,13 @@ module Glimmer
44
44
  # Follows the Proxy Design Pattern
45
45
  class WidgetProxy
46
46
  include Packages
47
- include Properties
47
+ include ProxyProperties
48
48
  include Custom::Drawable
49
49
 
50
50
  DEFAULT_STYLES = {
51
51
  'arrow' => [:arrow],
52
52
  'button' => [:push],
53
- 'canvas' => ([:double_buffered] if OS.windows?),
53
+ 'canvas' => ([:double_buffered] unless OS.mac?),
54
54
  'checkbox' => [:check],
55
55
  'check' => [:check],
56
56
  'drag_source' => [:drop_copy],
@@ -223,23 +223,11 @@ module Glimmer
223
223
  [args, extra_options]
224
224
  end
225
225
  end
226
-
227
- def has_attribute_getter?(attribute_getter_name, *args)
228
- attribute_getter_name = attribute_getter_name.to_s.underscore
229
- return false unless !attribute_getter_name.end_with?('=') && !attribute_getter_name.start_with?('set_')
230
- auto_exec do
231
- args.empty? && swt_widget.respond_to?(attribute_getter_name)
232
- end
233
- end
234
226
 
235
- def has_attribute_setter?(attribute_setter_name, *args)
236
- attribute_setter_name = attribute_setter_name.to_s
237
- underscored_attribute_setter_name = attribute_setter_name.underscore
238
- return false unless attribute_setter_name.end_with?('=') || (attribute_setter_name.start_with?('set_') && !args.empty?)
239
- attribute_name = underscored_attribute_setter_name.sub(/^set_/, '').sub(/=$/, '')
240
- has_attribute?(attribute_name, *args)
227
+ def proxy_source_object
228
+ @swt_widget
241
229
  end
242
-
230
+
243
231
  def has_attribute?(attribute_name, *args)
244
232
  # TODO test that attribute getter responds too
245
233
  widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
@@ -247,7 +235,7 @@ module Glimmer
247
235
  if widget_custom_attribute
248
236
  @swt_widget.respond_to?(widget_custom_attribute[:setter][:name])
249
237
  else
250
- @swt_widget.respond_to?(attribute_setter(attribute_name), args) || respond_to?(ruby_attribute_setter(attribute_name), args)
238
+ super
251
239
  end
252
240
  end
253
241
  end
@@ -264,17 +252,9 @@ module Glimmer
264
252
  result = if widget_custom_attribute
265
253
  swt_widget_operation = true
266
254
  widget_custom_attribute[:setter][:invoker].call(@swt_widget, args)
267
- elsif @swt_widget.respond_to?(attribute_setter(attribute_name))
268
- swt_widget_operation = true
269
- @swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
270
- elsif @swt_widget.respond_to?(ruby_attribute_setter(attribute_name))
271
- swt_widget_operation = true
272
- @swt_widget.send(ruby_attribute_setter(attribute_name), args)
273
255
  end
274
256
  end
275
- unless swt_widget_operation
276
- result = send(ruby_attribute_setter(attribute_name), args)
277
- end
257
+ result = super unless swt_widget_operation
278
258
  result
279
259
  end
280
260
 
@@ -290,24 +270,9 @@ module Glimmer
290
270
  else
291
271
  @swt_widget.send(widget_custom_attribute[:getter][:name])
292
272
  end
293
- elsif @swt_widget.respond_to?(attribute_getter(attribute_name))
294
- swt_widget_operation = true
295
- @swt_widget.send(attribute_getter(attribute_name))
296
- elsif @swt_widget.respond_to?(ruby_attribute_getter(attribute_name))
297
- swt_widget_operation = true
298
- @swt_widget.send(ruby_attribute_getter(attribute_name))
299
- elsif @swt_widget.respond_to?(attribute_name)
300
- swt_widget_operation = true
301
- @swt_widget.send(attribute_name)
302
- end
303
- end
304
- unless swt_widget_operation
305
- result = if respond_to?(ruby_attribute_getter(attribute_name))
306
- send(ruby_attribute_getter(attribute_name))
307
- else
308
- send(attribute_name)
309
273
  end
310
274
  end
275
+ result = super unless swt_widget_operation
311
276
  result
312
277
  end
313
278
 
@@ -326,7 +291,25 @@ module Glimmer
326
291
  @swt_widget.removeControlListener(listener.swt_listener)
327
292
  end
328
293
  end
294
+
295
+ def x
296
+ bounds.x
297
+ end
298
+
299
+ def y
300
+ bounds.y
301
+ end
302
+
303
+ def width
304
+ bounds.width
305
+ end
329
306
 
307
+ def height
308
+ bounds.height
309
+ end
310
+
311
+ # these work in tandem with the property_type_converters
312
+ # sometimes, they are specified in subclasses instead
330
313
  def widget_property_listener_installers
331
314
  @swt_widget_property_listener_installers ||= {
332
315
  Java::OrgEclipseSwtWidgets::Control => {
@@ -734,24 +717,11 @@ module Glimmer
734
717
  end
735
718
 
736
719
  def method_missing(method, *args, &block)
720
+ # TODO push most of this logic down to Properties (and perhaps create Listeners module as well)
737
721
  if can_handle_observation_request?(method)
738
722
  handle_observation_request(method, &block)
739
- elsif has_attribute_setter?(method, *args)
740
- set_attribute(method, *args)
741
- elsif has_attribute_getter?(method, *args)
742
- get_attribute(method, *args)
743
723
  else
744
- auto_exec do
745
- swt_widget.send(method, *args, &block)
746
- end
747
- end
748
- rescue => e
749
- begin
750
724
  super
751
- rescue Exception => inner_error
752
- Glimmer::Config.logger.error { "Neither WidgetProxy nor #{swt_widget.class.name} can handle the method ##{method}" }
753
- Glimmer::Config.logger.error { e.full_message }
754
- raise inner_error
755
725
  end
756
726
  end
757
727
 
@@ -759,7 +729,7 @@ module Glimmer
759
729
  result = super
760
730
  return true if result
761
731
  auto_exec do
762
- can_handle_observation_request?(method) || swt_widget.respond_to?(method, *args, &block)
732
+ can_handle_observation_request?(method)
763
733
  end
764
734
  end
765
735
 
@@ -946,6 +916,8 @@ module Glimmer
946
916
  color_converter = lambda do |value|
947
917
  if value.is_a?(Symbol) || value.is_a?(String)
948
918
  ColorProxy.new(value).swt_color
919
+ elsif value.is_a?(RGB)
920
+ ColorProxy.new(value.red, value.green, value.blue).swt_color
949
921
  else
950
922
  value
951
923
  end
@@ -1015,7 +987,7 @@ module Glimmer
1015
987
  foreground: color_converter,
1016
988
  link_foreground: color_converter,
1017
989
  font: lambda do |value|
1018
- if value.is_a?(Hash)
990
+ if value.is_a?(Hash) || value.is_a?(FontData)
1019
991
  font_properties = value
1020
992
  FontProxy.new(self, font_properties).swt_font
1021
993
  else
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  require_relative "contact_manager/contact_manager_presenter"
23
25
 
24
26
  class ContactManager
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  class LoginPresenter
23
25
 
24
26
  attr_accessor :user_name
@@ -19,6 +19,7 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
22
23
  require 'complex'
23
24
  require 'concurrent-ruby'
24
25
 
@@ -19,6 +19,7 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
22
23
  require 'fileutils'
23
24
 
24
25
  class Sample
@@ -19,7 +19,7 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- # Tetris App View Custom Shell (represents `tetris` keyword)
22
+ require 'glimmer-dsl-swt'
23
23
 
24
24
  require_relative 'tetris/model/game'
25
25
 
@@ -28,6 +28,7 @@ require_relative 'tetris/view/score_lane'
28
28
  require_relative 'tetris/view/high_score_dialog'
29
29
  require_relative 'tetris/view/tetris_menu_bar'
30
30
 
31
+ # Tetris App View Custom Shell (represents `tetris` keyword)
31
32
  class Tetris
32
33
  include Glimmer::UI::CustomShell
33
34
 
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  require_relative "tic_tac_toe/board"
23
25
 
24
26
  class TicTacToe
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2021 Andy Maleh
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  include Glimmer
23
25
 
24
26
  shell {
@@ -32,21 +34,21 @@ shell {
32
34
  grid_layout 2, false
33
35
  layout_data :fill, :fill, true, true
34
36
  label {text "First"}; text {text "Bullet"}
35
- label {text "Last"}; text {text "Tooth"}
37
+ label {text "Last"}; text {text "Tooth"}
36
38
  }
37
39
 
38
40
  group {
39
41
  layout_data :fill, :fill, true, true
40
42
  text "Gender"
41
43
  radio {text "Male"; selection true}
42
- radio {text "Female"}
44
+ radio {text "Female"}
43
45
  }
44
46
 
45
47
  group {
46
48
  layout_data :fill, :fill, true, true
47
49
  text "Role"
48
50
  check {text "Student"; selection true}
49
- check {text "Employee"; selection true}
51
+ check {text "Employee"; selection true}
50
52
  }
51
53
 
52
54
  group {
@@ -59,11 +61,11 @@ shell {
59
61
  button {
60
62
  text "save"
61
63
  layout_data :right, :center, true, true
62
- on_widget_selected {
64
+ on_widget_selected {
63
65
  message_box {
64
66
  text 'Profile Saved!'
65
67
  message 'User profile has been saved!'
66
- }.open
68
+ }.open
67
69
  }
68
70
  }
69
71
 
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  include Glimmer
23
25
 
24
26
  shell {
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer-dsl-swt'
23
+
22
24
  class HelloButton
23
25
  include Glimmer::UI::CustomShell
24
26
 
@@ -19,87 +19,167 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- include Glimmer
22
+ require 'glimmer-dsl-swt'
23
23
 
24
- image_object = image(File.expand_path('../../icons/scaffold_app.png', __dir__), width: 50)
25
-
26
- shell {
27
- text 'Hello, Canvas!'
28
- minimum_size 320, 400
29
-
30
- @canvas = canvas {
31
- background :yellow
32
- rectangle(0, 0, 220, 400) {
33
- transform {
34
- }
35
- background :red
36
- }
37
- rectangle(50, 20, 300, 150, 30, 50) {
38
- background :magenta
39
- }
40
- rectangle(150, 200, 100, 70, true) {
41
- background :dark_magenta
42
- foreground :yellow
43
- }
44
- rectangle(50, 200, 30, 70, false) {
45
- background :magenta
46
- foreground :dark_blue
47
- }
48
- rectangle(205, 50, 88, 96) {
49
- foreground :yellow
50
- }
51
- text('Picasso', 60, 80) {
52
- background :yellow
53
- foreground :dark_magenta
54
- font name: 'Courier', height: 30
55
- }
56
- oval(110, 310, 100, 100) {
57
- # patterns provide a differnet way to make gradients
58
- background_pattern 0, 0, 105, 0, :yellow, rgb(128, 138, 248)
59
- }
60
- arc(210, 210, 100, 100, 30, -77) {
61
- background :red
62
- }
63
- polygon(250, 210, 260, 170, 270, 210, 290, 230) {
64
- background :dark_yellow
65
- }
66
- polyline(250, 110, 260, 70, 270, 110, 290, 130, 250, 110)
67
- 3.times { |n|
68
- line(250, 120 + n*10, 270 + n*10, 80 + n*10) {
69
- foreground :yellow
70
- }
71
- }
72
- 10.times {|n|
73
- point(220 + n*5, 100 + n*5) {
74
- foreground :yellow
75
- }
76
- }
77
- image(image_object, 205, 55)
24
+ class HelloCanvas
25
+ include Glimmer::UI::CustomShell
78
26
 
79
- on_mouse_down { |mouse_event|
80
- @drag_detected = false
81
- @canvas.cursor = :hand
82
- @shape_to_move = @canvas.shape_at_location(mouse_event.x, mouse_event.y)
83
- }
84
-
85
- on_drag_detected { |drag_detect_event|
86
- @drag_detected = true
87
- @drag_current_x = drag_detect_event.x
88
- @drag_current_y = drag_detect_event.y
89
- }
90
-
91
- on_mouse_move { |mouse_event|
92
- if @drag_detected
93
- @shape_to_move&.move_by(mouse_event.x - @drag_current_x, mouse_event.y - @drag_current_y)
94
- @drag_current_x = mouse_event.x
95
- @drag_current_y = mouse_event.y
27
+ attr_accessor :selected_shape
28
+ attr_accessor :artist
29
+
30
+ before_body {
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
96
40
  end
97
41
  }
42
+ }
43
+
44
+ body {
45
+ shell {
46
+ text 'Hello, Canvas!'
47
+ minimum_size 320, 400
98
48
 
99
- on_mouse_up { |mouse_event|
100
- @canvas.cursor = :arrow
101
- @drag_detected = false
102
- @shape_to_move = nil
49
+ @canvas = canvas {
50
+ background :yellow
51
+ rectangle(0, 0, 220, 400) {
52
+ background rgb(255, 0, 0)
53
+ }
54
+ rectangle(50, 20, 300, 150, 30, 50) {
55
+ background :magenta
56
+ rectangle([:default, -70], :default, :default, [:default, 1]) {
57
+ foreground :cyan
58
+ text {
59
+ string bind(self, :artist)
60
+ x :default, 1 # add 1 pixel to default x (shape centered within parent horizontally)
61
+ y :default, 1 # add 1 pixel to default y (shape centered within parent vertically)
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
+ }
82
+ }
83
+ rectangle(150, 200, 100, 70, true) {
84
+ background :dark_magenta
85
+ foreground :yellow
86
+ }
87
+ rectangle(50, 200, 30, 70, false) {
88
+ background :magenta
89
+ foreground :dark_blue
90
+ }
91
+ oval(110, 310, 100, 100) {
92
+ # patterns provide a differnet way to make gradients
93
+ background_pattern 0, 0, 105, 0, :yellow, rgb(128, 138, 248)
94
+ }
95
+ arc(210, 210, 100, 100, 30, -77) {
96
+ background :red
97
+ }
98
+ polygon(250, 210, 260, 170, 270, 210, 290, 230) {
99
+ background :dark_yellow
100
+ }
101
+
102
+ menu {
103
+ menu_item {
104
+ text 'Change Background Color...'
105
+ enabled bind(self, :selected_shape) {|shape| shape.respond_to?(:background) && shape.background }
106
+ on_widget_selected {
107
+ @selected_shape&.background = color_dialog.open
108
+ self.selected_shape = nil
109
+ }
110
+ }
111
+ menu_item {
112
+ text 'Change Background Pattern Color 1...'
113
+ enabled bind(self, :selected_shape) {|shape| shape.respond_to?(:background_pattern) && shape.background_pattern }
114
+ on_widget_selected {
115
+ if @selected_shape
116
+ background_pattern_args = @selected_shape.background_pattern_args
117
+ background_pattern_args[5] = color_dialog.open
118
+ @selected_shape.background_pattern = background_pattern_args
119
+ self.selected_shape = nil
120
+ end
121
+ }
122
+ }
123
+ menu_item {
124
+ text 'Change Background Pattern Color 2...'
125
+ enabled bind(self, :selected_shape) {|shape| shape.respond_to?(:background_pattern) && shape.background_pattern }
126
+ on_widget_selected {
127
+ if @selected_shape
128
+ background_pattern_args = @selected_shape.background_pattern_args
129
+ background_pattern_args[6] = color_dialog.open
130
+ @selected_shape.background_pattern = background_pattern_args
131
+ self.selected_shape = nil
132
+ end
133
+ }
134
+ }
135
+ menu_item(:separator)
136
+ menu_item {
137
+ text 'Change Foreground Color...'
138
+ enabled bind(self, :selected_shape) {|shape| shape.respond_to?(:foreground) && shape.foreground }
139
+ on_widget_selected {
140
+ @selected_shape&.foreground = color_dialog.open
141
+ self.selected_shape = nil
142
+ }
143
+ }
144
+ }
145
+
146
+ on_mouse_down { |mouse_event|
147
+ @drag_detected = false
148
+ @canvas.cursor = :hand
149
+ self.selected_shape = @canvas.shape_at_location(mouse_event.x, mouse_event.y)
150
+ }
151
+
152
+ on_drag_detected { |drag_detect_event|
153
+ @drag_detected = true
154
+ @drag_current_x = drag_detect_event.x
155
+ @drag_current_y = drag_detect_event.y
156
+ }
157
+
158
+ on_mouse_move { |mouse_event|
159
+ if @drag_detected
160
+ @selected_shape&.move_by(mouse_event.x - @drag_current_x, mouse_event.y - @drag_current_y)
161
+ @drag_current_x = mouse_event.x
162
+ @drag_current_y = mouse_event.y
163
+ end
164
+ }
165
+
166
+ on_menu_detected { |menu_detect_event|
167
+ @menu_detected = true
168
+ }
169
+
170
+ on_mouse_up { |mouse_event|
171
+ @canvas.cursor = :arrow
172
+ @drag_detected = false
173
+ if @menu_detected
174
+ @menu_detected = nil
175
+ else
176
+ self.selected_shape = nil
177
+ end
178
+ }
179
+ }
103
180
  }
104
181
  }
105
- }.open
182
+ end
183
+
184
+ HelloCanvas.launch
185
+