glimmer-dsl-libui 0.4.19 → 0.5.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 +22 -0
- data/LICENSE.txt +1 -1
- data/README.md +452 -52
- data/VERSION +1 -1
- data/bin/girb_runner.rb +1 -1
- data/examples/area_based_custom_controls.rb +282 -0
- data/examples/snake/model/game.rb +18 -1
- data/examples/snake.rb +6 -2
- data/examples/snake2.rb +6 -2
- data/examples/tetris/model/block.rb +1 -1
- data/examples/tetris/model/game.rb +26 -24
- data/examples/tetris/model/past_game.rb +1 -1
- data/examples/tetris/model/tetromino.rb +1 -1
- data/examples/tetris.rb +51 -20
- data/examples/tic_tac_toe/board.rb +1 -1
- data/examples/tic_tac_toe/cell.rb +1 -1
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/bind_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/control_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/data_binding_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/dsl.rb +1 -1
- data/lib/glimmer/dsl/libui/file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/listener_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/observe_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/open_file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/operation_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/property_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/save_file_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/shape_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/shine_data_binding_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/string_expression.rb +1 -1
- data/lib/glimmer/dsl/libui/tab_item_expression.rb +1 -1
- data/lib/glimmer/fiddle_consumer.rb +1 -1
- data/lib/glimmer/libui/attributed_string.rb +1 -1
- data/lib/glimmer/libui/control_proxy/area_proxy/scrolling_area_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box/horizontal_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box/vertical_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/box.rb +2 -1
- data/lib/glimmer/libui/control_proxy/button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/checkbox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/button_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/checkbox_text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/image_text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/progress_bar_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/text_color_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column/text_column_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/date_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy/time_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/dual_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/editable_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/enableable_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy/password_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy/search_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/form_proxy.rb +2 -1
- data/lib/glimmer/libui/control_proxy/grid_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/group_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/image_part_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/image_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/label_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/matrix_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/about_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/preferences_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/quit_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/separator_menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/menu_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box/msg_box_error_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box/msg_box_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/message_box.rb +1 -1
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy/non_wrapping_multiline_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/open_type_features_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/tab_item_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/text_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/transformable.rb +1 -1
- data/lib/glimmer/libui/control_proxy/triple_column.rb +1 -1
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy.rb +2 -1
- data/lib/glimmer/libui/data_bindable.rb +1 -1
- data/lib/glimmer/libui/parent.rb +1 -1
- data/lib/glimmer/libui/shape/arc.rb +1 -1
- data/lib/glimmer/libui/shape/bezier.rb +1 -1
- data/lib/glimmer/libui/shape/circle.rb +1 -1
- data/lib/glimmer/libui/shape/figure.rb +1 -1
- data/lib/glimmer/libui/shape/line.rb +1 -1
- data/lib/glimmer/libui/shape/polybezier.rb +1 -1
- data/lib/glimmer/libui/shape/polygon.rb +1 -1
- data/lib/glimmer/libui/shape/polyline.rb +1 -1
- data/lib/glimmer/libui/shape/rectangle.rb +8 -3
- data/lib/glimmer/libui/shape/square.rb +10 -3
- data/lib/glimmer/libui/shape.rb +37 -1
- data/lib/glimmer/libui.rb +1 -1
- data/lib/glimmer-dsl-libui.rb +2 -1
- metadata +27 -11
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/bin/girb_runner.rb
CHANGED
@@ -0,0 +1,282 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
class AreaBasedCustomControls
|
4
|
+
include Glimmer
|
5
|
+
|
6
|
+
attr_accessor :label_width, :label_height, :label_font_descriptor,
|
7
|
+
:label_text_color, :label_background_fill, :label_border_stroke,
|
8
|
+
:label_text_x, :label_text_y,
|
9
|
+
:button_width, :button_height, :button_font_descriptor,
|
10
|
+
:button_text_color, :button_background_fill, :button_border_stroke,
|
11
|
+
:button_text_x, :button_text_y
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
self.label_width = 335
|
15
|
+
self.label_height = 50
|
16
|
+
self.label_font_descriptor = {family: OS.linux? ? 'Monospace Bold Italic' : 'Courier New', size: 16, weight: :bold, italic: :italic}
|
17
|
+
self.label_text_color = :red
|
18
|
+
self.label_background_fill = :yellow
|
19
|
+
self.label_border_stroke = :limegreen
|
20
|
+
|
21
|
+
self.button_width = 150
|
22
|
+
self.button_height = 50
|
23
|
+
self.button_font_descriptor = {family: OS.linux? ? 'Monospace Bold Italic' : 'Courier New', size: 36, weight: OS.linux? ? :normal : :bold, italic: :italic}
|
24
|
+
self.button_text_color = :green
|
25
|
+
self.button_background_fill = :yellow
|
26
|
+
self.button_border_stroke = :limegreen
|
27
|
+
end
|
28
|
+
|
29
|
+
def rebuild_text_label
|
30
|
+
@text_label.destroy
|
31
|
+
@text_label_vertical_box.content { # re-open vertical box content and shove in a new label
|
32
|
+
@text_label = text_label('This is a text label.',
|
33
|
+
width: label_width, height: label_height, font_descriptor: label_font_descriptor,
|
34
|
+
background_fill: label_background_fill, text_color: label_text_color, border_stroke: label_border_stroke,
|
35
|
+
text_x: label_text_x, text_y: label_text_y)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def rebuild_push_button
|
40
|
+
@push_button.destroy
|
41
|
+
@push_button_vertical_box.content { # re-open vertical box content and shove in a new button
|
42
|
+
@push_button = push_button('Push',
|
43
|
+
width: button_width, height: button_height, font_descriptor: button_font_descriptor,
|
44
|
+
background_fill: button_background_fill, text_color: button_text_color, border_stroke: button_border_stroke,
|
45
|
+
text_x: button_text_x, text_y: button_text_y) {
|
46
|
+
on_mouse_up do
|
47
|
+
message_box('Button Pushed', 'Thank you for pushing the button!')
|
48
|
+
end
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def launch
|
54
|
+
window('Area-Based Custom Controls', 385, 385) { |w|
|
55
|
+
margined true
|
56
|
+
|
57
|
+
tab {
|
58
|
+
tab_item('Text Label') {
|
59
|
+
@text_label_vertical_box = vertical_box {
|
60
|
+
vertical_box {
|
61
|
+
text_label('Text Label Form:', width: 385, height: 30, background_fill: OS.windows? ? :white : {a: 0}, border_stroke: OS.windows? ? :white : {a: 0}, font_descriptor: {size: 16, weight: :bold}, text_x: 0, text_y: OS.windows? ? 0 : 5)
|
62
|
+
|
63
|
+
horizontal_box {
|
64
|
+
label('Width')
|
65
|
+
spinbox(1, 1000) {
|
66
|
+
value <=> [self, :label_width, after_write: method(:rebuild_text_label)]
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
horizontal_box {
|
71
|
+
label('Height')
|
72
|
+
spinbox(1, 1000) {
|
73
|
+
value <=> [self, :label_height, after_write: method(:rebuild_text_label)]
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
horizontal_box {
|
78
|
+
label('Font')
|
79
|
+
font_button {
|
80
|
+
font <=> [self, :label_font_descriptor, after_write: method(:rebuild_text_label)]
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
horizontal_box {
|
85
|
+
label('Text Color')
|
86
|
+
color_button {
|
87
|
+
color <=> [self, :label_text_color, after_write: method(:rebuild_text_label)]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
horizontal_box {
|
92
|
+
label('Background Color')
|
93
|
+
color_button {
|
94
|
+
color <=> [self, :label_background_fill, after_write: method(:rebuild_text_label)]
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
horizontal_box {
|
99
|
+
label('Border Color')
|
100
|
+
color_button {
|
101
|
+
color <=> [self, :label_border_stroke, after_write: method(:rebuild_text_label)]
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
horizontal_box {
|
106
|
+
label('Text X (0=centered)')
|
107
|
+
spinbox(0, 1000) {
|
108
|
+
value <=> [self, :label_text_x, on_read: ->(x) {x.nil? ? 0 : x}, on_write: ->(x) {x == 0 ? nil : x}, after_write: method(:rebuild_text_label)]
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
horizontal_box {
|
113
|
+
label('Text Y (0=centered)')
|
114
|
+
spinbox(0, 1000) {
|
115
|
+
value <=> [self, :label_text_y, on_read: ->(y) {y.nil? ? 0 : y}, on_write: ->(y) {y == 0 ? nil : y}, after_write: method(:rebuild_text_label)]
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
@text_label = text_label('This is a text label.',
|
121
|
+
width: label_width, height: label_height, font_descriptor: label_font_descriptor,
|
122
|
+
background_fill: label_background_fill, text_color: label_text_color, border_stroke: label_border_stroke,
|
123
|
+
text_x: label_text_x, text_y: label_text_y)
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
tab_item('Push Button') {
|
128
|
+
@push_button_vertical_box = vertical_box {
|
129
|
+
vertical_box {
|
130
|
+
text_label('Push Button Form:', width: 385, height: 30, background_fill: OS.windows? ? :white : {a: 0}, border_stroke: OS.windows? ? :white : {a: 0}, font_descriptor: {size: 16, weight: :bold}, text_x: 0, text_y: OS.windows? ? 0 : 5)
|
131
|
+
|
132
|
+
horizontal_box {
|
133
|
+
label('Width')
|
134
|
+
spinbox(1, 1000) {
|
135
|
+
value <=> [self, :button_width, after_write: method(:rebuild_push_button)]
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
horizontal_box {
|
140
|
+
label('Height')
|
141
|
+
spinbox(1, 1000) {
|
142
|
+
value <=> [self, :button_height, after_write: method(:rebuild_push_button)]
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
horizontal_box {
|
147
|
+
label('Font')
|
148
|
+
font_button {
|
149
|
+
font <=> [self, :button_font_descriptor, after_write: method(:rebuild_push_button)]
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
horizontal_box {
|
154
|
+
label('Text Color')
|
155
|
+
color_button {
|
156
|
+
color <=> [self, :button_text_color, after_write: method(:rebuild_push_button)]
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
horizontal_box {
|
161
|
+
label('Background Color')
|
162
|
+
color_button {
|
163
|
+
color <=> [self, :button_background_fill, after_write: method(:rebuild_push_button)]
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
horizontal_box {
|
168
|
+
label('Border Color')
|
169
|
+
color_button {
|
170
|
+
color <=> [self, :button_border_stroke, after_write: method(:rebuild_push_button)]
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
horizontal_box {
|
175
|
+
label('Text X (0=centered)')
|
176
|
+
spinbox(0, 1000) {
|
177
|
+
value <=> [self, :button_text_x, on_read: ->(x) {x.nil? ? 0 : x}, on_write: ->(x) {x == 0 ? nil : x}, after_write: method(:rebuild_push_button)]
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
horizontal_box {
|
182
|
+
label('Text Y (0=centered)')
|
183
|
+
spinbox(0, 1000) {
|
184
|
+
value <=> [self, :button_text_y, on_read: ->(y) {y.nil? ? 0 : y}, on_write: ->(y) {y == 0 ? nil : y}, after_write: method(:rebuild_push_button)]
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
@push_button = push_button('Push',
|
190
|
+
width: button_width, height: button_height, font_descriptor: button_font_descriptor,
|
191
|
+
background_fill: button_background_fill, text_color: button_text_color, border_stroke: button_border_stroke,
|
192
|
+
text_x: button_text_x, text_y: button_text_y) {
|
193
|
+
on_mouse_up do
|
194
|
+
message_box('Button Pushed', 'Thank you for pushing the button!')
|
195
|
+
end
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}.show
|
201
|
+
end
|
202
|
+
|
203
|
+
# text label (area-based custom control) built with vector graphics on top of area.
|
204
|
+
#
|
205
|
+
# background_fill is transparent by default.
|
206
|
+
# background_fill can accept a single color or gradient stops just as per `fill` property in README.
|
207
|
+
# border_stroke is transparent by default.
|
208
|
+
# border_stroke can accept thickness and dashes in addition to color just as per `stroke` property in README.
|
209
|
+
# text_x and text_y are the offset of the label text in relation to its top-left corner.
|
210
|
+
# When text_x, text_y are left nil, the text is automatically centered in the label area.
|
211
|
+
# Sometimes, the centering calculation is not perfect due to using a custom font, so
|
212
|
+
# in that case, pass in text_x, and text_y manually.
|
213
|
+
def text_label(label_text,
|
214
|
+
width: 80, height: 30, font_descriptor: {},
|
215
|
+
background_fill: {a: 0}, text_color: :black, border_stroke: {a: 0},
|
216
|
+
text_x: nil, text_y: nil,
|
217
|
+
&content)
|
218
|
+
area { |the_area|
|
219
|
+
rectangle(1, 1, width, height) {
|
220
|
+
fill background_fill
|
221
|
+
}
|
222
|
+
rectangle(1, 1, width, height) {
|
223
|
+
stroke border_stroke
|
224
|
+
}
|
225
|
+
|
226
|
+
text_height = (font_descriptor[:size] || 12) * (OS.mac? ? 0.75 : 1.35)
|
227
|
+
text_width = (text_height * label_text.size) * (OS.mac? ? 0.75 : 0.60)
|
228
|
+
text_x ||= (width - text_width) / 2.0
|
229
|
+
text_y ||= (height - 4 - text_height) / 2.0
|
230
|
+
text(text_x, text_y, width) {
|
231
|
+
string(label_text) {
|
232
|
+
color text_color
|
233
|
+
font font_descriptor
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
content&.call(the_area)
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
# push button (area-based custom control) built with vector graphics on top of area.
|
242
|
+
#
|
243
|
+
# background_fill is white by default.
|
244
|
+
# background_fill can accept a single color or gradient stops just as per `fill` property in README.
|
245
|
+
# border_stroke is black by default.
|
246
|
+
# border_stroke can accept thickness and dashes in addition to color just as per `stroke` property in README.
|
247
|
+
# text_x and text_y are the offset of the button text in relation to its top-left corner.
|
248
|
+
# When text_x, text_y are left nil, the text is automatically centered in the button area.
|
249
|
+
# Sometimes, the centering calculation is not perfect due to using a custom font, so
|
250
|
+
# in that case, pass in text_x, and text_y manually.
|
251
|
+
#
|
252
|
+
# reuses the text_label custom control
|
253
|
+
def push_button(button_text,
|
254
|
+
width: 80, height: 30, font_descriptor: {},
|
255
|
+
background_fill: :white, text_color: :black, border_stroke: {r: 201, g: 201, b: 201},
|
256
|
+
text_x: nil, text_y: nil,
|
257
|
+
&content)
|
258
|
+
text_label(button_text,
|
259
|
+
width: width, height: height, font_descriptor: font_descriptor,
|
260
|
+
background_fill: background_fill, text_color: text_color, border_stroke: border_stroke,
|
261
|
+
text_x: text_x, text_y: text_y) { |the_area|
|
262
|
+
|
263
|
+
# dig into the_area content and grab elements to modify in mouse listeners below
|
264
|
+
background_rectangle = the_area.children[0]
|
265
|
+
button_string = the_area.children[2].children[0]
|
266
|
+
|
267
|
+
on_mouse_down do
|
268
|
+
background_rectangle.fill = {x0: 0, y0: 0, x1: 0, y1: height, stops: [{pos: 0, r: 72, g: 146, b: 247}, {pos: 1, r: 12, g: 85, b: 214}]}
|
269
|
+
button_string.color = :white
|
270
|
+
end
|
271
|
+
|
272
|
+
on_mouse_up do
|
273
|
+
background_rectangle.fill = background_fill
|
274
|
+
button_string.color = text_color
|
275
|
+
end
|
276
|
+
|
277
|
+
content&.call(the_area)
|
278
|
+
}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
AreaBasedCustomControls.new.launch
|
@@ -11,8 +11,9 @@ class Snake
|
|
11
11
|
FILE_HIGH_SCORE = File.expand_path(File.join(Dir.home, '.glimmer-snake'))
|
12
12
|
|
13
13
|
attr_reader :width, :height
|
14
|
-
attr_accessor :snake, :apple, :over, :score, :high_score
|
14
|
+
attr_accessor :snake, :apple, :over, :score, :high_score, :paused
|
15
15
|
alias over? over
|
16
|
+
alias paused? paused
|
16
17
|
|
17
18
|
def initialize(width = WIDTH_DEFAULT, height = HEIGHT_DEFAULT)
|
18
19
|
@width = width
|
@@ -42,6 +43,22 @@ class Snake
|
|
42
43
|
self.apple.generate
|
43
44
|
end
|
44
45
|
|
46
|
+
def pause
|
47
|
+
self.paused = true
|
48
|
+
end
|
49
|
+
|
50
|
+
def resume
|
51
|
+
self.paused = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def toggle_pause
|
55
|
+
unless paused?
|
56
|
+
pause
|
57
|
+
else
|
58
|
+
resume
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
45
62
|
# inspect is overridden to prevent printing very long stack traces
|
46
63
|
def inspect
|
47
64
|
"#{super[0, 75]}... >"
|
data/examples/snake.rb
CHANGED
@@ -32,7 +32,7 @@ class Snake
|
|
32
32
|
end
|
33
33
|
|
34
34
|
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
35
|
-
unless @game.over?
|
35
|
+
unless @game.paused? || @game.over?
|
36
36
|
process_queued_keypress
|
37
37
|
@game.snake.move
|
38
38
|
end
|
@@ -73,7 +73,11 @@ class Snake
|
|
73
73
|
}
|
74
74
|
|
75
75
|
on_key_up do |area_key_event|
|
76
|
-
|
76
|
+
if area_key_event[:key] == ' '
|
77
|
+
@game.toggle_pause
|
78
|
+
else
|
79
|
+
@keypress_queue << area_key_event[:ext_key]
|
80
|
+
end
|
77
81
|
end
|
78
82
|
}
|
79
83
|
end
|
data/examples/snake2.rb
CHANGED
@@ -40,7 +40,7 @@ class Snake
|
|
40
40
|
end
|
41
41
|
|
42
42
|
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
43
|
-
unless @game.over?
|
43
|
+
unless @game.paused? || @game.over?
|
44
44
|
process_queued_keypress
|
45
45
|
@game.snake.move
|
46
46
|
end
|
@@ -83,7 +83,11 @@ class Snake
|
|
83
83
|
}
|
84
84
|
|
85
85
|
on_key_up do |area_key_event|
|
86
|
-
|
86
|
+
if area_key_event[:key] == ' '
|
87
|
+
@game.toggle_pause
|
88
|
+
else
|
89
|
+
@keypress_queue << area_key_event[:ext_key]
|
90
|
+
end
|
87
91
|
end
|
88
92
|
}
|
89
93
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c)
|
1
|
+
# Copyright (c) 2021-2022 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
|
@@ -36,21 +36,27 @@ class Tetris
|
|
36
36
|
PREVIEW_PLAYFIELD_WIDTH = 4
|
37
37
|
PREVIEW_PLAYFIELD_HEIGHT = 2
|
38
38
|
SCORE_MULTIPLIER = {1 => 40, 2 => 100, 3 => 300, 4 => 1200}
|
39
|
+
UP_ARROW_ACTIONS = %i[instant_down rotate_right rotate_left]
|
40
|
+
SPEEDS = %i[snail sloth turtle rabbit gorilla bear horse gazelle cheetah falcon]
|
41
|
+
SPEED_INITIAL_DELAYS = SPEEDS.each_with_index.inject({}) {|hash, speed_index_pair| hash.merge(speed_index_pair.first => 1.1 - speed_index_pair.last*(0.1)) }
|
39
42
|
|
40
43
|
attr_reader :playfield_width, :playfield_height
|
41
|
-
attr_accessor :game_over, :paused, :preview_tetromino, :lines, :score, :level, :high_scores, :beeping, :added_high_score, :show_high_scores, :up_arrow_action
|
44
|
+
attr_accessor :game_over, :paused, :preview_tetromino, :lines, :score, :level, :high_scores, :beeping, :added_high_score, :show_high_scores, :up_arrow_action, :show_preview_tetromino, :initial_delay
|
42
45
|
alias game_over? game_over
|
43
46
|
alias paused? paused
|
44
47
|
alias beeping? beeping
|
45
48
|
alias added_high_score? added_high_score
|
49
|
+
alias show_preview_tetromino? show_preview_tetromino
|
46
50
|
|
47
51
|
def initialize(playfield_width = PLAYFIELD_WIDTH, playfield_height = PLAYFIELD_HEIGHT)
|
52
|
+
@initial_delay = SPEED_INITIAL_DELAYS[:snail]
|
48
53
|
@playfield_width = playfield_width
|
49
54
|
@playfield_height = playfield_height
|
50
55
|
@high_scores = []
|
51
56
|
@show_high_scores = false
|
52
57
|
@beeping = true
|
53
58
|
@up_arrow_action = :rotate_left
|
59
|
+
@show_preview_tetromino = true
|
54
60
|
load_high_scores!
|
55
61
|
end
|
56
62
|
|
@@ -200,35 +206,31 @@ class Tetris
|
|
200
206
|
end
|
201
207
|
|
202
208
|
def delay
|
203
|
-
[
|
209
|
+
[@initial_delay - (level.to_i * 0.1), 0.001].max
|
204
210
|
end
|
205
211
|
|
206
212
|
def beep
|
207
213
|
@beeper&.call if beeping
|
208
214
|
end
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
def rotate_right_on_up=(value)
|
219
|
-
self.up_arrow_action = :rotate_right if value
|
220
|
-
end
|
221
|
-
|
222
|
-
def rotate_right_on_up
|
223
|
-
self.up_arrow_action == :rotate_right
|
224
|
-
end
|
225
|
-
|
226
|
-
def rotate_left_on_up=(value)
|
227
|
-
self.up_arrow_action = :rotate_left if value
|
215
|
+
|
216
|
+
SPEED_INITIAL_DELAYS.each do |speed, speed_initial_day|
|
217
|
+
define_method("speed_#{speed}=") do |is_true|
|
218
|
+
self.initial_delay = speed_initial_day if is_true
|
219
|
+
end
|
220
|
+
|
221
|
+
define_method("speed_#{speed}") do
|
222
|
+
self.initial_delay == speed_initial_day
|
223
|
+
end
|
228
224
|
end
|
229
225
|
|
230
|
-
|
231
|
-
|
226
|
+
UP_ARROW_ACTIONS.each do |up_arrow_action_symbol|
|
227
|
+
define_method("#{up_arrow_action_symbol}_on_up=") do |is_true|
|
228
|
+
self.up_arrow_action = up_arrow_action_symbol if is_true
|
229
|
+
end
|
230
|
+
|
231
|
+
define_method("#{up_arrow_action_symbol}_on_up") do
|
232
|
+
self.up_arrow_action == up_arrow_action_symbol
|
233
|
+
end
|
232
234
|
end
|
233
235
|
|
234
236
|
def reset_tetrominoes
|
data/examples/tetris.rb
CHANGED
@@ -5,7 +5,7 @@ require_relative 'tetris/model/game'
|
|
5
5
|
class Tetris
|
6
6
|
include Glimmer
|
7
7
|
|
8
|
-
BLOCK_SIZE = 25
|
8
|
+
BLOCK_SIZE = OS.linux? ? 28 : 25
|
9
9
|
BEVEL_CONSTANT = 20
|
10
10
|
COLOR_GRAY = {r: 192, g: 192, b: 192}
|
11
11
|
|
@@ -71,18 +71,31 @@ class Tetris
|
|
71
71
|
|
72
72
|
Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
|
73
73
|
Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
|
74
|
-
|
74
|
+
preview_updater = proc do
|
75
75
|
Glimmer::LibUI.queue_main do
|
76
|
+
new_color = @game.preview_playfield[row][column].color
|
76
77
|
color = Glimmer::LibUI.interpret_color(new_color)
|
77
78
|
block = @preview_playfield_blocks[row][column]
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
if @game.show_preview_tetromino?
|
80
|
+
block[:background_square].fill = color
|
81
|
+
block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
|
82
|
+
block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
83
|
+
block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
84
|
+
block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
|
85
|
+
block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
|
86
|
+
else
|
87
|
+
transparent_color = {r: 255, g: 255, b: 255, a: 0}
|
88
|
+
block[:background_square].fill = transparent_color
|
89
|
+
block[:top_bevel_edge].fill = transparent_color
|
90
|
+
block[:right_bevel_edge].fill = transparent_color
|
91
|
+
block[:bottom_bevel_edge].fill = transparent_color
|
92
|
+
block[:left_bevel_edge].fill = transparent_color
|
93
|
+
block[:border_square].stroke = transparent_color
|
94
|
+
end
|
84
95
|
end
|
85
96
|
end
|
97
|
+
observe(@game.preview_playfield[row][column], :color, &preview_updater)
|
98
|
+
observe(@game, :show_preview_tetromino, &preview_updater)
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
@@ -130,6 +143,12 @@ class Tetris
|
|
130
143
|
}
|
131
144
|
|
132
145
|
menu('View') {
|
146
|
+
check_menu_item('Show Next Block Preview') {
|
147
|
+
checked <=> [@game, :show_preview_tetromino]
|
148
|
+
}
|
149
|
+
|
150
|
+
separator_menu_item
|
151
|
+
|
133
152
|
menu_item('Show High Scores') {
|
134
153
|
on_clicked do
|
135
154
|
show_high_scores
|
@@ -141,18 +160,28 @@ class Tetris
|
|
141
160
|
@game.clear_high_scores!
|
142
161
|
}
|
143
162
|
}
|
163
|
+
|
164
|
+
separator_menu_item
|
165
|
+
}
|
166
|
+
|
167
|
+
menu('Speed') {
|
168
|
+
Model::Game::SPEEDS.each do |speed|
|
169
|
+
radio_menu_item(speed.to_s.capitalize) {
|
170
|
+
checked <=> [@game, "speed_#{speed}"]
|
171
|
+
}
|
172
|
+
end
|
144
173
|
}
|
145
174
|
|
146
175
|
menu('Options') {
|
147
|
-
radio_menu_item('Instant Down on Up Arrow') {
|
176
|
+
radio_menu_item('Instant Down on Up Arrow') {
|
148
177
|
checked <=> [@game, :instant_down_on_up]
|
149
178
|
}
|
150
179
|
|
151
|
-
radio_menu_item('Rotate Right on Up Arrow') {
|
180
|
+
radio_menu_item('Rotate Right on Up Arrow') {
|
152
181
|
checked <=> [@game, :rotate_right_on_up]
|
153
182
|
}
|
154
183
|
|
155
|
-
radio_menu_item('Rotate Left on Up Arrow') {
|
184
|
+
radio_menu_item('Rotate Left on Up Arrow') {
|
156
185
|
checked <=> [@game, :rotate_left_on_up]
|
157
186
|
}
|
158
187
|
}
|
@@ -199,7 +228,7 @@ class Tetris
|
|
199
228
|
block = {}
|
200
229
|
bevel_pixel_size = 0.16 * block_size.to_f
|
201
230
|
color = Glimmer::LibUI.interpret_color(Model::Block::COLOR_CLEAR)
|
202
|
-
area {
|
231
|
+
block[:area] = area {
|
203
232
|
block[:background_square] = square(0, 0, block_size) {
|
204
233
|
fill color
|
205
234
|
}
|
@@ -275,12 +304,6 @@ class Tetris
|
|
275
304
|
|
276
305
|
def score_board(block_size: , &extra_content)
|
277
306
|
vertical_box {
|
278
|
-
horizontal_box {
|
279
|
-
label # filler
|
280
|
-
@preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
|
281
|
-
label # filler
|
282
|
-
}
|
283
|
-
|
284
307
|
horizontal_box {
|
285
308
|
label # filler
|
286
309
|
grid {
|
@@ -321,6 +344,12 @@ class Tetris
|
|
321
344
|
}
|
322
345
|
label # filler
|
323
346
|
}
|
347
|
+
|
348
|
+
horizontal_box {
|
349
|
+
label # filler
|
350
|
+
@preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
|
351
|
+
label # filler
|
352
|
+
}
|
324
353
|
|
325
354
|
extra_content&.call
|
326
355
|
}
|
@@ -329,9 +358,11 @@ class Tetris
|
|
329
358
|
def start_moving_tetrominos_down
|
330
359
|
unless @tetrominos_start_moving_down
|
331
360
|
@tetrominos_start_moving_down = true
|
332
|
-
|
361
|
+
tetromino_move = proc do
|
333
362
|
@game.down! if !@game.game_over? && !@game.paused?
|
363
|
+
Glimmer::LibUI.timer(@game.delay, repeat: false, &tetromino_move)
|
334
364
|
end
|
365
|
+
Glimmer::LibUI.timer(@game.delay, repeat: false, &tetromino_move)
|
335
366
|
end
|
336
367
|
end
|
337
368
|
|
@@ -360,7 +391,7 @@ class Tetris
|
|
360
391
|
|
361
392
|
def show_about_dialog
|
362
393
|
Glimmer::LibUI.queue_main do
|
363
|
-
msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
|
394
|
+
msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021-2022 Andy Maleh')
|
364
395
|
end
|
365
396
|
end
|
366
397
|
end
|
data/glimmer-dsl-libui.gemspec
CHANGED
Binary file
|