glimmer-dsl-swt 4.18.2.2 → 4.18.3.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -0
  3. data/README.md +213 -32
  4. data/VERSION +1 -1
  5. data/glimmer-dsl-swt.gemspec +19 -6
  6. data/lib/ext/glimmer/config.rb +24 -7
  7. data/lib/glimmer/data_binding/widget_binding.rb +14 -4
  8. data/lib/glimmer/dsl/swt/color_expression.rb +4 -4
  9. data/lib/glimmer/dsl/swt/data_binding_expression.rb +3 -3
  10. data/lib/glimmer/dsl/swt/display_expression.rb +3 -3
  11. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  12. data/lib/glimmer/dsl/swt/multiply_expression.rb +53 -0
  13. data/lib/glimmer/dsl/swt/property_expression.rb +4 -2
  14. data/lib/glimmer/dsl/swt/shape_expression.rb +2 -4
  15. data/lib/glimmer/dsl/swt/transform_expression.rb +55 -0
  16. data/lib/glimmer/dsl/swt/widget_expression.rb +2 -1
  17. data/lib/glimmer/rake_task/scaffold.rb +4 -3
  18. data/lib/glimmer/swt/color_proxy.rb +28 -6
  19. data/lib/glimmer/swt/custom/drawable.rb +8 -0
  20. data/lib/glimmer/swt/custom/shape.rb +66 -26
  21. data/lib/glimmer/swt/directory_dialog_proxy.rb +3 -3
  22. data/lib/glimmer/swt/display_proxy.rb +26 -5
  23. data/lib/glimmer/swt/file_dialog_proxy.rb +3 -3
  24. data/lib/glimmer/swt/layout_data_proxy.rb +3 -3
  25. data/lib/glimmer/swt/shell_proxy.rb +17 -5
  26. data/lib/glimmer/swt/transform_proxy.rb +109 -0
  27. data/lib/glimmer/swt/widget_listener_proxy.rb +14 -5
  28. data/lib/glimmer/swt/widget_proxy.rb +35 -26
  29. data/lib/glimmer/ui/custom_shell.rb +17 -3
  30. data/lib/glimmer/ui/custom_widget.rb +66 -45
  31. data/samples/elaborate/meta_sample.rb +102 -24
  32. data/samples/elaborate/tetris.rb +137 -0
  33. data/samples/elaborate/tetris/model/block.rb +48 -0
  34. data/samples/elaborate/tetris/model/game.rb +226 -0
  35. data/samples/elaborate/tetris/model/tetromino.rb +316 -0
  36. data/samples/elaborate/tetris/view/block.rb +70 -0
  37. data/samples/elaborate/tetris/view/game_over_dialog.rb +68 -0
  38. data/samples/elaborate/tetris/view/playfield.rb +56 -0
  39. data/samples/elaborate/tetris/view/score_lane.rb +87 -0
  40. data/samples/elaborate/tetris/view/tetris_menu_bar.rb +72 -0
  41. data/samples/elaborate/tic_tac_toe.rb +4 -4
  42. data/samples/hello/hello_canvas_transform.rb +40 -0
  43. data/samples/hello/hello_link.rb +1 -1
  44. metadata +17 -4
@@ -26,10 +26,12 @@ module Glimmer
26
26
  # Follows the Proxy Design Pattern
27
27
  class WidgetListenerProxy
28
28
 
29
- attr_reader :swt_widget, :swt_listener, :widget_add_listener_method, :swt_listener_class, :swt_listener_method, :event_type, :swt_constant
29
+ attr_reader :swt_widget, :swt_display, :swt_listener, :widget_add_listener_method, :swt_listener_class, :swt_listener_method, :event_type, :swt_constant
30
30
 
31
- def initialize(swt_widget:, swt_listener:, widget_add_listener_method: nil, swt_listener_class: nil, swt_listener_method: nil, event_type: nil, swt_constant: nil)
31
+ def initialize(swt_widget:nil, swt_display:nil, swt_listener:, widget_add_listener_method: nil, swt_listener_class: nil, swt_listener_method: nil, event_type: nil, swt_constant: nil, filter: false)
32
32
  @swt_widget = swt_widget
33
+ @swt_display = swt_display
34
+ @filter = filter
33
35
  @swt_listener = swt_listener
34
36
  @widget_add_listener_method = widget_add_listener_method
35
37
  @swt_listener_class = swt_listener_class
@@ -42,14 +44,21 @@ module Glimmer
42
44
  @widget_add_listener_method.sub('add', 'remove')
43
45
  end
44
46
 
45
- def unregister
46
- # TODO consider renaming to deregister (and in Observer too)
47
- if @event_type
47
+ def deregister
48
+ return if @swt_widget&.is_disposed || @swt_display&.is_disposed
49
+ if @swt_display
50
+ if @filter
51
+ @swt_display.removeFilter(@event_type, @swt_listener)
52
+ else
53
+ @swt_display.removeListener(@event_type, @swt_listener)
54
+ end
55
+ elsif @event_type
48
56
  @swt_widget.removeListener(@event_type, @swt_listener)
49
57
  else
50
58
  @swt_widget.send(widget_remove_listener_method, @swt_listener)
51
59
  end
52
60
  end
61
+ alias unregister deregister # TODO consider dropping unregister (and in Observer too)
53
62
  end
54
63
  end
55
64
  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)
@@ -687,7 +696,7 @@ module Glimmer
687
696
  safe_block = lambda { |*args| block.call(*args) unless @swt_widget.isDisposed }
688
697
  listener = listener_class.new(listener_method => safe_block)
689
698
  @swt_widget.send(widget_add_listener_method, listener)
690
- widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: listener, widget_add_listener_method: widget_add_listener_method, swt_listener_class: listener_class, swt_listener_method: listener_method)
699
+ WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: listener, widget_add_listener_method: widget_add_listener_method, swt_listener_class: listener_class, swt_listener_method: listener_method)
691
700
  end
692
701
 
693
702
  # Looks through SWT class add***Listener methods till it finds one for which
@@ -27,12 +27,21 @@ module Glimmer
27
27
  include SuperModule
28
28
  include Glimmer::UI::CustomWidget
29
29
 
30
+ class << self
31
+ attr_reader :launched_custom_shell
32
+
33
+ def launch(*args, &content)
34
+ @launched_custom_shell = send(keyword, *args, &content) if @launched_custom_shell.nil? || @launched_custom_shell.disposed?
35
+ @launched_custom_shell.open
36
+ end
37
+ end
38
+
30
39
  def initialize(parent, *swt_constants, options, &content)
31
40
  super
32
41
  @swt_widget.set_data('custom_shell', self)
33
42
  raise Error, 'Invalid custom shell body root! Must be a shell or another custom shell.' unless body_root.swt_widget.is_a?(org.eclipse.swt.widgets.Shell)
34
43
  end
35
-
44
+
36
45
  # Classes may override
37
46
  def open
38
47
  body_root.open
@@ -43,6 +52,7 @@ module Glimmer
43
52
  open
44
53
  end
45
54
 
55
+ # TODO consider using Forwardable instead
46
56
  def close
47
57
  body_root.close
48
58
  end
@@ -55,8 +65,12 @@ module Glimmer
55
65
  body_root.visible?
56
66
  end
57
67
 
58
- def center
59
- body_root.center
68
+ def disposed?
69
+ swt_widget.is_disposed
70
+ end
71
+
72
+ def center_within_display
73
+ body_root.center_within_display
60
74
  end
61
75
 
62
76
  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,39 +34,60 @@ 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 ||= {}
79
+ end
80
+
81
+ # Returns keyword to use for this custom widget
82
+ def keyword
83
+ self.name.underscore.gsub('::', '__')
84
+ end
85
+
86
+ # Returns shortcut keyword to use for this custom widget (keyword minus namespace)
87
+ def shortcut_keyword
88
+ self.name.underscore.gsub('::', '__').split('__').last
68
89
  end
69
-
90
+
70
91
  def add_custom_widget_namespaces_for(klass)
71
92
  Glimmer::UI::CustomWidget.namespaces_for_class(klass).drop(1).each do |namespace|
72
93
  Glimmer::UI::CustomWidget.custom_widget_namespaces << namespace
@@ -127,8 +148,7 @@ module Glimmer
127
148
  end
128
149
 
129
150
  def before_body(&block)
130
- @before_body_blocks ||= []
131
- @before_body_blocks << block
151
+ @before_body_block = block
132
152
  end
133
153
 
134
154
  def body(&block)
@@ -136,27 +156,28 @@ module Glimmer
136
156
  end
137
157
 
138
158
  def after_body(&block)
139
- @after_body_blocks ||= []
140
- @after_body_blocks << block
159
+ @after_body_block = block
141
160
  end
142
161
  end
143
162
 
144
- attr_reader :body_root, :swt_widget, :parent, :swt_style, :options
163
+ attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
145
164
 
146
165
  def initialize(parent, *swt_constants, options, &content)
147
- @parent = parent
148
166
  @swt_style = SWT::SWTProxy[*swt_constants]
149
167
  options ||= {}
150
168
  @options = self.class.options.merge(options)
151
169
  @content = Util::ProcTracker.new(content) if content
152
- execute_hooks('before_body')
170
+ execute_hook('before_body')
153
171
  body_block = self.class.instance_variable_get("@body_block")
154
172
  raise Glimmer::Error, 'Invalid custom widget for having no body! Please define body block!' if body_block.nil?
155
173
  @body_root = instance_exec(&body_block)
156
174
  raise Glimmer::Error, 'Invalid custom widget for having an empty body! Please fill body block!' if @body_root.nil?
157
175
  @swt_widget = @body_root.swt_widget
158
176
  @swt_widget.set_data('custom_widget', self)
159
- execute_hooks('after_body')
177
+ @parent = parent
178
+ @parent ||= @swt_widget.parent
179
+ @parent_proxy ||= @parent&.get_data('proxy')
180
+ execute_hook('after_body')
160
181
  end
161
182
 
162
183
  # Subclasses may override to perform post initialization work on an added child
@@ -211,10 +232,10 @@ module Glimmer
211
232
 
212
233
  # This method ensures it has an instance method not coming from Glimmer DSL
213
234
  def has_instance_method?(method_name)
214
- respond_to?(method_name) and
235
+ respond_to?(method_name) and
215
236
  !swt_widget&.respond_to?(method_name) and
216
237
  (method(method_name) rescue nil) and
217
- !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
238
+ !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
218
239
  !method(method_name)&.source_location&.first&.include?('glimmer/swt/widget_proxy.rb')
219
240
  end
220
241
 
@@ -265,22 +286,22 @@ module Glimmer
265
286
  end
266
287
  end
267
288
 
268
- alias local_respond_to? respond_to?
289
+ alias local_respond_to? respond_to?
269
290
  def respond_to?(method, *args, &block)
270
291
  super or
271
292
  can_handle_observation_request?(method) or
272
293
  body_root.respond_to?(method, *args, &block)
273
294
  end
274
-
295
+
275
296
  private
276
297
 
277
- def execute_hooks(hook_name)
278
- self.class.instance_variable_get("@#{hook_name}_blocks")&.each do |hook_block|
279
- temp_method_name = "#{hook_name}_block_#{hook_block.hash.abs}_#{(Time.now.to_f * 1_000_000).to_i}"
280
- singleton_class.define_method(temp_method_name, &hook_block)
281
- send(temp_method_name)
282
- singleton_class.send(:remove_method, temp_method_name)
283
- end
298
+ def execute_hook(hook_name)
299
+ hook_block = self.class.instance_variable_get("@#{hook_name}_block")
300
+ return if hook_block.nil?
301
+ temp_method_name = "#{hook_name}_block_#{hook_block.hash.abs}_#{(Time.now.to_f * 1_000_000).to_i}"
302
+ singleton_class.define_method(temp_method_name, &hook_block)
303
+ send(temp_method_name)
304
+ singleton_class.send(:remove_method, temp_method_name)
284
305
  end
285
306
  end
286
307
  end
@@ -1,9 +1,48 @@
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
+
1
22
  require 'fileutils'
2
23
  require 'etc'
3
24
 
4
25
  class Sample
5
26
  include Glimmer::DataBinding::ObservableModel
6
27
 
28
+ class << self
29
+ def glimmer_directory
30
+ File.expand_path('../../..', __FILE__)
31
+ end
32
+
33
+ def user_glimmer_directory
34
+ File.join(Etc.getpwuid.dir, '.glimmer-dsl-swt')
35
+ end
36
+
37
+ def ensure_user_glimmer_directory
38
+ unless @ensured_glimmer_directory
39
+ FileUtils.rm_rf(user_glimmer_directory)
40
+ FileUtils.cp_r(glimmer_directory, user_glimmer_directory)
41
+ @ensured_glimmer_directory = true
42
+ end
43
+ end
44
+ end
45
+
7
46
  attr_accessor :sample_directory, :file, :selected
8
47
 
9
48
  def initialize(file, sample_directory: )
@@ -38,25 +77,35 @@ class Sample
38
77
  File.basename(file) != 'meta_sample.rb'
39
78
  end
40
79
  alias launchable editable
80
+
81
+ def file_relative_path
82
+ file.sub(self.class.glimmer_directory, '')
83
+ end
84
+
85
+ def user_file
86
+ File.join(self.class.user_glimmer_directory, file_relative_path)
87
+ end
88
+
89
+ def user_file_parent_directory
90
+ File.dirname(user_file)
91
+ end
41
92
 
93
+ def directory
94
+ file.sub(/\.rb/, '')
95
+ end
96
+
42
97
  def launch(modified_code)
43
- parent_directory = File.basename(File.dirname(file))
44
- modified_file_parent_directory = File.join(Etc.getpwuid.dir, '.glimmer', 'samples', parent_directory)
45
- launch_file = modified_file = File.join(modified_file_parent_directory, File.basename(file))
98
+ launch_file = user_file
46
99
  begin
47
- FileUtils.mkdir_p(modified_file_parent_directory)
48
- FileUtils.cp_r(file, modified_file_parent_directory)
49
- FileUtils.cp_r(file.sub(/\.rb/, ''), modified_file_parent_directory) if File.exist?(file.sub(/\.rb/, ''))
50
- File.write(modified_file, modified_code)
100
+ FileUtils.cp_r(file, user_file_parent_directory)
101
+ FileUtils.cp_r(directory, user_file_parent_directory) if File.exist?(directory)
102
+ File.write(user_file, modified_code)
51
103
  rescue => e
52
104
  puts 'Error writing sample modifications. Launching original sample.'
53
105
  puts e.full_message
54
106
  launch_file = file # load original file if failed to write changes
55
107
  end
56
108
  load(launch_file)
57
- ensure
58
- FileUtils.rm_rf(modified_file)
59
- FileUtils.rm_rf(modified_file.sub(/\.rb/, ''))
60
109
  end
61
110
  end
62
111
 
@@ -141,17 +190,18 @@ class SampleDirectory
141
190
  end
142
191
 
143
192
  class MetaSampleApplication
144
- include Glimmer
193
+ include Glimmer::UI::CustomShell
145
194
 
146
- def initialize
195
+ before_body {
196
+ Sample.ensure_user_glimmer_directory
147
197
  selected_sample_directory = SampleDirectory.sample_directories.first
148
198
  selected_sample = selected_sample_directory.samples.first
149
199
  selected_sample_directory.selected_sample_name = selected_sample.name
150
- end
151
-
152
- def launch
153
200
  Display.app_name = 'Glimmer Meta-Sample'
154
- shell {
201
+ }
202
+
203
+ body {
204
+ shell(:fill_screen) {
155
205
  minimum_size 1280, 768
156
206
  text 'Glimmer Meta-Sample (The Sample of Samples)'
157
207
  image File.expand_path('../../icons/scaffold_app.png', __dir__)
@@ -197,11 +247,8 @@ class MetaSampleApplication
197
247
  on_widget_selected {
198
248
  begin
199
249
  SampleDirectory.selected_sample.launch(@code_text.text)
200
- rescue StandardError, SyntaxError => launch_error
201
- message_box {
202
- text 'Error Launching'
203
- message launch_error.full_message
204
- }.open
250
+ rescue LoadError, StandardError, SyntaxError => launch_error
251
+ error_dialog(message: launch_error.full_message).open
205
252
  end
206
253
  }
207
254
  }
@@ -222,10 +269,41 @@ class MetaSampleApplication
222
269
  editable bind(SampleDirectory, 'selected_sample.editable')
223
270
  }
224
271
 
225
- weights 4, 9
272
+ weights 4, 11
273
+ }
274
+ }
275
+ }
276
+
277
+ # Method-based error_dialog custom widget
278
+ def error_dialog(message:)
279
+ return if message.nil?
280
+ dialog(body_root) { |dialog_proxy|
281
+ row_layout(:vertical) {
282
+ center true
283
+ }
284
+
285
+ text 'Error Launching'
286
+
287
+ styled_text(:border, :h_scroll, :v_scroll) {
288
+ layout_data {
289
+ width body_root.bounds.width*0.75
290
+ height body_root.bounds.height*0.75
291
+ }
292
+
293
+ text message
294
+ editable false
295
+ caret nil
296
+ }
297
+
298
+ button {
299
+ text 'Close'
300
+
301
+ on_widget_selected {
302
+ dialog_proxy.close
303
+ }
226
304
  }
227
- }.open
305
+ }
228
306
  end
229
307
  end
230
308
 
231
- MetaSampleApplication.new.launch
309
+ MetaSampleApplication.launch