glimmer-dsl-swt 4.18.2.1 → 4.18.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +175 -32
  4. data/VERSION +1 -1
  5. data/glimmer-dsl-swt.gemspec +18 -6
  6. data/lib/glimmer/dsl/swt/color_expression.rb +4 -4
  7. data/lib/glimmer/dsl/swt/data_binding_expression.rb +3 -3
  8. data/lib/glimmer/dsl/swt/display_expression.rb +3 -3
  9. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  10. data/lib/glimmer/dsl/swt/multiply_expression.rb +53 -0
  11. data/lib/glimmer/dsl/swt/property_expression.rb +4 -2
  12. data/lib/glimmer/dsl/swt/shape_expression.rb +2 -4
  13. data/lib/glimmer/dsl/swt/transform_expression.rb +55 -0
  14. data/lib/glimmer/dsl/swt/widget_expression.rb +2 -1
  15. data/lib/glimmer/rake_task/scaffold.rb +4 -3
  16. data/lib/glimmer/swt/color_proxy.rb +28 -6
  17. data/lib/glimmer/swt/custom/drawable.rb +8 -0
  18. data/lib/glimmer/swt/custom/shape.rb +66 -26
  19. data/lib/glimmer/swt/display_proxy.rb +1 -1
  20. data/lib/glimmer/swt/layout_data_proxy.rb +3 -3
  21. data/lib/glimmer/swt/shell_proxy.rb +4 -3
  22. data/lib/glimmer/swt/transform_proxy.rb +109 -0
  23. data/lib/glimmer/swt/widget_proxy.rb +34 -25
  24. data/lib/glimmer/ui/custom_shell.rb +15 -2
  25. data/lib/glimmer/ui/custom_widget.rb +44 -31
  26. data/samples/elaborate/meta_sample.rb +21 -0
  27. data/samples/elaborate/tetris.rb +106 -0
  28. data/samples/elaborate/tetris/model/block.rb +48 -0
  29. data/samples/elaborate/tetris/model/game.rb +185 -0
  30. data/samples/elaborate/tetris/model/tetromino.rb +313 -0
  31. data/samples/elaborate/tetris/view/block.rb +70 -0
  32. data/samples/elaborate/tetris/view/game_over_dialog.rb +72 -0
  33. data/samples/elaborate/tetris/view/playfield.rb +56 -0
  34. data/samples/elaborate/tetris/view/score_lane.rb +87 -0
  35. data/samples/hello/hello_canvas_transform.rb +40 -0
  36. metadata +16 -4
@@ -24,6 +24,7 @@ require 'glimmer/swt/swt_proxy'
24
24
  require 'glimmer/swt/display_proxy'
25
25
  require 'glimmer/swt/color_proxy'
26
26
  require 'glimmer/swt/font_proxy'
27
+ require 'glimmer/swt/transform_proxy'
27
28
 
28
29
  module Glimmer
29
30
  module SWT
@@ -32,6 +33,7 @@ module Glimmer
32
33
  # swt_widget returns the parent (e.g. a `canvas` WidgetProxy), equivalent to `parent.swt_widget`
33
34
  # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
34
35
  class Shape
36
+ include Packages
35
37
  include Properties
36
38
  # TODO support textExtent sized shapes nested within text/string
37
39
  # TODO support a Pattern DSL for methods that take Pattern arguments
@@ -42,7 +44,17 @@ module Glimmer
42
44
  end
43
45
 
44
46
  def gc_instance_methods
45
- org.eclipse.swt.graphics.GC.instance_methods.map(&:to_s)
47
+ @gc_instance_methods ||= org.eclipse.swt.graphics.GC.instance_methods.map(&:to_s)
48
+ end
49
+
50
+ def keywords
51
+ @keywords ||= gc_instance_methods.select do |method_name|
52
+ !method_name.end_with?('=') && (method_name.start_with?('draw_') || method_name.start_with?('fill_'))
53
+ end.reject do |method_name|
54
+ gc_instance_methods.include?("#{method_name}=") || gc_instance_methods.include?("set_#{method_name}")
55
+ end.map do |method_name|
56
+ method_name.gsub(/(draw|fill|gradient|round)_/, '')
57
+ end.uniq.compact.to_a
46
58
  end
47
59
 
48
60
  def arg_options(args, extract: false)
@@ -52,11 +64,19 @@ module Glimmer
52
64
  end
53
65
 
54
66
  def method_name(keyword, args)
55
- keyword = keyword.to_s
56
- gradient = 'gradient_' if arg_options(args)[:gradient]
57
- round = 'round_' if arg_options(args)[:round]
58
- gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (arg_options(args)[:fill] || arg_options(args)[:gradient]) ? 'fill_' : 'draw_'
59
- "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword}"
67
+ method_arg_options = arg_options(args)
68
+ unless flyweight_method_names.keys.include?([keyword, method_arg_options])
69
+ keyword = keyword.to_s
70
+ gradient = 'gradient_' if method_arg_options[:gradient]
71
+ round = 'round_' if method_arg_options[:round]
72
+ gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (method_arg_options[:fill] || method_arg_options[:gradient]) ? 'fill_' : 'draw_'
73
+ flyweight_method_names[[keyword, method_arg_options]] = "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword}"
74
+ end
75
+ flyweight_method_names[[keyword, method_arg_options]]
76
+ end
77
+
78
+ def flyweight_method_names
79
+ @flyweight_method_names ||= {}
60
80
  end
61
81
  end
62
82
 
@@ -91,27 +111,12 @@ module Glimmer
91
111
  end
92
112
 
93
113
  def post_add_content
94
- event_handler = lambda do |event|
95
- @properties['background'] = [@parent.background] if fill? && !@properties.keys.map(&:to_s).include?('background')
96
- @properties['foreground'] = [@parent.foreground] if draw? && !@properties.keys.map(&:to_s).include?('foreground')
97
- @properties.each do |property, args|
98
- method_name = attribute_setter(property)
99
- apply_property_arg_conversions(method_name, args)
100
- event.gc.send(method_name, *args)
101
- end
102
- apply_shape_arg_conversions(@method_name, @args)
103
- apply_shape_arg_defaults(@method_name, @args)
104
- tolerate_shape_extra_args(@method_name, @args)
105
- event.gc.send(@method_name, *@args)
106
- end
107
- if parent.respond_to?(:swt_display)
108
- @paint_listener_proxy = @parent.on_swt_paint(&event_handler)
109
- else
110
- @paint_listener_proxy = @parent.on_paint_control(&event_handler)
111
- end
114
+ setup_paint_listener
115
+ @content_added = true
112
116
  end
113
117
 
114
- def apply_property_arg_conversions(method_name, args)
118
+ def apply_property_arg_conversions(method_name, property, args)
119
+ args = args.dup
115
120
  the_java_method = org.eclipse.swt.graphics.GC.java_class.declared_instance_methods.detect {|m| m.name == method_name}
116
121
  if (args.first.is_a?(Symbol) || args.first.is_a?(String))
117
122
  if the_java_method.parameter_types.first == Color.java_class
@@ -130,6 +135,9 @@ module Glimmer
130
135
  if args.first.is_a?(FontProxy)
131
136
  args[0] = args[0].swt_font
132
137
  end
138
+ if args.first.is_a?(TransformProxy)
139
+ args[0] = args[0].swt_transform
140
+ end
133
141
  if ['setBackgroundPattern', 'setForegroundPattern'].include?(method_name.to_s)
134
142
  args.each_with_index do |arg, i|
135
143
  if arg.is_a?(Symbol) || arg.is_a?(String)
@@ -142,6 +150,7 @@ module Glimmer
142
150
  args[0] = org.eclipse.swt.graphics.Pattern.new(*new_args)
143
151
  args[1..-1] = []
144
152
  end
153
+ args
145
154
  end
146
155
 
147
156
  def apply_shape_arg_conversions(method_name, args)
@@ -184,11 +193,42 @@ module Glimmer
184
193
 
185
194
  def set_attribute(attribute_name, *args)
186
195
  @properties[attribute_name] = args
196
+ if @content_added
197
+ @parent.resetup_shape_paint_listeners
198
+ @parent.redraw
199
+ end
187
200
  end
188
-
201
+
189
202
  def get_attribute(attribute_name)
190
203
  @properties.symbolize_keys[attribute_name.to_s.to_sym]
191
204
  end
205
+
206
+ def setup_paint_listener
207
+ if parent.respond_to?(:swt_display)
208
+ @paint_listener_proxy = @parent.on_swt_paint(&method(:paint))
209
+ else
210
+ @paint_listener_proxy = @parent.on_paint_control(&method(:paint))
211
+ end
212
+ end
213
+
214
+ def paint(paint_event)
215
+ @properties['background'] = [@parent.background] if fill? && !@properties.keys.map(&:to_s).include?('background')
216
+ @properties['foreground'] = [@parent.foreground] if draw? && !@properties.keys.map(&:to_s).include?('foreground')
217
+ @properties['font'] = [@parent.font] if draw? && !@properties.keys.map(&:to_s).include?('font')
218
+ @properties['transform'] = [nil] if !@properties.keys.map(&:to_s).include?('transform')
219
+ @properties.each do |property, args|
220
+ method_name = attribute_setter(property)
221
+ converted_args = apply_property_arg_conversions(method_name, property, args)
222
+ paint_event.gc.send(method_name, *converted_args)
223
+ if property == 'transform' && args.first.is_a?(TransformProxy)
224
+ args.first.swt_transform.dispose
225
+ end
226
+ end
227
+ apply_shape_arg_conversions(@method_name, @args)
228
+ apply_shape_arg_defaults(@method_name, @args)
229
+ tolerate_shape_extra_args(@method_name, @args)
230
+ paint_event.gc.send(@method_name, *@args)
231
+ end
192
232
 
193
233
  end
194
234
 
@@ -45,7 +45,7 @@ module Glimmer
45
45
  class << self
46
46
  # Returns singleton instance
47
47
  def instance(*args)
48
- if @instance.nil? || @instance.swt_display.isDisposed
48
+ if @instance.nil? || @instance.swt_display.nil? || @instance.swt_display.isDisposed
49
49
  @instance = new(*args)
50
50
  end
51
51
  @instance
@@ -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
@@ -46,6 +46,7 @@ module Glimmer
46
46
  @swt_widget = swt_widget
47
47
  else
48
48
  if args.first.is_a?(ShellProxy)
49
+ @parent_proxy = args[0]
49
50
  args[0] = args[0].swt_widget
50
51
  end
51
52
  style_args = args.select {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
@@ -78,7 +79,7 @@ module Glimmer
78
79
  end
79
80
 
80
81
  # Centers shell within monitor it is in
81
- def center
82
+ def center_within_display
82
83
  primary_monitor = @display.getPrimaryMonitor()
83
84
  monitor_bounds = primary_monitor.getBounds()
84
85
  shell_bounds = @swt_widget.getBounds()
@@ -101,13 +102,13 @@ module Glimmer
101
102
  else
102
103
  @opened_before = true
103
104
  @swt_widget.pack
104
- center
105
+ center_within_display
105
106
  @swt_widget.open
106
107
  end
107
108
  end
108
109
 
109
110
  def nested?
110
- !parent.nil?
111
+ !swt_widget&.parent.nil?
111
112
  end
112
113
 
113
114
  def hide
@@ -0,0 +1,109 @@
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/display_proxy'
23
+ require 'glimmer/swt/properties'
24
+ require 'glimmer/swt/custom/shape'
25
+
26
+ module Glimmer
27
+ module SWT
28
+ # Proxy for org.eclipse.swt.graphics.Transform
29
+ #
30
+ # Follows the Proxy Design Pattern
31
+ class TransformProxy
32
+ include Properties
33
+
34
+ include_package 'org.eclipse.swt.graphics'
35
+ include_package 'org.eclipse.swt.widgets'
36
+
37
+ attr_reader :swt_transform, :parent
38
+
39
+ def initialize(parent, *args, swt_transform: nil, multiply: false)
40
+ @parent = parent
41
+ @multiply = multiply
42
+ if swt_transform.nil?
43
+ if !args.first.is_a?(Display) && !args.first.is_a?(DisplayProxy)
44
+ args.prepend DisplayProxy.instance.swt_display
45
+ end
46
+ if args.first.is_a?(DisplayProxy)
47
+ args[0] = args[0].swt_display
48
+ end
49
+ if args.last.is_a?(TransformProxy)
50
+ args[-1] = args[-1].swt_transform
51
+ end
52
+ if args.last.nil? || args.last.is_a?(Transform)
53
+ @swt_transform = args.last
54
+ @parent&.set_attribute('transform', self)
55
+ else
56
+ @swt_transform = Transform.new(*args)
57
+ end
58
+ else
59
+ @swt_transform = swt_transform
60
+ end
61
+ end
62
+
63
+ def post_add_content
64
+ if @multiply
65
+ @parent.multiply(@swt_transform)
66
+ else
67
+ @parent&.set_attribute('transform', self)
68
+ end
69
+ end
70
+
71
+ def content(&block)
72
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::TransformExpression.new, &block)
73
+ end
74
+
75
+ def has_attribute?(attribute_name, *args)
76
+ @swt_transform.respond_to?(attribute_name) || @swt_transform.respond_to?(attribute_setter(attribute_name))
77
+ end
78
+
79
+ def set_attribute(attribute_name, *args)
80
+ if @swt_transform.respond_to?(attribute_name)
81
+ @swt_transform.send(attribute_name, *args)
82
+ elsif @swt_transform.respond_to?(attribute_setter(attribute_name))
83
+ @swt_transform.send(attribute_setter(attribute_name), *args)
84
+ end
85
+ end
86
+
87
+ def get_attribute(attribute_name)
88
+ if @swt_transform.respond_to?(attribute_getter(attribute_name))
89
+ @swt_transform.send(attribute_getter(attribute_name))
90
+ else
91
+ @swt_transform.send(attribute_name)
92
+ end
93
+ end
94
+
95
+ def method_missing(method_name, *args, &block)
96
+ result = @swt_transform.send(method_name, *args, &block)
97
+ result.nil? ? self : result
98
+ rescue => e
99
+ Glimmer::Config.logger.debug {"Neither MessageBoxProxy nor #{@swt_transform.class.name} can handle the method ##{method}"}
100
+ super
101
+ end
102
+
103
+ def respond_to?(method, *args, &block)
104
+ super ||
105
+ @swt_transform.respond_to?(method, *args, &block)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -74,12 +74,10 @@ module Glimmer
74
74
 
75
75
  DEFAULT_INITIALIZERS = {
76
76
  composite: lambda do |composite|
77
- if composite.get_layout.nil?
78
- layout = GridLayout.new
79
- layout.marginWidth = 15
80
- layout.marginHeight = 15
81
- composite.layout = layout
82
- end
77
+ composite.layout = GridLayout.new if composite.get_layout.nil?
78
+ end,
79
+ canvas: lambda do |canvas|
80
+ canvas.layout = nil unless canvas.get_layout.nil?
83
81
  end,
84
82
  scrolled_composite: lambda do |scrolled_composite|
85
83
  scrolled_composite.expand_horizontal = true
@@ -160,7 +158,7 @@ module Glimmer
160
158
  underscored_widget_name = self.class.underscored_widget_name(@swt_widget)
161
159
  parent_proxy_class = self.class.widget_proxy_class(self.class.underscored_widget_name(@swt_widget.parent))
162
160
  parent = swt_widget.parent
163
- @parent_proxy = parent.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
161
+ @parent_proxy = parent&.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
164
162
  end
165
163
  if @swt_widget&.get_data('proxy').nil?
166
164
  @swt_widget.set_data('proxy', self)
@@ -499,26 +497,37 @@ module Glimmer
499
497
 
500
498
  # This supports widgets in and out of basic SWT
501
499
  def self.swt_widget_class_for(underscored_widget_name)
502
- underscored_widget_name = KEYWORD_ALIASES[underscored_widget_name] if KEYWORD_ALIASES[underscored_widget_name]
503
- swt_widget_name = underscored_widget_name.camelcase(:upper)
504
- swt_widget_class = eval(swt_widget_name)
505
- # TODO fix issue with not detecting DateTime because it's conflicting with the Ruby DateTime
506
- unless swt_widget_class.ancestors.include?(org.eclipse.swt.widgets.Widget)
507
- swt_widget_class = swt_widget_class_manual_entries[underscored_widget_name]
508
- if swt_widget_class.nil?
509
- Glimmer::Config.logger.debug {"Class #{swt_widget_class} matching #{underscored_widget_name} is not a subclass of org.eclipse.swt.widgets.Widget"}
510
- return nil
500
+ # TODO clear memoization for a keyword if a custom widget was defined with that keyword
501
+ unless flyweight_swt_widget_classes.keys.include?(underscored_widget_name)
502
+ begin
503
+ underscored_widget_name = KEYWORD_ALIASES[underscored_widget_name] if KEYWORD_ALIASES[underscored_widget_name]
504
+ swt_widget_name = underscored_widget_name.camelcase(:upper)
505
+ swt_widget_class = eval(swt_widget_name)
506
+ # TODO fix issue with not detecting DateTime because it's conflicting with the Ruby DateTime
507
+ unless swt_widget_class.ancestors.include?(org.eclipse.swt.widgets.Widget)
508
+ swt_widget_class = swt_widget_class_manual_entries[underscored_widget_name]
509
+ if swt_widget_class.nil?
510
+ Glimmer::Config.logger.debug {"Class #{swt_widget_class} matching #{underscored_widget_name} is not a subclass of org.eclipse.swt.widgets.Widget"}
511
+ return nil
512
+ end
513
+ end
514
+ flyweight_swt_widget_classes[underscored_widget_name] = swt_widget_class
515
+ rescue SyntaxError, NameError => e
516
+ Glimmer::Config.logger.debug {e.full_message}
517
+ # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
518
+ nil
519
+ rescue => e
520
+ Glimmer::Config.logger.debug {e.full_message}
521
+ # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
522
+ nil
511
523
  end
512
524
  end
513
- swt_widget_class
514
- rescue SyntaxError, NameError => e
515
- Glimmer::Config.logger.debug {e.full_message}
516
- # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
517
- nil
518
- rescue => e
519
- Glimmer::Config.logger.debug {e.full_message}
520
- # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
521
- nil
525
+ flyweight_swt_widget_classes[underscored_widget_name]
526
+ end
527
+
528
+ # Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.
529
+ def self.flyweight_swt_widget_classes
530
+ @flyweight_swt_widget_classes ||= {}
522
531
  end
523
532
 
524
533
  def async_exec(&block)
@@ -27,6 +27,19 @@ module Glimmer
27
27
  include SuperModule
28
28
  include Glimmer::UI::CustomWidget
29
29
 
30
+ class << self
31
+ attr_reader :custom_shell
32
+
33
+ def launch
34
+ @custom_shell = send(self.name.underscore.gsub('::', '__'))
35
+ @custom_shell.open
36
+ end
37
+
38
+ def shutdown
39
+ @custom_shell.close
40
+ end
41
+ end
42
+
30
43
  def initialize(parent, *swt_constants, options, &content)
31
44
  super
32
45
  @swt_widget.set_data('custom_shell', self)
@@ -55,8 +68,8 @@ module Glimmer
55
68
  body_root.visible?
56
69
  end
57
70
 
58
- def center
59
- body_root.center
71
+ def center_within_display
72
+ body_root.center_within_display
60
73
  end
61
74
 
62
75
  def start_event_loop
@@ -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
@@ -34,37 +34,48 @@ module Glimmer
34
34
  include DataBinding::ObservableModel
35
35
 
36
36
  super_module_included do |klass|
37
+ # TODO clear memoization of WidgetProxy.swt_widget_class_for for a keyword if a custom widget was defined with that keyword
37
38
  klass.include(Glimmer) unless klass.name.include?('Glimmer::UI::CustomShell')
38
39
  Glimmer::UI::CustomWidget.add_custom_widget_namespaces_for(klass) unless klass.name.include?('Glimmer::UI::CustomShell')
39
40
  end
40
41
 
41
42
  class << self
42
43
  def for(underscored_custom_widget_name)
43
- extracted_namespaces = underscored_custom_widget_name.
44
- to_s.
45
- split(/__/).map do |namespace|
46
- namespace.camelcase(:upper)
47
- end
48
- custom_widget_namespaces.each do |base|
49
- extracted_namespaces.reduce(base) do |result, namespace|
50
- if !result.constants.include?(namespace)
51
- namespace = result.constants.detect {|c| c.to_s.upcase == namespace.to_s.upcase } || namespace
52
- end
53
- begin
54
- constant = result.const_get(namespace)
55
- return constant if constant.ancestors.include?(Glimmer::UI::CustomWidget)
56
- constant
57
- rescue => e
58
- # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
59
- result
44
+ unless flyweight_custom_widget_classes.keys.include?(underscored_custom_widget_name)
45
+ begin
46
+ extracted_namespaces = underscored_custom_widget_name.
47
+ to_s.
48
+ split(/__/).map do |namespace|
49
+ namespace.camelcase(:upper)
50
+ end
51
+ custom_widget_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_widget_classes[underscored_custom_widget_name] = constant = result.const_get(namespace)
58
+ return constant if constant.ancestors.include?(Glimmer::UI::CustomWidget)
59
+ flyweight_custom_widget_classes[underscored_custom_widget_name] = constant
60
+ rescue => e
61
+ # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
62
+ flyweight_custom_widget_classes[underscored_custom_widget_name] = result
63
+ end
64
+ end
60
65
  end
66
+ raise "#{underscored_custom_widget_name} has no custom widget 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_widget_classes[underscored_custom_widget_name] = nil
61
71
  end
62
72
  end
63
- raise "#{underscored_custom_widget_name} has no custom widget class!"
64
- rescue => e
65
- Glimmer::Config.logger.debug {e.message}
66
- Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
67
- nil
73
+ flyweight_custom_widget_classes[underscored_custom_widget_name]
74
+ end
75
+
76
+ # Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.
77
+ def flyweight_custom_widget_classes
78
+ @flyweight_custom_widget_classes ||= {}
68
79
  end
69
80
 
70
81
  def add_custom_widget_namespaces_for(klass)
@@ -141,10 +152,9 @@ module Glimmer
141
152
  end
142
153
  end
143
154
 
144
- attr_reader :body_root, :swt_widget, :parent, :swt_style, :options
155
+ attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
145
156
 
146
157
  def initialize(parent, *swt_constants, options, &content)
147
- @parent = parent
148
158
  @swt_style = SWT::SWTProxy[*swt_constants]
149
159
  options ||= {}
150
160
  @options = self.class.options.merge(options)
@@ -156,6 +166,9 @@ module Glimmer
156
166
  raise Glimmer::Error, 'Invalid custom widget for having an empty body! Please fill body block!' if @body_root.nil?
157
167
  @swt_widget = @body_root.swt_widget
158
168
  @swt_widget.set_data('custom_widget', self)
169
+ @parent = parent
170
+ @parent ||= @swt_widget.parent
171
+ @parent_proxy ||= @parent&.get_data('proxy')
159
172
  execute_hooks('after_body')
160
173
  end
161
174
 
@@ -211,10 +224,10 @@ module Glimmer
211
224
 
212
225
  # This method ensures it has an instance method not coming from Glimmer DSL
213
226
  def has_instance_method?(method_name)
214
- respond_to?(method_name) and
227
+ respond_to?(method_name) and
215
228
  !swt_widget&.respond_to?(method_name) and
216
229
  (method(method_name) rescue nil) and
217
- !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
230
+ !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
218
231
  !method(method_name)&.source_location&.first&.include?('glimmer/swt/widget_proxy.rb')
219
232
  end
220
233
 
@@ -265,13 +278,13 @@ module Glimmer
265
278
  end
266
279
  end
267
280
 
268
- alias local_respond_to? respond_to?
281
+ alias local_respond_to? respond_to?
269
282
  def respond_to?(method, *args, &block)
270
283
  super or
271
284
  can_handle_observation_request?(method) or
272
285
  body_root.respond_to?(method, *args, &block)
273
286
  end
274
-
287
+
275
288
  private
276
289
 
277
290
  def execute_hooks(hook_name)