glimmer-dsl-swt 4.20.0.3 → 4.20.2.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/README.md +12 -6
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_SAMPLES.md +34 -0
  6. data/docs/reference/GLIMMER_STYLE_GUIDE.md +4 -3
  7. data/glimmer-dsl-swt.gemspec +0 -0
  8. data/lib/glimmer/data_binding/shine.rb +5 -1
  9. data/lib/glimmer/data_binding/table_items_binding.rb +2 -2
  10. data/lib/glimmer/data_binding/tree_items_binding.rb +2 -2
  11. data/lib/glimmer/dsl/swt/shine_data_binding_expression.rb +6 -3
  12. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +2 -2
  13. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +17 -12
  14. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +3 -3
  15. data/lib/glimmer/swt/custom/animation.rb +6 -0
  16. data/lib/glimmer/swt/display_proxy.rb +11 -8
  17. data/lib/glimmer/swt/proxy_properties.rb +2 -1
  18. data/lib/glimmer/swt/table_proxy.rb +15 -8
  19. data/lib/glimmer/swt/widget_proxy.rb +2 -2
  20. data/lib/glimmer/ui/custom_shell.rb +3 -3
  21. data/lib/glimmer/ui/custom_widget.rb +5 -2
  22. data/samples/elaborate/calculator.rb +116 -0
  23. data/samples/elaborate/calculator/model/command.rb +105 -0
  24. data/samples/elaborate/calculator/model/command/all_clear.rb +17 -0
  25. data/samples/elaborate/calculator/model/command/command_history.rb +0 -0
  26. data/samples/elaborate/calculator/model/command/equals.rb +18 -0
  27. data/samples/elaborate/calculator/model/command/number.rb +20 -0
  28. data/samples/elaborate/calculator/model/command/operation.rb +27 -0
  29. data/samples/elaborate/calculator/model/command/operation/add.rb +15 -0
  30. data/samples/elaborate/calculator/model/command/operation/divide.rb +15 -0
  31. data/samples/elaborate/calculator/model/command/operation/multiply.rb +15 -0
  32. data/samples/elaborate/calculator/model/command/operation/subtract.rb +15 -0
  33. data/samples/elaborate/calculator/model/command/point.rb +20 -0
  34. data/samples/elaborate/calculator/model/presenter.rb +30 -0
  35. data/samples/elaborate/contact_manager.rb +1 -1
  36. data/samples/elaborate/login.rb +15 -13
  37. data/samples/elaborate/tetris.rb +6 -6
  38. data/samples/elaborate/tetris/view/high_score_dialog.rb +1 -1
  39. data/samples/elaborate/timer.rb +233 -0
  40. data/samples/elaborate/timer/alarm1.wav +0 -0
  41. data/samples/elaborate/timer/sounds/alarm1.wav +0 -0
  42. data/samples/elaborate/user_profile.rb +4 -2
  43. data/samples/elaborate/weather.rb +164 -0
  44. data/samples/hello/hello_canvas_animation_data_binding.rb +1 -1
  45. data/samples/hello/hello_cool_bar.rb +4 -4
  46. data/samples/hello/hello_custom_shell.rb +1 -1
  47. data/samples/hello/hello_table.rb +5 -5
  48. data/samples/hello/hello_text.rb +120 -0
  49. data/samples/hello/hello_tool_bar.rb +4 -4
  50. data/samples/hello/hello_tree.rb +11 -11
  51. metadata +20 -2
@@ -765,7 +765,7 @@ module Glimmer
765
765
 
766
766
  def can_add_listener?(underscored_listener_name)
767
767
  auto_exec do
768
- !self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
768
+ @swt_widget && !self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
769
769
  end
770
770
  end
771
771
 
@@ -838,7 +838,7 @@ module Glimmer
838
838
  widget_listener_proxy = nil
839
839
  safe_block = lambda { |*args| block.call(*args) unless @swt_widget.isDisposed }
840
840
  @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)
841
+ WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: @swt_widget.getListeners(event_type).last, event_type: event_type, swt_constant: swt_constant)
842
842
  end
843
843
  end
844
844
 
@@ -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
 
@@ -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 bind(@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
@@ -0,0 +1,27 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Operation < Command
5
+ def execute
6
+ if number1 && number2 && operation && !last_command.is_a?(Equals)
7
+ self.result = operation.calculate.to_s
8
+ self.number1 = self.result
9
+ else
10
+ self.result = last_result || '0'
11
+ self.operation = self
12
+ end
13
+ end
14
+
15
+ def calculate
16
+ calculation_result = BigDecimal.new(number1.to_s).send(operation_method, BigDecimal.new(number2.to_s)).to_f
17
+ calculation_result.to_s.match(/\.0+$/) ? calculation_result.to_i : calculation_result
18
+ end
19
+
20
+ # Subclasses must implement to indicate operation method on number (e.g. :+ for addition)
21
+ def operation_method
22
+ raise 'Not implemented!'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Operation < Command
5
+ class Add < Operation
6
+ keyword '+'
7
+
8
+ def operation_method
9
+ :+
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Operation < Command
5
+ class Divide < Operation
6
+ keywords '÷', '/'
7
+
8
+ def operation_method
9
+ :/
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Operation < Command
5
+ class Multiply < Operation
6
+ keywords '×', '*'
7
+
8
+ def operation_method
9
+ :*
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Operation < Command
5
+ class Subtract < Operation
6
+ keywords '−', '-'
7
+
8
+ def operation_method
9
+ :-
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ class Calculator
2
+ module Model
3
+ class Command
4
+ class Point < Command
5
+ keyword '.'
6
+
7
+ def execute
8
+ self.result = last_result.nil? || !last_command.is_a?(Number) ? '0.' : "#{last_result}."
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