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
@@ -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