glimmer-dsl-swt 4.18.4.2 → 4.18.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +84 -5072
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_COMMAND.md +591 -0
- data/docs/reference/GLIMMER_CONFIGURATION.md +183 -0
- data/docs/reference/GLIMMER_GIRB.md +30 -0
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +3276 -0
- data/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md +202 -0
- data/docs/reference/GLIMMER_SAMPLES.md +676 -0
- data/docs/reference/GLIMMER_STYLE_GUIDE.md +14 -0
- data/glimmer-dsl-swt.gemspec +16 -8
- data/lib/glimmer/dsl/swt/custom_widget_expression.rb +3 -3
- data/lib/glimmer/dsl/swt/exec_expression.rb +1 -1
- data/lib/glimmer/dsl/swt/observe_expression.rb +8 -5
- data/lib/glimmer/dsl/swt/pixel_expression.rb +38 -0
- data/lib/glimmer/dsl/swt/timer_exec_expression.rb +35 -0
- data/lib/glimmer/dsl/swt/widget_expression.rb +1 -0
- data/lib/glimmer/swt/custom/animation.rb +9 -8
- data/lib/glimmer/swt/custom/code_text.rb +24 -20
- data/lib/glimmer/swt/custom/drawable.rb +21 -5
- data/lib/glimmer/swt/custom/shape.rb +62 -57
- data/lib/glimmer/swt/display_proxy.rb +11 -10
- data/lib/glimmer/swt/properties.rb +35 -10
- data/lib/glimmer/swt/shell_proxy.rb +1 -1
- data/lib/glimmer/swt/widget_proxy.rb +16 -3
- data/lib/glimmer/ui/custom_widget.rb +17 -0
- data/samples/elaborate/mandelbrot_fractal.rb +103 -0
- data/samples/elaborate/meta_sample.rb +1 -1
- data/samples/elaborate/tetris.rb +20 -21
- data/samples/elaborate/tetris/view/playfield.rb +1 -1
- data/samples/elaborate/tetris/view/tetris_menu_bar.rb +13 -11
- data/samples/hello/hello_canvas_transform.rb +1 -1
- metadata +14 -6
- data/samples/elaborate/meta_sample/meta_sample_logo.png +0 -0
- data/samples/hello/hello_canvas_transform/hello_canvas_transform_image.png +0 -0
@@ -81,15 +81,15 @@ module Glimmer
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def async_exec(&block)
|
84
|
-
@swt_display.
|
84
|
+
@swt_display.asyncExec(&block)
|
85
85
|
end
|
86
86
|
|
87
87
|
def sync_exec(&block)
|
88
|
-
@swt_display.
|
88
|
+
@swt_display.syncExec(&block)
|
89
89
|
end
|
90
90
|
|
91
|
-
def timer_exec(&block)
|
92
|
-
@swt_display.
|
91
|
+
def timer_exec(delay_in_millis, &block)
|
92
|
+
@swt_display.timerExec(delay_in_millis, &block)
|
93
93
|
end
|
94
94
|
|
95
95
|
def on_widget_disposed(&block)
|
@@ -137,12 +137,13 @@ module Glimmer
|
|
137
137
|
add_swt_event_filter(constant_name, &block)
|
138
138
|
elsif observation_request.start_with?('on_')
|
139
139
|
event_name = observation_request.sub(/^on_/, '')
|
140
|
-
if OBSERVED_MENU_ITEMS.include?(event_name)
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
140
|
+
if OBSERVED_MENU_ITEMS.include?(event_name) && OS.mac?
|
141
|
+
system_menu = swt_display.getSystemMenu
|
142
|
+
menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
|
143
|
+
display_mac_event_registration = menu_item.addListener(SWTProxy[:Selection], &block)
|
144
|
+
# TODO enable this code and test on the Mac to ensure automatic cleanup of mac event registrations in custom widgets
|
145
|
+
# Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(display_mac_event_registration)
|
146
|
+
display_mac_event_registration
|
146
147
|
end
|
147
148
|
end
|
148
149
|
end
|
@@ -22,28 +22,53 @@
|
|
22
22
|
module Glimmer
|
23
23
|
module SWT
|
24
24
|
module Properties
|
25
|
+
class << self
|
26
|
+
def ruby_attribute_setter(attribute_name)
|
27
|
+
@ruby_attribute_setters ||= {}
|
28
|
+
@ruby_attribute_setters[attribute_name] ||= "#{normalized_attribute(attribute_name)}="
|
29
|
+
end
|
30
|
+
|
31
|
+
def attribute_setter(attribute_name)
|
32
|
+
@attribute_setters ||= {}
|
33
|
+
@attribute_setters[attribute_name] ||= "set#{normalized_attribute(attribute_name).camelcase(:upper)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def attribute_getter(attribute_name)
|
37
|
+
@attribute_getters ||= {}
|
38
|
+
@attribute_getters[attribute_name] ||= "get#{normalized_attribute(attribute_name).camelcase(:upper)}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def normalized_attribute(attribute_name)
|
42
|
+
@normalized_attributes ||= {}
|
43
|
+
if @normalized_attributes[attribute_name].nil?
|
44
|
+
attribute_name = attribute_name.to_s if attribute_name.is_a?(Symbol)
|
45
|
+
attribute_name = attribute_name.underscore unless attribute_name.downcase?
|
46
|
+
attribute_name = attribute_name.sub(/^get_/, '') if attribute_name.start_with?('get_')
|
47
|
+
attribute_name = attribute_name.sub(/^set_/, '') if attribute_name.start_with?('set_')
|
48
|
+
attribute_name = attribute_name.sub(/=$/, '') if attribute_name.end_with?('=')
|
49
|
+
@normalized_attributes[attribute_name] = attribute_name
|
50
|
+
end
|
51
|
+
@normalized_attributes[attribute_name]
|
52
|
+
end
|
53
|
+
alias ruby_attribute_getter normalized_attribute
|
54
|
+
end
|
55
|
+
|
25
56
|
def ruby_attribute_setter(attribute_name)
|
26
|
-
|
57
|
+
Glimmer::SWT::Properties.ruby_attribute_setter(attribute_name)
|
27
58
|
end
|
28
59
|
|
29
60
|
def attribute_setter(attribute_name)
|
30
|
-
|
61
|
+
Glimmer::SWT::Properties.attribute_setter(attribute_name)
|
31
62
|
end
|
32
63
|
|
33
64
|
def attribute_getter(attribute_name)
|
34
|
-
|
65
|
+
Glimmer::SWT::Properties.attribute_getter(attribute_name)
|
35
66
|
end
|
36
67
|
|
37
68
|
def normalized_attribute(attribute_name)
|
38
|
-
|
39
|
-
attribute_name = attribute_name.underscore unless attribute_name.downcase?
|
40
|
-
attribute_name = attribute_name.sub(/^get_/, '') if attribute_name.start_with?('get_')
|
41
|
-
attribute_name = attribute_name.sub(/^set_/, '') if attribute_name.start_with?('set_')
|
42
|
-
attribute_name = attribute_name.sub(/=$/, '') if attribute_name.end_with?('=')
|
43
|
-
attribute_name
|
69
|
+
Glimmer::SWT::Properties.normalized_attribute(attribute_name)
|
44
70
|
end
|
45
71
|
alias ruby_attribute_getter normalized_attribute
|
46
|
-
|
47
72
|
end
|
48
73
|
end
|
49
74
|
end
|
@@ -164,7 +164,7 @@ module Glimmer
|
|
164
164
|
minimum_size = @swt_widget.getMinimumSize
|
165
165
|
@swt_widget.setMinimumSize(bounds.width, bounds.height)
|
166
166
|
listener = on_control_resized { @swt_widget.setBounds(bounds) }
|
167
|
-
@swt_widget.
|
167
|
+
@swt_widget.layout(true, true)
|
168
168
|
@swt_widget.removeControlListener(listener.swt_listener)
|
169
169
|
@swt_widget.setMinimumSize(minimum_size)
|
170
170
|
elsif OS.linux?
|
@@ -50,6 +50,7 @@ module Glimmer
|
|
50
50
|
DEFAULT_STYLES = {
|
51
51
|
'arrow' => [:arrow],
|
52
52
|
'button' => [:push],
|
53
|
+
'canvas' => [:double_buffered],
|
53
54
|
'checkbox' => [:check],
|
54
55
|
'check' => [:check],
|
55
56
|
'drag_source' => [:drop_copy],
|
@@ -136,7 +137,8 @@ module Glimmer
|
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
139
|
-
attr_reader :parent_proxy, :swt_widget, :drag_source_proxy, :drop_target_proxy, :drag_source_style, :drag_source_transfer, :drop_target_transfer
|
140
|
+
attr_reader :parent_proxy, :swt_widget, :drag_source_proxy, :drop_target_proxy, :drag_source_style, :drag_source_transfer, :drop_target_transfer, :finished_add_content
|
141
|
+
alias finished_add_content? finished_add_content
|
140
142
|
|
141
143
|
# Initializes a new SWT Widget
|
142
144
|
#
|
@@ -169,6 +171,7 @@ module Glimmer
|
|
169
171
|
if respond_to?(:on_widget_disposed)
|
170
172
|
on_widget_disposed {
|
171
173
|
clear_shapes
|
174
|
+
deregister_shape_painting
|
172
175
|
}
|
173
176
|
end
|
174
177
|
end
|
@@ -178,11 +181,17 @@ module Glimmer
|
|
178
181
|
# No Op by default
|
179
182
|
end
|
180
183
|
|
181
|
-
# Subclasses may override to perform post add_content work
|
184
|
+
# Subclasses may override to perform post add_content work.
|
185
|
+
# Make sure its logic detects if it ran before since it could run multiple times
|
186
|
+
# when adding content multiple times post creation.
|
182
187
|
def post_add_content
|
183
188
|
# No Op by default
|
184
189
|
end
|
185
|
-
|
190
|
+
|
191
|
+
def finish_add_content!
|
192
|
+
@finished_add_content = true
|
193
|
+
end
|
194
|
+
|
186
195
|
def extract_args(underscored_widget_name, args)
|
187
196
|
@arg_extractor_mapping ||= {
|
188
197
|
'menu_item' => lambda do |args|
|
@@ -544,6 +553,10 @@ module Glimmer
|
|
544
553
|
DisplayProxy.instance.sync_exec(&block)
|
545
554
|
end
|
546
555
|
|
556
|
+
def timer_exec(delay_in_millis, &block)
|
557
|
+
DisplayProxy.instance.timer_exec(delay_in_millis, &block)
|
558
|
+
end
|
559
|
+
|
547
560
|
def has_style?(style)
|
548
561
|
comparison = interpret_style(style)
|
549
562
|
(@swt_widget.style & comparison) == comparison
|
@@ -158,11 +158,17 @@ module Glimmer
|
|
158
158
|
def after_body(&block)
|
159
159
|
@after_body_block = block
|
160
160
|
end
|
161
|
+
|
162
|
+
# Current custom widgets being rendered. Useful to yoke all observers evaluated during rendering of their custom widgets for automatical disposal on_widget_disposed
|
163
|
+
def current_custom_widgets
|
164
|
+
@current_custom_widgets ||= []
|
165
|
+
end
|
161
166
|
end
|
162
167
|
|
163
168
|
attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
|
164
169
|
|
165
170
|
def initialize(parent, *swt_constants, options, &content)
|
171
|
+
Glimmer::UI::CustomWidget.current_custom_widgets << self
|
166
172
|
@parent_proxy = @parent = parent
|
167
173
|
@parent_proxy = @parent&.get_data('proxy') if @parent.respond_to?(:get_data) && @parent.get_data('proxy')
|
168
174
|
@swt_style = SWT::SWTProxy[*swt_constants]
|
@@ -177,6 +183,9 @@ module Glimmer
|
|
177
183
|
@swt_widget = @body_root.swt_widget
|
178
184
|
@swt_widget.set_data('custom_widget', self)
|
179
185
|
execute_hook('after_body')
|
186
|
+
@dispose_listener_registration = @body_root.on_widget_disposed do
|
187
|
+
observer_registrations.each(&:deregister)
|
188
|
+
end
|
180
189
|
end
|
181
190
|
|
182
191
|
# Subclasses may override to perform post initialization work on an added child
|
@@ -184,6 +193,10 @@ module Glimmer
|
|
184
193
|
# No Op by default
|
185
194
|
end
|
186
195
|
|
196
|
+
def observer_registrations
|
197
|
+
@observer_registrations ||= []
|
198
|
+
end
|
199
|
+
|
187
200
|
def can_handle_observation_request?(observation_request)
|
188
201
|
observation_request = observation_request.to_s
|
189
202
|
result = false
|
@@ -273,6 +286,10 @@ module Glimmer
|
|
273
286
|
SWT::DisplayProxy.instance.sync_exec(&block)
|
274
287
|
end
|
275
288
|
|
289
|
+
def timer_exec(delay_in_millis, &block)
|
290
|
+
SWT::DisplayProxy.instance.timer_exec(delay_in_millis, &block)
|
291
|
+
end
|
292
|
+
|
276
293
|
# Returns content block if used as an attribute reader (no args)
|
277
294
|
# Otherwise, if a block is passed, it adds it as content to this custom widget
|
278
295
|
def content(&block)
|
@@ -0,0 +1,103 @@
|
|
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 'complex'
|
23
|
+
require 'bigdecimal'
|
24
|
+
require 'concurrent-ruby'
|
25
|
+
|
26
|
+
# Mandelbrot implementation
|
27
|
+
# Courtesy of open-source code at:
|
28
|
+
# https://github.com/gotbadger/ruby-mandelbrot
|
29
|
+
class Mandelbrot
|
30
|
+
|
31
|
+
attr_accessor :max_iterations
|
32
|
+
|
33
|
+
def initialize(max_iterations)
|
34
|
+
@max_iterations = max_iterations
|
35
|
+
end
|
36
|
+
|
37
|
+
def calculate_all(x_array, y_array)
|
38
|
+
thread_pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count)
|
39
|
+
width = x_array.size
|
40
|
+
height = y_array.size
|
41
|
+
pixel_rows_array = Concurrent::Array.new(height)
|
42
|
+
height.times do |y|
|
43
|
+
pixel_rows_array[y] ||= Concurrent::Array.new(width)
|
44
|
+
width.times do |x|
|
45
|
+
thread_pool.post do
|
46
|
+
pixel_rows_array[y][x] = calculate(x_array[x], y_array[y]).last
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
thread_pool.shutdown
|
51
|
+
thread_pool.wait_for_termination
|
52
|
+
pixel_rows_array
|
53
|
+
end
|
54
|
+
|
55
|
+
def calculate(x,y)
|
56
|
+
base_case = [Complex(x,y), 0]
|
57
|
+
Array.new(max_iterations, base_case).inject(base_case) do |prev ,base|
|
58
|
+
z, itr = prev
|
59
|
+
c, _ = base
|
60
|
+
val = z*z + c
|
61
|
+
itr += 1 unless val.abs < 2
|
62
|
+
[val, itr]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class MandelbrotFractal
|
68
|
+
include Glimmer::UI::CustomShell
|
69
|
+
|
70
|
+
before_body {
|
71
|
+
@colors = [[0, 0, 0]] + 40.times.map { |i| [255 - i*5, 255 - i*5, 55 + i*5] }
|
72
|
+
@colors = @colors.map {|color_data| rgb(*color_data).swt_color}
|
73
|
+
mandelbrot = Mandelbrot.new(@colors.size - 1)
|
74
|
+
@y_array = (1.0).step(-1,-0.0030).to_a
|
75
|
+
@x_array = (-2.0).step(0.5,0.0030).to_a
|
76
|
+
@height = @y_array.size
|
77
|
+
@width = @x_array.size
|
78
|
+
@pixel_rows_array = mandelbrot.calculate_all(@x_array, @y_array)
|
79
|
+
@image = Image.new(display.swt_display, @width, @height)
|
80
|
+
image_gc = org.eclipse.swt.graphics.GC.new(@image)
|
81
|
+
@height.times { |y|
|
82
|
+
@width.times { |x|
|
83
|
+
new_foreground = @colors[@pixel_rows_array[y][x]]
|
84
|
+
image_gc.foreground = @current_foreground = new_foreground unless new_foreground == @current_foreground
|
85
|
+
image_gc.draw_point x, y
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
body {
|
91
|
+
shell {
|
92
|
+
text 'Mandelbrot Fractal'
|
93
|
+
minimum_size @width, @height + 12
|
94
|
+
image @image
|
95
|
+
|
96
|
+
canvas {
|
97
|
+
image(@image, 0, 0)
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
MandelbrotFractal.launch
|
@@ -203,7 +203,7 @@ class MetaSampleApplication
|
|
203
203
|
shell(:fill_screen) {
|
204
204
|
minimum_size 1280, 768
|
205
205
|
text 'Glimmer Meta-Sample (The Sample of Samples)'
|
206
|
-
image File.expand_path('
|
206
|
+
image File.expand_path('../../icons/scaffold_app.png', __dir__)
|
207
207
|
|
208
208
|
sash_form {
|
209
209
|
composite {
|
data/samples/elaborate/tetris.rb
CHANGED
@@ -51,11 +51,12 @@ class Tetris
|
|
51
51
|
end
|
52
52
|
|
53
53
|
Display.app_name = 'Glimmer Tetris'
|
54
|
+
|
54
55
|
display {
|
55
|
-
@
|
56
|
+
@keyboard_down_listener = on_swt_keydown { |key_event|
|
56
57
|
case key_event.keyCode
|
57
58
|
when swt(:arrow_down), 's'.bytes.first
|
58
|
-
game.down!
|
59
|
+
game.down! if OS.mac?
|
59
60
|
when swt(:arrow_up)
|
60
61
|
case game.up_arrow_action
|
61
62
|
when :instant_down
|
@@ -69,7 +70,7 @@ class Tetris
|
|
69
70
|
game.left!
|
70
71
|
when swt(:arrow_right), 'd'.bytes.first
|
71
72
|
game.right!
|
72
|
-
when swt(:shift), swt(:alt)
|
73
|
+
when swt(:shift), swt(:alt)
|
73
74
|
if key_event.keyLocation == swt(:right) # right shift key
|
74
75
|
game.rotate!(:right)
|
75
76
|
elsif key_event.keyLocation == swt(:left) # left shift key
|
@@ -77,6 +78,16 @@ class Tetris
|
|
77
78
|
end
|
78
79
|
end
|
79
80
|
}
|
81
|
+
|
82
|
+
# invoke game.down! on keyup with Windows/Linux since they seem to group-render similar events, preventing intermediate renders (causing invisiblity while holding keys)
|
83
|
+
if !OS.mac?
|
84
|
+
@keyboard_up_listener = on_swt_keyup { |key_event|
|
85
|
+
case key_event.keyCode
|
86
|
+
when swt(:arrow_down), 's'.bytes.first
|
87
|
+
game.down!
|
88
|
+
end
|
89
|
+
}
|
90
|
+
end
|
80
91
|
|
81
92
|
# if running in app mode, set the Mac app about dialog (ignored in platforms)
|
82
93
|
@about_observer = on_about {
|
@@ -128,10 +139,6 @@ class Tetris
|
|
128
139
|
score_lane(game: game, block_size: BLOCK_SIZE) {
|
129
140
|
layout_data(:fill, :fill, true, true)
|
130
141
|
}
|
131
|
-
|
132
|
-
on_widget_disposed {
|
133
|
-
deregister_observers
|
134
|
-
}
|
135
142
|
}
|
136
143
|
}
|
137
144
|
|
@@ -148,26 +155,26 @@ class Tetris
|
|
148
155
|
color = colored ? color(([:white] + Model::Tetromino::LETTER_COLORS.values).sample) : color(:white)
|
149
156
|
x = column * icon_block_size
|
150
157
|
y = row * icon_block_size
|
151
|
-
rectangle(x, y, icon_block_size, icon_block_size
|
158
|
+
rectangle(x, y, icon_block_size, icon_block_size) {
|
152
159
|
background color
|
153
160
|
}
|
154
|
-
polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size
|
161
|
+
polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
|
155
162
|
background rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
|
156
163
|
}
|
157
|
-
polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size
|
164
|
+
polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
|
158
165
|
background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
|
159
166
|
}
|
160
|
-
polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size
|
167
|
+
polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
|
161
168
|
background rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
|
162
169
|
}
|
163
|
-
polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size
|
170
|
+
polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
|
164
171
|
background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
|
165
172
|
}
|
166
173
|
}
|
167
174
|
}
|
168
175
|
}
|
169
176
|
end
|
170
|
-
|
177
|
+
|
171
178
|
def start_moving_tetrominos_down
|
172
179
|
Thread.new do
|
173
180
|
@mutex.synchronize do
|
@@ -195,14 +202,6 @@ class Tetris
|
|
195
202
|
message "Glimmer Tetris\n\nGlimmer DSL for SWT Sample\n\nCopyright (c) 2007-2021 Andy Maleh"
|
196
203
|
}.open
|
197
204
|
end
|
198
|
-
|
199
|
-
def deregister_observers
|
200
|
-
@show_high_scores_observer&.deregister
|
201
|
-
@game_over_observer&.deregister
|
202
|
-
@keyboard_listener&.deregister
|
203
|
-
@about_observer&.deregister
|
204
|
-
@quit_observer&.deregister
|
205
|
-
end
|
206
205
|
end
|
207
206
|
|
208
207
|
Tetris.launch
|
@@ -23,6 +23,8 @@ class Tetris
|
|
23
23
|
module View
|
24
24
|
class TetrisMenuBar
|
25
25
|
include Glimmer::UI::CustomWidget
|
26
|
+
|
27
|
+
COMMAND_KEY = OS.mac? ? :command : :ctrl
|
26
28
|
|
27
29
|
options :game
|
28
30
|
|
@@ -34,7 +36,7 @@ class Tetris
|
|
34
36
|
menu_item {
|
35
37
|
text '&Start'
|
36
38
|
enabled bind(game, :game_over)
|
37
|
-
accelerator
|
39
|
+
accelerator COMMAND_KEY, :s
|
38
40
|
|
39
41
|
on_widget_selected {
|
40
42
|
game.start!
|
@@ -42,14 +44,14 @@ class Tetris
|
|
42
44
|
}
|
43
45
|
menu_item(:check) {
|
44
46
|
text '&Pause'
|
45
|
-
accelerator
|
47
|
+
accelerator COMMAND_KEY, :p
|
46
48
|
enabled bind(game, :game_over, on_read: :!) {|value| value && !game.show_high_scores}
|
47
49
|
enabled bind(game, :show_high_scores, on_read: :!) {|value| value && !game.game_over}
|
48
50
|
selection bind(game, :paused)
|
49
51
|
}
|
50
52
|
menu_item {
|
51
53
|
text '&Restart'
|
52
|
-
accelerator
|
54
|
+
accelerator COMMAND_KEY, :r
|
53
55
|
|
54
56
|
on_widget_selected {
|
55
57
|
game.restart!
|
@@ -58,7 +60,7 @@ class Tetris
|
|
58
60
|
menu_item(:separator)
|
59
61
|
menu_item {
|
60
62
|
text '&Exit'
|
61
|
-
accelerator
|
63
|
+
accelerator COMMAND_KEY, :x
|
62
64
|
|
63
65
|
on_widget_selected {
|
64
66
|
parent_proxy.close
|
@@ -73,12 +75,12 @@ class Tetris
|
|
73
75
|
text '&High Scores'
|
74
76
|
menu_item(:check) {
|
75
77
|
text '&Show'
|
76
|
-
accelerator
|
78
|
+
accelerator COMMAND_KEY, :shift, :h
|
77
79
|
selection bind(game, :show_high_scores)
|
78
80
|
}
|
79
81
|
menu_item {
|
80
82
|
text '&Clear'
|
81
|
-
accelerator
|
83
|
+
accelerator COMMAND_KEY, :shift, :c
|
82
84
|
|
83
85
|
on_widget_selected {
|
84
86
|
game.clear_high_scores!
|
@@ -91,24 +93,24 @@ class Tetris
|
|
91
93
|
text '&Options'
|
92
94
|
menu_item(:check) {
|
93
95
|
text '&Beeping'
|
94
|
-
accelerator
|
96
|
+
accelerator COMMAND_KEY, :b
|
95
97
|
selection bind(game, :beeping)
|
96
98
|
}
|
97
99
|
menu {
|
98
100
|
text 'Up Arrow'
|
99
101
|
menu_item(:radio) {
|
100
102
|
text '&Instant Down'
|
101
|
-
accelerator
|
103
|
+
accelerator COMMAND_KEY, :shift, :i
|
102
104
|
selection bind(game, :instant_down_on_up, computed_by: :up_arrow_action)
|
103
105
|
}
|
104
106
|
menu_item(:radio) {
|
105
107
|
text 'Rotate &Right'
|
106
|
-
accelerator
|
108
|
+
accelerator COMMAND_KEY, :shift, :r
|
107
109
|
selection bind(game, :rotate_right_on_up, computed_by: :up_arrow_action)
|
108
110
|
}
|
109
111
|
menu_item(:radio) {
|
110
112
|
text 'Rotate &Left'
|
111
|
-
accelerator
|
113
|
+
accelerator COMMAND_KEY, :shift, :l
|
112
114
|
selection bind(game, :rotate_left_on_up, computed_by: :up_arrow_action)
|
113
115
|
}
|
114
116
|
}
|
@@ -119,7 +121,7 @@ class Tetris
|
|
119
121
|
|
120
122
|
menu_item {
|
121
123
|
text '&About'
|
122
|
-
accelerator
|
124
|
+
accelerator COMMAND_KEY, :shift, :a
|
123
125
|
|
124
126
|
on_widget_selected {
|
125
127
|
parent_custom_shell&.show_about_dialog
|