glimmer-dsl-gtk 0.0.1 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,338 @@
1
+ require 'glimmer-dsl-gtk'
2
+
3
+ require_relative 'tetris/model/game'
4
+
5
+ class Tetris
6
+ include Glimmer
7
+
8
+ BLOCK_SIZE = 25
9
+ BEVEL_CONSTANT = 20
10
+ COLOR_GRAY = [192, 192, 192]
11
+
12
+ def initialize
13
+ @game = Model::Game.new
14
+ end
15
+
16
+ def launch
17
+ create_gui
18
+ register_observers
19
+ @game.start!
20
+ @main_window.show
21
+ end
22
+
23
+ def create_gui
24
+ @main_window = window {
25
+ title 'Glimmer Tetris'
26
+ default_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE # + 98
27
+
28
+ box(:vertical) {
29
+ tetris_menu_bar
30
+
31
+ box(:horizontal) {
32
+ @playfield_blocks = playfield(playfield_width: @game.playfield_width, playfield_height: @game.playfield_height, block_size: BLOCK_SIZE)
33
+
34
+ score_board
35
+ }
36
+
37
+ }
38
+
39
+ on(:key_press_event) do |widget, key_event|
40
+ case key_event.keyval
41
+ when 65364 # down arrow
42
+ @game.down!
43
+ when 32 # space
44
+ @game.down!(instant: true)
45
+ when 65362 # up arrow
46
+ case @game.up_arrow_action
47
+ when :instant_down
48
+ @game.down!(instant: true)
49
+ when :rotate_right
50
+ @game.rotate!(:right)
51
+ when :rotate_left
52
+ @game.rotate!(:left)
53
+ end
54
+ when 65361 # left arrow
55
+ @game.left!
56
+ when 65363 # right arrow
57
+ @game.right!
58
+ when 65506 # right shift
59
+ @game.rotate!(:right)
60
+ when 65505 # left shift
61
+ @game.rotate!(:left)
62
+ else
63
+ # Do Nothing
64
+ end
65
+ end
66
+ }
67
+ end
68
+
69
+ def register_observers
70
+ observe(@game, :game_over) do |game_over|
71
+ if game_over
72
+ show_game_over_dialog
73
+ else
74
+ start_moving_tetrominos_down
75
+ end
76
+ end
77
+
78
+ @game.playfield_height.times do |row|
79
+ @game.playfield_width.times do |column|
80
+ observe(@game.playfield[row][column], :color) do |new_color|
81
+ color = new_color
82
+ block = @playfield_blocks[row][column]
83
+ block[:background_square].fill = color
84
+ block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
85
+ block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
86
+ block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
87
+ block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
88
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
89
+ block[:drawing_area].queue_draw
90
+ false
91
+ end
92
+ end
93
+ end
94
+
95
+ Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
96
+ Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
97
+ observe(@game.preview_playfield[row][column], :color) do |new_color|
98
+ color = new_color
99
+ block = @preview_playfield_blocks[row][column]
100
+ block[:background_square].fill = color
101
+ block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
102
+ block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
103
+ block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
104
+ block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
105
+ block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
106
+ block[:drawing_area].queue_draw
107
+ end
108
+ end
109
+ end
110
+
111
+ observe(@game, :score) do |new_score|
112
+ @score_label.text = new_score.to_s
113
+ end
114
+
115
+ observe(@game, :lines) do |new_lines|
116
+ @lines_label.text = new_lines.to_s
117
+ end
118
+
119
+ observe(@game, :level) do |new_level|
120
+ @level_label.text = new_level.to_s
121
+ end
122
+ end
123
+
124
+ def tetris_menu_bar
125
+ menu_bar {
126
+ menu_item(label: 'Game') { |mi|
127
+ m = menu {
128
+ check_menu_item(label: 'Pause') {
129
+ on(:activate) do
130
+ @game.paused = !@game.paused?
131
+ end
132
+ }
133
+
134
+ menu_item(label: 'Restart') {
135
+ on(:activate) do
136
+ @game.restart!
137
+ end
138
+ }
139
+
140
+ separator_menu_item
141
+
142
+ menu_item(label: 'Exit') {
143
+ on(:activate) do
144
+ @main_window.close
145
+ end
146
+ }
147
+ }
148
+ mi.submenu = m.gtk
149
+ }
150
+
151
+ menu_item(label: 'View') { |mi|
152
+ m = menu {
153
+ menu_item(label: 'Show High Scores') {
154
+ on(:activate) do
155
+ show_high_score_dialog
156
+ end
157
+ }
158
+
159
+ menu_item(label: 'Clear High Scores') {
160
+ on(:activate) do
161
+ @game.clear_high_scores!
162
+ end
163
+ }
164
+ }
165
+ mi.submenu = m.gtk
166
+ }
167
+
168
+ menu_item(label: 'Options') { |mi|
169
+ m = menu {
170
+ rmi = radio_menu_item(nil, 'Instant Down on Up') {
171
+ on(:activate) do
172
+ @game.instant_down_on_up!
173
+ end
174
+ }
175
+
176
+ default_rmi = radio_menu_item(rmi.group, 'Rotate Right on Up') {
177
+ on(:activate) do
178
+ @game.rotate_right_on_up!
179
+ end
180
+ }
181
+ default_rmi.activate
182
+
183
+ radio_menu_item(rmi.group, 'Rotate Left on Up') {
184
+ on(:activate) do
185
+ @game.rotate_left_on_up!
186
+ end
187
+ }
188
+ }
189
+ mi.submenu = m.gtk
190
+ }
191
+
192
+ menu_item(label: 'Options') { |mi|
193
+ m = menu {
194
+ menu_item(label: 'About') {
195
+ on(:activate) do
196
+ show_about_dialog
197
+ end
198
+ }
199
+ }
200
+ mi.submenu = m.gtk
201
+ }
202
+ }
203
+ end
204
+
205
+ def score_board
206
+ box(:vertical) {
207
+ label
208
+ @preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)
209
+
210
+ label
211
+ label('Score')
212
+ @score_label = label
213
+
214
+ label
215
+ label('Lines')
216
+ @lines_label = label
217
+
218
+ label
219
+ label('Level')
220
+ @level_label = label
221
+ label
222
+ }
223
+ end
224
+
225
+ def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
226
+ blocks = []
227
+ box(:vertical) {
228
+ playfield_height.times.map do |row|
229
+ blocks << []
230
+ box(:horizontal) {
231
+ playfield_width.times.map do |column|
232
+ blocks.last << block(row: row, column: column, block_size: block_size)
233
+ end
234
+ }
235
+ end
236
+
237
+ extra_content&.call
238
+ }
239
+ blocks
240
+ end
241
+
242
+ def block(row: , column: , block_size: , &extra_content)
243
+ block = {}
244
+ bevel_pixel_size = 0.16 * block_size.to_f
245
+ color = Model::Block::COLOR_CLEAR
246
+ block[:drawing_area] = drawing_area {
247
+ size_request block_size, block_size
248
+
249
+ block[:background_square] = square(0, 0, block_size) {
250
+ fill *color
251
+ }
252
+
253
+ block[:top_bevel_edge] = polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
254
+ fill color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT
255
+ }
256
+
257
+ 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) {
258
+ fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
259
+ }
260
+
261
+ 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) {
262
+ fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
263
+ }
264
+
265
+ block[:left_bevel_edge] = polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
266
+ fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
267
+ }
268
+
269
+ block[:border_square] = square(0, 0, block_size) {
270
+ stroke *COLOR_GRAY
271
+ }
272
+
273
+ extra_content&.call
274
+ }
275
+ block
276
+ end
277
+
278
+ def start_moving_tetrominos_down
279
+ unless @tetrominos_start_moving_down
280
+ @tetrominos_start_moving_down = true
281
+ GLib::Timeout.add(@game.delay*1000) do
282
+ @game.down! if !@game.game_over? && !@game.paused?
283
+ true
284
+ end
285
+ end
286
+ end
287
+
288
+ def show_game_over_dialog
289
+ message_dialog(@main_window) { |md|
290
+ title 'Game Over!'
291
+ text "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}"
292
+
293
+ on(:response) do
294
+ md.destroy
295
+ end
296
+ }.show
297
+
298
+ @game.restart!
299
+ false
300
+ end
301
+
302
+ def show_high_score_dialog
303
+ game_paused = !!@game.paused
304
+ @game.paused = true
305
+
306
+ if @game.high_scores.empty?
307
+ high_scores_string = "No games have been scored yet."
308
+ else
309
+ high_scores_string = @game.high_scores.map do |high_score|
310
+ "#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
311
+ end.join("\n")
312
+ end
313
+
314
+ message_dialog(@main_window) { |md|
315
+ title 'High Scores'
316
+ text high_scores_string
317
+
318
+ on(:response) do
319
+ md.destroy
320
+ end
321
+ }.show
322
+
323
+ @game.paused = game_paused
324
+ end
325
+
326
+ def show_about_dialog
327
+ message_dialog(@main_window) { |md|
328
+ title 'About'
329
+ text "Glimmer Tetris\n\nGlimmer DSL for GTK\n\nElaborate Sample\n\nCopyright (c) 2021-2022 Andy Maleh"
330
+
331
+ on(:response) do
332
+ md.destroy
333
+ end
334
+ }.show
335
+ end
336
+ end
337
+
338
+ Tetris.new.launch
@@ -0,0 +1,141 @@
1
+ require 'glimmer-dsl-gtk'
2
+
3
+ include Glimmer
4
+
5
+ application('org.glimmer.hello-application') {
6
+ on(:activate) do |app|
7
+ application_window(app) {
8
+ title 'Widget Gallery'
9
+
10
+ notebook { |n|
11
+ f1 = frame {
12
+ alignment(1, 1, 1, 1) {
13
+ padding 15, 15, 15, 15
14
+
15
+ box(:vertical) {
16
+ spacing 10
17
+
18
+ label('Entry')
19
+ entry {
20
+ text 'Enter One Line of Text'
21
+ }
22
+
23
+ label('Search Entry')
24
+ search_entry {
25
+ text 'Enter Search Term'
26
+ }
27
+
28
+ label('Spin Button')
29
+ spin_button(1, 100, 1) {
30
+ }
31
+
32
+ label('Combo Box Text')
33
+ cb = combo_box_text {
34
+ }
35
+ 3.times { |n| cb.append_text "Option #{n + 1}" }
36
+ }
37
+ }
38
+ }
39
+ n.set_tab_label_text(f1.gtk, 'Text')
40
+
41
+ f2 = frame {
42
+ alignment(1, 1, 1, 1) {
43
+ padding 15, 15, 15, 15
44
+
45
+ box(:vertical) {
46
+ spacing 10
47
+
48
+ label('Button')
49
+ button('Push Me')
50
+
51
+ label('Radio Button')
52
+ box(:horizontal) {
53
+ rb = radio_button('One')
54
+ radio_button(rb, 'Two')
55
+ radio_button(rb, 'Three')
56
+ }
57
+
58
+ label('Check Button')
59
+ box(:horizontal) {
60
+ check_button('One')
61
+ check_button('Two')
62
+ check_button('Three')
63
+ }
64
+ }
65
+ }
66
+ }
67
+ n.set_tab_label_text(f2.gtk, 'Button')
68
+
69
+ f3 = frame {
70
+ alignment(1, 1, 1, 1) {
71
+ padding 15, 15, 15, 15
72
+
73
+ box(:vertical) {
74
+ spacing 10
75
+
76
+ label('Horizontal Scale')
77
+ h_scale(1, 100, 1) {
78
+ visible true
79
+ }
80
+
81
+ label('Vertical Scale')
82
+ v_scale(1, 100, 1) {
83
+ visible true
84
+ height_request 200
85
+ }
86
+ }
87
+ }
88
+ }
89
+ n.set_tab_label_text(f3.gtk, 'Selection')
90
+
91
+ f4 = frame {
92
+ alignment(1, 1, 1, 1) {
93
+ padding 15, 15, 15, 15
94
+
95
+ box(:vertical) {
96
+ spacing 10
97
+
98
+ label('Expander')
99
+ 3.times do |n|
100
+ expander {
101
+ label "Item #{n + 1}"
102
+
103
+ label("Item #{n + 1} Expanded") {
104
+ }
105
+ }
106
+ end
107
+ }
108
+ }
109
+ }
110
+ n.set_tab_label_text(f4.gtk, 'Organizer')
111
+
112
+ f5 = frame {
113
+ alignment(1, 1, 1, 1) {
114
+ padding 15, 15, 15, 15
115
+
116
+ box(:vertical) {
117
+ spacing 10
118
+
119
+ label('Progress Bar')
120
+ pb = progress_bar {
121
+ text 'Progress Bar'
122
+ }
123
+ Thread.new do
124
+ 101.times.cycle do |n|
125
+ pb.fraction = n / 100.0
126
+ sleep(0.1) # yields back to main GUI thread
127
+ end
128
+ end
129
+
130
+ label('Spinner')
131
+ spinner {
132
+ active true
133
+ }
134
+ }
135
+ }
136
+ }
137
+ n.set_tab_label_text(f5.gtk, 'Progress')
138
+ }
139
+ }.present
140
+ end
141
+ }.run
@@ -0,0 +1,84 @@
1
+ require 'glimmer-dsl-gtk'
2
+
3
+ include Glimmer
4
+
5
+ window {
6
+ title 'Hello, Drawing Area!'
7
+ default_size 400, 400
8
+
9
+ drawing_area {
10
+ paint 255, 255, 255
11
+
12
+ arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90) {
13
+ fill 255, 0, 0
14
+ stroke 0, 128, 255
15
+ line_width 3
16
+ }
17
+
18
+ arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30) {
19
+ fill 255, 0, 0
20
+ stroke 0, 128, 255
21
+ line_width 3
22
+ }
23
+
24
+ circle(85, 285, 45) {
25
+ fill 255, 0, 0
26
+ stroke 0, 128, 255
27
+ line_width 3
28
+ }
29
+
30
+ rectangle(140, 40, 180, 90) {
31
+ fill 255, 255, 0
32
+ stroke 255, 0, 0
33
+ line_width 3
34
+ }
35
+
36
+ rounded_rectangle(140, 140, 180, 90, 30, 20) {
37
+ fill 255, 255, 0
38
+ stroke 255, 0, 0
39
+ line_width 3
40
+ }
41
+
42
+ triangle(140, 240, 320, 240, 230, 330) {
43
+ fill 255, 255, 0
44
+ stroke 255, 0, 0
45
+ line_width 3
46
+ }
47
+
48
+ path {
49
+ move_to 160, 100
50
+ curve_to 190, 60, 200, 80, 210, 70
51
+ curve_to 240, 80, 250, 100, 260, 90
52
+ curve_to 290, 90, 300, 110, 310, 100
53
+
54
+ fill 0, 255, 0
55
+ stroke 0, 0, 255
56
+ line_width 3
57
+ }
58
+
59
+ path {
60
+ move_to 200, 150
61
+ line_to 270, 170
62
+ line_to 250, 220
63
+ line_to 220, 190
64
+ line_to 200, 200
65
+ line_to 180, 170
66
+ close_path
67
+
68
+ fill 0, 255, 0
69
+ stroke 0, 0, 255
70
+ line_width 3
71
+ }
72
+
73
+ polygon(200, 260, 270, 270, 250, 290, 220, 290, 200, 280, 180, 270) {
74
+ fill 0, 255, 0
75
+ stroke 0, 0, 255
76
+ line_width 3
77
+ }
78
+
79
+ polyline(270, 320, 250, 340, 220, 340, 200, 330, 180, 320) {
80
+ stroke 0, 0, 255
81
+ line_width 3
82
+ }
83
+ }
84
+ }.show
@@ -0,0 +1,139 @@
1
+ require 'glimmer-dsl-gtk'
2
+
3
+ include Glimmer
4
+
5
+ window {
6
+ title 'Hello, Drawing Area (Manual)!'
7
+ default_size 400, 400
8
+
9
+ drawing_area {
10
+ on(:draw) do |drawing_area_widget, cairo_context|
11
+ cairo_context.set_source_rgb(255/255.0, 255/255.0, 255/255.0)
12
+ cairo_context.paint
13
+
14
+ cairo_context.arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90)
15
+ cairo_context.set_source_rgb(255, 0, 0)
16
+ cairo_context.fill
17
+
18
+ cairo_context.arc(85, 85, 45, (Math::PI/180)*90, -(Math::PI/180)*90)
19
+ cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
20
+ cairo_context.set_line_width(3)
21
+ cairo_context.stroke
22
+
23
+ cairo_context.arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30)
24
+ cairo_context.set_source_rgb(255/255.0, 0, 0)
25
+ cairo_context.fill
26
+
27
+ cairo_context.arc(85, 185, 45, (Math::PI/180)*100, -(Math::PI/180)*30)
28
+ cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
29
+ cairo_context.set_line_width(3)
30
+ cairo_context.stroke
31
+
32
+ cairo_context.circle(85, 285, 45)
33
+ cairo_context.set_source_rgb(255/255.0, 0, 0)
34
+ cairo_context.fill
35
+
36
+ cairo_context.circle(85, 285, 45)
37
+ cairo_context.set_source_rgb(0, 128/255.0, 255/255.0)
38
+ cairo_context.set_line_width(3)
39
+ cairo_context.stroke
40
+
41
+ cairo_context.rectangle(140, 40, 180, 90)
42
+ cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
43
+ cairo_context.fill
44
+
45
+ cairo_context.rectangle(140, 40, 180, 90)
46
+ cairo_context.set_source_rgb(255/255.0, 0, 0)
47
+ cairo_context.set_line_width(3)
48
+ cairo_context.stroke
49
+
50
+ cairo_context.rounded_rectangle(140, 140, 180, 90, 30, 20)
51
+ cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
52
+ cairo_context.fill
53
+
54
+ cairo_context.rounded_rectangle(140, 140, 180, 90, 30, 20)
55
+ cairo_context.set_source_rgb(255/255.0, 0, 0)
56
+ cairo_context.set_line_width(3)
57
+ cairo_context.stroke
58
+
59
+ cairo_context.triangle(140, 240, 320, 240, 230, 330)
60
+ cairo_context.set_source_rgb(255/255.0, 255/255.0, 0)
61
+ cairo_context.fill
62
+
63
+ cairo_context.triangle(140, 240, 320, 240, 230, 330)
64
+ cairo_context.set_source_rgb(255/255.0, 0, 0)
65
+ cairo_context.set_line_width(3)
66
+ cairo_context.stroke
67
+
68
+ cairo_context.new_path
69
+ cairo_context.move_to 160, 100
70
+ cairo_context.curve_to 190, 60, 200, 80, 210, 70
71
+ cairo_context.curve_to 240, 80, 250, 100, 260, 90
72
+ cairo_context.curve_to 290, 90, 300, 110, 310, 100
73
+ cairo_context.set_source_rgb(0, 255/255.0, 0)
74
+ cairo_context.fill
75
+
76
+ cairo_context.new_path
77
+ cairo_context.move_to 160, 100
78
+ cairo_context.curve_to 190, 60, 200, 80, 210, 70
79
+ cairo_context.curve_to 240, 80, 250, 100, 260, 90
80
+ cairo_context.curve_to 290, 90, 300, 110, 310, 100
81
+ cairo_context.set_source_rgb(0, 0, 255/255.0)
82
+ cairo_context.stroke
83
+
84
+ cairo_context.new_path
85
+ cairo_context.move_to 200, 150
86
+ cairo_context.line_to 270, 170
87
+ cairo_context.line_to 250, 220
88
+ cairo_context.line_to 220, 190
89
+ cairo_context.line_to 200, 200
90
+ cairo_context.line_to 180, 170
91
+ cairo_context.close_path
92
+ cairo_context.set_source_rgb(0, 255/255.0, 0)
93
+ cairo_context.fill
94
+
95
+ cairo_context.new_path
96
+ cairo_context.move_to 200, 150
97
+ cairo_context.line_to 270, 170
98
+ cairo_context.line_to 250, 220
99
+ cairo_context.line_to 220, 190
100
+ cairo_context.line_to 200, 200
101
+ cairo_context.line_to 180, 170
102
+ cairo_context.close_path
103
+ cairo_context.set_source_rgb(0, 0, 255/255.0)
104
+ cairo_context.stroke
105
+
106
+ cairo_context.new_path
107
+ cairo_context.move_to 200, 260
108
+ cairo_context.line_to 270, 270
109
+ cairo_context.line_to 250, 290
110
+ cairo_context.line_to 220, 290
111
+ cairo_context.line_to 200, 280
112
+ cairo_context.line_to 180, 270
113
+ cairo_context.close_path
114
+ cairo_context.set_source_rgb(0, 255/255.0, 0)
115
+ cairo_context.fill
116
+
117
+ cairo_context.new_path
118
+ cairo_context.move_to 200, 260
119
+ cairo_context.line_to 270, 270
120
+ cairo_context.line_to 250, 290
121
+ cairo_context.line_to 220, 290
122
+ cairo_context.line_to 200, 280
123
+ cairo_context.line_to 180, 270
124
+ cairo_context.close_path
125
+ cairo_context.set_source_rgb(0, 0, 255/255.0)
126
+ cairo_context.stroke
127
+
128
+ cairo_context.new_path
129
+ cairo_context.move_to 200, 260
130
+ cairo_context.move_to 270, 320
131
+ cairo_context.line_to 250, 340
132
+ cairo_context.line_to 220, 340
133
+ cairo_context.line_to 200, 330
134
+ cairo_context.line_to 180, 320
135
+ cairo_context.set_source_rgb(0, 0, 255/255.0)
136
+ cairo_context.stroke
137
+ end
138
+ }
139
+ }.show