glimmer-dsl-swt 4.20.0.4 → 4.20.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +13 -7
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +5 -2
  6. data/docs/reference/GLIMMER_SAMPLES.md +13 -0
  7. data/docs/reference/GLIMMER_STYLE_GUIDE.md +4 -3
  8. data/glimmer-dsl-swt.gemspec +0 -0
  9. data/lib/glimmer/data_binding/shine.rb +2 -1
  10. data/lib/glimmer/data_binding/table_items_binding.rb +2 -2
  11. data/lib/glimmer/data_binding/tree_items_binding.rb +2 -2
  12. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +1 -1
  13. data/lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb +1 -1
  14. data/lib/glimmer/dsl/swt/shine_data_binding_expression.rb +6 -5
  15. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +2 -2
  16. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +17 -12
  17. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +3 -3
  18. data/lib/glimmer/rake_task/scaffold.rb +2 -2
  19. data/lib/glimmer/swt/custom/animation.rb +6 -0
  20. data/lib/glimmer/swt/custom/checkbox_group.rb +1 -1
  21. data/lib/glimmer/swt/custom/radio_group.rb +2 -1
  22. data/lib/glimmer/swt/display_proxy.rb +11 -8
  23. data/lib/glimmer/swt/proxy_properties.rb +7 -6
  24. data/lib/glimmer/swt/table_proxy.rb +15 -8
  25. data/lib/glimmer/swt/widget_proxy.rb +5 -2
  26. data/lib/glimmer/ui/custom_shape.rb +1 -1
  27. data/lib/glimmer/ui/custom_shell.rb +3 -3
  28. data/lib/glimmer/ui/custom_widget.rb +6 -3
  29. data/samples/elaborate/calculator.rb +116 -0
  30. data/samples/elaborate/calculator/model/command.rb +105 -0
  31. data/samples/elaborate/calculator/model/command/all_clear.rb +17 -0
  32. data/samples/elaborate/calculator/model/command/command_history.rb +0 -0
  33. data/samples/elaborate/calculator/model/command/equals.rb +18 -0
  34. data/samples/elaborate/calculator/model/command/number.rb +20 -0
  35. data/samples/elaborate/calculator/model/command/operation.rb +27 -0
  36. data/samples/elaborate/calculator/model/command/operation/add.rb +15 -0
  37. data/samples/elaborate/calculator/model/command/operation/divide.rb +15 -0
  38. data/samples/elaborate/calculator/model/command/operation/multiply.rb +15 -0
  39. data/samples/elaborate/calculator/model/command/operation/subtract.rb +15 -0
  40. data/samples/elaborate/calculator/model/command/point.rb +20 -0
  41. data/samples/elaborate/calculator/model/presenter.rb +30 -0
  42. data/samples/elaborate/contact_manager.rb +2 -2
  43. data/samples/elaborate/meta_sample.rb +5 -5
  44. data/samples/elaborate/tetris.rb +6 -6
  45. data/samples/elaborate/tetris/view/bevel.rb +11 -11
  46. data/samples/elaborate/tetris/view/block.rb +1 -1
  47. data/samples/elaborate/tetris/view/high_score_dialog.rb +4 -4
  48. data/samples/elaborate/tetris/view/score_lane.rb +3 -3
  49. data/samples/elaborate/tetris/view/tetris_menu_bar.rb +9 -9
  50. data/samples/elaborate/timer.rb +233 -0
  51. data/samples/elaborate/timer/alarm1.wav +0 -0
  52. data/samples/elaborate/timer/sounds/alarm1.wav +0 -0
  53. data/samples/elaborate/user_profile.rb +4 -2
  54. data/samples/elaborate/weather.rb +1 -1
  55. data/samples/hello/hello_canvas_animation_data_binding.rb +1 -1
  56. data/samples/hello/hello_checkbox_group.rb +1 -1
  57. data/samples/hello/hello_code_text.rb +3 -3
  58. data/samples/hello/hello_cool_bar.rb +5 -5
  59. data/samples/hello/hello_cursor.rb +1 -1
  60. data/samples/hello/hello_custom_shell.rb +1 -1
  61. data/samples/hello/hello_directory_dialog.rb +1 -1
  62. data/samples/hello/hello_radio_group.rb +2 -2
  63. data/samples/hello/hello_table.rb +4 -4
  64. data/samples/hello/hello_text.rb +120 -0
  65. data/samples/hello/hello_tool_bar.rb +5 -5
  66. data/samples/hello/hello_tree.rb +11 -11
  67. metadata +19 -2
@@ -33,6 +33,7 @@ module Glimmer
33
33
  # default implementation of attribute setters/getters
34
34
  # It tries swt_widget, swt_display, swt_image, and swt_dialog by default.
35
35
  def proxy_source_object
36
+ # TODO the logic here should not be needed if derived with polymorphism. Consider removing.
36
37
  if respond_to?(:swt_widget)
37
38
  swt_widget
38
39
  elsif respond_to?(:swt_display)
@@ -62,7 +63,7 @@ module Glimmer
62
63
 
63
64
  def has_attribute?(attribute_name, *args)
64
65
  Glimmer::SWT::DisplayProxy.instance.auto_exec do
65
- proxy_source_object&.respond_to?(attribute_setter(attribute_name), args) ||
66
+ proxy_source_object&.respond_to?(attribute_setter(attribute_name), args) or
66
67
  respond_to?(ruby_attribute_setter(attribute_name), args)
67
68
  end
68
69
  end
@@ -80,7 +81,7 @@ module Glimmer
80
81
  end
81
82
  end
82
83
  unless swt_widget_operation
83
- result = send(ruby_attribute_setter(attribute_name), args)
84
+ result = send(ruby_attribute_setter(attribute_name), args) if respond_to?(ruby_attribute_setter(attribute_name), args)
84
85
  end
85
86
  result
86
87
  end
@@ -101,10 +102,10 @@ module Glimmer
101
102
  end
102
103
  end
103
104
  unless swt_widget_operation
104
- result = if respond_to?(ruby_attribute_getter(attribute_name))
105
- send(ruby_attribute_getter(attribute_name))
106
- else
107
- send(attribute_name)
105
+ if respond_to?(ruby_attribute_getter(attribute_name))
106
+ result = send(ruby_attribute_getter(attribute_name))
107
+ elsif respond_to?(attribute_name)
108
+ result = send(attribute_name)
108
109
  end
109
110
  end
110
111
  result
@@ -250,19 +250,13 @@ module Glimmer
250
250
  alias editable? editable
251
251
 
252
252
  def initialize(underscored_widget_name, parent, args)
253
- @editable = args.delete(:editable)
253
+ editable_style = args.delete(:editable)
254
254
  super
255
255
  @table_editor = TableEditor.new(swt_widget)
256
256
  @table_editor.horizontalAlignment = SWTProxy[:left]
257
257
  @table_editor.grabHorizontal = true
258
258
  @table_editor.minimumHeight = 20
259
- if editable?
260
- content {
261
- on_mouse_up { |event|
262
- edit_table_item(event.table_item, event.column_index)
263
- }
264
- }
265
- end
259
+ self.editable = editable_style
266
260
  end
267
261
 
268
262
  def items
@@ -283,6 +277,19 @@ module Glimmer
283
277
  end
284
278
  end
285
279
 
280
+ def editable=(value)
281
+ @editable = value
282
+ if @editable
283
+ content {
284
+ @editable_on_mouse_up = on_mouse_up { |event|
285
+ edit_table_item(event.table_item, event.column_index)
286
+ }
287
+ }
288
+ else
289
+ @editable_on_mouse_up.deregister if @editable_on_mouse_up
290
+ end
291
+ end
292
+
286
293
  def sort_block=(comparator)
287
294
  @sort_block = comparator
288
295
  end
@@ -232,9 +232,12 @@ module Glimmer
232
232
  def has_attribute?(attribute_name, *args)
233
233
  # TODO test that attribute getter responds too
234
234
  widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
235
+ property_type_converter = property_type_converters[attribute_name.to_s.to_sym]
235
236
  auto_exec do
236
237
  if widget_custom_attribute
237
238
  @swt_widget.respond_to?(widget_custom_attribute[:setter][:name])
239
+ elsif property_type_converter
240
+ true
238
241
  else
239
242
  super
240
243
  end
@@ -765,7 +768,7 @@ module Glimmer
765
768
 
766
769
  def can_add_listener?(underscored_listener_name)
767
770
  auto_exec do
768
- !self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
771
+ @swt_widget && !self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
769
772
  end
770
773
  end
771
774
 
@@ -838,7 +841,7 @@ module Glimmer
838
841
  widget_listener_proxy = nil
839
842
  safe_block = lambda { |*args| block.call(*args) unless @swt_widget.isDisposed }
840
843
  @swt_widget.addListener(event_type, &safe_block)
841
- widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: @swt_widget.getListeners(event_type).last, event_type: event_type, swt_constant: swt_constant)
844
+ WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: @swt_widget.getListeners(event_type).last, event_type: event_type, swt_constant: swt_constant)
842
845
  end
843
846
  end
844
847
 
@@ -248,7 +248,7 @@ module Glimmer
248
248
  # Otherwise, if a block is passed, it adds it as content to this custom shape
249
249
  def content(&block)
250
250
  if block_given?
251
- body_root.content(&block)
251
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::CustomShapeExpression.new, self.class.keyword, &block)
252
252
  else
253
253
  @content
254
254
  end
@@ -31,9 +31,9 @@ module Glimmer
31
31
  class << self
32
32
  def launch(*args, &content)
33
33
  auto_exec do
34
- @launched_custom_shell = send(keyword, *args, &content)
35
- @launched_custom_shell.swt_widget.set_data('launched', true)
36
- @launched_custom_shell.open
34
+ launched_custom_shell = send(keyword, *args, &content)
35
+ launched_custom_shell.swt_widget.set_data('launched', true)
36
+ launched_custom_shell.open
37
37
  end
38
38
  end
39
39
  end
@@ -186,8 +186,11 @@ module Glimmer
186
186
  @swt_widget.set_data('custom_widget', self)
187
187
  end
188
188
  execute_hook('after_body')
189
- @dispose_listener_registration = @body_root.on_widget_disposed do
190
- observer_registrations.each(&:deregister)
189
+ auto_exec do
190
+ @dispose_listener_registration = @body_root.on_widget_disposed do
191
+ observer_registrations.compact.each(&:deregister)
192
+ observer_registrations.clear
193
+ end
191
194
  end
192
195
  end
193
196
 
@@ -293,7 +296,7 @@ module Glimmer
293
296
  # Otherwise, if a block is passed, it adds it as content to this custom widget
294
297
  def content(&block)
295
298
  if block_given?
296
- body_root.content(&block)
299
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::CustomWidgetExpression.new, self.class.keyword, &block)
297
300
  else
298
301
  @content
299
302
  end
@@ -0,0 +1,116 @@
1
+ require 'glimmer-dsl-swt'
2
+ require 'bigdecimal'
3
+
4
+ require_relative 'calculator/model/presenter'
5
+
6
+ # This sample demonstrates use of MVP (Model-View-Presenter) Architectural Pattern
7
+ # to data-bind View widgets to object-oriented Models taking advantage of design patterns
8
+ # like Command Design Pattern.
9
+ class Calculator
10
+ include Glimmer::UI::CustomShell
11
+
12
+ BUTTON_FONT = {height: 14}
13
+ BUTTON_FONT_OPERATION = {height: 18}
14
+ BUTTON_FONT_BIG = {height: 28}
15
+
16
+ attr_reader :presenter
17
+
18
+ before_body {
19
+ @presenter = Model::Presenter.new
20
+
21
+ Display.setAppName('Glimmer Calculator')
22
+
23
+ display {
24
+ on_swt_keydown { |key_event|
25
+ char = key_event.character.chr rescue nil
26
+ @presenter.press(char)
27
+ }
28
+
29
+ on_about {
30
+ display_about_dialog
31
+ }
32
+ }
33
+ }
34
+
35
+ body {
36
+ shell {
37
+ grid_layout 4, true
38
+
39
+ minimum_size (OS.mac? ? 320 : (OS.windows? ? 390 : 520)), 240
40
+ text "Glimmer Calculator"
41
+
42
+ on_shell_closed do
43
+ @presenter.purge_command_history
44
+ end
45
+
46
+ # Setting styled_text to multi in order for alignment options to activate
47
+ styled_text(:multi, :wrap, :border) {
48
+ text <= [@presenter, :result]
49
+ alignment swt(:right)
50
+ right_margin 5
51
+ font height: 40
52
+ layout_data(:fill, :fill, true, true) {
53
+ horizontal_span 4
54
+ }
55
+ editable false
56
+ caret nil
57
+ }
58
+ command_button('AC')
59
+ operation_button('÷')
60
+ operation_button('×')
61
+ operation_button('−')
62
+ (7..9).each { |number|
63
+ number_button(number)
64
+ }
65
+ operation_button('+', font: BUTTON_FONT_BIG, vertical_span: 2)
66
+ (4..6).each { |number|
67
+ number_button(number)
68
+ }
69
+ (1..3).each { |number|
70
+ number_button(number)
71
+ }
72
+ command_button('=', font: BUTTON_FONT_BIG, vertical_span: 2)
73
+ number_button(0, horizontal_span: 2)
74
+ operation_button('.')
75
+ }
76
+ }
77
+
78
+ def number_button(number, options = {})
79
+ command_button(number, options)
80
+ end
81
+
82
+ def operation_button(operation, options = {})
83
+ command_button(operation, options.merge(font: BUTTON_FONT_OPERATION))
84
+ end
85
+
86
+ def command_button(command, options = {})
87
+ command = command.to_s
88
+ options[:font] ||= BUTTON_FONT
89
+ options[:horizontal_span] ||= 1
90
+ options[:vertical_span] ||= 1
91
+
92
+ button { |proxy|
93
+ text command
94
+ font options[:font]
95
+
96
+ layout_data(:fill, :fill, true, true) {
97
+ horizontal_span options[:horizontal_span]
98
+ vertical_span options[:vertical_span]
99
+ }
100
+
101
+ on_widget_selected {
102
+ @presenter.press(command)
103
+ }
104
+ }
105
+ end
106
+
107
+ def display_about_dialog
108
+ message_box(body_root) {
109
+ text 'About'
110
+ message "Glimmer - Calculator\n\nCopyright (c) 2007-2021 Andy Maleh"
111
+ }.open
112
+ end
113
+
114
+ end
115
+
116
+ Calculator.launch
@@ -0,0 +1,105 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class << self
5
+ attr_accessor :number1, :number2, :operation
6
+
7
+ # Keyword string representing calculator command (e.g. '+' for Add command)
8
+ # Subclasses must call to define a single keyword
9
+ def keyword(keyword_text)
10
+ Command.keyword_to_command_class_mapping[keyword_text] = self
11
+ end
12
+
13
+ # Keyword string array representing calculator command (e.g. ('0'..'9').to_a)
14
+ # Subclasses must call to define multiple keywords
15
+ def keywords(*keyword_text_array)
16
+ keyword_text_array.flatten.each do |keyword_text|
17
+ keyword(keyword_text)
18
+ end
19
+ end
20
+
21
+ def keyword_to_command_class_mapping
22
+ @keyword_to_command_class_mapping ||= {}
23
+ end
24
+
25
+ def command_history
26
+ @command_history ||= []
27
+ end
28
+
29
+ def purge_command_history
30
+ Command.command_history.clear
31
+ self.number1 = nil
32
+ self.number2 = nil
33
+ self.operation = nil
34
+ end
35
+
36
+ def for(button)
37
+ command_class = keyword_to_command_class_mapping[button]
38
+ command_class&.new(button)&.tap do |command|
39
+ command.execute
40
+ command_history << command
41
+ end
42
+ end
43
+ end
44
+
45
+ attr_reader :button
46
+ attr_accessor :result
47
+
48
+ def initialize(button)
49
+ @button = button
50
+ end
51
+
52
+ def number1
53
+ Command.number1
54
+ end
55
+
56
+ def number1=(value)
57
+ Command.number1 = value.to_f
58
+ end
59
+
60
+ def number2
61
+ Command.number2
62
+ end
63
+
64
+ def number2=(value)
65
+ Command.number2 = value.to_f
66
+ end
67
+
68
+ def operation
69
+ Command.operation
70
+ end
71
+
72
+ def operation=(op)
73
+ Command.operation = op
74
+ end
75
+
76
+ def last_result
77
+ last_command&.result
78
+ end
79
+
80
+ def last_command
81
+ command_history.last
82
+ end
83
+
84
+ def command_history
85
+ Command.command_history
86
+ end
87
+
88
+ def execute
89
+ raise 'Not implemented! Please override in a subclass.'
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Dir[File.join(File.dirname(__FILE__), 'command', '**', '*.rb')].each {|f| require(f)} # disabled for Opal compatibility
96
+
97
+ require_relative 'command/all_clear'
98
+ require_relative 'command/equals'
99
+ require_relative 'command/number'
100
+ require_relative 'command/operation'
101
+ require_relative 'command/point'
102
+ require_relative 'command/operation/add'
103
+ require_relative 'command/operation/divide'
104
+ require_relative 'command/operation/multiply'
105
+ require_relative 'command/operation/subtract'
@@ -0,0 +1,17 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class AllClear < Command
5
+ keywords 'AC', 'c', 'C', 8.chr, 27.chr, 127.chr
6
+
7
+ def execute
8
+ self.result = '0'
9
+ self.number1 = nil
10
+ self.number2 = nil
11
+ self.operation = nil
12
+ command_history.clear
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Equals < Command
5
+ keywords '=', "\r"
6
+
7
+ def execute
8
+ if number1 && number2 && operation
9
+ self.result = operation.calculate.to_s
10
+ self.number1 = self.result
11
+ else
12
+ self.result = last_result || '0'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Number < Command
5
+ keywords ('0'..'9').to_a
6
+
7
+ def execute
8
+ self.result = last_result.nil? || (!last_command.is_a?(Number) && !last_command.is_a?(Point)) ? button : last_result + button
9
+ if operation.nil? || last_command.is_a?(Equals)
10
+ self.number1 = self.result
11
+ self.number2 = nil
12
+ self.operation = nil
13
+ else
14
+ self.number2 = self.result
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end