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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/README.md +12 -6
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_SAMPLES.md +34 -0
- data/docs/reference/GLIMMER_STYLE_GUIDE.md +4 -3
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/glimmer/data_binding/shine.rb +5 -1
- data/lib/glimmer/data_binding/table_items_binding.rb +2 -2
- data/lib/glimmer/data_binding/tree_items_binding.rb +2 -2
- data/lib/glimmer/dsl/swt/shine_data_binding_expression.rb +6 -3
- data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +2 -2
- data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +17 -12
- data/lib/glimmer/dsl/swt/widget_listener_expression.rb +3 -3
- data/lib/glimmer/swt/custom/animation.rb +6 -0
- data/lib/glimmer/swt/display_proxy.rb +11 -8
- data/lib/glimmer/swt/proxy_properties.rb +2 -1
- data/lib/glimmer/swt/table_proxy.rb +15 -8
- data/lib/glimmer/swt/widget_proxy.rb +2 -2
- data/lib/glimmer/ui/custom_shell.rb +3 -3
- data/lib/glimmer/ui/custom_widget.rb +5 -2
- data/samples/elaborate/calculator.rb +116 -0
- data/samples/elaborate/calculator/model/command.rb +105 -0
- data/samples/elaborate/calculator/model/command/all_clear.rb +17 -0
- data/samples/elaborate/calculator/model/command/command_history.rb +0 -0
- data/samples/elaborate/calculator/model/command/equals.rb +18 -0
- data/samples/elaborate/calculator/model/command/number.rb +20 -0
- data/samples/elaborate/calculator/model/command/operation.rb +27 -0
- data/samples/elaborate/calculator/model/command/operation/add.rb +15 -0
- data/samples/elaborate/calculator/model/command/operation/divide.rb +15 -0
- data/samples/elaborate/calculator/model/command/operation/multiply.rb +15 -0
- data/samples/elaborate/calculator/model/command/operation/subtract.rb +15 -0
- data/samples/elaborate/calculator/model/command/point.rb +20 -0
- data/samples/elaborate/calculator/model/presenter.rb +30 -0
- data/samples/elaborate/contact_manager.rb +1 -1
- data/samples/elaborate/login.rb +15 -13
- data/samples/elaborate/tetris.rb +6 -6
- data/samples/elaborate/tetris/view/high_score_dialog.rb +1 -1
- data/samples/elaborate/timer.rb +233 -0
- data/samples/elaborate/timer/alarm1.wav +0 -0
- data/samples/elaborate/timer/sounds/alarm1.wav +0 -0
- data/samples/elaborate/user_profile.rb +4 -2
- data/samples/elaborate/weather.rb +164 -0
- data/samples/hello/hello_canvas_animation_data_binding.rb +1 -1
- data/samples/hello/hello_cool_bar.rb +4 -4
- data/samples/hello/hello_custom_shell.rb +1 -1
- data/samples/hello/hello_table.rb +5 -5
- data/samples/hello/hello_text.rb +120 -0
- data/samples/hello/hello_tool_bar.rb +4 -4
- data/samples/hello/hello_tree.rb +11 -11
- 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
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
190
|
-
|
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
|
File without changes
|
@@ -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,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
|