glimmer-dsl-swt 4.20.0.3 → 4.20.2.1

Sign up to get free protection for your applications and to get access to all the features.
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