glimmer-dsl-gtk 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/LICENSE.txt +56 -20
- data/README.md +1068 -36
- data/VERSION +1 -1
- data/bin/girb +58 -22
- data/bin/girb_runner.rb +58 -20
- data/glimmer-dsl-gtk.gemspec +0 -0
- data/lib/glimmer/dsl/gtk/dsl.rb +58 -18
- data/lib/glimmer/dsl/gtk/observe_expression.rb +35 -0
- data/lib/glimmer/dsl/gtk/on_expression.rb +56 -18
- data/lib/glimmer/dsl/gtk/operation_expression.rb +79 -0
- data/lib/glimmer/dsl/gtk/property_expression.rb +59 -21
- data/lib/glimmer/dsl/gtk/shape_expression.rb +86 -0
- data/lib/glimmer/dsl/gtk/widget_expression.rb +57 -19
- data/lib/glimmer/gtk/shape/arc.rb +70 -0
- data/lib/glimmer/gtk/shape/arc_negative.rb +70 -0
- data/lib/glimmer/gtk/shape/circle.rb +67 -0
- data/lib/glimmer/gtk/shape/path.rb +113 -0
- data/lib/glimmer/gtk/shape/polygon.rb +92 -0
- data/lib/glimmer/gtk/shape/polyline.rb +91 -0
- data/lib/glimmer/gtk/shape/rectangle.rb +70 -0
- data/lib/glimmer/gtk/shape/rounded_rectangle.rb +70 -0
- data/lib/glimmer/gtk/shape/square.rb +76 -0
- data/lib/glimmer/gtk/shape/triangle.rb +67 -0
- data/lib/glimmer/gtk/shape.rb +230 -0
- data/lib/glimmer/gtk/widget_proxy/application_proxy.rb +56 -18
- data/lib/glimmer/gtk/widget_proxy/box_proxy.rb +56 -18
- data/lib/glimmer/gtk/widget_proxy/drawing_area_proxy.rb +102 -0
- data/lib/glimmer/gtk/widget_proxy/message_dialog_proxy.rb +56 -18
- data/lib/glimmer/gtk/widget_proxy/window_proxy.rb +56 -18
- data/lib/glimmer/gtk/widget_proxy.rb +72 -32
- data/lib/glimmer/gtk.rb +59 -21
- data/lib/glimmer-dsl-gtk.rb +56 -18
- data/samples/elaborate/tetris/model/block.rb +48 -0
- data/samples/elaborate/tetris/model/game.rb +320 -0
- data/samples/elaborate/tetris/model/past_game.rb +39 -0
- data/samples/elaborate/tetris/model/tetromino.rb +329 -0
- data/samples/elaborate/tetris.rb +338 -0
- data/samples/elaborate/widget_gallery.rb +141 -0
- data/samples/hello/hello_drawing_area.rb +84 -0
- data/samples/hello/hello_drawing_area_manual.rb +139 -0
- metadata +29 -6
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 GTK 0.0.
|
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 GTK 0.0.5
|
2
2
|
## Ruby-GNOME Desktop Development GUI Library
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-gtk.svg)](http://badge.fury.io/rb/glimmer-dsl-gtk)
|
4
4
|
[![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
@@ -26,11 +26,11 @@ window {
|
|
26
26
|
}.show
|
27
27
|
```
|
28
28
|
|
29
|
-
Mac
|
29
|
+
Linux | Mac | Windows
|
30
|
+
------|-----|--------
|
31
|
+
![hello world screenshot Windows](/screenshots/glimmer-dsl-gtk-linux-hello-world.png) | ![hello world screenshot Mac](/screenshots/glimmer-dsl-gtk-mac-hello-world.png) | ![hello world screenshot Windows](/screenshots/glimmer-dsl-gtk-windows-hello-world.png)
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
NOTE: Glimmer DSL for GTK is currently in early alpha mode (incomplete proof-of-concept). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
|
33
|
+
NOTE: Glimmer DSL for GTK is currently in early alpha mode (incomplete proof-of-concept). If you want it developed faster, then [open an issue report](https://github.com/AndyObtiva/glimmer-dsl-gtk/issues/new). I have completed some GitHub project features much faster before due to [issue reports](https://github.com/AndyObtiva/glimmer-dsl-gtk/issues) and [pull requests](https://github.com/AndyObtiva/glimmer-dsl-gtk/pulls). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
|
34
34
|
|
35
35
|
Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
|
36
36
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
|
@@ -40,6 +40,33 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
40
40
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
41
41
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
|
42
42
|
|
43
|
+
## Prerequisites
|
44
|
+
|
45
|
+
### Linux
|
46
|
+
|
47
|
+
GNOME-based Linux installations do not need any pre-requisites since they have GTK built-in, so you can skip to [Setup](#setup) right away.
|
48
|
+
|
49
|
+
Still, if you run into issues installing the GTK gem in [Setup](#setup), you may try these commands first:
|
50
|
+
```
|
51
|
+
sudo apt-get install libgtk-3-dev
|
52
|
+
```
|
53
|
+
|
54
|
+
Or run this command if all else fails:
|
55
|
+
```
|
56
|
+
sudo apt install -y -V libgirepository1.0-dev
|
57
|
+
```
|
58
|
+
|
59
|
+
### Mac
|
60
|
+
|
61
|
+
On the Mac, make sure to:
|
62
|
+
- Have [Homebrew](https://brew.sh/) installed
|
63
|
+
- Run this [Homebrew](https://brew.sh/) command to have GTK display GUI icons: `brew install adwaita-icon-theme`
|
64
|
+
- (Optional) You can upgrade your GTK3/GTK4/GTK+ by running: `brew install gtk+3` / `brew install gtk+4` / `brew install gtk+`
|
65
|
+
|
66
|
+
### Windows
|
67
|
+
|
68
|
+
Make sure to install [Ruby](https://www.ruby-lang.org) with MSYS & MING toolchains from [RubyInstaller](https://rubyinstaller.org/downloads/)
|
69
|
+
|
43
70
|
## Setup
|
44
71
|
|
45
72
|
### Option 1: Install
|
@@ -53,7 +80,7 @@ gem install glimmer-dsl-gtk
|
|
53
80
|
|
54
81
|
Add the following to `Gemfile`:
|
55
82
|
```
|
56
|
-
gem 'glimmer-dsl-gtk', '~> 0.0.
|
83
|
+
gem 'glimmer-dsl-gtk', '~> 0.0.5'
|
57
84
|
```
|
58
85
|
|
59
86
|
And, then run:
|
@@ -80,9 +107,9 @@ window {
|
|
80
107
|
}.show
|
81
108
|
```
|
82
109
|
|
83
|
-
For actual application development outside of simple demos, mixin the `Glimmer` module into
|
110
|
+
For actual application development outside of simple demos, mixin the `Glimmer` module into a custom application class instead:
|
84
111
|
|
85
|
-
```
|
112
|
+
```ruby
|
86
113
|
require 'glimmer-dsl-gtk'
|
87
114
|
|
88
115
|
class SomeGlimmerApplication
|
@@ -109,6 +136,175 @@ SomeGlimmerApplication.new.launch
|
|
109
136
|
- Properties: All GTK widget properties can be set via lowercase underscored names (without the 'set_' prefix) nested under widget keywords (e.g. `window {title 'Hello, World'}` sets `title` property of `window`)
|
110
137
|
- Signals: All GTK signals can be wired with `on(signal) { ... }` syntax (e.g. `on(:activate) { do_something }`)
|
111
138
|
|
139
|
+
### MVC Observer Pattern
|
140
|
+
|
141
|
+
In Smalltalk-MVC ([Model View Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) Architectural Pattern), the View is an active View that observes the Model for changes and updates itself.
|
142
|
+
|
143
|
+
![MVC](http://3.bp.blogspot.com/-4eW59Ao0ess/ToiBzAiYdZI/AAAAAAAAAOg/SiYa6XHwBFE/s320/Screen+shot+2011-10-02+at+10.22.11+AM.png)
|
144
|
+
|
145
|
+
This can be achieved with the Glimmer GUI DSL using the `observe` keyword, which takes a model (any object, including `self`) and attribute Symbol or String expression (e.g. `:count` or `'address.street'`).
|
146
|
+
|
147
|
+
The model is automatically enhanced as an `Glimmer::DataBinding::ObservableModel` / `Glimmer::DataBinding::ObservableHash` / `Glimmer::DataBinding::ObservableArray` depending on its type to support notifying observers of attribute changes (when performed using the attribute writer, which automatically calls added method `notify_observers(attribute)`)
|
148
|
+
|
149
|
+
Note that it is usually recommended to observe external model objects (not `self`), but `self` is OK in very simple cases or presentation-related attributes only.
|
150
|
+
|
151
|
+
### Declarative Cairo Graphics
|
152
|
+
|
153
|
+
[Cairo](https://www.cairographics.org/) is the engine behind drawing arbitrary 2D geometric shapes in [GTK](https://www.gtk.org/).
|
154
|
+
|
155
|
+
In [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk), you can draw Cairo shapes declaratively in a way similar to how SVG works, but using one language; Ruby, thus being able to utilize Ruby logic (e.g. if statement or each loop) with it effortlessly when needed.
|
156
|
+
|
157
|
+
Below is a quick tutorial consisting of samples inspired and ported from [Mohit Sindhwani's blog post "Cairo with Ruby - Samples using RCairo"](https://notepad.onghu.com/2021/cairo-samples-in-ruby/).
|
158
|
+
|
159
|
+
### Arc
|
160
|
+
|
161
|
+
Example (you may copy/paste in [`girb`](#girb-glimmer-irb))
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
require 'glimmer-dsl-gtk'
|
165
|
+
|
166
|
+
include Glimmer
|
167
|
+
|
168
|
+
window {
|
169
|
+
title 'Hello, Drawing Area!'
|
170
|
+
default_size 256, 256
|
171
|
+
|
172
|
+
drawing_area {
|
173
|
+
# Surface Paint
|
174
|
+
paint 242.25, 242.25, 242.25
|
175
|
+
|
176
|
+
# Set up the parameters
|
177
|
+
xc = 128.0
|
178
|
+
yc = 128.0
|
179
|
+
radius = 100.0
|
180
|
+
angle1 = 45.0 * (Math::PI/180.0) # angles are specified
|
181
|
+
angle2 = 180.0 * (Math::PI/180.0) # in radians
|
182
|
+
|
183
|
+
# The main arc
|
184
|
+
arc(xc, yc, radius, angle1, angle2) {
|
185
|
+
stroke 0, 0, 0
|
186
|
+
line_width 10
|
187
|
+
}
|
188
|
+
|
189
|
+
# Draw helping lines
|
190
|
+
|
191
|
+
# First, the circle at the centre
|
192
|
+
arc(xc, yc, 10.0, 0, 2*Math::PI) {
|
193
|
+
fill 255, 51, 51, 0.6
|
194
|
+
}
|
195
|
+
|
196
|
+
# Then, the lines reaching out
|
197
|
+
path {
|
198
|
+
arc xc, yc, radius, angle1, angle1
|
199
|
+
line_to xc, yc
|
200
|
+
arc xc, yc, radius, angle2, angle2
|
201
|
+
line_to xc, yc
|
202
|
+
|
203
|
+
stroke 255, 51, 51, 0.6
|
204
|
+
line_width 6
|
205
|
+
}
|
206
|
+
}
|
207
|
+
}.show
|
208
|
+
```
|
209
|
+
|
210
|
+
![Arc](/screenshots/glimmer-dsl-gtk-mac-cairo-arc.png)
|
211
|
+
|
212
|
+
### Arc Negative
|
213
|
+
|
214
|
+
Example (you may copy/paste in [`girb`](#girb-glimmer-irb))
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
require 'glimmer-dsl-gtk'
|
218
|
+
|
219
|
+
include Glimmer
|
220
|
+
|
221
|
+
window {
|
222
|
+
title 'Arc Negative'
|
223
|
+
default_size 256, 256
|
224
|
+
|
225
|
+
drawing_area {
|
226
|
+
# Surface Paint
|
227
|
+
paint 255, 255, 255
|
228
|
+
|
229
|
+
# Set up the parameters
|
230
|
+
xc = 128.0
|
231
|
+
yc = 128.0
|
232
|
+
radius = 100.0
|
233
|
+
angle1 = 45.0 * (Math::PI/180.0) # angles are specified
|
234
|
+
angle2 = 180.0 * (Math::PI/180.0) # in radians
|
235
|
+
|
236
|
+
# The main negative arc
|
237
|
+
arc_negative(xc, yc, radius, angle1, angle2) {
|
238
|
+
stroke 0, 0, 0
|
239
|
+
line_width 10
|
240
|
+
}
|
241
|
+
|
242
|
+
# Draw helping lines
|
243
|
+
|
244
|
+
# First, the circle at the centre
|
245
|
+
arc(xc, yc, 10.0, 0, 2*Math::PI) {
|
246
|
+
fill 255, 51, 51, 0.6
|
247
|
+
}
|
248
|
+
|
249
|
+
# Then, the lines reaching out
|
250
|
+
path {
|
251
|
+
arc(xc, yc, radius, angle1, angle1)
|
252
|
+
line_to(xc, yc)
|
253
|
+
arc(xc, yc, radius, angle2, angle2)
|
254
|
+
line_to(xc, yc)
|
255
|
+
|
256
|
+
stroke 255, 51, 51, 0.6
|
257
|
+
line_width 6
|
258
|
+
}
|
259
|
+
}
|
260
|
+
}.show
|
261
|
+
```
|
262
|
+
|
263
|
+
![Arc Negative](/screenshots/glimmer-dsl-gtk-mac-cairo-arc-negative.png)
|
264
|
+
|
265
|
+
### Clip
|
266
|
+
|
267
|
+
Example (you may copy/paste in [`girb`](#girb-glimmer-irb))
|
268
|
+
|
269
|
+
```ruby
|
270
|
+
require 'glimmer-dsl-gtk'
|
271
|
+
|
272
|
+
include Glimmer
|
273
|
+
|
274
|
+
window {
|
275
|
+
title 'Clip'
|
276
|
+
default_size 256, 256
|
277
|
+
|
278
|
+
drawing_area {
|
279
|
+
# Surface Paint
|
280
|
+
paint 255, 255, 255
|
281
|
+
|
282
|
+
# Designate arc as the clipping area
|
283
|
+
arc(128.0, 128.0, 76.8, 0, 2 * Math::PI) {
|
284
|
+
clip true
|
285
|
+
}
|
286
|
+
|
287
|
+
# Rectangle will get clipped by arc
|
288
|
+
rectangle(0, 0, 256, 256) {
|
289
|
+
fill 0, 0, 0
|
290
|
+
}
|
291
|
+
|
292
|
+
# Path will get clipped by arc
|
293
|
+
path {
|
294
|
+
move_to 0, 0
|
295
|
+
line_to 256, 256
|
296
|
+
move_to 256, 0
|
297
|
+
line_to 0, 256
|
298
|
+
|
299
|
+
stroke 0, 255, 0
|
300
|
+
line_width 10
|
301
|
+
}
|
302
|
+
}
|
303
|
+
}.show
|
304
|
+
```
|
305
|
+
|
306
|
+
![Clip](/screenshots/glimmer-dsl-gtk-mac-cairo-clip.png)
|
307
|
+
|
112
308
|
## Girb (Glimmer IRB)
|
113
309
|
|
114
310
|
You can run the `girb` command (`bin/girb` if you cloned the project locally):
|
@@ -117,7 +313,17 @@ You can run the `girb` command (`bin/girb` if you cloned the project locally):
|
|
117
313
|
girb
|
118
314
|
```
|
119
315
|
|
120
|
-
|
316
|
+
Linux
|
317
|
+
|
318
|
+
![girb screenshot linux](/screenshots/glimmer-dsl-gtk-linux-girb.png)
|
319
|
+
|
320
|
+
Mac
|
321
|
+
|
322
|
+
![girb screenshot mac](/screenshots/glimmer-dsl-gtk-mac-girb.png)
|
323
|
+
|
324
|
+
Windows
|
325
|
+
|
326
|
+
![girb screenshot windows](/screenshots/glimmer-dsl-gtk-windows-girb.png)
|
121
327
|
|
122
328
|
This gives you `irb` with the `glimmer-dsl-gtk` gem loaded and the `Glimmer` module mixed into the main object for easy experimentation with GUI.
|
123
329
|
|
@@ -125,15 +331,17 @@ Gotcha: On the Mac, when you close a window opened in `girb`, it remains open un
|
|
125
331
|
|
126
332
|
## Samples
|
127
333
|
|
334
|
+
You may checkout the [samples](samples) directory for examples of using [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk).
|
335
|
+
|
128
336
|
### Hello Samples
|
129
337
|
|
130
338
|
#### Hello, World!
|
131
339
|
|
132
340
|
[samples/hello/hello_world.rb](/samples/hello/hello_world.rb)
|
133
341
|
|
134
|
-
Mac
|
135
|
-
|
136
|
-
![hello world screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-world.png)
|
342
|
+
Linux | Mac | Windows
|
343
|
+
------|-----|--------
|
344
|
+
![hello world screenshot Windows](/screenshots/glimmer-dsl-gtk-linux-hello-world.png) | ![hello world screenshot Mac](/screenshots/glimmer-dsl-gtk-mac-hello-world.png) | ![hello world screenshot Windows](/screenshots/glimmer-dsl-gtk-windows-hello-world.png)
|
137
345
|
|
138
346
|
Run (via installed gem):
|
139
347
|
|
@@ -161,9 +369,9 @@ window {
|
|
161
369
|
|
162
370
|
[samples/hello/hello_application.rb](/samples/hello/hello_application.rb)
|
163
371
|
|
164
|
-
Mac
|
165
|
-
|
166
|
-
![hello application screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-application.png)
|
372
|
+
Linux | Mac | Windows
|
373
|
+
------|-----|--------
|
374
|
+
![hello application screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-application.png) | ![hello application screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-application.png) | ![hello application screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-application.png)
|
167
375
|
|
168
376
|
Run (via installed gem):
|
169
377
|
|
@@ -197,11 +405,9 @@ application('org.glimmer.hello-application', :flags_none) {
|
|
197
405
|
|
198
406
|
[samples/hello/hello_button.rb](/samples/hello/hello_button.rb)
|
199
407
|
|
200
|
-
Mac
|
201
|
-
|
202
|
-
![hello button screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-button.png)
|
203
|
-
|
204
|
-
![hello button clicked screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-button-clicked.png)
|
408
|
+
Linux | Mac | Windows
|
409
|
+
------|-----|--------
|
410
|
+
![hello button screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-button.png) ![hello button clicked screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-button-clicked.png) | ![hello button screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-button.png) ![hello button clicked screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-button-clicked.png) | ![hello button screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-button.png) ![hello button clicked screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-button-clicked.png)
|
205
411
|
|
206
412
|
Run (via installed gem):
|
207
413
|
|
@@ -244,11 +450,9 @@ window { |w|
|
|
244
450
|
|
245
451
|
[samples/hello/hello_entry.rb](/samples/hello/hello_entry.rb)
|
246
452
|
|
247
|
-
Mac
|
248
|
-
|
249
|
-
![hello entry screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-entry.png)
|
250
|
-
|
251
|
-
![hello entry submitted screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-entry-submitted.png)
|
453
|
+
Linux | Mac | Windows
|
454
|
+
------|-----|--------
|
455
|
+
![hello entry screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-entry.png) ![hello entry submitted screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-entry-submitted.png) | ![hello entry screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-entry.png) ![hello entry submitted screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-entry-submitted.png) | ![hello entry screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-entry.png) ![hello entry submitted screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-entry-submitted.png)
|
252
456
|
|
253
457
|
Run (via installed gem):
|
254
458
|
|
@@ -297,6 +501,844 @@ window { |w|
|
|
297
501
|
}.show
|
298
502
|
```
|
299
503
|
|
504
|
+
#### Hello, Drawing Area!
|
505
|
+
|
506
|
+
This demonstrates the very intuitive (Glimmer-only) declarative cairo shape drawing syntax for the `drawing_area` widget.
|
507
|
+
|
508
|
+
[samples/hello/hello_drawing_area.rb](/samples/hello/hello_drawing_area.rb)
|
509
|
+
|
510
|
+
Linux | Mac | Windows
|
511
|
+
------|-----|--------
|
512
|
+
![hello drawing area screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-drawing-area.png) | ![hello drawing area screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-drawing-area.png) | ![hello drawing area screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-drawing-area.png)
|
513
|
+
|
514
|
+
Run (via installed gem):
|
515
|
+
|
516
|
+
```
|
517
|
+
ruby -r glimmer-dsl-gtk -e "require 'samples/hello/hello_drawing_area'"
|
518
|
+
```
|
519
|
+
|
520
|
+
Run (via locally cloned project):
|
521
|
+
|
522
|
+
```
|
523
|
+
ruby -r ./lib/glimmer-dsl-gtk.rb samples/hello/hello_drawing_area.rb
|
524
|
+
```
|
525
|
+
|
526
|
+
Code:
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
require 'glimmer-dsl-gtk'
|
530
|
+
|
531
|
+
include Glimmer
|
532
|
+
|
533
|
+
window {
|
534
|
+
title 'Hello, Drawing Area!'
|
535
|
+
default_size 400, 400
|
536
|
+
|
537
|
+
drawing_area {
|
538
|
+
paint 255, 255, 255
|
539
|
+
|
540
|
+
arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90) {
|
541
|
+
fill 255, 0, 0
|
542
|
+
stroke 0, 128, 255
|
543
|
+
line_width 3
|
544
|
+
}
|
545
|
+
|
546
|
+
arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30) {
|
547
|
+
fill 255, 0, 0
|
548
|
+
stroke 0, 128, 255
|
549
|
+
line_width 3
|
550
|
+
}
|
551
|
+
|
552
|
+
circle(85, 285, 45) {
|
553
|
+
fill 255, 0, 0
|
554
|
+
stroke 0, 128, 255
|
555
|
+
line_width 3
|
556
|
+
}
|
557
|
+
|
558
|
+
rectangle(140, 40, 180, 90) {
|
559
|
+
fill 255, 255, 0
|
560
|
+
stroke 255, 0, 0
|
561
|
+
line_width 3
|
562
|
+
}
|
563
|
+
|
564
|
+
rounded_rectangle(140, 140, 180, 90, 30, 20) {
|
565
|
+
fill 255, 255, 0
|
566
|
+
stroke 255, 0, 0
|
567
|
+
line_width 3
|
568
|
+
}
|
569
|
+
|
570
|
+
triangle(140, 240, 320, 240, 230, 330) {
|
571
|
+
fill 255, 255, 0
|
572
|
+
stroke 255, 0, 0
|
573
|
+
line_width 3
|
574
|
+
}
|
575
|
+
|
576
|
+
path {
|
577
|
+
move_to 160, 100
|
578
|
+
curve_to 190, 60, 200, 80, 210, 70
|
579
|
+
curve_to 240, 80, 250, 100, 260, 90
|
580
|
+
curve_to 290, 90, 300, 110, 310, 100
|
581
|
+
|
582
|
+
fill 0, 255, 0
|
583
|
+
stroke 0, 0, 255
|
584
|
+
line_width 3
|
585
|
+
}
|
586
|
+
|
587
|
+
path {
|
588
|
+
move_to 200, 150
|
589
|
+
line_to 270, 170
|
590
|
+
line_to 250, 220
|
591
|
+
line_to 220, 190
|
592
|
+
line_to 200, 200
|
593
|
+
line_to 180, 170
|
594
|
+
close_path
|
595
|
+
|
596
|
+
fill 0, 255, 0
|
597
|
+
stroke 0, 0, 255
|
598
|
+
line_width 3
|
599
|
+
}
|
600
|
+
|
601
|
+
polygon(200, 260, 270, 270, 250, 290, 220, 290, 200, 280, 180, 270) {
|
602
|
+
fill 0, 255, 0
|
603
|
+
stroke 0, 0, 255
|
604
|
+
line_width 3
|
605
|
+
}
|
606
|
+
|
607
|
+
polyline(270, 320, 250, 340, 220, 340, 200, 330, 180, 320) {
|
608
|
+
stroke 0, 0, 255
|
609
|
+
line_width 3
|
610
|
+
}
|
611
|
+
}
|
612
|
+
}.show
|
613
|
+
```
|
614
|
+
|
615
|
+
#### Hello, Drawing Area (Manual)!
|
616
|
+
|
617
|
+
This demonstrates the manual (non-Glimmer) imperative cairo shape drawing syntax for the `drawing_area` widget (might be useful in very exceptional rare cases).
|
618
|
+
|
619
|
+
[samples/hello/hello_drawing_area_manual.rb](/samples/hello/hello_drawing_area_manual.rb)
|
620
|
+
|
621
|
+
Linux | Mac | Windows
|
622
|
+
------|-----|--------
|
623
|
+
![hello drawing area manual screenshot](/screenshots/glimmer-dsl-gtk-linux-hello-drawing-area-manual.png) | ![hello drawing area manual screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-drawing-area-manual.png) | ![hello drawing area manual screenshot](/screenshots/glimmer-dsl-gtk-windows-hello-drawing-area-manual.png)
|
624
|
+
|
625
|
+
Run (via installed gem):
|
626
|
+
|
627
|
+
```
|
628
|
+
ruby -r glimmer-dsl-gtk -e "require 'samples/hello/hello_drawing_area_manual'"
|
629
|
+
```
|
630
|
+
|
631
|
+
Run (via locally cloned project):
|
632
|
+
|
633
|
+
```
|
634
|
+
ruby -r ./lib/glimmer-dsl-gtk.rb samples/hello/hello_drawing_area_manual.rb
|
635
|
+
```
|
636
|
+
|
637
|
+
Code:
|
638
|
+
|
639
|
+
```ruby
|
640
|
+
require 'glimmer-dsl-gtk'
|
641
|
+
|
642
|
+
include Glimmer
|
643
|
+
|
644
|
+
window {
|
645
|
+
title 'Hello, Drawing Area (Manual)!'
|
646
|
+
default_size 400, 400
|
647
|
+
|
648
|
+
drawing_area {
|
649
|
+
on(:draw) do |drawing_area_widget, cairo_context|
|
650
|
+
cairo_context.set_source_rgb(255/255.0, 255/255.0, 255/255.0)
|
651
|
+
cairo_context.paint
|
652
|
+
|
653
|
+
cairo_context.arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90)
|
654
|
+
cairo_context.set_source_rgb(255, 0, 0)
|
655
|
+
cairo_context.fill
|
656
|
+
|
657
|
+
cairo_context.arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90)
|
658
|
+
cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
|
659
|
+
cairo_context.set_line_width(3)
|
660
|
+
cairo_context.stroke
|
661
|
+
|
662
|
+
cairo_context.arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30)
|
663
|
+
cairo_context.set_source_rgb(255/255.0, 0, 0)
|
664
|
+
cairo_context.fill
|
665
|
+
|
666
|
+
cairo_context.arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30)
|
667
|
+
cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
|
668
|
+
cairo_context.set_line_width(3)
|
669
|
+
cairo_context.stroke
|
670
|
+
|
671
|
+
cairo_context.circle(85, 285, 45)
|
672
|
+
cairo_context.set_source_rgb(255/255.0, 0, 0)
|
673
|
+
cairo_context.fill
|
674
|
+
|
675
|
+
cairo_context.circle(85, 285, 45)
|
676
|
+
cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
|
677
|
+
cairo_context.set_line_width(3)
|
678
|
+
cairo_context.stroke
|
679
|
+
|
680
|
+
cairo_context.rectangle(140, 40, 180, 90)
|
681
|
+
cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
|
682
|
+
cairo_context.fill
|
683
|
+
|
684
|
+
cairo_context.rectangle(140, 40, 180, 90)
|
685
|
+
cairo_context.set_source_rgb(255/255.0, 0, 0)
|
686
|
+
cairo_context.set_line_width(3)
|
687
|
+
cairo_context.stroke
|
688
|
+
|
689
|
+
cairo_context.rounded_rectangle(140, 140, 180, 90, 30, 20)
|
690
|
+
cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
|
691
|
+
cairo_context.fill
|
692
|
+
|
693
|
+
cairo_context.rounded_rectangle(140, 140, 180, 90, 30, 20)
|
694
|
+
cairo_context.set_source_rgb(255/255.0, 0, 0)
|
695
|
+
cairo_context.set_line_width(3)
|
696
|
+
cairo_context.stroke
|
697
|
+
|
698
|
+
cairo_context.triangle(140, 240, 320, 240, 230, 330)
|
699
|
+
cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
|
700
|
+
cairo_context.fill
|
701
|
+
|
702
|
+
cairo_context.triangle(140, 240, 320, 240, 230, 330)
|
703
|
+
cairo_context.set_source_rgb(255/255.0, 0, 0)
|
704
|
+
cairo_context.set_line_width(3)
|
705
|
+
cairo_context.stroke
|
706
|
+
|
707
|
+
cairo_context.new_path
|
708
|
+
cairo_context.move_to 160, 100
|
709
|
+
cairo_context.curve_to 190, 60, 200, 80, 210, 70
|
710
|
+
cairo_context.curve_to 240, 80, 250, 100, 260, 90
|
711
|
+
cairo_context.curve_to 290, 90, 300, 110, 310, 100
|
712
|
+
cairo_context.set_source_rgb(0, 255/255.0, 0)
|
713
|
+
cairo_context.fill
|
714
|
+
|
715
|
+
cairo_context.new_path
|
716
|
+
cairo_context.move_to 160, 100
|
717
|
+
cairo_context.curve_to 190, 60, 200, 80, 210, 70
|
718
|
+
cairo_context.curve_to 240, 80, 250, 100, 260, 90
|
719
|
+
cairo_context.curve_to 290, 90, 300, 110, 310, 100
|
720
|
+
cairo_context.set_source_rgb(0, 0, 255/255.0)
|
721
|
+
cairo_context.stroke
|
722
|
+
|
723
|
+
cairo_context.new_path
|
724
|
+
cairo_context.move_to 200, 150
|
725
|
+
cairo_context.line_to 270, 170
|
726
|
+
cairo_context.line_to 250, 220
|
727
|
+
cairo_context.line_to 220, 190
|
728
|
+
cairo_context.line_to 200, 200
|
729
|
+
cairo_context.line_to 180, 170
|
730
|
+
cairo_context.close_path
|
731
|
+
cairo_context.set_source_rgb(0, 255/255.0, 0)
|
732
|
+
cairo_context.fill
|
733
|
+
|
734
|
+
cairo_context.new_path
|
735
|
+
cairo_context.move_to 200, 150
|
736
|
+
cairo_context.line_to 270, 170
|
737
|
+
cairo_context.line_to 250, 220
|
738
|
+
cairo_context.line_to 220, 190
|
739
|
+
cairo_context.line_to 200, 200
|
740
|
+
cairo_context.line_to 180, 170
|
741
|
+
cairo_context.close_path
|
742
|
+
cairo_context.set_source_rgb(0, 0, 255/255.0)
|
743
|
+
cairo_context.stroke
|
744
|
+
|
745
|
+
cairo_context.new_path
|
746
|
+
cairo_context.move_to 200, 260
|
747
|
+
cairo_context.line_to 270, 270
|
748
|
+
cairo_context.line_to 250, 290
|
749
|
+
cairo_context.line_to 220, 290
|
750
|
+
cairo_context.line_to 200, 280
|
751
|
+
cairo_context.line_to 180, 270
|
752
|
+
cairo_context.close_path
|
753
|
+
cairo_context.set_source_rgb(0, 255/255.0, 0)
|
754
|
+
cairo_context.fill
|
755
|
+
|
756
|
+
cairo_context.new_path
|
757
|
+
cairo_context.move_to 200, 260
|
758
|
+
cairo_context.line_to 270, 270
|
759
|
+
cairo_context.line_to 250, 290
|
760
|
+
cairo_context.line_to 220, 290
|
761
|
+
cairo_context.line_to 200, 280
|
762
|
+
cairo_context.line_to 180, 270
|
763
|
+
cairo_context.close_path
|
764
|
+
cairo_context.set_source_rgb(0, 0, 255/255.0)
|
765
|
+
cairo_context.stroke
|
766
|
+
|
767
|
+
cairo_context.new_path
|
768
|
+
cairo_context.move_to 200, 260
|
769
|
+
cairo_context.move_to 270, 320
|
770
|
+
cairo_context.line_to 250, 340
|
771
|
+
cairo_context.line_to 220, 340
|
772
|
+
cairo_context.line_to 200, 330
|
773
|
+
cairo_context.line_to 180, 320
|
774
|
+
cairo_context.set_source_rgb(0, 0, 255/255.0)
|
775
|
+
cairo_context.stroke
|
776
|
+
end
|
777
|
+
}
|
778
|
+
}.show
|
779
|
+
```
|
780
|
+
|
781
|
+
### Elaborate Samples
|
782
|
+
|
783
|
+
#### Widget Gallery
|
784
|
+
|
785
|
+
[samples/elaborate/widget_gallery.rb](/samples/elaborate/widget_gallery.rb)
|
786
|
+
|
787
|
+
Linux | Mac | Windows
|
788
|
+
------|-----|--------
|
789
|
+
![widget gallery text](/screenshots/glimmer-dsl-gtk-linux-widget-gallery-text.png) ![widget gallery button](/screenshots/glimmer-dsl-gtk-linux-widget-gallery-button.png) ![widget gallery selection](/screenshots/glimmer-dsl-gtk-linux-widget-gallery-selection.png) ![widget gallery organizer](/screenshots/glimmer-dsl-gtk-linux-widget-gallery-organizer.png) ![widget gallery progress](/screenshots/glimmer-dsl-gtk-linux-widget-gallery-progress.png) | ![widget gallery text](/screenshots/glimmer-dsl-gtk-mac-widget-gallery-text.png) ![widget gallery button](/screenshots/glimmer-dsl-gtk-mac-widget-gallery-button.png) ![widget gallery selection](/screenshots/glimmer-dsl-gtk-mac-widget-gallery-selection.png) ![widget gallery organizer](/screenshots/glimmer-dsl-gtk-mac-widget-gallery-organizer.png) ![widget gallery progress](/screenshots/glimmer-dsl-gtk-mac-widget-gallery-progress.png) | ![widget gallery text](/screenshots/glimmer-dsl-gtk-windows-widget-gallery-text.png) ![widget gallery button](/screenshots/glimmer-dsl-gtk-windows-widget-gallery-button.png) ![widget gallery selection](/screenshots/glimmer-dsl-gtk-windows-widget-gallery-selection.png) ![widget gallery organizer](/screenshots/glimmer-dsl-gtk-windows-widget-gallery-organizer.png) ![widget gallery progress](/screenshots/glimmer-dsl-gtk-windows-widget-gallery-progress.png)
|
790
|
+
|
791
|
+
Run (via installed gem):
|
792
|
+
|
793
|
+
```
|
794
|
+
ruby -r glimmer-dsl-gtk -e "require 'samples/elaborate/widget_gallery'"
|
795
|
+
```
|
796
|
+
|
797
|
+
Run (via locally cloned project):
|
798
|
+
|
799
|
+
```
|
800
|
+
ruby -r ./lib/glimmer-dsl-gtk.rb samples/elaborate/widget_gallery.rb
|
801
|
+
```
|
802
|
+
|
803
|
+
Code:
|
804
|
+
|
805
|
+
```ruby
|
806
|
+
require 'glimmer-dsl-gtk'
|
807
|
+
|
808
|
+
include Glimmer
|
809
|
+
|
810
|
+
application('org.glimmer.hello-application') {
|
811
|
+
on(:activate) do |app|
|
812
|
+
application_window(app) {
|
813
|
+
title 'Widget Gallery'
|
814
|
+
|
815
|
+
notebook { |n|
|
816
|
+
f1 = frame {
|
817
|
+
alignment(1, 1, 1, 1) {
|
818
|
+
padding 15, 15, 15, 15
|
819
|
+
|
820
|
+
box(:vertical) {
|
821
|
+
spacing 10
|
822
|
+
|
823
|
+
label('Entry')
|
824
|
+
entry {
|
825
|
+
text 'Enter One Line of Text'
|
826
|
+
}
|
827
|
+
|
828
|
+
label('Search Entry')
|
829
|
+
search_entry {
|
830
|
+
text 'Enter Search Term'
|
831
|
+
}
|
832
|
+
|
833
|
+
label('Spin Button')
|
834
|
+
spin_button(1, 100, 1) {
|
835
|
+
}
|
836
|
+
|
837
|
+
label('Combo Box Text')
|
838
|
+
cb = combo_box_text {
|
839
|
+
}
|
840
|
+
3.times { |n| cb.append_text "Option #{n + 1}" }
|
841
|
+
}
|
842
|
+
}
|
843
|
+
}
|
844
|
+
n.set_tab_label_text(f1.gtk, 'Text')
|
845
|
+
|
846
|
+
f2 = frame {
|
847
|
+
alignment(1, 1, 1, 1) {
|
848
|
+
padding 15, 15, 15, 15
|
849
|
+
|
850
|
+
box(:vertical) {
|
851
|
+
spacing 10
|
852
|
+
|
853
|
+
label('Button')
|
854
|
+
button('Push Me')
|
855
|
+
|
856
|
+
label('Radio Button')
|
857
|
+
box(:horizontal) {
|
858
|
+
rb = radio_button('One')
|
859
|
+
radio_button(rb, 'Two')
|
860
|
+
radio_button(rb, 'Three')
|
861
|
+
}
|
862
|
+
|
863
|
+
label('Check Button')
|
864
|
+
box(:horizontal) {
|
865
|
+
check_button('One')
|
866
|
+
check_button('Two')
|
867
|
+
check_button('Three')
|
868
|
+
}
|
869
|
+
}
|
870
|
+
}
|
871
|
+
}
|
872
|
+
n.set_tab_label_text(f2.gtk, 'Button')
|
873
|
+
|
874
|
+
f3 = frame {
|
875
|
+
alignment(1, 1, 1, 1) {
|
876
|
+
padding 15, 15, 15, 15
|
877
|
+
|
878
|
+
box(:vertical) {
|
879
|
+
spacing 10
|
880
|
+
|
881
|
+
label('Horizontal Scale')
|
882
|
+
h_scale(1, 100, 1) {
|
883
|
+
visible true
|
884
|
+
}
|
885
|
+
|
886
|
+
label('Vertical Scale')
|
887
|
+
v_scale(1, 100, 1) {
|
888
|
+
visible true
|
889
|
+
height_request 200
|
890
|
+
}
|
891
|
+
}
|
892
|
+
}
|
893
|
+
}
|
894
|
+
n.set_tab_label_text(f3.gtk, 'Selection')
|
895
|
+
|
896
|
+
f4 = frame {
|
897
|
+
alignment(1, 1, 1, 1) {
|
898
|
+
padding 15, 15, 15, 15
|
899
|
+
|
900
|
+
box(:vertical) {
|
901
|
+
spacing 10
|
902
|
+
|
903
|
+
label('Expander')
|
904
|
+
3.times do |n|
|
905
|
+
expander {
|
906
|
+
label "Item #{n + 1}"
|
907
|
+
|
908
|
+
label("Item #{n + 1} Expanded") {
|
909
|
+
}
|
910
|
+
}
|
911
|
+
end
|
912
|
+
}
|
913
|
+
}
|
914
|
+
}
|
915
|
+
n.set_tab_label_text(f4.gtk, 'Organizer')
|
916
|
+
|
917
|
+
f5 = frame {
|
918
|
+
alignment(1, 1, 1, 1) {
|
919
|
+
padding 15, 15, 15, 15
|
920
|
+
|
921
|
+
box(:vertical) {
|
922
|
+
spacing 10
|
923
|
+
|
924
|
+
label('Progress Bar')
|
925
|
+
pb = progress_bar {
|
926
|
+
text 'Progress Bar'
|
927
|
+
}
|
928
|
+
Thread.new do
|
929
|
+
101.times.cycle do |n|
|
930
|
+
pb.fraction = n / 100.0
|
931
|
+
sleep(0.1) # yields back to main GUI thread
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
935
|
+
label('Spinner')
|
936
|
+
spinner {
|
937
|
+
active true
|
938
|
+
}
|
939
|
+
}
|
940
|
+
}
|
941
|
+
}
|
942
|
+
n.set_tab_label_text(f5.gtk, 'Progress')
|
943
|
+
}
|
944
|
+
}.present
|
945
|
+
end
|
946
|
+
}.run
|
947
|
+
```
|
948
|
+
|
949
|
+
#### Tetris
|
950
|
+
|
951
|
+
[samples/elaborate/tetris.rb](/samples/elaborate/tetris.rb)
|
952
|
+
|
953
|
+
Linux | Mac | Windows
|
954
|
+
------|-----|--------
|
955
|
+
![tetris](/screenshots/glimmer-dsl-gtk-linux-tetris.png) | ![tetris](/screenshots/glimmer-dsl-gtk-mac-tetris.png) | ![tetris](/screenshots/glimmer-dsl-gtk-windows-tetris.png)
|
956
|
+
|
957
|
+
Run (via installed gem):
|
958
|
+
|
959
|
+
```
|
960
|
+
ruby -r glimmer-dsl-gtk -e "require 'samples/elaborate/tetris'"
|
961
|
+
```
|
962
|
+
|
963
|
+
Run (via locally cloned project):
|
964
|
+
|
965
|
+
```
|
966
|
+
ruby -r ./lib/glimmer-dsl-gtk.rb samples/elaborate/tetris.rb
|
967
|
+
```
|
968
|
+
|
969
|
+
Code:
|
970
|
+
|
971
|
+
```ruby
|
972
|
+
require 'glimmer-dsl-gtk'
|
973
|
+
|
974
|
+
require_relative 'tetris/model/game'
|
975
|
+
|
976
|
+
class Tetris
|
977
|
+
include Glimmer
|
978
|
+
|
979
|
+
BLOCK_SIZE = 25
|
980
|
+
BEVEL_CONSTANT = 20
|
981
|
+
COLOR_GRAY = [192, 192, 192]
|
982
|
+
|
983
|
+
def initialize
|
984
|
+
@game = Model::Game.new
|
985
|
+
end
|
986
|
+
|
987
|
+
def launch
|
988
|
+
create_gui
|
989
|
+
register_observers
|
990
|
+
@game.start!
|
991
|
+
@main_window.show
|
992
|
+
end
|
993
|
+
|
994
|
+
def create_gui
|
995
|
+
@main_window = window {
|
996
|
+
title 'Glimmer Tetris'
|
997
|
+
default_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE # + 98
|
998
|
+
|
999
|
+
box(:vertical) {
|
1000
|
+
tetris_menu_bar
|
1001
|
+
|
1002
|
+
box(:horizontal) {
|
1003
|
+
@playfield_blocks = playfield(playfield_width: @game.playfield_width, playfield_height: @game.playfield_height, block_size: BLOCK_SIZE)
|
1004
|
+
|
1005
|
+
score_board
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
on(:key_press_event) do |widget, key_event|
|
1011
|
+
case key_event.keyval
|
1012
|
+
when 65364 # down arrow
|
1013
|
+
@game.down!
|
1014
|
+
when 32 # space
|
1015
|
+
@game.down!(instant: true)
|
1016
|
+
when 65362 # up arrow
|
1017
|
+
case @game.up_arrow_action
|
1018
|
+
when :instant_down
|
1019
|
+
@game.down!(instant: true)
|
1020
|
+
when :rotate_right
|
1021
|
+
@game.rotate!(:right)
|
1022
|
+
when :rotate_left
|
1023
|
+
@game.rotate!(:left)
|
1024
|
+
end
|
1025
|
+
when 65361 # left arrow
|
1026
|
+
@game.left!
|
1027
|
+
when 65363 # right arrow
|
1028
|
+
@game.right!
|
1029
|
+
when 65506 # right shift
|
1030
|
+
@game.rotate!(:right)
|
1031
|
+
when 65505 # left shift
|
1032
|
+
@game.rotate!(:left)
|
1033
|
+
else
|
1034
|
+
# Do Nothing
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
}
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
def register_observers
|
1041
|
+
observe(@game, :game_over) do |game_over|
|
1042
|
+
if game_over
|
1043
|
+
show_game_over_dialog
|
1044
|
+
else
|
1045
|
+
start_moving_tetrominos_down
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
@game.playfield_height.times do |row|
|
1050
|
+
@game.playfield_width.times do |column|
|
1051
|
+
observe(@game.playfield[row][column], :color) do |new_color|
|
1052
|
+
color = new_color
|
1053
|
+
block = @playfield_blocks[row][column]
|
1054
|
+
block[:background_square].fill = color
|
1055
|
+
block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
|
1056
|
+
block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1057
|
+
block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1058
|
+
block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1059
|
+
block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
|
1060
|
+
block[:drawing_area].queue_draw
|
1061
|
+
false
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
|
1067
|
+
Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
|
1068
|
+
observe(@game.preview_playfield[row][column], :color) do |new_color|
|
1069
|
+
color = new_color
|
1070
|
+
block = @preview_playfield_blocks[row][column]
|
1071
|
+
block[:background_square].fill = color
|
1072
|
+
block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
|
1073
|
+
block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1074
|
+
block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1075
|
+
block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
|
1076
|
+
block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
|
1077
|
+
block[:drawing_area].queue_draw
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
observe(@game, :score) do |new_score|
|
1083
|
+
@score_label.text = new_score.to_s
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
observe(@game, :lines) do |new_lines|
|
1087
|
+
@lines_label.text = new_lines.to_s
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
observe(@game, :level) do |new_level|
|
1091
|
+
@level_label.text = new_level.to_s
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def tetris_menu_bar
|
1096
|
+
menu_bar {
|
1097
|
+
menu_item(label: 'Game') { |mi|
|
1098
|
+
m = menu {
|
1099
|
+
check_menu_item(label: 'Pause') {
|
1100
|
+
on(:activate) do
|
1101
|
+
@game.paused = !@game.paused?
|
1102
|
+
end
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
menu_item(label: 'Restart') {
|
1106
|
+
on(:activate) do
|
1107
|
+
@game.restart!
|
1108
|
+
end
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
separator_menu_item
|
1112
|
+
|
1113
|
+
menu_item(label: 'Exit') {
|
1114
|
+
on(:activate) do
|
1115
|
+
@main_window.close
|
1116
|
+
end
|
1117
|
+
}
|
1118
|
+
}
|
1119
|
+
mi.submenu = m.gtk
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
menu_item(label: 'View') { |mi|
|
1123
|
+
m = menu {
|
1124
|
+
menu_item(label: 'Show High Scores') {
|
1125
|
+
on(:activate) do
|
1126
|
+
show_high_score_dialog
|
1127
|
+
end
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
menu_item(label: 'Clear High Scores') {
|
1131
|
+
on(:activate) do
|
1132
|
+
@game.clear_high_scores!
|
1133
|
+
end
|
1134
|
+
}
|
1135
|
+
}
|
1136
|
+
mi.submenu = m.gtk
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
menu_item(label: 'Options') { |mi|
|
1140
|
+
m = menu {
|
1141
|
+
rmi = radio_menu_item(nil, 'Instant Down on Up') {
|
1142
|
+
on(:activate) do
|
1143
|
+
@game.instant_down_on_up!
|
1144
|
+
end
|
1145
|
+
}
|
1146
|
+
|
1147
|
+
default_rmi = radio_menu_item(rmi.group, 'Rotate Right on Up') {
|
1148
|
+
on(:activate) do
|
1149
|
+
@game.rotate_right_on_up!
|
1150
|
+
end
|
1151
|
+
}
|
1152
|
+
default_rmi.activate
|
1153
|
+
|
1154
|
+
radio_menu_item(rmi.group, 'Rotate Left on Up') {
|
1155
|
+
on(:activate) do
|
1156
|
+
@game.rotate_left_on_up!
|
1157
|
+
end
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
mi.submenu = m.gtk
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
menu_item(label: 'Options') { |mi|
|
1164
|
+
m = menu {
|
1165
|
+
menu_item(label: 'About') {
|
1166
|
+
on(:activate) do
|
1167
|
+
show_about_dialog
|
1168
|
+
end
|
1169
|
+
}
|
1170
|
+
}
|
1171
|
+
mi.submenu = m.gtk
|
1172
|
+
}
|
1173
|
+
}
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
def score_board
|
1177
|
+
box(:vertical) {
|
1178
|
+
label
|
1179
|
+
@preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
|
1180
|
+
|
1181
|
+
label
|
1182
|
+
label('Score')
|
1183
|
+
@score_label = label
|
1184
|
+
|
1185
|
+
label
|
1186
|
+
label('Lines')
|
1187
|
+
@lines_label = label
|
1188
|
+
|
1189
|
+
label
|
1190
|
+
label('Level')
|
1191
|
+
@level_label = label
|
1192
|
+
label
|
1193
|
+
}
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
|
1197
|
+
blocks = []
|
1198
|
+
box(:vertical) {
|
1199
|
+
playfield_height.times.map do |row|
|
1200
|
+
blocks << []
|
1201
|
+
box(:horizontal) {
|
1202
|
+
playfield_width.times.map do |column|
|
1203
|
+
blocks.last << block(row: row, column: column, block_size: block_size)
|
1204
|
+
end
|
1205
|
+
}
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
extra_content&.call
|
1209
|
+
}
|
1210
|
+
blocks
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
def block(row: , column: , block_size: , &extra_content)
|
1214
|
+
block = {}
|
1215
|
+
bevel_pixel_size = 0.16 * block_size.to_f
|
1216
|
+
color = Model::Block::COLOR_CLEAR
|
1217
|
+
block[:drawing_area] = drawing_area {
|
1218
|
+
size_request block_size, block_size
|
1219
|
+
|
1220
|
+
block[:background_square] = square(0, 0, block_size) {
|
1221
|
+
fill *color
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
block[:top_bevel_edge] = polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
|
1225
|
+
fill color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT
|
1226
|
+
}
|
1227
|
+
|
1228
|
+
block[:right_bevel_edge] = 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) {
|
1229
|
+
fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
block[:bottom_bevel_edge] = 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) {
|
1233
|
+
fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
block[:left_bevel_edge] = polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
|
1237
|
+
fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
block[:border_square] = square(0, 0, block_size) {
|
1241
|
+
stroke *COLOR_GRAY
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
extra_content&.call
|
1245
|
+
}
|
1246
|
+
block
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
def start_moving_tetrominos_down
|
1250
|
+
unless @tetrominos_start_moving_down
|
1251
|
+
@tetrominos_start_moving_down = true
|
1252
|
+
GLib::Timeout.add(@game.delay*1000) do
|
1253
|
+
@game.down! if !@game.game_over? && !@game.paused?
|
1254
|
+
true
|
1255
|
+
end
|
1256
|
+
end
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
def show_game_over_dialog
|
1260
|
+
message_dialog(@main_window) { |md|
|
1261
|
+
title 'Game Over!'
|
1262
|
+
text "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}"
|
1263
|
+
|
1264
|
+
on(:response) do
|
1265
|
+
md.destroy
|
1266
|
+
end
|
1267
|
+
}.show
|
1268
|
+
|
1269
|
+
@game.restart!
|
1270
|
+
false
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
def show_high_score_dialog
|
1274
|
+
game_paused = !!@game.paused
|
1275
|
+
@game.paused = true
|
1276
|
+
|
1277
|
+
if @game.high_scores.empty?
|
1278
|
+
high_scores_string = "No games have been scored yet."
|
1279
|
+
else
|
1280
|
+
high_scores_string = @game.high_scores.map do |high_score|
|
1281
|
+
"#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
|
1282
|
+
end.join("\n")
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
message_dialog(@main_window) { |md|
|
1286
|
+
title 'High Scores'
|
1287
|
+
text high_scores_string
|
1288
|
+
|
1289
|
+
on(:response) do
|
1290
|
+
md.destroy
|
1291
|
+
end
|
1292
|
+
}.show
|
1293
|
+
|
1294
|
+
@game.paused = game_paused
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
def show_about_dialog
|
1298
|
+
message_dialog(@main_window) { |md|
|
1299
|
+
title 'About'
|
1300
|
+
text "Glimmer Tetris\n\nGlimmer DSL for GTK\n\nElaborate Sample\n\nCopyright (c) 2021-2022 Andy Maleh"
|
1301
|
+
|
1302
|
+
on(:response) do
|
1303
|
+
md.destroy
|
1304
|
+
end
|
1305
|
+
}.show
|
1306
|
+
end
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
Tetris.new.launch
|
1310
|
+
```
|
1311
|
+
|
1312
|
+
## Resources
|
1313
|
+
|
1314
|
+
- Ruby-Gnome Project: https://github.com/ruby-gnome/ruby-gnome
|
1315
|
+
- GTK3 API Documentation: https://gnome.pages.gitlab.gnome.org/gtk/gtk3/
|
1316
|
+
- GTK3 Widget Gallery: https://docs.gtk.org/gtk3/visual_index.html
|
1317
|
+
|
1318
|
+
## Process
|
1319
|
+
|
1320
|
+
[Glimmer Process](https://github.com/AndyObtiva/glimmer/blob/master/PROCESS.md)
|
1321
|
+
|
1322
|
+
## Help
|
1323
|
+
|
1324
|
+
### Issues
|
1325
|
+
|
1326
|
+
If you encounter [issues](https://github.com/AndyObtiva/glimmer-dsl-gtk/issues) that are not reported, discover missing features that are not mentioned in [TODO.md](TODO.md), or think up better ways to use GTK than what is possible with [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk), you may submit an [issue](https://github.com/AndyObtiva/glimmer-dsl-gtk/issues/new) or [pull request](https://github.com/AndyObtiva/glimmer-dsl-gtk/compare) on [GitHub](https://github.com). In the meantime while waiting for a fix, you may try older gem versions of [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk) in case you find one that does not have the issue and actually works.
|
1327
|
+
|
1328
|
+
### Chat
|
1329
|
+
|
1330
|
+
If you need live help, try to [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
1331
|
+
|
1332
|
+
## Planned Features and Feature Suggestions
|
1333
|
+
|
1334
|
+
These features have been planned or suggested. You might see them in a future version of [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk). You are welcome to contribute more feature suggestions.
|
1335
|
+
|
1336
|
+
[TODO.md](TODO.md)
|
1337
|
+
|
1338
|
+
## Change Log
|
1339
|
+
|
1340
|
+
[CHANGELOG.md](CHANGELOG.md)
|
1341
|
+
|
300
1342
|
## Contributing
|
301
1343
|
|
302
1344
|
- Check out the latest master to make sure the feature hasn't been
|
@@ -313,16 +1355,6 @@ window { |w|
|
|
313
1355
|
is fine, but please isolate to its own commit so I can cherry-pick
|
314
1356
|
around it.
|
315
1357
|
|
316
|
-
## Planned Features and Feature Suggestions
|
317
|
-
|
318
|
-
These features have been planned or suggested. You might see them in a future version of [Glimmer DSL for GTK](https://rubygems.org/gems/glimmer-dsl-gtk). You are welcome to contribute more feature suggestions.
|
319
|
-
|
320
|
-
[TODO.md](TODO.md)
|
321
|
-
|
322
|
-
## Change Log
|
323
|
-
|
324
|
-
[CHANGELOG.md](CHANGELOG.md)
|
325
|
-
|
326
1358
|
## Contributors
|
327
1359
|
|
328
1360
|
* [Andy Maleh](https://github.com/AndyObtiva) (Founder)
|
@@ -331,7 +1363,7 @@ These features have been planned or suggested. You might see them in a future ve
|
|
331
1363
|
|
332
1364
|
## Copyright
|
333
1365
|
|
334
|
-
[
|
1366
|
+
[LGPL](LICENSE.txt)
|
335
1367
|
|
336
1368
|
Copyright (c) 2021 Andy Maleh.
|
337
1369
|
|