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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/LICENSE.txt +56 -20
  4. data/README.md +1068 -36
  5. data/VERSION +1 -1
  6. data/bin/girb +58 -22
  7. data/bin/girb_runner.rb +58 -20
  8. data/glimmer-dsl-gtk.gemspec +0 -0
  9. data/lib/glimmer/dsl/gtk/dsl.rb +58 -18
  10. data/lib/glimmer/dsl/gtk/observe_expression.rb +35 -0
  11. data/lib/glimmer/dsl/gtk/on_expression.rb +56 -18
  12. data/lib/glimmer/dsl/gtk/operation_expression.rb +79 -0
  13. data/lib/glimmer/dsl/gtk/property_expression.rb +59 -21
  14. data/lib/glimmer/dsl/gtk/shape_expression.rb +86 -0
  15. data/lib/glimmer/dsl/gtk/widget_expression.rb +57 -19
  16. data/lib/glimmer/gtk/shape/arc.rb +70 -0
  17. data/lib/glimmer/gtk/shape/arc_negative.rb +70 -0
  18. data/lib/glimmer/gtk/shape/circle.rb +67 -0
  19. data/lib/glimmer/gtk/shape/path.rb +113 -0
  20. data/lib/glimmer/gtk/shape/polygon.rb +92 -0
  21. data/lib/glimmer/gtk/shape/polyline.rb +91 -0
  22. data/lib/glimmer/gtk/shape/rectangle.rb +70 -0
  23. data/lib/glimmer/gtk/shape/rounded_rectangle.rb +70 -0
  24. data/lib/glimmer/gtk/shape/square.rb +76 -0
  25. data/lib/glimmer/gtk/shape/triangle.rb +67 -0
  26. data/lib/glimmer/gtk/shape.rb +230 -0
  27. data/lib/glimmer/gtk/widget_proxy/application_proxy.rb +56 -18
  28. data/lib/glimmer/gtk/widget_proxy/box_proxy.rb +56 -18
  29. data/lib/glimmer/gtk/widget_proxy/drawing_area_proxy.rb +102 -0
  30. data/lib/glimmer/gtk/widget_proxy/message_dialog_proxy.rb +56 -18
  31. data/lib/glimmer/gtk/widget_proxy/window_proxy.rb +56 -18
  32. data/lib/glimmer/gtk/widget_proxy.rb +72 -32
  33. data/lib/glimmer/gtk.rb +59 -21
  34. data/lib/glimmer-dsl-gtk.rb +56 -18
  35. data/samples/elaborate/tetris/model/block.rb +48 -0
  36. data/samples/elaborate/tetris/model/game.rb +320 -0
  37. data/samples/elaborate/tetris/model/past_game.rb +39 -0
  38. data/samples/elaborate/tetris/model/tetromino.rb +329 -0
  39. data/samples/elaborate/tetris.rb +338 -0
  40. data/samples/elaborate/widget_gallery.rb +141 -0
  41. data/samples/hello/hello_drawing_area.rb +84 -0
  42. data/samples/hello/hello_drawing_area_manual.rb +139 -0
  43. 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
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 Screenshot:
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
- ![hello world screenshot](/screenshots/glimmer-dsl-gtk-mac-hello-world.png)
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.1'
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 an application class instead:
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
- ![girb screenshot](/screenshots/glimmer-dsl-gtk-mac-girb.png)
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 Screenshot:
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 Screenshot:
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 Screenshot:
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 Screenshot:
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
- [MIT](LICENSE.txt)
1366
+ [LGPL](LICENSE.txt)
335
1367
 
336
1368
  Copyright (c) 2021 Andy Maleh.
337
1369