glimmer-dsl-swt 4.18.6.3 → 4.18.7.0

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.
@@ -84,7 +84,7 @@ module Glimmer
84
84
  end
85
85
 
86
86
  def content(&block)
87
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::DisplayExpression.new, &block)
87
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::DisplayExpression.new, 'display', &block)
88
88
  end
89
89
 
90
90
  # asynchronously executes the block (required from threads other than first GUI thread)
@@ -51,7 +51,7 @@ module Glimmer
51
51
  end
52
52
 
53
53
  def content(&block)
54
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::MessageBoxExpression.new, &block)
54
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::MessageBoxExpression.new, 'message_box', &block)
55
55
  end
56
56
 
57
57
  # TODO refactor the following methods to put in a JavaBean mixin or somethin (perhaps contribute to OSS project too)
@@ -186,7 +186,7 @@ module Glimmer
186
186
  end
187
187
 
188
188
  def content(&block)
189
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShellExpression.new, &block)
189
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShellExpression.new, 'shell', &block)
190
190
  end
191
191
 
192
192
  # (happens as part of `#open`)
@@ -73,7 +73,7 @@ module Glimmer
73
73
  end
74
74
 
75
75
  def content(&block)
76
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::TransformExpression.new, &block)
76
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::TransformExpression.new, 'transform', &block)
77
77
  end
78
78
 
79
79
  def proxy_source_object
@@ -712,7 +712,7 @@ module Glimmer
712
712
 
713
713
  def content(&block)
714
714
  auto_exec do
715
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::WidgetExpression.new, &block)
715
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::WidgetExpression.new, @keyword, &block)
716
716
  end
717
717
  end
718
718
 
@@ -0,0 +1,281 @@
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'
23
+ require 'glimmer/ui'
24
+ require 'glimmer/error'
25
+ require 'glimmer/swt/swt_proxy'
26
+ require 'glimmer/swt/display_proxy'
27
+ require 'glimmer/util/proc_tracker'
28
+ require 'glimmer/data_binding/observer'
29
+ require 'glimmer/data_binding/observable_model'
30
+
31
+ module Glimmer
32
+ module UI
33
+ module CustomShape
34
+ include SuperModule
35
+ include DataBinding::ObservableModel
36
+
37
+ super_module_included do |klass|
38
+ klass.include(Glimmer)
39
+ Glimmer::UI::CustomShape.add_custom_shape_namespaces_for(klass)
40
+ end
41
+
42
+ class << self
43
+ def for(underscored_custom_shape_name)
44
+ unless flyweight_custom_shape_classes.keys.include?(underscored_custom_shape_name)
45
+ begin
46
+ extracted_namespaces = underscored_custom_shape_name.
47
+ to_s.
48
+ split(/__/).map do |namespace|
49
+ namespace.camelcase(:upper)
50
+ end
51
+ custom_shape_namespaces.each do |base|
52
+ extracted_namespaces.reduce(base) do |result, namespace|
53
+ if !result.constants.include?(namespace)
54
+ namespace = result.constants.detect {|c| c.to_s.upcase == namespace.to_s.upcase } || namespace
55
+ end
56
+ begin
57
+ flyweight_custom_shape_classes[underscored_custom_shape_name] = constant = result.const_get(namespace)
58
+ return constant if constant.ancestors.include?(Glimmer::UI::CustomShape)
59
+ flyweight_custom_shape_classes[underscored_custom_shape_name] = constant
60
+ rescue => e
61
+ # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
62
+ flyweight_custom_shape_classes[underscored_custom_shape_name] = result
63
+ end
64
+ end
65
+ end
66
+ raise "#{underscored_custom_shape_name} has no custom shape class!"
67
+ rescue => e
68
+ Glimmer::Config.logger.debug {e.message}
69
+ Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
70
+ flyweight_custom_shape_classes[underscored_custom_shape_name] = nil
71
+ end
72
+ end
73
+ flyweight_custom_shape_classes[underscored_custom_shape_name]
74
+ end
75
+
76
+ # Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.
77
+ def flyweight_custom_shape_classes
78
+ @flyweight_custom_shape_classes ||= {}
79
+ end
80
+
81
+ # Returns keyword to use for this custom shape
82
+ def keyword
83
+ self.name.underscore.gsub('::', '__')
84
+ end
85
+
86
+ # Returns shortcut keyword to use for this custom shape (keyword minus namespace)
87
+ def shortcut_keyword
88
+ self.name.underscore.gsub('::', '__').split('__').last
89
+ end
90
+
91
+ def add_custom_shape_namespaces_for(klass)
92
+ Glimmer::UI::CustomShape.namespaces_for_class(klass).drop(1).each do |namespace|
93
+ Glimmer::UI::CustomShape.custom_shape_namespaces << namespace
94
+ end
95
+ end
96
+
97
+ def namespaces_for_class(m)
98
+ return [m] if m.name.nil?
99
+ namespace_constants = m.name.split(/::/).map(&:to_sym)
100
+ namespace_constants.reduce([Object]) do |output, namespace_constant|
101
+ output += [output.last.const_get(namespace_constant)]
102
+ end[1..-1].uniq.reverse
103
+ end
104
+
105
+ def custom_shape_namespaces
106
+ @custom_shape_namespaces ||= reset_custom_shape_namespaces
107
+ end
108
+
109
+ def reset_custom_shape_namespaces
110
+ @custom_shape_namespaces = Set[Object, Glimmer::UI]
111
+ end
112
+
113
+ # Allows defining convenience option accessors for an array of option names
114
+ # Example: `options :color1, :color2` defines `#color1` and `#color2`
115
+ # where they return the instance values `options[:color1]` and `options[:color2]`
116
+ # respectively.
117
+ # Can be called multiple times to set more options additively.
118
+ # When passed no arguments, it returns list of all option names captured so far
119
+ def options(*new_options)
120
+ new_options = new_options.compact.map(&:to_s).map(&:to_sym)
121
+ if new_options.empty?
122
+ @options ||= {} # maps options to defaults
123
+ else
124
+ new_options = new_options.reduce({}) {|new_options_hash, new_option| new_options_hash.merge(new_option => nil)}
125
+ @options = options.merge(new_options)
126
+ def_option_attr_accessors(new_options)
127
+ end
128
+ end
129
+
130
+ def option(new_option, default: nil)
131
+ new_option = new_option.to_s.to_sym
132
+ new_options = {new_option => default}
133
+ @options = options.merge(new_options)
134
+ def_option_attr_accessors(new_options)
135
+ end
136
+
137
+ def def_option_attr_accessors(new_options)
138
+ new_options.each do |option, default|
139
+ class_eval <<-end_eval, __FILE__, __LINE__
140
+ def #{option}
141
+ options[:#{option}]
142
+ end
143
+ def #{option}=(option_value)
144
+ self.options[:#{option}] = option_value
145
+ end
146
+ end_eval
147
+ end
148
+ end
149
+
150
+ def before_body(&block)
151
+ @before_body_block = block
152
+ end
153
+
154
+ def body(&block)
155
+ @body_block = block
156
+ end
157
+
158
+ def after_body(&block)
159
+ @after_body_block = block
160
+ end
161
+
162
+ # Current custom shapes being rendered. Useful to yoke all observers evaluated during rendering of their custom shapes for automatical disposal on_shape_disposed
163
+ def current_custom_shapes
164
+ @current_custom_shapes ||= []
165
+ end
166
+ end
167
+
168
+ attr_reader :body_root, :args, :parent, :parent_proxy, :options
169
+
170
+ def initialize(parent, *args, options, &content)
171
+ Glimmer::UI::CustomShape.current_custom_shapes << self
172
+ @parent_proxy = @parent = parent
173
+ @parent_proxy = @parent&.get_data('proxy') if @parent.respond_to?(:get_data) && @parent.get_data('proxy')
174
+ @args = args
175
+ options ||= {}
176
+ @options = self.class.options.merge(options)
177
+ @content = Util::ProcTracker.new(content) if content
178
+ execute_hook('before_body')
179
+ body_block = self.class.instance_variable_get("@body_block")
180
+ raise Glimmer::Error, 'Invalid custom shape for having no body! Please define body block!' if body_block.nil?
181
+ @body_root = instance_exec(&body_block)
182
+ raise Glimmer::Error, 'Invalid custom shape for having an empty body! Please fill body block!' if @body_root.nil?
183
+ auto_exec do
184
+ @body_root.set_data('custom_shape', self)
185
+ end
186
+ execute_hook('after_body')
187
+ end
188
+
189
+ # Subclasses may override to perform post initialization work on an added child
190
+ def post_initialize_child(child)
191
+ # No Op by default
192
+ end
193
+
194
+ def observer_registrations
195
+ @observer_registrations ||= []
196
+ end
197
+
198
+ def has_attribute?(attribute_name, *args)
199
+ has_instance_method?(attribute_setter(attribute_name)) ||
200
+ @body_root.has_attribute?(attribute_name, *args)
201
+ end
202
+
203
+ def set_attribute(attribute_name, *args)
204
+ if has_instance_method?(attribute_setter(attribute_name))
205
+ send(attribute_setter(attribute_name), *args)
206
+ else
207
+ @body_root.set_attribute(attribute_name, *args)
208
+ end
209
+ end
210
+
211
+ # This method ensures it has an instance method not coming from Glimmer DSL
212
+ def has_instance_method?(method_name)
213
+ respond_to?(method_name) and
214
+ !body_root&.respond_to?(method_name) and
215
+ (method(method_name) rescue nil) and
216
+ !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
217
+ !method(method_name)&.source_location&.first&.include?('glimmer/swt/custom/shape.rb')
218
+ end
219
+
220
+ def get_attribute(attribute_name)
221
+ if has_instance_method?(attribute_name)
222
+ send(attribute_name)
223
+ else
224
+ @body_root.get_attribute(attribute_name)
225
+ end
226
+ end
227
+
228
+ def attribute_setter(attribute_name)
229
+ "#{attribute_name}="
230
+ end
231
+
232
+ # TODO see if it is worth it to eliminate duplication of async_exec/sync_exec
233
+ # delegation to DisplayProxy, via a module
234
+
235
+ def async_exec(&block)
236
+ SWT::DisplayProxy.instance.async_exec(&block)
237
+ end
238
+
239
+ def sync_exec(&block)
240
+ SWT::DisplayProxy.instance.sync_exec(&block)
241
+ end
242
+
243
+ def timer_exec(delay_in_millis, &block)
244
+ SWT::DisplayProxy.instance.timer_exec(delay_in_millis, &block)
245
+ end
246
+
247
+ # Returns content block if used as an attribute reader (no args)
248
+ # Otherwise, if a block is passed, it adds it as content to this custom shape
249
+ def content(&block)
250
+ if block_given?
251
+ body_root.content(&block)
252
+ else
253
+ @content
254
+ end
255
+ end
256
+
257
+ def method_missing(method, *args, &block)
258
+ # TODO Consider supporting a glimmer error silencing option for methods defined here
259
+ # but fail the glimmer DSL for the right reason to avoid seeing noise in the log output
260
+ body_root.send(method, *args, &block)
261
+ end
262
+
263
+ alias local_respond_to? respond_to?
264
+ def respond_to?(method, *args, &block)
265
+ super or
266
+ body_root.respond_to?(method, *args, &block)
267
+ end
268
+
269
+ private
270
+
271
+ def execute_hook(hook_name)
272
+ hook_block = self.class.instance_variable_get("@#{hook_name}_block")
273
+ return if hook_block.nil?
274
+ temp_method_name = "#{hook_name}_block_#{hook_block.hash.abs}_#{(Time.now.to_f * 1_000_000).to_i}"
275
+ singleton_class.define_method(temp_method_name, &hook_block)
276
+ send(temp_method_name)
277
+ singleton_class.send(:remove_method, temp_method_name)
278
+ end
279
+ end
280
+ end
281
+ end
@@ -53,6 +53,9 @@ class HelloCanvas
53
53
  }
54
54
  rectangle(50, 20, 300, 150, 30, 50) {
55
55
  background :magenta
56
+ rectangle(:default, :default, :max, :max, 30, 50) {
57
+ foreground :yellow
58
+ }
56
59
  rectangle([:default, -70], :default, :default, [:default, 1]) {
57
60
  foreground :cyan
58
61
  text {
@@ -22,7 +22,7 @@
22
22
  require 'glimmer-dsl-swt'
23
23
 
24
24
  class HelloCanvasDataBinding
25
- include Glimmer::GUI::CustomWindow
25
+ include Glimmer::GUI::CustomWindow # alias for Glimmer::UI::CustomShell
26
26
 
27
27
  CANVAS_WIDTH = 300
28
28
  CANVAS_HEIGHT = 300
@@ -0,0 +1,78 @@
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
+ # Creates a class-based custom shape representing the `stick_figure` keyword by convention
25
+ class StickFigure
26
+ include Glimmer::UI::CustomShape
27
+
28
+ options :x, :y, :width, :height
29
+
30
+ before_body {
31
+ @head_width = width*0.2
32
+ @head_height = height*0.2
33
+ @trunk_height = height*0.4
34
+ @extremity_length = height*0.4
35
+ }
36
+
37
+ body {
38
+ shape(x + @head_width/2.0 + @extremity_length, y) {
39
+ oval(0, 0, @head_width, @head_height)
40
+ line(@head_width/2.0, @head_height, @head_width/2.0, @head_height + @trunk_height)
41
+ line(@head_width/2.0, @head_height + @trunk_height, @head_width/2.0 + @extremity_length, @head_height + @trunk_height + @extremity_length)
42
+ line(@head_width/2.0, @head_height + @trunk_height, @head_width/2.0 - @extremity_length, @head_height + @trunk_height + @extremity_length)
43
+ line(@head_width/2.0, @head_height*2, @head_width/2.0 + @extremity_length, @head_height + @trunk_height - @extremity_length)
44
+ line(@head_width/2.0, @head_height*2, @head_width/2.0 - @extremity_length, @head_height + @trunk_height - @extremity_length)
45
+ }
46
+ }
47
+ end
48
+
49
+ class HelloCustomShape
50
+ include Glimmer::UI::CustomShell
51
+
52
+ WIDTH = 220
53
+ HEIGHT = 235
54
+
55
+ body {
56
+ shell {
57
+ text 'Hello, Custom Shape!'
58
+ minimum_size WIDTH, HEIGHT
59
+
60
+ @canvas = canvas {
61
+ background :white
62
+
63
+ 15.times { |n|
64
+ x_location = (rand*WIDTH/2).to_i%WIDTH + (rand*25).to_i
65
+ y_location = (rand*HEIGHT/2).to_i%HEIGHT + (rand*25).to_i
66
+ foreground_color = rgb(rand*255, rand*255, rand*255)
67
+
68
+ stick_figure(x: x_location, y: y_location, width: 50, height: 50) {
69
+ foreground foreground_color
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ end
76
+
77
+ HelloCustomShape.launch
78
+
@@ -0,0 +1,71 @@
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
+ class HelloShape
25
+ include Glimmer::UI::CustomShell
26
+
27
+ body {
28
+ shell {
29
+ text 'Hello, Shape!'
30
+ minimum_size 200, 225
31
+
32
+ @canvas = canvas {
33
+ background :white
34
+
35
+ 15.times { |n|
36
+ x_location = (rand*125).to_i%200 + (rand*25).to_i
37
+ y_location = (rand*125).to_i%200 + (rand*25).to_i
38
+ foreground_color = rgb(rand*255, rand*255, rand*255)
39
+
40
+ stick_figure(x_location, y_location, 50, 50) {
41
+ foreground foreground_color
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ # method-based custom shape using `shape` keyword as a composite shape containing nested shapes
49
+ def stick_figure(x, y, width, height, &block)
50
+ head_width = width*0.2
51
+ head_height = height*0.2
52
+ trunk_height = height*0.4
53
+ extremity_length = height*0.4
54
+
55
+ shape(x + head_width/2.0 + extremity_length, y) {
56
+ # common attributes go here before nested shapes
57
+ block.call # invoking content block (e.g. used from the outside to set foreground)
58
+
59
+ # nested shapes go here
60
+ oval(0, 0, head_width, head_height)
61
+ line(head_width/2.0, head_height, head_width/2.0, head_height + trunk_height)
62
+ line(head_width/2.0, head_height + trunk_height, head_width/2.0 + extremity_length, head_height + trunk_height + extremity_length)
63
+ line(head_width/2.0, head_height + trunk_height, head_width/2.0 - extremity_length, head_height + trunk_height + extremity_length)
64
+ line(head_width/2.0, head_height*2, head_width/2.0 + extremity_length, head_height + trunk_height - extremity_length)
65
+ line(head_width/2.0, head_height*2, head_width/2.0 - extremity_length, head_height + trunk_height - extremity_length)
66
+ }
67
+ end
68
+ end
69
+
70
+ HelloShape.launch
71
+