glimmer-dsl-swt 4.20.0.1 → 4.20.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +17 -13
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +10 -7
- data/docs/reference/GLIMMER_SAMPLES.md +168 -49
- data/docs/reference/GLIMMER_STYLE_GUIDE.md +4 -3
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/glimmer/data_binding/shine.rb +3 -1
- data/lib/glimmer/data_binding/table_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/widget_expression.rb +2 -0
- data/lib/glimmer/dsl/swt/widget_listener_expression.rb +3 -3
- data/lib/glimmer/rake_task/scaffold.rb +0 -2
- data/lib/glimmer/swt/combo_proxy.rb +48 -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/tool_bar_proxy.rb +51 -0
- data/lib/glimmer/swt/widget_proxy.rb +8 -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/login.rb +15 -13
- data/samples/elaborate/tetris.rb +4 -4
- data/samples/elaborate/tetris/model/game.rb +0 -3
- 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_cool_bar.rb +147 -0
- data/samples/hello/hello_layout.rb +6 -2
- data/samples/hello/hello_shell.rb +205 -0
- data/samples/hello/hello_table.rb +5 -5
- data/samples/hello/hello_text.rb +120 -0
- data/samples/hello/hello_tool_bar.rb +143 -0
- metadata +25 -2
@@ -7,8 +7,9 @@
|
|
7
7
|
- Widget properties are declared with underscored lowercase versions of the SWT properties
|
8
8
|
- Widget property declarations always have arguments and never take a block
|
9
9
|
- Widget property arguments are never wrapped inside parentheses
|
10
|
-
- Widget listeners are always declared starting with `on_` prefix and affixing listener event method name afterwards in underscored lowercase form
|
10
|
+
- Widget listeners are always declared starting with `on_` prefix and affixing listener event method name afterwards in underscored lowercase form. Their multi-line blocks rely on the `do; end` style.
|
11
11
|
- Widget listeners are always followed by a block using curly braces (Only when declared in DSL. When invoked on widget object directly outside of GUI declarations, standard Ruby conventions apply)
|
12
12
|
- Data-binding is done via `bind` keyword, which always takes arguments wrapped in parentheses
|
13
|
-
- Custom widget body
|
14
|
-
- Custom widgets receive additional arguments
|
13
|
+
- Custom widget `body`, `before_body`, and `after_body` blocks open their blocks and close them with curly braces.
|
14
|
+
- Custom widgets receive additional keyword arguments called options, which come after the SWT styles.
|
15
|
+
- Pure logic multi-line blocks that do not constitute GUI DSL view elements (such as `Thread.new`, `loop`, `each` and `observe` blocks) rely on the `do; end` style to clearly separate logic code from view code.
|
data/glimmer-dsl-swt.gemspec
CHANGED
Binary file
|
@@ -33,8 +33,10 @@ module Glimmer
|
|
33
33
|
|
34
34
|
def <=>(other)
|
35
35
|
if other.is_a?(Array)
|
36
|
+
args_clone = other.clone
|
37
|
+
@parent.editable = true if @parent.is_a?(Glimmer::SWT::TableProxy) # TODO consider a polymorphic way to perform this
|
36
38
|
@parent.content {
|
37
|
-
send(@parent_attribute, bind(*
|
39
|
+
send(@parent_attribute, bind(*args_clone))
|
38
40
|
}
|
39
41
|
else # || other.is_a?(Hash) # TODO support hash e.g. {model: model_obj, attribute: :some_attribute, more-options...}
|
40
42
|
original_compare(other)
|
@@ -34,11 +34,11 @@ module Glimmer
|
|
34
34
|
include_package 'org.eclipse.swt'
|
35
35
|
include_package 'org.eclipse.swt.widgets'
|
36
36
|
|
37
|
-
def initialize(parent, model_binding, column_properties)
|
37
|
+
def initialize(parent, model_binding, column_properties = nil)
|
38
38
|
@table = parent
|
39
39
|
@model_binding = model_binding
|
40
40
|
@read_only_sort = @model_binding.binding_options[:read_only_sort]
|
41
|
-
@column_properties = column_properties
|
41
|
+
@column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
|
42
42
|
if @table.respond_to?(:column_properties=)
|
43
43
|
@table.column_properties = @column_properties
|
44
44
|
else # assume custom widget
|
@@ -29,12 +29,15 @@ module Glimmer
|
|
29
29
|
module DSL
|
30
30
|
module SWT
|
31
31
|
class ShineDataBindingExpression < Expression
|
32
|
+
include_package 'org.eclipse.swt.widgets'
|
33
|
+
|
32
34
|
def can_interpret?(parent, keyword, *args, &block)
|
33
35
|
args.size == 0 and
|
34
36
|
block.nil? and
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
(
|
38
|
+
(parent.respond_to?(:set_attribute) and parent.respond_to?(:has_attribute?) and parent.has_attribute?(keyword)) or
|
39
|
+
(parent.respond_to?(:swt_widget) and parent.swt_widget.is_a?(Table))
|
40
|
+
) and
|
38
41
|
!parent.is_a?(Glimmer::UI::CustomWidget) and
|
39
42
|
!parent.is_a?(Glimmer::UI::CustomShape) and
|
40
43
|
!(parent.respond_to?(:swt_widget) && parent.swt_widget.class == org.eclipse.swt.widgets.Canvas && keyword == 'image')
|
@@ -35,10 +35,10 @@ module Glimmer
|
|
35
35
|
block.nil? and
|
36
36
|
parent.respond_to?(:swt_widget) and
|
37
37
|
parent.swt_widget.is_a?(Table) and
|
38
|
-
args.size
|
38
|
+
args.size.between?(1, 2) and
|
39
39
|
args[0].is_a?(DataBinding::ModelBinding) and
|
40
40
|
args[0].evaluate_property.is_a?(Array) and
|
41
|
-
args[1].is_a?(Array)
|
41
|
+
(args[1].nil? or args[1].is_a?(Array))
|
42
42
|
end
|
43
43
|
|
44
44
|
def interpret(parent, keyword, *args, &block)
|
@@ -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
|
@@ -441,8 +441,6 @@ module Glimmer
|
|
441
441
|
require '#{file_name(app_name)}/view/app_view'
|
442
442
|
|
443
443
|
class #{class_name(app_name)}
|
444
|
-
include Glimmer
|
445
|
-
|
446
444
|
APP_ROOT = File.expand_path('../..', __FILE__)
|
447
445
|
VERSION = File.read(File.join(APP_ROOT, 'VERSION'))
|
448
446
|
LICENSE = File.read(File.join(APP_ROOT, 'LICENSE.txt'))
|
@@ -0,0 +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
|
+
|
22
|
+
require 'glimmer/swt/widget_proxy'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module SWT
|
26
|
+
# Proxy for org.eclipse.swt.widgets.Combo
|
27
|
+
#
|
28
|
+
# Follows the Proxy Design Pattern
|
29
|
+
class ComboProxy < WidgetProxy
|
30
|
+
attr_accessor :tool_item_proxy, :swt_tool_item
|
31
|
+
|
32
|
+
def initialize(*init_args, &block)
|
33
|
+
super
|
34
|
+
self.tool_item_proxy = WidgetProxy.new("tool_item", parent_proxy, [:separator]) if parent_proxy.swt_widget.is_a?(ToolBar)
|
35
|
+
self.swt_tool_item = tool_item_proxy&.swt_widget
|
36
|
+
end
|
37
|
+
|
38
|
+
def post_add_content
|
39
|
+
if self.tool_item_proxy
|
40
|
+
self.swt_widget.pack
|
41
|
+
self.tool_item_proxy.text = 'filler' # text seems needed (any text works)
|
42
|
+
self.tool_item_proxy.width = swt_widget.size.x
|
43
|
+
self.tool_item_proxy.control = swt_widget
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -42,7 +42,7 @@ module Glimmer
|
|
42
42
|
|
43
43
|
OBSERVED_MENU_ITEMS = ['about', 'preferences', 'quit']
|
44
44
|
|
45
|
-
class
|
45
|
+
class ConcreteListener
|
46
46
|
include org.eclipse.swt.widgets.Listener
|
47
47
|
|
48
48
|
def initialize(&listener_block)
|
@@ -194,15 +194,17 @@ module Glimmer
|
|
194
194
|
observation_request = observation_request.to_s
|
195
195
|
if observation_request.start_with?('on_swt_')
|
196
196
|
constant_name = observation_request.sub(/^on_swt_/, '')
|
197
|
-
add_swt_event_filter(constant_name, &block)
|
197
|
+
swt_event_reg = add_swt_event_filter(constant_name, &block)
|
198
|
+
Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(swt_event_reg)
|
199
|
+
swt_event_reg
|
198
200
|
elsif observation_request.start_with?('on_')
|
199
201
|
event_name = observation_request.sub(/^on_/, '')
|
200
202
|
if OBSERVED_MENU_ITEMS.include?(event_name) && OS.mac?
|
201
203
|
system_menu = swt_display.getSystemMenu
|
202
204
|
menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
|
203
|
-
|
204
|
-
|
205
|
-
|
205
|
+
listener = ConcreteListener.new(&block)
|
206
|
+
display_mac_event_registration = menu_item.addListener(SWTProxy[:Selection], listener)
|
207
|
+
Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(display_mac_event_registration)
|
206
208
|
display_mac_event_registration
|
207
209
|
end
|
208
210
|
end
|
@@ -210,15 +212,16 @@ module Glimmer
|
|
210
212
|
|
211
213
|
def add_swt_event_filter(swt_constant, &block)
|
212
214
|
event_type = SWTProxy[swt_constant]
|
213
|
-
|
215
|
+
swt_listener = ConcreteListener.new(&block)
|
216
|
+
@swt_display.addFilter(event_type, swt_listener)
|
214
217
|
#WidgetListenerProxy.new(@swt_display.getListeners(event_type).last)
|
215
218
|
WidgetListenerProxy.new(
|
216
219
|
swt_display: @swt_display,
|
217
220
|
event_type: event_type,
|
218
221
|
filter: true,
|
219
|
-
swt_listener:
|
222
|
+
swt_listener: swt_listener,
|
220
223
|
widget_add_listener_method: 'addFilter',
|
221
|
-
swt_listener_class:
|
224
|
+
swt_listener_class: ConcreteListener,
|
222
225
|
swt_listener_method: 'handleEvent'
|
223
226
|
)
|
224
227
|
end
|
@@ -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
|
@@ -250,19 +250,13 @@ module Glimmer
|
|
250
250
|
alias editable? editable
|
251
251
|
|
252
252
|
def initialize(underscored_widget_name, parent, args)
|
253
|
-
|
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
|
-
|
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
|
@@ -0,0 +1,51 @@
|
|
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
|
+
|
22
|
+
require 'glimmer/swt/widget_proxy'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module SWT
|
26
|
+
# Proxy for org.eclipse.swt.widgets.ToolBarProxy
|
27
|
+
#
|
28
|
+
# Follows the Proxy Design Pattern
|
29
|
+
class ToolBarProxy < WidgetProxy
|
30
|
+
attr_accessor :cool_item_proxy, :swt_cool_item
|
31
|
+
|
32
|
+
def initialize(*init_args, &block)
|
33
|
+
super
|
34
|
+
self.cool_item_proxy = WidgetProxy.new("cool_item", parent_proxy, []) if parent_proxy.swt_widget.is_a?(CoolBar)
|
35
|
+
self.swt_cool_item = cool_item_proxy&.swt_widget
|
36
|
+
end
|
37
|
+
|
38
|
+
def post_add_content
|
39
|
+
apply_preferred_size if cool_item_proxy
|
40
|
+
end
|
41
|
+
|
42
|
+
def apply_preferred_size
|
43
|
+
swt_widget.pack
|
44
|
+
size = swt_widget.size
|
45
|
+
cool_item_proxy.control = swt_widget
|
46
|
+
preferred = swt_cool_item.computeSize(size.x, size.y)
|
47
|
+
swt_cool_item.setPreferredSize(preferred)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -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
|
|
@@ -1006,6 +1006,12 @@ module Glimmer
|
|
1006
1006
|
image: lambda do |*value|
|
1007
1007
|
ImageProxy.create(*value).swt_image
|
1008
1008
|
end,
|
1009
|
+
disabled_image: lambda do |*value|
|
1010
|
+
ImageProxy.create(*value).swt_image
|
1011
|
+
end,
|
1012
|
+
hot_image: lambda do |*value|
|
1013
|
+
ImageProxy.create(*value).swt_image
|
1014
|
+
end,
|
1009
1015
|
images: lambda do |array|
|
1010
1016
|
array.to_a.map do |value|
|
1011
1017
|
ImageProxy.create(value).swt_image
|
@@ -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
|