glimmer-dsl-swt 4.18.5.1 → 4.18.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +15 -12
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +205 -24
- data/docs/reference/GLIMMER_SAMPLES.md +8 -0
- data/glimmer-dsl-swt.gemspec +8 -3
- data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
- data/lib/glimmer/swt/custom/drawable.rb +10 -2
- data/lib/glimmer/swt/custom/shape.rb +449 -54
- data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
- data/lib/glimmer/swt/custom/shape/cubic.rb +108 -0
- data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
- data/lib/glimmer/swt/custom/shape/image.rb +35 -9
- data/lib/glimmer/swt/custom/shape/line.rb +121 -4
- data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
- data/lib/glimmer/swt/custom/shape/path.rb +197 -0
- data/lib/glimmer/swt/custom/shape/path_segment.rb +86 -0
- data/lib/glimmer/swt/custom/shape/point.rb +42 -4
- data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
- data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
- data/lib/glimmer/swt/custom/shape/quad.rb +104 -0
- data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
- data/lib/glimmer/swt/custom/shape/text.rb +13 -3
- data/lib/glimmer/swt/dialog_proxy.rb +4 -0
- data/lib/glimmer/swt/proxy_properties.rb +1 -1
- data/lib/glimmer/swt/transform_proxy.rb +20 -4
- data/lib/glimmer/swt/widget_proxy.rb +17 -1
- data/samples/elaborate/contact_manager.rb +2 -0
- data/samples/elaborate/login.rb +2 -0
- data/samples/elaborate/mandelbrot_fractal.rb +2 -1
- data/samples/elaborate/meta_sample.rb +1 -0
- data/samples/elaborate/tetris.rb +2 -1
- data/samples/elaborate/tic_tac_toe.rb +2 -0
- data/samples/elaborate/user_profile.rb +10 -8
- data/samples/hello/hello_browser.rb +2 -0
- data/samples/hello/hello_button.rb +2 -0
- data/samples/hello/hello_canvas.rb +40 -23
- data/samples/hello/hello_canvas_animation.rb +2 -0
- data/samples/hello/hello_canvas_path.rb +223 -0
- data/samples/hello/hello_canvas_transform.rb +2 -0
- data/samples/hello/hello_checkbox.rb +2 -0
- data/samples/hello/hello_checkbox_group.rb +2 -0
- data/samples/hello/hello_code_text.rb +2 -0
- data/samples/hello/hello_color_dialog.rb +2 -0
- data/samples/hello/hello_combo.rb +2 -0
- data/samples/hello/hello_computed.rb +2 -0
- data/samples/hello/hello_cursor.rb +2 -0
- data/samples/hello/hello_custom_shell.rb +1 -0
- data/samples/hello/hello_custom_widget.rb +2 -0
- data/samples/hello/hello_date_time.rb +2 -0
- data/samples/hello/hello_dialog.rb +2 -0
- data/samples/hello/hello_directory_dialog.rb +2 -0
- data/samples/hello/hello_drag_and_drop.rb +5 -3
- data/samples/hello/hello_expand_bar.rb +2 -0
- data/samples/hello/hello_file_dialog.rb +2 -0
- data/samples/hello/hello_font_dialog.rb +2 -0
- data/samples/hello/hello_group.rb +2 -0
- data/samples/hello/hello_link.rb +2 -0
- data/samples/hello/hello_list_multi_selection.rb +2 -0
- data/samples/hello/hello_list_single_selection.rb +2 -0
- data/samples/hello/hello_menu_bar.rb +2 -0
- data/samples/hello/hello_message_box.rb +2 -0
- data/samples/hello/hello_pop_up_context_menu.rb +2 -0
- data/samples/hello/hello_progress_bar.rb +2 -0
- data/samples/hello/hello_radio.rb +2 -0
- data/samples/hello/hello_radio_group.rb +2 -0
- data/samples/hello/hello_sash_form.rb +2 -0
- data/samples/hello/hello_spinner.rb +2 -0
- data/samples/hello/hello_styled_text.rb +19 -17
- data/samples/hello/hello_tab.rb +2 -0
- data/samples/hello/hello_table.rb +2 -0
- data/samples/hello/hello_world.rb +2 -0
- metadata +7 -2
@@ -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
|
-
[:
|
46
|
+
[:string, :x, :y]
|
47
47
|
end
|
48
48
|
|
49
49
|
def text_transparent_parameter_names
|
50
|
-
[:
|
50
|
+
[:string, :x, :y, :is_transparent]
|
51
51
|
end
|
52
52
|
|
53
53
|
def text_flags_parameter_names
|
54
|
-
[:
|
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/
|
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
|
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
|
-
|
88
|
-
|
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]
|
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
|
data/samples/elaborate/login.rb
CHANGED
@@ -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.
|
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)
|
data/samples/elaborate/tetris.rb
CHANGED
@@ -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
|
-
|
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
|
|
@@ -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,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
|
-
|
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 {
|
@@ -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
|
+
|