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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +15 -12
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +205 -24
  6. data/docs/reference/GLIMMER_SAMPLES.md +8 -0
  7. data/glimmer-dsl-swt.gemspec +8 -3
  8. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  9. data/lib/glimmer/swt/custom/drawable.rb +10 -2
  10. data/lib/glimmer/swt/custom/shape.rb +449 -54
  11. data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
  12. data/lib/glimmer/swt/custom/shape/cubic.rb +108 -0
  13. data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
  14. data/lib/glimmer/swt/custom/shape/image.rb +35 -9
  15. data/lib/glimmer/swt/custom/shape/line.rb +121 -4
  16. data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
  17. data/lib/glimmer/swt/custom/shape/path.rb +197 -0
  18. data/lib/glimmer/swt/custom/shape/path_segment.rb +86 -0
  19. data/lib/glimmer/swt/custom/shape/point.rb +42 -4
  20. data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
  21. data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
  22. data/lib/glimmer/swt/custom/shape/quad.rb +104 -0
  23. data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
  24. data/lib/glimmer/swt/custom/shape/text.rb +13 -3
  25. data/lib/glimmer/swt/dialog_proxy.rb +4 -0
  26. data/lib/glimmer/swt/proxy_properties.rb +1 -1
  27. data/lib/glimmer/swt/transform_proxy.rb +20 -4
  28. data/lib/glimmer/swt/widget_proxy.rb +17 -1
  29. data/samples/elaborate/contact_manager.rb +2 -0
  30. data/samples/elaborate/login.rb +2 -0
  31. data/samples/elaborate/mandelbrot_fractal.rb +2 -1
  32. data/samples/elaborate/meta_sample.rb +1 -0
  33. data/samples/elaborate/tetris.rb +2 -1
  34. data/samples/elaborate/tic_tac_toe.rb +2 -0
  35. data/samples/elaborate/user_profile.rb +10 -8
  36. data/samples/hello/hello_browser.rb +2 -0
  37. data/samples/hello/hello_button.rb +2 -0
  38. data/samples/hello/hello_canvas.rb +40 -23
  39. data/samples/hello/hello_canvas_animation.rb +2 -0
  40. data/samples/hello/hello_canvas_path.rb +223 -0
  41. data/samples/hello/hello_canvas_transform.rb +2 -0
  42. data/samples/hello/hello_checkbox.rb +2 -0
  43. data/samples/hello/hello_checkbox_group.rb +2 -0
  44. data/samples/hello/hello_code_text.rb +2 -0
  45. data/samples/hello/hello_color_dialog.rb +2 -0
  46. data/samples/hello/hello_combo.rb +2 -0
  47. data/samples/hello/hello_computed.rb +2 -0
  48. data/samples/hello/hello_cursor.rb +2 -0
  49. data/samples/hello/hello_custom_shell.rb +1 -0
  50. data/samples/hello/hello_custom_widget.rb +2 -0
  51. data/samples/hello/hello_date_time.rb +2 -0
  52. data/samples/hello/hello_dialog.rb +2 -0
  53. data/samples/hello/hello_directory_dialog.rb +2 -0
  54. data/samples/hello/hello_drag_and_drop.rb +5 -3
  55. data/samples/hello/hello_expand_bar.rb +2 -0
  56. data/samples/hello/hello_file_dialog.rb +2 -0
  57. data/samples/hello/hello_font_dialog.rb +2 -0
  58. data/samples/hello/hello_group.rb +2 -0
  59. data/samples/hello/hello_link.rb +2 -0
  60. data/samples/hello/hello_list_multi_selection.rb +2 -0
  61. data/samples/hello/hello_list_single_selection.rb +2 -0
  62. data/samples/hello/hello_menu_bar.rb +2 -0
  63. data/samples/hello/hello_message_box.rb +2 -0
  64. data/samples/hello/hello_pop_up_context_menu.rb +2 -0
  65. data/samples/hello/hello_progress_bar.rb +2 -0
  66. data/samples/hello/hello_radio.rb +2 -0
  67. data/samples/hello/hello_radio_group.rb +2 -0
  68. data/samples/hello/hello_sash_form.rb +2 -0
  69. data/samples/hello/hello_spinner.rb +2 -0
  70. data/samples/hello/hello_styled_text.rb +19 -17
  71. data/samples/hello/hello_tab.rb +2 -0
  72. data/samples/hello/hello_table.rb +2 -0
  73. data/samples/hello/hello_world.rb +2 -0
  74. metadata +7 -2
@@ -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
@@ -80,6 +81,24 @@ module Glimmer
80
81
  end
81
82
  end
82
83
 
84
+ def point_xy_array
85
+ [[x, y], [x + calculated_width, y], [x + calculated_width, y + calculated_height], [x, y + calculated_height]]
86
+ end
87
+
88
+ def absolute_point_xy_array
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]]
90
+ end
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)
93
+ def include?(x, y)
94
+ if filled?
95
+ contain?(x, y)
96
+ else
97
+ comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
98
+ comparison_lines.any? {|line| Line.include?(line.first.first, line.first.last, line.last.first, line.last.last, x, y)}
99
+ end
100
+ end
101
+
83
102
  end
84
103
  end
85
104
  end
@@ -43,15 +43,15 @@ module Glimmer
43
43
  end
44
44
 
45
45
  def text_parameter_names
46
- [:text, :x, :y]
46
+ [:string, :x, :y]
47
47
  end
48
48
 
49
49
  def text_transparent_parameter_names
50
- [:text, :x, :y, :is_transparent]
50
+ [:string, :x, :y, :is_transparent]
51
51
  end
52
52
 
53
53
  def text_flags_parameter_names
54
- [:text, :x, :y, :flags]
54
+ [:string, :x, :y, :flags]
55
55
  end
56
56
 
57
57
  def set_parameter_attribute(attribute_name, *args)
@@ -66,7 +66,17 @@ module Glimmer
66
66
  super
67
67
  end
68
68
 
69
+ def width
70
+ @extent&.x
71
+ end
72
+
73
+ def height
74
+ @extent&.y
75
+ end
76
+
69
77
  end
78
+
79
+ String = Text
70
80
  end
71
81
  end
72
82
  end
@@ -52,6 +52,10 @@ module Glimmer
52
52
  def dialog_class(keyword)
53
53
  the_class = eval(keyword.camelcase(:upper))
54
54
  the_class if the_class.ancestors.include?(org.eclipse.swt.widgets.Dialog)
55
+ rescue => e
56
+ Glimmer::Config.logger.debug {"Dialog for keyword #{keyword} not found!"}
57
+ Glimmer::Config.logger.debug { e.full_message }
58
+ nil
55
59
  end
56
60
  end
57
61
 
@@ -73,7 +73,7 @@ module Glimmer
73
73
  Glimmer::SWT::DisplayProxy.instance.auto_exec do
74
74
  result = if proxy_source_object&.respond_to?(attribute_setter(attribute_name))
75
75
  swt_widget_operation = true
76
- proxy_source_object&.send(attribute_setter(attribute_name), *args) unless proxy_source_object&.send(attribute_getter(attribute_name)) == args.first
76
+ proxy_source_object&.send(attribute_setter(attribute_name), *args) unless (proxy_source_object&.respond_to?(attribute_getter(attribute_name)) && proxy_source_object&.send(attribute_getter(attribute_name))) == args.first
77
77
  elsif proxy_source_object&.respond_to?(ruby_attribute_setter(attribute_name))
78
78
  swt_widget_operation = true
79
79
  proxy_source_object&.send(ruby_attribute_setter(attribute_name), args)
@@ -20,7 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/swt/display_proxy'
23
- require 'glimmer/swt/properties'
23
+ require 'glimmer/swt/proxy_properties'
24
24
  require 'glimmer/swt/custom/shape'
25
25
 
26
26
  module Glimmer
@@ -29,7 +29,7 @@ module Glimmer
29
29
  #
30
30
  # Follows the Proxy Design Pattern
31
31
  class TransformProxy
32
- include Properties
32
+ include ProxyProperties
33
33
 
34
34
  include_package 'org.eclipse.swt.graphics'
35
35
  include_package 'org.eclipse.swt.widgets'
@@ -80,12 +80,28 @@ module Glimmer
80
80
  @swt_transform
81
81
  end
82
82
 
83
+ def has_attribute?(attribute_name, *args)
84
+ Glimmer::SWT::DisplayProxy.instance.auto_exec { @swt_transform.respond_to?(attribute_name) } || super
85
+ end
86
+
87
+ def set_attribute(attribute_name, *args)
88
+ if @swt_transform.respond_to?(attribute_name)
89
+ Glimmer::SWT::DisplayProxy.instance.auto_exec { @swt_transform.send(attribute_name, *args) }
90
+ else
91
+ super
92
+ end
93
+ end
94
+
83
95
  def method_missing(method_name, *args, &block)
84
96
  result = Glimmer::SWT::DisplayProxy.instance.auto_exec { @swt_transform.send(method_name, *args, &block) }
85
97
  result.nil? ? self : result
86
98
  rescue => e
87
- Glimmer::Config.logger.debug {"Neither MessageBoxProxy nor #{@swt_transform.class.name} can handle the method ##{method}"}
88
- super
99
+ begin
100
+ super
101
+ rescue Exception => inner_e
102
+ Glimmer::Config.logger.error {"Neither TransformProxy nor #{@swt_transform.class.name} can handle the method ##{method}"}
103
+ Glimmer::Config.logger.error {e.full_message}
104
+ end
89
105
  end
90
106
 
91
107
  def respond_to?(method, *args, &block)
@@ -50,7 +50,7 @@ module Glimmer
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],
@@ -291,6 +291,22 @@ module Glimmer
291
291
  @swt_widget.removeControlListener(listener.swt_listener)
292
292
  end
293
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
306
+
307
+ def height
308
+ bounds.height
309
+ end
294
310
 
295
311
  # these work in tandem with the property_type_converters
296
312
  # sometimes, they are specified in subclasses instead
@@ -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
 
@@ -378,7 +379,7 @@ class MandelbrotFractal
378
379
  image @mandelbrot_image
379
380
  }
380
381
  @canvas.set_size @mandelbrot_image.bounds.width, @mandelbrot_image.bounds.height
381
- @scrolled_composite.swt_widget.set_min_size(Point.new(@mandelbrot_image.bounds.width, @mandelbrot_image.bounds.height))
382
+ @scrolled_composite.set_min_size(Point.new(@mandelbrot_image.bounds.width, @mandelbrot_image.bounds.height))
382
383
  if @location_x && @location_y
383
384
  # center on mouse click location
384
385
  factor = (zoom / last_zoom)
@@ -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,13 +19,26 @@
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 HelloCanvas
23
25
  include Glimmer::UI::CustomShell
24
26
 
25
27
  attr_accessor :selected_shape
28
+ attr_accessor :artist
26
29
 
27
30
  before_body {
28
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
+ }
29
42
  }
30
43
 
31
44
  body {
@@ -36,12 +49,36 @@ class HelloCanvas
36
49
  @canvas = canvas {
37
50
  background :yellow
38
51
  rectangle(0, 0, 220, 400) {
39
- transform {
40
- }
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
+ 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
+ }
45
82
  }
46
83
  rectangle(150, 200, 100, 70, true) {
47
84
  background :dark_magenta
@@ -51,14 +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
- }
57
- text('Picasso', 60, 80) {
58
- background :yellow
59
- foreground :dark_magenta
60
- font name: 'Courier', height: 30
61
- }
62
91
  oval(110, 310, 100, 100) {
63
92
  # patterns provide a differnet way to make gradients
64
93
  background_pattern 0, 0, 105, 0, :yellow, rgb(128, 138, 248)
@@ -69,18 +98,6 @@ class HelloCanvas
69
98
  polygon(250, 210, 260, 170, 270, 210, 290, 230) {
70
99
  background :dark_yellow
71
100
  }
72
- polyline(250, 110, 260, 70, 270, 110, 290, 130, 250, 110)
73
- 3.times { |n|
74
- line(250, 120 + n*10, 270 + n*10, 80 + n*10) {
75
- foreground :yellow
76
- }
77
- }
78
- 10.times {|n|
79
- point(220 + n*5, 100 + n*5) {
80
- foreground :yellow
81
- }
82
- }
83
- image(@image_object, 205, 55)
84
101
 
85
102
  menu {
86
103
  menu_item {
@@ -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 {
@@ -0,0 +1,223 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-swt'
23
+
24
+ # This Sample is an Early Alpha (New Canvas Path DSL Feature)
25
+
26
+ class HelloCanvasPath
27
+ class Stock
28
+ class << self
29
+ attr_writer :stock_price_min, :stock_price_max
30
+
31
+ def stock_price_min
32
+ @stock_price_min ||= 1
33
+ end
34
+
35
+ def stock_price_max
36
+ @stock_price_max ||= 600
37
+ end
38
+ end
39
+
40
+ attr_reader :name, :stock_prices
41
+ attr_accessor :stock_price
42
+
43
+ def initialize(name, stock_price)
44
+ @name = name
45
+ @stock_price = stock_price
46
+ @stock_prices = [@stock_price]
47
+ @delta_sign = 1
48
+ start_new_trend!
49
+ end
50
+
51
+ def tick!
52
+ @tick_count = @tick_count.to_i + 1
53
+ delta = @tick_count%@trend_length
54
+ if delta == 0
55
+ @delta_sign *= -1
56
+ start_new_trend!
57
+ end
58
+ stock_prices << self.stock_price = [[@stock_price + @delta_sign*delta, Stock.stock_price_min].max, Stock.stock_price_max].min
59
+ end
60
+
61
+ def start_new_trend!
62
+ @trend_length = (rand*25).to_i + 1
63
+ end
64
+ end
65
+
66
+ include Glimmer::UI::CustomShell
67
+
68
+ before_body {
69
+ @stocks = [
70
+ Stock.new('AAPL', 121),
71
+ Stock.new('MSFT', 232),
72
+ ]
73
+ @stock_colors = [:red, :dark_green, :blue, :magenta]
74
+ max_stock_name_width = 0
75
+ left_margin = 5
76
+ @tabs = ['Cubic Bezier Curves', 'Quadratic Bezier Curves', 'Lines', 'Points'].map {|title| {title: title, paths: [], transforms: []}}
77
+ @stocks.each_with_index do |stock, i|
78
+ x = 0
79
+ observe(stock, :stock_price) do |new_price|
80
+ begin
81
+ @tabs.each do |tab|
82
+ new_x = x
83
+ new_y = @tabs.first[:canvas].bounds.height - new_price - 1
84
+ max_stock_name_width = tab[:text]&.bounds&.width if tab[:text]&.bounds&.width.to_f > max_stock_name_width
85
+ if new_x > 0
86
+ case tab[:title]
87
+ when 'Cubic Bezier Curves'
88
+ if stock.stock_prices[i] && stock.stock_prices[i - 1] && stock.stock_prices[i - 2]
89
+ tab[:paths][i].content {
90
+ cubic(new_x - 2, @tabs.first[:canvas].bounds.height - stock.stock_prices[i - 2] - 1, new_x - 1, @tabs.first[:canvas].bounds.height - stock.stock_prices[i - 1] - 1, new_x, new_y)
91
+ tab[:transforms][i] ||= transform {
92
+ translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0
93
+ }
94
+ }
95
+ end
96
+ when 'Quadratic Bezier Curves'
97
+ if stock.stock_prices[i] && stock.stock_prices[i - 1]
98
+ tab[:paths][i].content {
99
+ quad(new_x - 1, @tabs.first[:canvas].bounds.height - stock.stock_prices[i - 1] - 1, new_x, new_y)
100
+ tab[:transforms][i] ||= transform {
101
+ translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0
102
+ }
103
+ }
104
+ end
105
+ when 'Lines'
106
+ tab[:paths][i].content {
107
+ line(new_x, new_y)
108
+ tab[:transforms][i] ||= transform {
109
+ translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0
110
+ }
111
+ }
112
+ when 'Points'
113
+ tab[:paths][i].content {
114
+ point(new_x, new_y)
115
+ tab[:transforms][i] ||= transform {
116
+ translate max_stock_name_width + 5 + left_margin, tab[:text].bounds.height / 2.0
117
+ }
118
+ }
119
+ end
120
+ new_x_location = new_x + max_stock_name_width + 5 + left_margin + 5
121
+ canvas_width = tab[:canvas].bounds.width
122
+ if new_x_location > canvas_width
123
+ tab[:canvas].set_size(new_x_location, @tabs.first[:canvas].bounds.height)
124
+ tab[:canvas].cursor = :hand
125
+ tab[:scrolled_composite].set_min_size(new_x_location, @tabs.first[:canvas].bounds.height)
126
+ tab[:scrolled_composite].set_origin(tab[:scrolled_composite].origin.x + 1, tab[:scrolled_composite].origin.y) if (tab[:scrolled_composite].origin.x + tab[:scrolled_composite].client_area.width) == canvas_width
127
+ end
128
+ else
129
+ tab[:canvas].content {
130
+ tab[:text] = text(stock.name, new_x + left_margin, new_y) {
131
+ foreground @stock_colors[i]
132
+ }
133
+ }
134
+ end
135
+ end
136
+ x += 1
137
+ rescue => e
138
+ Glimmer::Config.logger.error {e.full_message}
139
+ end
140
+ end
141
+ end
142
+ }
143
+
144
+ after_body {
145
+ @thread = Thread.new {
146
+ loop {
147
+ @stocks.each(&:tick!)
148
+ sleep(0.01)
149
+ }
150
+ }
151
+ }
152
+
153
+ body {
154
+ shell {
155
+ fill_layout {
156
+ margin_width 15
157
+ margin_height 15
158
+ }
159
+ text 'Hello, Canvas Path!'
160
+ minimum_size 650, 650
161
+ background :white
162
+
163
+ tab_folder {
164
+ @tabs.each do |tab|
165
+ tab_item {
166
+ fill_layout {
167
+ margin_width 0
168
+ margin_height 0
169
+ }
170
+ text tab[:title]
171
+
172
+ tab[:scrolled_composite] = scrolled_composite {
173
+ tab[:canvas] = canvas {
174
+ background :white
175
+
176
+ @stocks.count.times do |n|
177
+ tab[:paths][n] = path {
178
+ foreground @stock_colors[n]
179
+ }
180
+ end
181
+
182
+ on_mouse_down {
183
+ @drag_detected = false
184
+ }
185
+
186
+ on_drag_detected { |drag_detect_event|
187
+ @drag_detected = true
188
+ @drag_start_x = drag_detect_event.x
189
+ @drag_start_y = drag_detect_event.y
190
+ }
191
+
192
+ on_mouse_move { |mouse_event|
193
+ if @drag_detected
194
+ origin = tab[:scrolled_composite].origin
195
+ new_x = origin.x - (mouse_event.x - @drag_start_x)
196
+ new_y = origin.y - (mouse_event.y - @drag_start_y)
197
+ tab[:scrolled_composite].set_origin(new_x, new_y)
198
+ end
199
+ }
200
+
201
+ on_mouse_up { |mouse_event|
202
+ @drag_detected = false
203
+ }
204
+ }
205
+ }
206
+ }
207
+ end
208
+ }
209
+
210
+ on_swt_show {
211
+ Stock.stock_price_min = 25
212
+ Stock.stock_price_max = @tabs.first[:canvas].bounds.height - 6
213
+ }
214
+
215
+ on_widget_disposed {
216
+ @thread.kill # safe to kill as memory is in data only
217
+ }
218
+ }
219
+ }
220
+ end
221
+
222
+ HelloCanvasPath.launch
223
+