glimmer-dsl-opal 0.27.0 → 0.28.3

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +71 -3
  4. data/VERSION +1 -1
  5. data/lib/glimmer/dsl/opal/dsl.rb +3 -0
  6. data/lib/glimmer/dsl/opal/image_expression.rb +64 -0
  7. data/lib/glimmer/dsl/opal/property_expression.rb +1 -2
  8. data/lib/glimmer/dsl/opal/shape_expression.rb +35 -6
  9. data/lib/glimmer/swt/canvas_proxy.rb +27 -0
  10. data/lib/glimmer/swt/composite_proxy.rb +0 -2
  11. data/lib/glimmer/swt/custom/shape/arc.rb +75 -0
  12. data/lib/glimmer/swt/custom/shape/image.rb +98 -0
  13. data/lib/glimmer/swt/custom/shape/line.rb +53 -0
  14. data/lib/glimmer/swt/custom/shape/oval.rb +58 -0
  15. data/lib/glimmer/swt/custom/shape/point.rb +53 -0
  16. data/lib/glimmer/swt/custom/shape/polygon.rb +53 -0
  17. data/lib/glimmer/swt/custom/shape/polyline.rb +53 -0
  18. data/lib/glimmer/swt/custom/shape/rectangle.rb +101 -0
  19. data/lib/glimmer/swt/custom/shape/text.rb +114 -0
  20. data/lib/glimmer/swt/custom/shape.rb +205 -0
  21. data/lib/glimmer/swt/image_proxy.rb +29 -0
  22. data/lib/glimmer/swt/menu_proxy.rb +1 -1
  23. data/lib/glimmer/swt/point.rb +2 -0
  24. data/lib/glimmer/swt/rectangle.rb +7 -0
  25. data/lib/glimmer/swt/widget_proxy.rb +15 -4
  26. data/lib/glimmer-dsl-opal/samples/elaborate/tetris/view/block.rb +44 -0
  27. data/lib/glimmer-dsl-opal/samples/elaborate/tetris.rb +4 -8
  28. data/lib/glimmer-dsl-opal/samples/elaborate/weather.rb +4 -3
  29. data/lib/glimmer-dsl-opal/samples/hello/hello_canvas.rb +106 -0
  30. data/lib/glimmer-dsl-opal/samples/hello/hello_text.rb +1 -1
  31. data/lib/glimmer-dsl-opal/samples/hello/images/scaffold_app.png +0 -0
  32. data/lib/glimmer-dsl-opal/vendor/two.min.js +24 -0
  33. data/lib/glimmer-dsl-opal.rb +1 -0
  34. metadata +19 -2
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2020-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/swt/custom/shape'
23
+ require 'glimmer/swt/swt_proxy'
24
+ require 'glimmer/swt/display_proxy'
25
+ require 'glimmer/swt/color_proxy'
26
+ # require 'glimmer/swt/transform_proxy'
27
+
28
+ module Glimmer
29
+ module SWT
30
+ module Custom
31
+ class Shape
32
+ class Text < Shape
33
+ def parameter_names
34
+ if text_parameter_names.size == @args.size
35
+ @parameter_names = text_parameter_names
36
+ elsif text_transparent_parameter_names.size == @args.size
37
+ @parameter_names = text_transparent_parameter_names
38
+ elsif text_flags_parameter_names.size == @args.size
39
+ @parameter_names = text_flags_parameter_names
40
+ end
41
+ @parameter_names || text_parameter_names
42
+ end
43
+
44
+ def possible_parameter_names
45
+ # TODO refactor and improve this method through meta-programming (and share across other shapes)
46
+ (text_parameter_names + text_transparent_parameter_names + text_flags_parameter_names).uniq
47
+ end
48
+
49
+ def text_parameter_names
50
+ [:string, :x, :y]
51
+ end
52
+
53
+ def text_transparent_parameter_names
54
+ [:string, :x, :y, :is_transparent]
55
+ end
56
+
57
+ def text_flags_parameter_names
58
+ [:string, :x, :y, :flags]
59
+ end
60
+
61
+ def set_parameter_attribute(attribute_name, *args)
62
+ if @parameter_names.to_a.map(&:to_s).include?(attribute_name.to_s)
63
+ super(attribute_name, *args)
64
+ build_dom
65
+ reattach(dom_element)
66
+ return
67
+ end
68
+ if text_parameter_names.map(&:to_s).include?(attribute_name.to_s)
69
+ @parameter_names = text_parameter_names
70
+ elsif text_transparent_parameter_names.map(&:to_s).include?(attribute_name.to_s)
71
+ @parameter_names = text_transparent_parameter_names
72
+ elsif text_flags_parameter_names.map(&:to_s).include?(attribute_name.to_s)
73
+ @parameter_names = text_flags_parameter_names
74
+ end
75
+ super(attribute_name, *args)
76
+ end
77
+
78
+ def reattach(old_element)
79
+ old_element.attr('x', Element[@dom].attr('x'))
80
+ old_element.attr('y', Element[@dom].attr('y'))
81
+ old_element.text(Element[@dom].html)
82
+ end
83
+
84
+ def background=(value)
85
+ # TODO override background= to fill a rectangle containing text, matching its size
86
+ # For now, disable background when foreground is not set
87
+ super(value) unless foreground.nil?
88
+ end
89
+
90
+ def foreground=(value)
91
+ super(value)
92
+ self.background = value
93
+ end
94
+
95
+ def element
96
+ 'text'
97
+ end
98
+
99
+ def dom
100
+ shape_id = id
101
+ shape_class = name
102
+ @dom ||= xml {
103
+ tag(:_name => 'text', id: shape_id, class: shape_class, x: @args[1], y: @args[2]) {
104
+ @args[0]
105
+ }
106
+ }.to_s
107
+ end
108
+
109
+ end
110
+ String = Text
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,205 @@
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/swt/property_owner'
23
+ require 'glimmer/swt/swt_proxy'
24
+ require 'glimmer/swt/display_proxy'
25
+ require 'glimmer/swt/color_proxy'
26
+ require 'glimmer/swt/font_proxy'
27
+ # require 'glimmer/swt/transform_proxy'
28
+ require 'glimmer/swt/point'
29
+ require 'glimmer/swt/rectangle'
30
+
31
+ module Glimmer
32
+ module SWT
33
+ module Custom
34
+ # Represents a shape (graphics) to be drawn on a control/widget/canvas/display
35
+ # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
36
+ class Shape < WidgetProxy
37
+ include PropertyOwner
38
+
39
+ class << self
40
+ def create(parent, keyword, args, &property_block)
41
+ potential_shape_class_name = keyword.to_s.camelcase(:upper).to_sym
42
+ if constants.include?(potential_shape_class_name)
43
+ const_get(potential_shape_class_name).new(parent, args, &property_block)
44
+ else
45
+ new(parent, args, &property_block)
46
+ end
47
+ end
48
+
49
+ def valid?(parent, keyword, args, &block)
50
+ return true if keyword.to_s == 'shape'
51
+ keywords.include?(keyword.to_s)
52
+ end
53
+
54
+ def keywords
55
+ constants.select do |constant|
56
+ constant_value = const_get(constant)
57
+ constant_value.respond_to?(:ancestors) && constant_value.ancestors.include?(Glimmer::SWT::Custom::Shape)
58
+ end.map {|constant| constant.to_s.underscore}
59
+ end
60
+
61
+ end
62
+
63
+ def background=(value)
64
+ value = ColorProxy.new(value) if value.is_a?(String) || value.is_a?(Symbol)
65
+ @background = value
66
+ dom_element.css('fill', background.to_css) unless background.nil?
67
+ end
68
+
69
+ def foreground=(value)
70
+ value = ColorProxy.new(value) if value.is_a?(String) || value.is_a?(Symbol)
71
+ @foreground = value
72
+ dom_element.css('stroke', foreground.to_css) unless foreground.nil?
73
+ dom_element.css('fill', 'transparent') if background.nil?
74
+ end
75
+
76
+ def post_add_content
77
+ # TODO avoid rendering unless args changed from initialize args (due to setting of piecemeal attributes)
78
+ render
79
+ end
80
+
81
+ def render(custom_parent_dom_element: nil, brand_new: false)
82
+ super(custom_parent_dom_element: nil, brand_new: false)
83
+ self.background = background
84
+ self.foreground = foreground
85
+ self.font = font
86
+ end
87
+
88
+ # parameter names for arguments to pass to SWT GC.xyz method for rendering shape (e.g. draw_image(image, x, y) yields :image, :x, :y parameter names)
89
+ def parameter_names
90
+ [:x, :y, :width, :height]
91
+ end
92
+
93
+ # subclasses may override to specify location parameter names if different from x and y (e.g. all polygon points are location parameters)
94
+ # used in calculating movement changes
95
+ def location_parameter_names
96
+ [:x, :y]
97
+ end
98
+
99
+ def possible_parameter_names
100
+ parameter_names
101
+ end
102
+
103
+ def parameter_name?(attribute_name)
104
+ possible_parameter_names.map(&:to_s).include?(attribute_getter(attribute_name))
105
+ end
106
+
107
+ def current_parameter_name?(attribute_name)
108
+ parameter_names.include?(attribute_name.to_s.to_sym)
109
+ end
110
+
111
+ def parameter_index(attribute_name)
112
+ parameter_names.index(attribute_name.to_s.to_sym)
113
+ end
114
+
115
+ def get_parameter_attribute(attribute_name)
116
+ @args[parameter_index(attribute_getter(attribute_name))]
117
+ end
118
+
119
+ def set_parameter_attribute(attribute_name, *args)
120
+ @args[parameter_index(attribute_getter(attribute_name))] = args.size == 1 ? args.first : args
121
+ end
122
+
123
+ def has_attribute?(attribute_name, *args)
124
+ parameter_name?(attribute_name) or
125
+ (respond_to?(attribute_name, super: true) and respond_to?(attribute_setter(attribute_name), super: true))
126
+ end
127
+
128
+ def set_attribute(attribute_name, *args)
129
+ attribute_getter_name = attribute_getter(attribute_name)
130
+ attribute_setter_name = attribute_setter(attribute_name)
131
+ if parameter_name?(attribute_name)
132
+ return if attribute_getter_name == (args.size == 1 ? args.first : args)
133
+ set_parameter_attribute(attribute_getter_name, *args)
134
+ elsif (respond_to?(attribute_name, super: true) and respond_to?(attribute_setter_name, super: true))
135
+ return if self.send(attribute_getter_name) == (args.size == 1 ? args.first : args)
136
+ self.send(attribute_setter_name, *args)
137
+ end
138
+ end
139
+
140
+ def get_attribute(attribute_name)
141
+ if parameter_name?(attribute_name)
142
+ arg_index = parameter_index(attribute_name)
143
+ @args[arg_index] if arg_index
144
+ elsif (respond_to?(attribute_name, super: true) and respond_to?(attribute_setter(attribute_name), super: true))
145
+ self.send(attribute_name)
146
+ end
147
+ end
148
+
149
+ # TODO look why image is not working with the method_missing and respond_to? on shape
150
+ def method_missing(method_name, *args, &block)
151
+ if method_name.to_s.end_with?('=')
152
+ set_attribute(method_name, *args)
153
+ elsif has_attribute?(method_name) && args.empty?
154
+ get_attribute(method_name)
155
+ else # TODO support proxying calls to handle_observation_request for listeners just like WidgetProxy
156
+ super(method_name, *args, &block)
157
+ end
158
+ end
159
+
160
+ def respond_to?(method_name, *args, &block)
161
+ options = args.last if args.last.is_a?(Hash)
162
+ super_invocation = options && options[:super]
163
+ if !super_invocation && has_attribute?(method_name)
164
+ true
165
+ else
166
+ super(method_name, *args, &block)
167
+ end
168
+ end
169
+
170
+ def attach(the_parent_dom_element)
171
+ the_parent_dom_element.html("#{the_parent_dom_element.html()}\n#{@dom}")
172
+ end
173
+
174
+ def element
175
+ 'g'
176
+ end
177
+
178
+ def dom
179
+ shape_id = id
180
+ shape_class = name
181
+ @dom ||= xml {
182
+ g(id: shape_id, class: shape_class) {
183
+ }
184
+ }.to_s
185
+ end
186
+
187
+ # TODO implement shape_at_location potentially with document.elementFromPoint(x, y);
188
+
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+
195
+ end
196
+
197
+ require 'glimmer/swt/custom/shape/arc'
198
+ require 'glimmer/swt/custom/shape/image'
199
+ require 'glimmer/swt/custom/shape/line'
200
+ require 'glimmer/swt/custom/shape/oval'
201
+ require 'glimmer/swt/custom/shape/point'
202
+ require 'glimmer/swt/custom/shape/polygon'
203
+ require 'glimmer/swt/custom/shape/polyline'
204
+ require 'glimmer/swt/custom/shape/rectangle'
205
+ require 'glimmer/swt/custom/shape/text'
@@ -0,0 +1,29 @@
1
+ module Glimmer
2
+ module SWT
3
+ # emulating org.eclipse.swt.graphics.Image
4
+ class ImageProxy
5
+ class << self
6
+ def create(*args, &content)
7
+ if args.size == 1 && args.first.is_a?(ImageProxy)
8
+ args.first
9
+ else
10
+ new(*args, &content)
11
+ end
12
+ end
13
+ end
14
+
15
+ attr_reader :file_path, :width, :height
16
+
17
+ def initialize(*args)
18
+ options = args.last.is_a?(Hash) ? args.last : {}
19
+ # TODO support a parent as a first argument before the file path
20
+ @file_path = args.first
21
+ @width = options[:width]
22
+ @height = options[:height]
23
+ end
24
+
25
+ # TODO implement scale_to
26
+ end
27
+ # TODO alias as org.eclipse.swt.graphics.Image
28
+ end
29
+ end
@@ -198,6 +198,7 @@ module Glimmer
198
198
  # delay this till all children rendered (perhaps post_add_content block)
199
199
  parent_dom_element.css('position', 'relative')
200
200
  parent_dom_element.css('margin-top', '30px')
201
+ parent_dom_element.css('height', '114%')
201
202
  redraw
202
203
  `$(#{path}).menu({
203
204
  position: { my: "top", at: "bottom" },
@@ -222,7 +223,6 @@ module Glimmer
222
223
  @visible = value
223
224
  if @visible
224
225
  parent.menu_requested = true
225
- parent.dom_element.css('position', 'relative')
226
226
  render
227
227
  dom_element.css('position', 'absolute')
228
228
  dom_element.css('left', parent.menu_x - parent.dom_element.offset.left)
@@ -1,5 +1,7 @@
1
1
  module Glimmer
2
2
  module SWT
3
+ # emulating org.eclipse.swt.graphics.Point
3
4
  Point = Struct.new(:x, :y)
5
+ # TODO alias as org.eclipse.swt.graphics.Point
4
6
  end
5
7
  end
@@ -0,0 +1,7 @@
1
+ module Glimmer
2
+ module SWT
3
+ # emulating org.eclipse.swt.graphics.Rectangle
4
+ Rectangle = Struct.new(:x, :y, :width, :height)
5
+ # TODO alias as org.eclipse.swt.graphics.Rectangle
6
+ end
7
+ end
@@ -30,7 +30,7 @@ module Glimmer
30
30
  class WidgetProxy
31
31
  include Glimmer
32
32
  include PropertyOwner
33
-
33
+
34
34
  Event = Struct.new(:widget, keyword_init: true)
35
35
 
36
36
  JS_KEY_CODE_TO_SWT_KEY_CODE_MAP = {
@@ -295,6 +295,7 @@ module Glimmer
295
295
  end
296
296
 
297
297
  def font=(value)
298
+ return if value.nil?
298
299
  @font = value.is_a?(FontProxy) ? value : FontProxy.new(self, value)
299
300
  dom_element.css('font-family', @font.name) unless @font.nil?
300
301
  dom_element.css('font-style', 'italic') if @font&.style == :italic || [@font&.style].flatten.compact.include?(:italic)
@@ -331,9 +332,10 @@ module Glimmer
331
332
  brand_new = @dom.nil? || old_element.empty? || brand_new
332
333
  build_dom(layout: !custom_parent_dom_element) # TODO handle custom parent layout by passing parent instead of parent dom element
333
334
  if brand_new
334
- the_parent_dom_element.append(@dom) # TODO make a method attach to allow subclasses to override if needed
335
+ # TODO make a method attach to allow subclasses to override if needed
336
+ attach(the_parent_dom_element)
335
337
  else
336
- old_element.replace_with(@dom)
338
+ reattach(old_element)
337
339
  end
338
340
  observation_requests&.each do |keyword, event_listener_set|
339
341
  event_listener_set.each do |event_listener|
@@ -347,6 +349,14 @@ module Glimmer
347
349
  content_on_render_blocks.each { |content_block| content(&content_block) } unless skip_content_on_render_blocks?
348
350
  end
349
351
  alias redraw render
352
+
353
+ def attach(the_parent_dom_element)
354
+ the_parent_dom_element.append(@dom)
355
+ end
356
+
357
+ def reattach(old_element)
358
+ old_element.replace_with(@dom)
359
+ end
350
360
 
351
361
  def content_on_render_blocks
352
362
  @content_on_render_blocks ||= []
@@ -367,7 +377,7 @@ module Glimmer
367
377
  def build_dom(layout: true)
368
378
  # TODO consider passing parent element instead and having table item include a table cell widget only for opal
369
379
  @dom = nil
370
- @dom = dom
380
+ @dom = dom # TODO unify how to build dom for most widgets based on element, id, and name (class)
371
381
  @dom = @parent.get_layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.get_layout
372
382
  @dom
373
383
  end
@@ -1143,6 +1153,7 @@ require 'glimmer/swt/combo_proxy'
1143
1153
  require 'glimmer/swt/c_combo_proxy'
1144
1154
  require 'glimmer/swt/checkbox_proxy'
1145
1155
  require 'glimmer/swt/composite_proxy'
1156
+ require 'glimmer/swt/canvas_proxy'
1146
1157
  require 'glimmer/swt/date_time_proxy'
1147
1158
  require 'glimmer/swt/group_proxy'
1148
1159
  require 'glimmer/swt/label_proxy'
@@ -25,10 +25,54 @@ class Tetris
25
25
  include Glimmer::UI::CustomWidget
26
26
 
27
27
  options :game_playfield, :block_size, :row, :column
28
+
29
+ attr_accessor :bevel_pixel_size
30
+
31
+ before_body do
32
+ self.bevel_pixel_size = 0.16*block_size.to_f
33
+ end
28
34
 
29
35
  body {
30
36
  canvas { |canvas_proxy|
31
37
  background <= [game_playfield[row][column], :color]
38
+ polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
39
+ background <= [game_playfield[row][column], :color, on_read: ->(color_value) {
40
+ unless color_value.nil?
41
+ color = color(color_value)
42
+ rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
43
+ end
44
+ }]
45
+ }
46
+ polygon(block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size, block_size) {
47
+ background <= [game_playfield[row][column], :color, on_read: ->(color_value) {
48
+ unless color_value.nil?
49
+ color = color(color_value)
50
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
51
+ end
52
+ }]
53
+ }
54
+ polygon(block_size, block_size, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size) {
55
+ background <= [game_playfield[row][column], :color, on_read: ->(color_value) {
56
+ unless color_value.nil?
57
+ color = color(color_value)
58
+ rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
59
+ end
60
+ }]
61
+ }
62
+ polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
63
+ background <= [game_playfield[row][column], :color, on_read: ->(color_value) {
64
+ unless color_value.nil?
65
+ color = color(color_value)
66
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
67
+ end
68
+ }]
69
+ }
70
+ rectangle(0, 0, block_size, block_size) {
71
+ foreground <= [game_playfield[row][column], :color, on_read: ->(color_value) {
72
+ color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
73
+ }]
74
+ }
75
+
32
76
  }
33
77
  }
34
78
  end