glimmer-dsl-libui 0.2.15 → 0.2.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
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
+ class Tetris
23
+ module Model
24
+ class PastGame
25
+ attr_accessor :name, :score, :lines, :level
26
+
27
+ def initialize(name, score, lines, level)
28
+ @name = name
29
+ @score = score.to_i
30
+ @lines = lines.to_i
31
+ @level = level.to_i
32
+ end
33
+
34
+ def to_a
35
+ [@name, @score, @lines, @level]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,329 @@
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_relative 'block'
23
+
24
+ require 'matrix'
25
+
26
+ class Tetris
27
+ module Model
28
+ class Tetromino
29
+ ORIENTATIONS = [:north, :east, :south, :west]
30
+
31
+ LETTER_COLORS = {
32
+ I: :cyan,
33
+ J: :blue,
34
+ L: :olive,
35
+ O: :yellow,
36
+ S: :lime,
37
+ T: :magenta,
38
+ Z: :red,
39
+ }
40
+
41
+ attr_reader :game, :letter, :preview
42
+ alias preview? preview
43
+ attr_accessor :orientation, :blocks, :row, :column
44
+
45
+ def initialize(game)
46
+ @game = game
47
+ @letter = LETTER_COLORS.keys.sample
48
+ @orientation = :north
49
+ @blocks = default_blocks
50
+ @preview = true
51
+ new_row = 0
52
+ new_column = (Model::Game::PREVIEW_PLAYFIELD_WIDTH - width)/2
53
+ update_playfield(new_row, new_column)
54
+ end
55
+
56
+ def playfield
57
+ @preview ? game.preview_playfield : game.playfield
58
+ end
59
+
60
+ def launch!
61
+ remove_from_playfield
62
+ @preview = false
63
+ new_row = 1 - height
64
+ new_column = (game.playfield_width - width)/2
65
+ update_playfield(new_row, new_column)
66
+ game.tetrominoes << self
67
+ end
68
+
69
+ def update_playfield(new_row = nil, new_column = nil)
70
+ remove_from_playfield
71
+ if !new_row.nil? && !new_column.nil?
72
+ @row = new_row
73
+ @column = new_column
74
+ add_to_playfield
75
+ end
76
+ end
77
+
78
+ def add_to_playfield
79
+ update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
80
+ playfield[playfield_row][playfield_column].color = blocks[row_index][column_index].color if playfield_row >= 0 && playfield[playfield_row][playfield_column]&.clear? && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column].color != blocks[row_index][column_index].color
81
+ end
82
+ end
83
+
84
+ def remove_from_playfield
85
+ return if @row.nil? || @column.nil?
86
+ update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
87
+ playfield[playfield_row][playfield_column].clear if playfield_row >= 0 && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column]&.color == color
88
+ end
89
+ end
90
+
91
+ def stopped?
92
+ return true if @stopped || @preview
93
+ playfield_remaining_heights = game.playfield_remaining_heights(self)
94
+ result = bottom_most_blocks.any? do |bottom_most_block|
95
+ playfield_column = @column + bottom_most_block[:column_index]
96
+ playfield_remaining_heights[playfield_column] &&
97
+ @row + bottom_most_block[:row_index] >= playfield_remaining_heights[playfield_column] - 1
98
+ end
99
+ if result && !game.hypothetical?
100
+ @stopped = result
101
+ game.consider_eliminating_lines
102
+ @game.consider_adding_tetromino
103
+ end
104
+ result
105
+ end
106
+
107
+ # Returns bottom-most blocks of a tetromino, which could be from multiple rows depending on shape (e.g. T)
108
+ def bottom_most_blocks
109
+ width.times.map do |column_index|
110
+ row_blocks_with_row_index = @blocks.each_with_index.to_a.reverse.detect do |row_blocks, row_index|
111
+ !row_blocks[column_index].clear?
112
+ end
113
+ bottom_most_block = row_blocks_with_row_index[0][column_index]
114
+ bottom_most_block_row = row_blocks_with_row_index[1]
115
+ {
116
+ block: bottom_most_block,
117
+ row_index: bottom_most_block_row,
118
+ column_index: column_index
119
+ }
120
+ end
121
+ end
122
+
123
+ def bottom_most_block_for_column(column)
124
+ bottom_most_blocks.detect {|bottom_most_block| (@column + bottom_most_block[:column_index]) == column}
125
+ end
126
+
127
+ def right_blocked?
128
+ (@column == game.playfield_width - width) ||
129
+ right_most_blocks.any? { |right_most_block|
130
+ (@row + right_most_block[:row_index]) >= 0 &&
131
+ playfield[@row + right_most_block[:row_index]][@column + right_most_block[:column_index] + 1].occupied?
132
+ }
133
+ end
134
+
135
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
136
+ def right_most_blocks
137
+ @blocks.each_with_index.map do |row_blocks, row_index|
138
+ column_block_with_column_index = row_blocks.each_with_index.to_a.reverse.detect do |column_block, column_index|
139
+ !column_block.clear?
140
+ end
141
+ if column_block_with_column_index
142
+ right_most_block = column_block_with_column_index[0]
143
+ {
144
+ block: right_most_block,
145
+ row_index: row_index,
146
+ column_index: column_block_with_column_index[1]
147
+ }
148
+ end
149
+ end.compact
150
+ end
151
+
152
+ def left_blocked?
153
+ (@column == 0) ||
154
+ left_most_blocks.any? { |left_most_block|
155
+ (@row + left_most_block[:row_index]) >= 0 &&
156
+ playfield[@row + left_most_block[:row_index]][@column + left_most_block[:column_index] - 1].occupied?
157
+ }
158
+ end
159
+
160
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
161
+ def left_most_blocks
162
+ @blocks.each_with_index.map do |row_blocks, row_index|
163
+ column_block_with_column_index = row_blocks.each_with_index.to_a.detect do |column_block, column_index|
164
+ !column_block.clear?
165
+ end
166
+ if column_block_with_column_index
167
+ left_most_block = column_block_with_column_index[0]
168
+ {
169
+ block: left_most_block,
170
+ row_index: row_index,
171
+ column_index: column_block_with_column_index[1]
172
+ }
173
+ end
174
+ end.compact
175
+ end
176
+
177
+ def width
178
+ @blocks[0].size
179
+ end
180
+
181
+ def height
182
+ @blocks.size
183
+ end
184
+
185
+ def down!(instant: false)
186
+ launch! if preview?
187
+ unless stopped?
188
+ block_count = 1
189
+ if instant
190
+ remaining_height, bottom_touching_block = remaining_height_and_bottom_touching_block
191
+ block_count = remaining_height - @row
192
+ end
193
+ new_row = @row + block_count
194
+ update_playfield(new_row, @column)
195
+ end
196
+ end
197
+
198
+ def left!
199
+ unless left_blocked?
200
+ new_column = @column - 1
201
+ update_playfield(@row, new_column)
202
+ end
203
+ end
204
+
205
+ def right!
206
+ unless right_blocked?
207
+ new_column = @column + 1
208
+ update_playfield(@row, new_column)
209
+ end
210
+ end
211
+
212
+ # Rotate in specified direcation, which can be :right (clockwise) or :left (counterclockwise)
213
+ def rotate!(direction)
214
+ return if stopped?
215
+ can_rotate = nil
216
+ new_blocks = nil
217
+ game.hypothetical do
218
+ hypothetical_rotated_tetromino = hypothetical_tetromino
219
+ new_blocks = hypothetical_rotated_tetromino.rotate_blocks(direction)
220
+ can_rotate = !hypothetical_rotated_tetromino.stopped? && !hypothetical_rotated_tetromino.right_blocked? && !hypothetical_rotated_tetromino.left_blocked?
221
+ end
222
+ if can_rotate
223
+ remove_from_playfield
224
+ self.orientation = ORIENTATIONS[ORIENTATIONS.rotate(direction == :right ? -1 : 1).index(@orientation)]
225
+ self.blocks = new_blocks
226
+ update_playfield(@row, @column)
227
+ end
228
+ rescue => e
229
+ puts e.full_message
230
+ end
231
+
232
+ def rotate_blocks(direction)
233
+ new_blocks = Matrix[*@blocks].transpose.to_a
234
+ if direction == :right
235
+ new_blocks = new_blocks.map(&:reverse)
236
+ else
237
+ new_blocks = new_blocks.reverse
238
+ end
239
+ Matrix[*new_blocks].to_a
240
+ end
241
+
242
+ def hypothetical_tetromino
243
+ clone.tap do |hypo_clone|
244
+ remove_from_playfield
245
+ hypo_clone.blocks = @blocks.map do |row_blocks|
246
+ row_blocks.map do |column_block|
247
+ column_block.clone
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ def remaining_height_and_bottom_touching_block
254
+ playfield_remaining_heights = game.playfield_remaining_heights(self)
255
+ bottom_most_blocks.map do |bottom_most_block|
256
+ playfield_column = @column + bottom_most_block[:column_index]
257
+ [playfield_remaining_heights[playfield_column] - (bottom_most_block[:row_index] + 1), bottom_most_block]
258
+ end.min_by(&:first)
259
+ end
260
+
261
+ def default_blocks
262
+ case @letter
263
+ when :I
264
+ [
265
+ [block, block, block, block]
266
+ ]
267
+ when :J
268
+ [
269
+ [block, block, block],
270
+ [empty, empty, block],
271
+ ]
272
+ when :L
273
+ [
274
+ [block, block, block],
275
+ [block, empty, empty],
276
+ ]
277
+ when :O
278
+ [
279
+ [block, block],
280
+ [block, block],
281
+ ]
282
+ when :S
283
+ [
284
+ [empty, block, block],
285
+ [block, block, empty],
286
+ ]
287
+ when :T
288
+ [
289
+ [block, block, block],
290
+ [empty, block, empty],
291
+ ]
292
+ when :Z
293
+ [
294
+ [block, block, empty],
295
+ [empty, block, block],
296
+ ]
297
+ end
298
+ end
299
+
300
+ def color
301
+ LETTER_COLORS[@letter]
302
+ end
303
+
304
+ def include_block?(block)
305
+ @blocks.flatten.include?(block)
306
+ end
307
+
308
+ private
309
+
310
+ def block
311
+ Block.new(color)
312
+ end
313
+
314
+ def empty
315
+ Block.new
316
+ end
317
+
318
+ def update_playfield_block(&updater)
319
+ @row.upto(@row + height - 1) do |playfield_row|
320
+ @column.upto(@column + width - 1) do |playfield_column|
321
+ row_index = playfield_row - @row
322
+ column_index = playfield_column - @column
323
+ updater.call(playfield_row, playfield_column, row_index, column_index)
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+ end
@@ -0,0 +1,262 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ require_relative 'tetris/model/game'
4
+
5
+ class Tetris
6
+ include Glimmer
7
+
8
+ BLOCK_SIZE = 25
9
+ BEVEL_CONSTANT = 20
10
+ COLOR_GRAY = {r: 192, g: 192, b: 192}
11
+
12
+ attr_reader :game
13
+
14
+ def initialize
15
+ @game = Model::Game.new
16
+ end
17
+
18
+ def launch
19
+ create_gui
20
+ register_observers
21
+ @game.start!
22
+ @main_window.show
23
+ end
24
+
25
+ def create_gui
26
+ @main_window = window('Glimmer Tetris') {
27
+ content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
28
+
29
+ vertical_box {
30
+ label { # filler
31
+ stretchy false
32
+ }
33
+
34
+ score_board(block_size: BLOCK_SIZE) {
35
+ stretchy false
36
+ }
37
+
38
+ @playfield_blocks = playfield(playfield_width: Model::Game::PLAYFIELD_WIDTH, playfield_height: Model::Game::PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
39
+ }
40
+ }
41
+ end
42
+
43
+ def register_observers
44
+ Glimmer::DataBinding::Observer.proc do |game_over|
45
+ if game_over
46
+ show_game_over_dialog
47
+ else
48
+ start_moving_tetrominos_down
49
+ end
50
+ end.observe(@game, :game_over)
51
+
52
+ Model::Game::PLAYFIELD_HEIGHT.times do |row|
53
+ Model::Game::PLAYFIELD_WIDTH.times do |column|
54
+ Glimmer::DataBinding::Observer.proc do |new_color|
55
+ Glimmer::LibUI.queue_main do
56
+ color = Glimmer::LibUI.interpret_color(new_color)
57
+ block = @playfield_blocks[row][column]
58
+ block[:background_square].fill = color
59
+ block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
60
+ block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
61
+ block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
62
+ block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
63
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
64
+ end
65
+ end.observe(@game.playfield[row][column], :color)
66
+ end
67
+ end
68
+
69
+ Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
70
+ Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
71
+ Glimmer::DataBinding::Observer.proc do |new_color|
72
+ Glimmer::LibUI.queue_main do
73
+ color = Glimmer::LibUI.interpret_color(new_color)
74
+ block = @preview_playfield_blocks[row][column]
75
+ block[:background_square].fill = color
76
+ block[:top_bevel_edge].fill = {r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT}
77
+ block[:right_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
78
+ block[:bottom_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
79
+ block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
80
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
81
+ end
82
+ end.observe(@game.preview_playfield[row][column], :color)
83
+ end
84
+ end
85
+
86
+ Glimmer::DataBinding::Observer.proc do |new_score|
87
+ Glimmer::LibUI.queue_main do
88
+ @score_label.text = new_score.to_s
89
+ end
90
+ end.observe(@game, :score)
91
+
92
+ Glimmer::DataBinding::Observer.proc do |new_lines|
93
+ Glimmer::LibUI.queue_main do
94
+ @lines_label.text = new_lines.to_s
95
+ end
96
+ end.observe(@game, :lines)
97
+
98
+ Glimmer::DataBinding::Observer.proc do |new_level|
99
+ Glimmer::LibUI.queue_main do
100
+ @level_label.text = new_level.to_s
101
+ end
102
+ end.observe(@game, :level)
103
+ end
104
+
105
+ def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
106
+ blocks = []
107
+ vertical_box {
108
+ padded false
109
+
110
+ playfield_height.times.map do |row|
111
+ blocks << []
112
+ horizontal_box {
113
+ padded false
114
+
115
+ playfield_width.times.map do |column|
116
+ blocks.last << block(row: row, column: column, block_size: block_size)
117
+ end
118
+ }
119
+ end
120
+
121
+ extra_content&.call
122
+ }
123
+ blocks
124
+ end
125
+
126
+ def block(row: , column: , block_size: , &extra_content)
127
+ block = {}
128
+ bevel_pixel_size = 0.16 * block_size.to_f
129
+ color = Glimmer::LibUI.interpret_color(Model::Block::COLOR_CLEAR)
130
+ area {
131
+ block[:background_square] = path {
132
+ square(0, 0, block_size)
133
+
134
+ fill color
135
+ }
136
+ block[:top_bevel_edge] = path {
137
+ polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
138
+
139
+ fill r: color[:r] + 4*BEVEL_CONSTANT, g: color[:g] + 4*BEVEL_CONSTANT, b: color[:b] + 4*BEVEL_CONSTANT
140
+ }
141
+ block[:right_bevel_edge] = path {
142
+ polygon(block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size, block_size)
143
+
144
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
145
+ }
146
+ block[:bottom_bevel_edge] = path {
147
+ polygon(block_size, block_size, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size)
148
+
149
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
150
+ }
151
+ block[:left_bevel_edge] = path {
152
+ polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size)
153
+
154
+ fill r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT
155
+ }
156
+ block[:border_square] = path {
157
+ square(0, 0, block_size)
158
+
159
+ stroke COLOR_GRAY
160
+ }
161
+
162
+ on_key_down do |key_event|
163
+ case key_event
164
+ in ext_key: :down
165
+ game.down!
166
+ in key: ' '
167
+ game.down!(instant: true)
168
+ in ext_key: :up
169
+ case game.up_arrow_action
170
+ when :instant_down
171
+ game.down!(instant: true)
172
+ when :rotate_right
173
+ game.rotate!(:right)
174
+ when :rotate_left
175
+ game.rotate!(:left)
176
+ end
177
+ in ext_key: :left
178
+ game.left!
179
+ in ext_key: :right
180
+ game.right!
181
+ in modifier: :shift
182
+ game.rotate!(:right)
183
+ in modifier: :control
184
+ game.rotate!(:left)
185
+ else
186
+ # Do Nothing
187
+ end
188
+ end
189
+
190
+ extra_content&.call
191
+ }
192
+ block
193
+ end
194
+
195
+ def score_board(block_size: , &extra_content)
196
+ vertical_box {
197
+ horizontal_box {
198
+ label # filler
199
+ @preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: block_size)
200
+ label # filler
201
+ }
202
+
203
+ horizontal_box {
204
+ label # filler
205
+ grid {
206
+ stretchy false
207
+
208
+ label('Score') {
209
+ left 0
210
+ top 0
211
+ halign :fill
212
+ }
213
+ @score_label = label {
214
+ left 0
215
+ top 1
216
+ halign :center
217
+ }
218
+
219
+ label('Lines') {
220
+ left 1
221
+ top 0
222
+ halign :fill
223
+ }
224
+ @lines_label = label {
225
+ left 1
226
+ top 1
227
+ halign :center
228
+ }
229
+
230
+ label('Level') {
231
+ left 2
232
+ top 0
233
+ halign :fill
234
+ }
235
+ @level_label = label {
236
+ left 2
237
+ top 1
238
+ halign :center
239
+ }
240
+ }
241
+ label # filler
242
+ }
243
+
244
+ extra_content&.call
245
+ }
246
+ end
247
+
248
+ def start_moving_tetrominos_down
249
+ Glimmer::LibUI.timer(@game.delay) do
250
+ @game.down! if !@game.game_over? && !@game.paused?
251
+ end
252
+ end
253
+
254
+ def show_game_over_dialog
255
+ Glimmer::LibUI.queue_main do
256
+ msg_box('Game Over', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
257
+ @game.restart!
258
+ end
259
+ end
260
+ end
261
+
262
+ Tetris.new.launch
Binary file
@@ -37,6 +37,7 @@ module Glimmer
37
37
  end
38
38
 
39
39
  def interpret(parent, keyword, *args, &block)
40
+ args = [args] if args.size > 1 && Glimmer::LibUI::Shape.shape_class(keyword).parameters.size == 1
40
41
  Glimmer::LibUI::Shape.create(keyword, parent, args, &block)
41
42
  end
42
43
 
@@ -109,6 +109,31 @@ module Glimmer
109
109
  queue_redraw_all
110
110
  end
111
111
 
112
+ def request_auto_redraw
113
+ # TODO implement functionality to delay queuing area redraws until post_add_content has been called (area definition is done). Maybe offer an option to enable redrawing before area is closed too.
114
+ queue_redraw_all if auto_redraw_enabled?
115
+ end
116
+
117
+ def auto_redraw_enabled(value = nil)
118
+ if value.nil?
119
+ @auto_redraw_enabled = true if @auto_redraw_enabled.nil?
120
+ @auto_redraw_enabled
121
+ else
122
+ @auto_redraw_enabled = !!value
123
+ end
124
+ end
125
+ alias auto_redraw_enabled? auto_redraw_enabled
126
+ alias auto_redraw_enabled= auto_redraw_enabled
127
+ alias set_auto_redraw_enabled auto_redraw_enabled
128
+
129
+ def pause_auto_redraw
130
+ self.auto_redraw_enabled = false
131
+ end
132
+
133
+ def resume_auto_redraw
134
+ self.auto_redraw_enabled = true
135
+ end
136
+
112
137
  private
113
138
 
114
139
  def build_control