glimmer-dsl-swt 4.18.2.3 → 4.18.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 813f7cef0d25c94aa62c0cd57d3445a3eb13acb229bdd59264f7d4a0268f1ed3
4
- data.tar.gz: dccf84bac2d2ca037df0b4157335fd7451fc2701d90a79df18abc61971725df6
3
+ metadata.gz: 9e12bb24a84b93822013eef2122021cd5e6a8f90f9e450ac83f7bd5b5f0b7b55
4
+ data.tar.gz: dfdba626253a34506b99971821378e8579eac7f21a955ddbd7bc0543f770ad51
5
5
  SHA512:
6
- metadata.gz: 9702ce2c81c56ddf6c56e590c7f30509149d75fbd6ee8e01da4bb5e0405381fae39da688ec30ab0686ff987cdc4eee06992d7c4b365a32f8bc2d773ea23e3b05
7
- data.tar.gz: 4d1a2dfa58fffa6dd037ef07463056ccc70d09261bb0720f238332c07284347993c94e96ef5d18bb9a7f1f75d71b72ed2fdfe72202320f8de489624ac9084edc
6
+ metadata.gz: d489317bc86659858e1215aca4f35441aa123f59affb4f35fe9fce1ec04f220f3856f5d203d686a1091a7a1652b746a9453ce598eb684910b1ded8717fc1552b
7
+ data.tar.gz: 10c31c53aab7d5a8905c6448f66dcacb01c98b952c9934ae1e5236437e583d37aa607161f38946754938c9fc655c876064cc268a93d73d8746667d69d69f684b
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ### 4.18.2.4
4
+
5
+ - Tetris scoring
6
+ - Tetris eliminated Line tracking
7
+ - Tetris level tracking and speed-ups
8
+ - Tetris preview upcoming tetromino shape
9
+ - Added parent_proxy to CustomWidget and CustomShell classes
10
+ - Update CustomShell#center and ShellProxy#center to center_within_display to avoid clash with `row_layout` center property
11
+ - Fixed issue with shell/dialog/custom-shell not maintaining parent when not passed
12
+ - Fix Tetris sideways edge detection
13
+
3
14
  ### 4.18.2.3
4
15
 
5
16
  - Added Tetris Elaborate Sample
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.2.3
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.2.4
2
2
  ## JRuby Desktop Development GUI Framework
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
4
4
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
@@ -226,6 +226,11 @@ Glimmer App:
226
226
 
227
227
  [![Math Bowling App Screenshot](https://raw.githubusercontent.com/AndyObtiva/MathBowling/master/Math-Bowling-Screenshot.png)](https://github.com/AndyObtiva/MathBowling)
228
228
 
229
+ **Note:** I offer Glimmer as an open-source project that represents my interests in Ruby Programming, Desktop GUI application development with SWT, Object Oriented Design, Design Patterns, and Software Architecture.
230
+ Additionally, I am sharing my professional experience and expertise in Eclipse SWT given that I am an [EclipseCon](http://andymaleh.blogspot.com/2007/03/eclipsecon-2007-day-3.html)/[EclipseWorld](http://andymaleh.blogspot.com/2008/11/eclipseworld-2008-highlights.html) presenter and have built professional applications in SWT/JFace/RCP for Obtiva and the Pampered Chef in the past. This is also done in the hopes that it would indirectly bring me work in a field I am extremely passionate about.
231
+ That said, please keep in mind that I myself am learning topics in Software Engineering too everyday, including newer editions of SWT and JRuby, which seem to pop up every quarter.
232
+ If you see anything that needs to be improved, please do not hesitate to contact me on [Gitter](https://gitter.im/AndyObtiva/glimmer) or submit [Issues](https://github.com/AndyObtiva/glimmer-dsl-swt/issues)/[Pull-Requests](https://github.com/AndyObtiva/glimmer-dsl-swt/pulls).
233
+
229
234
  ## Table of contents
230
235
 
231
236
  - [Glimmer (JRuby Desktop Development GUI Framework)](#jruby-desktop-development-gui-framework)
@@ -301,7 +306,7 @@ Glimmer App:
301
306
  - [Custom Widget API](#custom-widget-api)
302
307
  - [Content/Options Example](#contentoptions-example)
303
308
  - [Gotcha](#gotcha)
304
- - [Final Notes](#final-notes)
309
+ - [Custom Widget Final Notes](#custom-widget-final-notes)
305
310
  - [Custom Shells](#custom-shells)
306
311
  - [Drag and Drop](#drag-and-drop)
307
312
  - [Miscellaneous](#miscellaneous)
@@ -453,7 +458,7 @@ jgem install glimmer-dsl-swt
453
458
 
454
459
  Or this command if you want a specific version:
455
460
  ```
456
- jgem install glimmer-dsl-swt -v 4.18.2.3
461
+ jgem install glimmer-dsl-swt -v 4.18.2.4
457
462
 
458
463
 
459
464
  ```
@@ -473,7 +478,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
473
478
 
474
479
  Add the following to `Gemfile`:
475
480
  ```
476
- gem 'glimmer-dsl-swt', '~> 4.18.2.3
481
+ gem 'glimmer-dsl-swt', '~> 4.18.2.4
477
482
  '
478
483
  ```
479
484
 
@@ -532,7 +537,7 @@ bin/glimmer samples
532
537
  Below are the full usage instructions that come up when running `glimmer` without args.
533
538
 
534
539
  ```
535
- Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.18.2.3
540
+ Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.18.2.4
536
541
 
537
542
 
538
543
 
@@ -1013,7 +1018,7 @@ Output:
1013
1018
 
1014
1019
  Css glimmer-dsl-css 1.1.0 AndyMaleh Glimmer DSL for CSS
1015
1020
  Opal glimmer-dsl-opal 0.10.2 AndyMaleh Glimmer DSL for Opal
1016
- Swt glimmer-dsl-swt 4.18.2.3
1021
+ Swt glimmer-dsl-swt 4.18.2.4
1017
1022
 
1018
1023
  AndyMaleh Glimmer DSL for SWT
1019
1024
  Tk glimmer-dsl-tk 0.0.6 AndyMaleh Glimmer DSL for Tk
@@ -2340,25 +2345,33 @@ Example (you may copy/paste in [`girb`](#girb-glimmer-irb-command)):
2340
2345
  ```ruby
2341
2346
  include Glimmer
2342
2347
 
2348
+ # image object has to be declared outside the canvas and shell to avoid confusing with canvas image property
2349
+ image_object = image(File.expand_path('./icons/scaffold_app.png'), width: 100)
2350
+
2343
2351
  shell {
2344
2352
  text 'Canvas Example'
2345
2353
  minimum_size 320, 400
2346
2354
 
2347
2355
  canvas {
2348
- background :yellow
2356
+ background :dark_yellow
2349
2357
  rectangle(0, 0, 220, 400, fill: true) {
2350
- background :red
2358
+ background :dark_red
2351
2359
  }
2352
2360
  rectangle(50, 20, 300, 150, 30, 50, round: true, fill: true) {
2353
- background :magenta
2361
+ background :yellow
2354
2362
  }
2355
2363
  rectangle(150, 200, 100, 70, true, gradient: true) {
2356
- background :dark_magenta
2364
+ background :dark_red
2357
2365
  foreground :yellow
2358
2366
  }
2367
+ text('Glimmer', 208, 83) {
2368
+ font height: 25, style: :bold
2369
+ }
2359
2370
  rectangle(200, 80, 108, 36) {
2360
- foreground color(:dark_blue)
2371
+ foreground :black
2372
+ line_width 3
2361
2373
  }
2374
+ image(image_object, 70, 50)
2362
2375
  }
2363
2376
  }.open
2364
2377
  ```
@@ -2400,7 +2413,11 @@ shell {
2400
2413
  }.open
2401
2414
  ```
2402
2415
 
2403
- In any case, if there is anything missing you would like added to the Glimmer Shape DSL that you saw available in the SWT APIs, you may [report an issue](https://github.com/AndyObtiva/glimmer-dsl-swt/issues) or implement yourself and [contribute](#contributing) via a Pull Request.
2416
+ In any case, if there is anything missing you would like added to the Glimmer Shape DSL that you saw available in the SWT APIs, you may [report an issue](https://github.com/AndyObtiva/glimmer-dsl-swt/issues) or implement yourself and [contribute](#contributing) via a [Pull Request](https://github.com/AndyObtiva/glimmer-dsl-swt/pulls).
2417
+
2418
+ #### Shapes inside a Widget
2419
+
2420
+ Keep in mind that the Shape DSL can be used inside any widget, not just `canvas`. Unlike shapes on a `canvas`, which are standalone graphics, when included in a widget, which already has its own look and feel, shapes are used as a decorative add-on that complements its look by getting painted on top of it. For example, shapes were used to decorate `composite` blocks in the [Tetris](#tetris) sample to have a more bevel look. In summary, Shapes can be used in a hybrid approach (shapes inside a widget), not just standalone in a `canvas`.
2404
2421
 
2405
2422
  ### Canvas Animation DSL
2406
2423
 
@@ -2944,7 +2961,7 @@ If you need a better widget with the ability to customize the date format patter
2944
2961
 
2945
2962
  ### Observer
2946
2963
 
2947
- Glimmer comes with `Observer` module, which is used internally for data-binding, but can also be used externally for custom use of the Observer Pattern. It is hidden when observing widgets, and used explicitly when observing models.
2964
+ Glimmer comes with the `Observer` mixin module, which is used internally for data-binding, but can also be used externally for custom use of the Observer Pattern. It is hidden when observing widgets, and used explicitly when observing models. In bidirectional data-binding, `Observer` is automatically unregistered from models once a widget is disposed to avoid memory leaks and worrying about managing them yourself.
2948
2965
 
2949
2966
  #### Observing Widgets
2950
2967
 
@@ -3310,7 +3327,7 @@ body {
3310
3327
 
3311
3328
  The `text` method invoked in the custom widget body will call the one you defined above it. To avoid this gotcha, simply name the text property above something else, like `custom_text`.
3312
3329
 
3313
- #### Final Notes
3330
+ #### Custom Widget Final Notes
3314
3331
 
3315
3332
  This [Eclipse guide](https://www.eclipse.org/articles/Article-Writing%20Your%20Own%20Widget/Writing%20Your%20Own%20Widget.htm) for how to write custom SWT widgets is also applicable to Glimmer Custom Widgets written in Ruby. I recommend reading it:
3316
3333
  [https://www.eclipse.org/articles/Article-Writing%20Your%20Own%20Widget/Writing%20Your%20Own%20Widget.htm](https://www.eclipse.org/articles/Article-Writing%20Your%20Own%20Widget/Writing%20Your%20Own%20Widget.htm)
@@ -4640,10 +4657,12 @@ This sample demonstrates how to build an interactive animated game with MVC arch
4640
4657
 
4641
4658
  Code:
4642
4659
 
4643
- [samples/elaborate/tic_tac_toe.rb](samples/elaborate/tetris.rb)
4660
+ [samples/elaborate/tetris.rb](samples/elaborate/tetris.rb)
4644
4661
 
4645
4662
  ![Tetris](images/glimmer-tetris.png)
4646
4663
 
4664
+ ![Tetris Game Over](images/glimmer-tetris-game-over.png)
4665
+
4647
4666
  ### External Samples
4648
4667
 
4649
4668
  #### Glimmer Calculator
@@ -4697,6 +4716,8 @@ If you have a Glimmer app you would like referenced here, please mention in a Pu
4697
4716
 
4698
4717
  Note: this section mostly applies to Mac and Windows. On Linux, you can just run `glimmer package:gem` and after installing the gem, you get an executable matching the name of the app/custom-shell-gem you are building (e.g. `calculator` command becomes available after installing the [glimmer-cs-calculator](https://github.com/AndyObtiva/glimmer-cs-calculator) gem)
4699
4718
 
4719
+ Note 2: Glimmer packaging has a strong dependency on JDK8 at the moment. JDK9 & JDK10 might work, but JDK11 and onward definitely won't since they dropped javapackager, which later came back as jpackage in JDK14, but it's not ready for prime time yet. Just stick to JDK8 for now, strongly supported by Oracle for the next 6 years at least.
4720
+
4700
4721
  Glimmer simplifies the process of native-executable packaging and distribution on Mac and Windows via a single `glimmer package` command:
4701
4722
 
4702
4723
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.18.2.3
1
+ 4.18.2.4
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-swt 4.18.2.3 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.2.4 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.2.3"
9
+ s.version = "4.18.2.4"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-01-23"
14
+ s.date = "2021-01-24"
15
15
  s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.executables = ["glimmer".freeze, "girb".freeze]
@@ -137,7 +137,9 @@ Gem::Specification.new do |s|
137
137
  "samples/elaborate/tetris/model/game.rb",
138
138
  "samples/elaborate/tetris/model/tetromino.rb",
139
139
  "samples/elaborate/tetris/view/block.rb",
140
+ "samples/elaborate/tetris/view/game_over_dialog.rb",
140
141
  "samples/elaborate/tetris/view/playfield.rb",
142
+ "samples/elaborate/tetris/view/score_lane.rb",
141
143
  "samples/elaborate/tic_tac_toe.rb",
142
144
  "samples/elaborate/tic_tac_toe/board.rb",
143
145
  "samples/elaborate/tic_tac_toe/cell.rb",
@@ -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
@@ -46,6 +46,7 @@ module Glimmer
46
46
  @swt_widget = swt_widget
47
47
  else
48
48
  if args.first.is_a?(ShellProxy)
49
+ @parent_proxy = args[0]
49
50
  args[0] = args[0].swt_widget
50
51
  end
51
52
  style_args = args.select {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
@@ -78,7 +79,7 @@ module Glimmer
78
79
  end
79
80
 
80
81
  # Centers shell within monitor it is in
81
- def center
82
+ def center_within_display
82
83
  primary_monitor = @display.getPrimaryMonitor()
83
84
  monitor_bounds = primary_monitor.getBounds()
84
85
  shell_bounds = @swt_widget.getBounds()
@@ -101,7 +102,7 @@ module Glimmer
101
102
  else
102
103
  @opened_before = true
103
104
  @swt_widget.pack
104
- center
105
+ center_within_display
105
106
  @swt_widget.open
106
107
  end
107
108
  end
@@ -158,7 +158,7 @@ module Glimmer
158
158
  underscored_widget_name = self.class.underscored_widget_name(@swt_widget)
159
159
  parent_proxy_class = self.class.widget_proxy_class(self.class.underscored_widget_name(@swt_widget.parent))
160
160
  parent = swt_widget.parent
161
- @parent_proxy = parent.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
161
+ @parent_proxy = parent&.get_data('proxy') || parent_proxy_class.new(swt_widget: parent)
162
162
  end
163
163
  if @swt_widget&.get_data('proxy').nil?
164
164
  @swt_widget.set_data('proxy', self)
@@ -68,8 +68,8 @@ module Glimmer
68
68
  body_root.visible?
69
69
  end
70
70
 
71
- def center
72
- body_root.center
71
+ def center_within_display
72
+ body_root.center_within_display
73
73
  end
74
74
 
75
75
  def start_event_loop
@@ -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
@@ -141,10 +141,9 @@ module Glimmer
141
141
  end
142
142
  end
143
143
 
144
- attr_reader :body_root, :swt_widget, :parent, :swt_style, :options
144
+ attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
145
145
 
146
146
  def initialize(parent, *swt_constants, options, &content)
147
- @parent = parent
148
147
  @swt_style = SWT::SWTProxy[*swt_constants]
149
148
  options ||= {}
150
149
  @options = self.class.options.merge(options)
@@ -156,6 +155,9 @@ module Glimmer
156
155
  raise Glimmer::Error, 'Invalid custom widget for having an empty body! Please fill body block!' if @body_root.nil?
157
156
  @swt_widget = @body_root.swt_widget
158
157
  @swt_widget.set_data('custom_widget', self)
158
+ @parent = parent
159
+ @parent ||= @swt_widget.parent
160
+ @parent_proxy ||= @parent&.get_data('proxy')
159
161
  execute_hooks('after_body')
160
162
  end
161
163
 
@@ -211,10 +213,10 @@ module Glimmer
211
213
 
212
214
  # This method ensures it has an instance method not coming from Glimmer DSL
213
215
  def has_instance_method?(method_name)
214
- respond_to?(method_name) and
216
+ respond_to?(method_name) and
215
217
  !swt_widget&.respond_to?(method_name) and
216
218
  (method(method_name) rescue nil) and
217
- !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
219
+ !method(method_name)&.source_location&.first&.include?('glimmer/dsl/engine.rb') and
218
220
  !method(method_name)&.source_location&.first&.include?('glimmer/swt/widget_proxy.rb')
219
221
  end
220
222
 
@@ -265,13 +267,13 @@ module Glimmer
265
267
  end
266
268
  end
267
269
 
268
- alias local_respond_to? respond_to?
270
+ alias local_respond_to? respond_to?
269
271
  def respond_to?(method, *args, &block)
270
272
  super or
271
273
  can_handle_observation_request?(method) or
272
274
  body_root.respond_to?(method, *args, &block)
273
275
  end
274
-
276
+
275
277
  private
276
278
 
277
279
  def execute_hooks(hook_name)
@@ -24,6 +24,8 @@
24
24
  require_relative 'tetris/model/game'
25
25
 
26
26
  require_relative 'tetris/view/playfield'
27
+ require_relative 'tetris/view/score_lane'
28
+ require_relative 'tetris/view/game_over_dialog'
27
29
 
28
30
  class Tetris
29
31
  include Glimmer::UI::CustomShell
@@ -31,58 +33,50 @@ class Tetris
31
33
  BLOCK_SIZE = 25
32
34
  PLAYFIELD_WIDTH = 10
33
35
  PLAYFIELD_HEIGHT = 20
36
+ PREVIEW_PLAYFIELD_WIDTH = 4
37
+ PREVIEW_PLAYFIELD_HEIGHT = 2
34
38
 
35
39
  before_body {
36
- Model::Game.configure_beeper do
37
- display.beep
38
- end
39
-
40
- Model::Game.start
41
-
42
40
  display {
43
41
  on_swt_keydown { |key_event|
44
- unless Model::Game.current_tetromino.stopped?
45
- case key_event.keyCode
46
- when swt(:arrow_down)
47
- Model::Game.current_tetromino.down
48
- when swt(:arrow_left)
49
- Model::Game.current_tetromino.left
50
- when swt(:arrow_right)
51
- Model::Game.current_tetromino.right
52
- when swt(:shift)
53
- if key_event.keyLocation == swt(:right) # right shift key
54
- Model::Game.current_tetromino.rotate(:right)
55
- elsif key_event.keyLocation == swt(:left) # left shift key
56
- Model::Game.current_tetromino.rotate(:left)
57
- end
58
- when 'd'.bytes.first, swt(:arrow_up)
42
+ case key_event.keyCode
43
+ when swt(:arrow_down)
44
+ Model::Game.current_tetromino.down
45
+ when swt(:arrow_left)
46
+ Model::Game.current_tetromino.left
47
+ when swt(:arrow_right)
48
+ Model::Game.current_tetromino.right
49
+ when swt(:shift)
50
+ if key_event.keyLocation == swt(:right) # right shift key
59
51
  Model::Game.current_tetromino.rotate(:right)
60
- when 'a'.bytes.first
52
+ elsif key_event.keyLocation == swt(:left) # left shift key
61
53
  Model::Game.current_tetromino.rotate(:left)
62
54
  end
55
+ when 'd'.bytes.first, swt(:arrow_up)
56
+ Model::Game.current_tetromino.rotate(:right)
57
+ when 'a'.bytes.first
58
+ Model::Game.current_tetromino.rotate(:left)
63
59
  end
64
60
  }
65
61
  }
62
+
63
+ Model::Game.configure_beeper do
64
+ async_exec {
65
+ display.beep
66
+ }
67
+ end
66
68
  }
67
69
 
68
70
  after_body {
71
+ Model::Game.start
72
+
69
73
  Thread.new {
70
74
  loop {
71
- sleep(0.9)
75
+ sleep(Model::Game.delay)
72
76
  sync_exec {
73
- unless @game_over
77
+ unless Model::Game.game_over?
74
78
  Model::Game.current_tetromino.down
75
- if Model::Game.current_tetromino.stopped? && Model::Game.current_tetromino.row <= 0
76
- @game_over = true
77
- display.beep
78
- message_box(:icon_error) {
79
- text 'Tetris'
80
- message 'Game Over!'
81
- }.open
82
- Model::Game.restart
83
- @game_over = false
84
- end
85
- Model::Game.consider_adding_tetromino
79
+ game_over_dialog(parent_shell: body_root).open if Model::Game.current_tetromino.row <= 0 && Model::Game.current_tetromino.stopped?
86
80
  end
87
81
  }
88
82
  }
@@ -91,10 +85,22 @@ class Tetris
91
85
 
92
86
  body {
93
87
  shell(:no_resize) {
88
+ grid_layout {
89
+ num_columns 2
90
+ make_columns_equal_width false
91
+ margin_width 0
92
+ margin_height 0
93
+ horizontal_spacing 0
94
+ }
95
+
94
96
  text 'Glimmer Tetris'
95
97
  background :gray
98
+
99
+ playfield(game_playfield: Model::Game.playfield, playfield_width: PLAYFIELD_WIDTH, playfield_height: PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
96
100
 
97
- playfield(playfield_width: PLAYFIELD_WIDTH, playfield_height: PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
101
+ score_lane(block_size: BLOCK_SIZE) {
102
+ layout_data(:fill, :fill, false, true)
103
+ }
98
104
  }
99
105
  }
100
106
  end
@@ -31,6 +31,7 @@ class Tetris
31
31
  @color = color
32
32
  end
33
33
 
34
+ # Clears block color. `quietly` option indicates if it should not notify observers by setting value quietly via variable not attribute writer.
34
35
  def clear
35
36
  self.color = COLOR_CLEAR
36
37
  end
@@ -45,4 +46,3 @@ class Tetris
45
46
  end
46
47
  end
47
48
  end
48
-
@@ -25,10 +25,16 @@ require_relative 'tetromino'
25
25
  class Tetris
26
26
  module Model
27
27
  class Game
28
+ SCORE_MULTIPLIER = {1 => 40, 2 => 100, 3 => 300, 4 => 1200}
29
+
28
30
  class << self
31
+ attr_accessor :game_over, :preview_tetromino, :lines, :score, :level
32
+ alias game_over? game_over
33
+
29
34
  def consider_adding_tetromino
30
35
  if tetrominoes.empty? || Game.current_tetromino.stopped?
31
- tetrominoes << Tetromino.new
36
+ preview_tetromino.launch!
37
+ preview_next_tetromino!
32
38
  end
33
39
  end
34
40
 
@@ -42,22 +48,70 @@ class Tetris
42
48
 
43
49
  # Returns blocks in the playfield
44
50
  def playfield
45
- @playfield ||= PLAYFIELD_HEIGHT.times.map {
51
+ @playfield ||= @original_playfield = PLAYFIELD_HEIGHT.times.map {
46
52
  PLAYFIELD_WIDTH.times.map {
47
53
  Block.new
48
54
  }
49
55
  }
50
56
  end
51
57
 
58
+ def hypothetical(&block)
59
+ @playfield = hypothetical_playfield
60
+ block.call
61
+ @playfield = @original_playfield
62
+ end
63
+
64
+ def hypothetical?
65
+ @playfield != @original_playfield
66
+ end
67
+
68
+ def hypothetical_playfield
69
+ PLAYFIELD_HEIGHT.times.map { |row|
70
+ PLAYFIELD_WIDTH.times.map { |column|
71
+ playfield[row][column].clone
72
+ }
73
+ }
74
+ end
75
+
76
+ def preview_playfield
77
+ @preview_playfield ||= PREVIEW_PLAYFIELD_HEIGHT.times.map {|row|
78
+ PREVIEW_PLAYFIELD_WIDTH.times.map {|column|
79
+ Block.new
80
+ }
81
+ }
82
+ end
83
+
84
+ def preview_next_tetromino!
85
+ self.preview_tetromino = Tetromino.new
86
+ end
87
+
88
+ def calculate_score!(eliminated_lines)
89
+ new_score = SCORE_MULTIPLIER[eliminated_lines] * (level + 1)
90
+ self.score += new_score
91
+ end
92
+
93
+ def level_up!
94
+ self.level += 1 if lines >= self.level*10
95
+ end
96
+
97
+ def delay
98
+ [1.1 - (level.to_i * 0.1), 0.001].max
99
+ end
100
+
52
101
  def consider_eliminating_lines
53
- cleared_line = false
102
+ eliminated_lines = 0
54
103
  playfield.each_with_index do |row, playfield_row|
55
104
  if row.all? {|block| !block.clear?}
56
- cleared_line = true
105
+ eliminated_lines += 1
57
106
  shift_blocks_down_above_row(playfield_row)
58
107
  end
59
108
  end
60
- beep if cleared_line
109
+ if eliminated_lines > 0
110
+ beep
111
+ self.lines += eliminated_lines
112
+ level_up!
113
+ calculate_score!(eliminated_lines)
114
+ end
61
115
  end
62
116
 
63
117
  def beep
@@ -79,14 +133,21 @@ class Tetris
79
133
  playfield[0].each(&:clear)
80
134
  end
81
135
 
82
- def restart
136
+ def start
137
+ self.level = 1
138
+ self.score = 0
139
+ self.lines = @previoius_lines = 0
83
140
  reset_playfield
141
+ reset_preview_playfield
84
142
  reset_tetrominoes
143
+ preview_next_tetromino!
144
+ consider_adding_tetromino
145
+ self.game_over = false
85
146
  end
86
- alias start restart
147
+ alias restart start
87
148
 
88
149
  def reset_tetrominoes
89
- @tetrominoes = [Tetromino.new]
150
+ @tetrominoes = []
90
151
  end
91
152
 
92
153
  def reset_playfield
@@ -97,14 +158,22 @@ class Tetris
97
158
  end
98
159
  end
99
160
 
161
+ def reset_preview_playfield
162
+ preview_playfield.each do |row|
163
+ row.each do |block|
164
+ block.clear
165
+ end
166
+ end
167
+ end
168
+
100
169
  def playfield_remaining_heights(tetromino = nil)
101
170
  PLAYFIELD_WIDTH.times.map do |playfield_column|
102
171
  (playfield.each_with_index.detect do |row, playfield_row|
103
172
  !row[playfield_column].clear? &&
104
173
  (
105
174
  tetromino.nil? ||
106
- tetromino.bottom_block_for_column(playfield_column).nil? ||
107
- (playfield_row > tetromino.row + tetromino.bottom_block_for_column(playfield_column)[:row])
175
+ (bottom_most_block = tetromino.bottom_most_block_for_column(playfield_column)).nil? ||
176
+ (playfield_row > tetromino.row + bottom_most_block[:row])
108
177
  )
109
178
  end || [nil, PLAYFIELD_HEIGHT])[1]
110
179
  end.to_a
@@ -38,16 +38,31 @@ class Tetris
38
38
  Z: :red,
39
39
  }
40
40
 
41
- attr_reader :letter
41
+ attr_reader :letter, :preview
42
+ alias preview? preview
42
43
  attr_accessor :orientation, :blocks, :row, :column
43
44
 
44
45
  def initialize
45
46
  @letter = LETTER_COLORS.keys.sample
46
47
  @orientation = :north
47
48
  @blocks = default_blocks
49
+ @preview = true
50
+ new_row = 0
51
+ new_column = (PREVIEW_PLAYFIELD_WIDTH - width)/2
52
+ update_playfield(new_row, new_column)
53
+ end
54
+
55
+ def playfield
56
+ @preview ? Game.preview_playfield : Game.playfield
57
+ end
58
+
59
+ def launch!
60
+ remove_from_playfield
61
+ @preview = false
48
62
  new_row = 1 - height
49
63
  new_column = (PLAYFIELD_WIDTH - width)/2
50
64
  update_playfield(new_row, new_column)
65
+ Game.tetrominoes << self
51
66
  end
52
67
 
53
68
  def update_playfield(new_row = nil, new_column = nil)
@@ -61,58 +76,101 @@ class Tetris
61
76
 
62
77
  def add_to_playfield
63
78
  update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
64
- Game.playfield[playfield_row][playfield_column].color = blocks[row_index][column_index].color if playfield_row >= 0 && Game.playfield[playfield_row][playfield_column].clear? && !blocks[row_index][column_index].clear?
79
+ 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?
65
80
  end
66
81
  end
67
82
 
68
83
  def remove_from_playfield
69
84
  return if @row.nil? || @column.nil?
70
85
  update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
71
- Game.playfield[playfield_row][playfield_column].clear if playfield_row >= 0 && !blocks[row_index][column_index].clear? && Game.playfield[playfield_row][playfield_column].color == color
86
+ playfield[playfield_row][playfield_column].clear if playfield_row >= 0 && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column]&.color == color
72
87
  end
73
88
  end
74
89
 
75
- def stopped?(blocks: nil)
76
- blocks ||= @blocks
90
+ def stopped?
91
+ return true if @stopped || @preview
77
92
  playfield_remaining_heights = Game.playfield_remaining_heights(self)
78
- result = bottom_blocks(blocks).any? do |bottom_block|
79
- playfield_column = @column + bottom_block[:column_index]
80
- !bottom_block[:block].clear? &&
81
- (@row + bottom_block[:row]) >= playfield_remaining_heights[playfield_column] - 1
93
+ result = bottom_most_blocks.any? do |bottom_most_block|
94
+ playfield_column = @column + bottom_most_block[:column_index]
95
+ playfield_remaining_heights[playfield_column] &&
96
+ @row + bottom_most_block[:row] >= playfield_remaining_heights[playfield_column] - 1
97
+ end
98
+ if result && !Game.hypothetical?
99
+ @stopped = result
100
+ Game.consider_eliminating_lines
101
+ Model::Game.consider_adding_tetromino
82
102
  end
83
- Game.consider_eliminating_lines if result
84
103
  result
85
104
  end
86
105
 
87
- # Returns blocks at the bottom of a tetromino, which could be from multiple rows depending on shape (e.g. T)
88
- def bottom_blocks(blocks = nil)
89
- blocks ||= @blocks
106
+ # Returns bottom-most blocks of a tetromino, which could be from multiple rows depending on shape (e.g. T)
107
+ def bottom_most_blocks
90
108
  width.times.map do |column_index|
91
109
  row_blocks_with_row_index = @blocks.each_with_index.to_a.reverse.detect do |row_blocks, row_index|
92
110
  !row_blocks[column_index].clear?
93
111
  end
94
- bottom_block = row_blocks_with_row_index[0][column_index]
95
- bottom_block_row = row_blocks_with_row_index[1]
112
+ bottom_most_block = row_blocks_with_row_index[0][column_index]
113
+ bottom_most_block_row = row_blocks_with_row_index[1]
96
114
  {
97
- block: bottom_block,
98
- row: bottom_block_row,
115
+ block: bottom_most_block,
116
+ row: bottom_most_block_row,
99
117
  column_index: column_index
100
118
  }
101
119
  end
102
120
  end
103
121
 
104
- def bottom_block_for_column(column)
105
- bottom_blocks.detect {|bottom_block| (@column + bottom_block[:column_index]) == column}
122
+ def bottom_most_block_for_column(column)
123
+ bottom_most_blocks.detect {|bottom_most_block| (@column + bottom_most_block[:column_index]) == column}
106
124
  end
107
125
 
108
126
  def right_blocked?
109
- (@column == PLAYFIELD_WIDTH - width) || Game.playfield[row][column + width].occupied?
127
+ (@column == PLAYFIELD_WIDTH - width) ||
128
+ right_most_blocks.any? { |right_most_block|
129
+ playfield[@row + right_most_block[:row_index]][@column + right_most_block[:column_index] + 1].occupied?
130
+ }
110
131
  end
111
132
 
112
- def left_blocked?
113
- (@column == 0) || Game.playfield[row][column - 1].occupied?
133
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
134
+ def right_most_blocks
135
+ @blocks.each_with_index.map do |row_blocks, row_index|
136
+ column_block_with_column_index = row_blocks.each_with_index.to_a.reverse.detect do |column_block, column_index|
137
+ !column_block.clear?
138
+ end
139
+ if column_block_with_column_index
140
+ right_most_block = column_block_with_column_index[0]
141
+ {
142
+ block: right_most_block,
143
+ row_index: row_index,
144
+ column_index: column_block_with_column_index[1]
145
+ }
146
+ end
147
+ end.compact
114
148
  end
115
149
 
150
+ def left_blocked?
151
+ (@column == 0) ||
152
+ left_most_blocks.any? { |left_most_block|
153
+ playfield[@row + left_most_block[:row_index]][@column + left_most_block[:column_index] - 1].occupied?
154
+ }
155
+ end
156
+
157
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
158
+ def left_most_blocks
159
+ @blocks.each_with_index.map do |row_blocks, row_index|
160
+ column_block_with_column_index = row_blocks.each_with_index.to_a.detect do |column_block, column_index|
161
+ !column_block.clear?
162
+ end
163
+ if column_block_with_column_index
164
+ left_most_block = column_block_with_column_index[0]
165
+ {
166
+ block: left_most_block,
167
+ row_index: row_index,
168
+ column_index: column_block_with_column_index[1]
169
+ }
170
+ end
171
+ end.compact
172
+ end
173
+
116
174
  def width
117
175
  @blocks[0].size
118
176
  end
@@ -122,6 +180,7 @@ class Tetris
122
180
  end
123
181
 
124
182
  def down
183
+ launch! if preview?
125
184
  unless stopped?
126
185
  new_row = @row + 1
127
186
  update_playfield(new_row, @column)
@@ -145,20 +204,42 @@ class Tetris
145
204
  # Rotate in specified direcation, which can be :right (clockwise) or :left (counterclockwise)
146
205
  def rotate(direction)
147
206
  return if stopped?
148
- array_rotation_value = direction == :right ? -1 : 1
149
- self.orientation = ORIENTATIONS[ORIENTATIONS.rotate(array_rotation_value).index(@orientation)]
150
- new_blocks = Matrix[*@blocks].transpose.to_a
151
- if direction == :right
152
- new_blocks = new_blocks.map(&:reverse)
153
- else
154
- new_blocks = new_blocks.reverse
207
+ can_rotate = nil
208
+ new_blocks = nil
209
+ Game.hypothetical do
210
+ hypothetical_rotated_tetromino = hypothetical_tetromino
211
+ new_blocks = hypothetical_rotated_tetromino.rotate_blocks(direction)
212
+ can_rotate = !hypothetical_rotated_tetromino.stopped? && !hypothetical_rotated_tetromino.right_blocked? && !hypothetical_rotated_tetromino.left_blocked?
155
213
  end
156
- new_blocks = Matrix[*new_blocks].to_a
157
- unless stopped?(blocks: new_blocks) || right_blocked? || left_blocked?
214
+ if can_rotate
158
215
  remove_from_playfield
216
+ self.orientation = ORIENTATIONS[ORIENTATIONS.rotate(direction == :right ? -1 : 1).index(@orientation)]
159
217
  self.blocks = new_blocks
160
218
  update_playfield(@row, @column)
161
219
  end
220
+ rescue => e
221
+ puts e.full_message
222
+ end
223
+
224
+ def rotate_blocks(direction)
225
+ new_blocks = Matrix[*@blocks].transpose.to_a
226
+ if direction == :right
227
+ new_blocks = new_blocks.map(&:reverse)
228
+ else
229
+ new_blocks = new_blocks.reverse
230
+ end
231
+ Matrix[*new_blocks].to_a
232
+ end
233
+
234
+ def hypothetical_tetromino
235
+ clone.tap do |hypo_clone|
236
+ remove_from_playfield
237
+ hypo_clone.blocks = @blocks.map do |row_blocks|
238
+ row_blocks.map do |column_block|
239
+ column_block.clone
240
+ end
241
+ end
242
+ end
162
243
  end
163
244
 
164
245
  def default_blocks
@@ -204,6 +285,10 @@ class Tetris
204
285
  LETTER_COLORS[@letter]
205
286
  end
206
287
 
288
+ def include_block?(block)
289
+ @blocks.flatten.include?(block)
290
+ end
291
+
207
292
  private
208
293
 
209
294
  def block
@@ -24,16 +24,13 @@ class Tetris
24
24
  class Block
25
25
  include Glimmer::UI::CustomWidget
26
26
 
27
- options :block_size, :row, :column
27
+ options :game_playfield, :block_size, :row, :column
28
28
 
29
29
  body {
30
30
  composite {
31
31
  layout nil
32
- layout_data {
33
- width_hint block_size
34
- height_hint block_size
35
- }
36
- background bind(Model::Game.playfield[row][column], :color)
32
+ background bind(game_playfield[row][column], :color)
33
+ # TODO improve shapes to have a bevel look
37
34
  rectangle(0, 0, block_size, block_size)
38
35
  rectangle(3, 3, block_size - 6, block_size - 6) {
39
36
  foreground :gray
@@ -0,0 +1,72 @@
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 View
24
+ class GameOverDialog
25
+ include Glimmer::UI::CustomShell
26
+
27
+ options :parent_shell
28
+
29
+ body {
30
+ dialog(parent_shell) {
31
+ row_layout {
32
+ type :vertical
33
+ center true
34
+ }
35
+ text 'Tetris'
36
+
37
+ label(:center) {
38
+ text 'Game Over!'
39
+ font name: 'Menlo', height: 30, style: :bold
40
+ }
41
+ label # filler
42
+ button {
43
+ text 'Play Again?'
44
+
45
+ on_widget_selected {
46
+ Model::Game.restart
47
+
48
+ body_root.close
49
+ }
50
+ }
51
+
52
+ on_shell_activated {
53
+ Model::Game.game_over = true
54
+ display.beep
55
+ }
56
+
57
+ on_shell_closed {
58
+ exit_game
59
+ }
60
+
61
+ on_key_pressed { |event|
62
+ exit_game if event.keyCode == swt(:cr)
63
+ }
64
+ }
65
+ }
66
+
67
+ def exit_game
68
+ display.dispose if Model::Game.game_over?
69
+ end
70
+ end
71
+ end
72
+ end
@@ -26,20 +26,27 @@ class Tetris
26
26
  class Playfield
27
27
  include Glimmer::UI::CustomWidget
28
28
 
29
- options :playfield_width, :playfield_height, :block_size
29
+ options :game_playfield, :playfield_width, :playfield_height, :block_size
30
30
 
31
31
  body {
32
32
  composite {
33
- grid_layout(playfield_width, true) {
33
+ grid_layout {
34
+ num_columns playfield_width
35
+ make_columns_equal_width true
34
36
  margin_width block_size
35
37
  margin_height block_size
36
38
  horizontal_spacing 0
37
39
  vertical_spacing 0
38
40
  }
39
-
41
+
40
42
  playfield_height.times { |row|
41
43
  playfield_width.times { |column|
42
- block(block_size: block_size, row: row, column: column)
44
+ block(game_playfield: game_playfield, block_size: block_size, row: row, column: column) {
45
+ layout_data {
46
+ width_hint block_size
47
+ height_hint block_size
48
+ }
49
+ }
43
50
  }
44
51
  }
45
52
  }
@@ -0,0 +1,87 @@
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
+ require_relative 'playfield'
24
+
25
+ class Tetris
26
+ module View
27
+ class ScoreLane
28
+ include Glimmer::UI::CustomWidget
29
+
30
+ options :block_size
31
+
32
+ before_body {
33
+ @font_name = 'Menlo'
34
+ @font_height = 32
35
+ }
36
+
37
+ body {
38
+ composite {
39
+ row_layout {
40
+ type :vertical
41
+ center true
42
+ fill true
43
+ margin_width 0
44
+ margin_right block_size
45
+ margin_height block_size
46
+ }
47
+ label(:center) {
48
+ text 'Next'
49
+ font name: @font_name, height: @font_height, style: :bold
50
+ }
51
+ playfield(game_playfield: Model::Game.preview_playfield, playfield_width: PREVIEW_PLAYFIELD_WIDTH, playfield_height: PREVIEW_PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
52
+
53
+ label(:center) {
54
+ text 'Score'
55
+ font name: @font_name, height: @font_height, style: :bold
56
+ }
57
+ label(:center) {
58
+ text bind(Model::Game, :score)
59
+ font height: @font_height
60
+ }
61
+
62
+ label # spacer
63
+
64
+ label(:center) {
65
+ text 'Lines'
66
+ font name: @font_name, height: @font_height, style: :bold
67
+ }
68
+ label(:center) {
69
+ text bind(Model::Game, :lines)
70
+ font height: @font_height
71
+ }
72
+
73
+ label # spacer
74
+
75
+ label(:center) {
76
+ text 'Level'
77
+ font name: @font_name, height: @font_height, style: :bold
78
+ }
79
+ label(:center) {
80
+ text bind(Model::Game, :level)
81
+ font height: @font_height
82
+ }
83
+ }
84
+ }
85
+ end
86
+ end
87
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.2.3
4
+ version: 4.18.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-23 00:00:00.000000000 Z
11
+ date: 2021-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -470,7 +470,9 @@ files:
470
470
  - samples/elaborate/tetris/model/game.rb
471
471
  - samples/elaborate/tetris/model/tetromino.rb
472
472
  - samples/elaborate/tetris/view/block.rb
473
+ - samples/elaborate/tetris/view/game_over_dialog.rb
473
474
  - samples/elaborate/tetris/view/playfield.rb
475
+ - samples/elaborate/tetris/view/score_lane.rb
474
476
  - samples/elaborate/tic_tac_toe.rb
475
477
  - samples/elaborate/tic_tac_toe/board.rb
476
478
  - samples/elaborate/tic_tac_toe/cell.rb