teek 0.1.0

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +21 -0
  4. data/README.md +139 -0
  5. data/Rakefile +316 -0
  6. data/ext/teek/extconf.rb +79 -0
  7. data/ext/teek/stubs.h +33 -0
  8. data/ext/teek/tcl9compat.h +211 -0
  9. data/ext/teek/tcltkbridge.c +1597 -0
  10. data/ext/teek/tcltkbridge.h +42 -0
  11. data/ext/teek/tkfont.c +218 -0
  12. data/ext/teek/tkphoto.c +477 -0
  13. data/ext/teek/tkwin.c +144 -0
  14. data/lib/teek/background_none.rb +158 -0
  15. data/lib/teek/background_ractor4x.rb +410 -0
  16. data/lib/teek/background_thread.rb +272 -0
  17. data/lib/teek/debugger.rb +742 -0
  18. data/lib/teek/demo_support.rb +150 -0
  19. data/lib/teek/ractor_support.rb +246 -0
  20. data/lib/teek/version.rb +5 -0
  21. data/lib/teek.rb +540 -0
  22. data/sample/calculator.rb +260 -0
  23. data/sample/debug_demo.rb +45 -0
  24. data/sample/goldberg.rb +1803 -0
  25. data/sample/goldberg_helpers.rb +170 -0
  26. data/sample/minesweeper/assets/MINESWEEPER_0.png +0 -0
  27. data/sample/minesweeper/assets/MINESWEEPER_1.png +0 -0
  28. data/sample/minesweeper/assets/MINESWEEPER_2.png +0 -0
  29. data/sample/minesweeper/assets/MINESWEEPER_3.png +0 -0
  30. data/sample/minesweeper/assets/MINESWEEPER_4.png +0 -0
  31. data/sample/minesweeper/assets/MINESWEEPER_5.png +0 -0
  32. data/sample/minesweeper/assets/MINESWEEPER_6.png +0 -0
  33. data/sample/minesweeper/assets/MINESWEEPER_7.png +0 -0
  34. data/sample/minesweeper/assets/MINESWEEPER_8.png +0 -0
  35. data/sample/minesweeper/assets/MINESWEEPER_F.png +0 -0
  36. data/sample/minesweeper/assets/MINESWEEPER_M.png +0 -0
  37. data/sample/minesweeper/assets/MINESWEEPER_X.png +0 -0
  38. data/sample/minesweeper/minesweeper.rb +452 -0
  39. data/sample/threading_demo.rb +499 -0
  40. data/teek.gemspec +32 -0
  41. metadata +179 -0
@@ -0,0 +1,1803 @@
1
+ # frozen_string_literal: true
2
+ # teek-record: title=Tk Goldberg (demonstration)
3
+ #
4
+ # Teek Goldberg demo
5
+ #
6
+ # Ported from tk-ng's Ruby/Tk Goldberg demo, which was based on
7
+ # TkGoldberg.tcl by Keith Vetter, March 2003.
8
+ # Ruby/Tk version by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
9
+ #
10
+ # "Man will always find a difficult means to perform a simple task"
11
+ # - Rube Goldberg
12
+
13
+ require_relative '../lib/teek'
14
+ require_relative 'goldberg_helpers'
15
+
16
+ class TkGoldberg_Demo
17
+ include GoldbergHelpers
18
+
19
+ def initialize(app, parent, toplevel)
20
+ @app = app
21
+ @parent = parent
22
+ @top = toplevel
23
+
24
+ # Animation state
25
+ @mode = :MSTART
26
+ @active = [0]
27
+ @cnt = 0
28
+ @step = {}
29
+ @XY = {}
30
+ @timer_running = false
31
+
32
+ # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
33
+ @speed = [1, 10, 20, 50, 80, 100, 150, 200, 300, 400, 500]
34
+
35
+ # Colors
36
+ @C = {}
37
+ @C['fg'] = 'black'
38
+ @C['bg'] = 'cornflowerblue'
39
+
40
+ @C['0'] = 'white'; @C['1a'] = 'darkgreen'; @C['1b'] = 'yellow'
41
+ @C['2'] = 'red'; @C['3a'] = 'green'; @C['3b'] = 'darkblue'
42
+ @C['4'] = @C['fg']; @C['5a'] = 'brown'; @C['5b'] = 'white'
43
+ @C['6'] = 'magenta'; @C['7'] = 'green'; @C['8'] = @C['fg']
44
+ @C['9'] = 'blue4'; @C['10a'] = 'white'; @C['10b'] = 'cyan'
45
+ @C['11a'] = 'yellow'; @C['11b'] = 'mediumblue'; @C['12'] = 'tan2'
46
+ @C['13a'] = 'yellow'; @C['13b'] = 'red'; @C['14'] = 'white'
47
+ @C['15a'] = 'green'; @C['15b'] = 'yellow'; @C['16'] = 'gray65'
48
+ @C['17'] = '#A65353'; @C['18'] = @C['fg']; @C['19'] = 'gray50'
49
+ @C['20'] = 'cyan'; @C['21'] = 'gray65'; @C['22'] = @C['20']
50
+ @C['23a'] = 'blue'; @C['23b'] = 'red'; @C['23c'] = 'yellow'
51
+ @C['24a'] = 'red'; @C['24b'] = 'white';
52
+
53
+ # Tcl variables for widget binding
54
+ @tv_speed = TclVar.new(@app, 'speed', 5)
55
+ @tv_cnt = TclVar.new(@app, 'cnt', 0)
56
+ @tv_message = TclVar.new(@app, 'message', "\\nWelcome\\nto\\nRuby/Tk")
57
+ @tv_pause = TclVar.new(@app, 'pause', 0)
58
+ @tv_details = TclVar.new(@app, 'details', 1)
59
+ @tv_step = {}
60
+
61
+ @XY6 = {
62
+ '-1'=>[366, 207], '-2'=>[349, 204], '-3'=>[359, 193], '-4'=>[375, 192],
63
+ '-5'=>[340, 190], '-6'=>[349, 177], '-7'=>[366, 177], '-8'=>[380, 176],
64
+ '-9'=>[332, 172], '-10'=>[342, 161], '-11'=>[357, 164],
65
+ '-12'=>[372, 163], '-13'=>[381, 149], '-14'=>[364, 151],
66
+ '-15'=>[349, 146], '-16'=>[333, 148], '0'=>[357, 219],
67
+ '1'=>[359, 261], '2'=>[359, 291], '3'=>[359, 318], '4'=>[361, 324],
68
+ '5'=>[365, 329], '6'=>[367, 334], '7'=>[367, 340], '8'=>[366, 346],
69
+ '9'=>[364, 350], '10'=>[361, 355], '11'=>[359, 370], '12'=>[359, 391],
70
+ '13,0'=>[360, 456], '13,1'=>[376, 456], '13,2'=>[346, 456],
71
+ '13,3'=>[330, 456], '13,4'=>[353, 444], '13,5'=>[368, 443],
72
+ '13,6'=>[339, 442], '13,7'=>[359, 431], '13,8'=>[380, 437],
73
+ '13,9'=>[345, 428], '13,10'=>[328, 434], '13,11'=>[373, 424],
74
+ '13,12'=>[331, 420], '13,13'=>[360, 417], '13,14'=>[345, 412],
75
+ '13,15'=>[376, 410], '13,16'=>[360, 403]
76
+ }
77
+
78
+ do_display
79
+ reset
80
+
81
+ # Start the animation timer
82
+ @timer_running = true
83
+ schedule_timer
84
+ end
85
+
86
+ # ----------------------------------------------------------------
87
+ # Timer (replaces TkTimer)
88
+ # ----------------------------------------------------------------
89
+
90
+ def schedule_timer
91
+ return unless @timer_running
92
+ delay = @speed[@tv_speed.to_i]
93
+ @app.after(delay) { timer_tick }
94
+ end
95
+
96
+ def timer_tick
97
+ return unless @timer_running
98
+ new_delay = go
99
+ @app.after(new_delay) { timer_tick }
100
+ end
101
+
102
+ def stop_timer
103
+ @timer_running = false
104
+ end
105
+
106
+ # ----------------------------------------------------------------
107
+ # UI setup
108
+ # ----------------------------------------------------------------
109
+
110
+ def do_display
111
+ @ctrl = "#{@parent}.ctrl"
112
+ @app.tcl_eval("frame #{@ctrl} -relief ridge -bd 2 -padx 5 -pady 5")
113
+
114
+ @screen = "#{@parent}.screen"
115
+ @app.tcl_eval("frame #{@screen} -bd 2 -relief raised")
116
+ @app.tcl_eval("pack #{@screen} -side left -fill both -expand 1")
117
+
118
+ @canvas = "#{@screen}.c"
119
+ @app.tcl_eval("canvas #{@canvas} -width 850 -height 700 " \
120
+ "-bg #{@C['bg']} -highlightthickness 0 " \
121
+ "-scrollregion {0 0 1000 1000}")
122
+ @app.tcl_eval("#{@canvas} yview moveto 0.05")
123
+ @app.tcl_eval("pack #{@canvas} -in #{@screen} -side top -fill both -expand 1")
124
+
125
+ canvas_bind('Button-3') { toggle_pause }
126
+ canvas_bind('Destroy') { stop_timer }
127
+
128
+ do_ctrl_frame
129
+ do_detail_frame
130
+
131
+ # Info label (placed over the canvas)
132
+ msg = "#{@parent}.msg"
133
+ @app.tcl_eval("label #{msg} -bg #{@C['bg']} -fg white " \
134
+ "-font {Arial 10} -wraplength 600 -justify left " \
135
+ "-text {This is a demonstration of just how complex you can make your animations become. Click the ball to start things moving!\n\"Man will always find a difficult means to perform a simple task\" - Rube Goldberg}")
136
+ @app.tcl_eval("place #{msg} -in #{@canvas} -relx 0 -rely 0 -anchor nw")
137
+
138
+ # Button bar (placed over the canvas, top-right)
139
+ btnframe = "#{@parent}.btnf"
140
+ @app.tcl_eval("frame #{btnframe} -bg #{@C['bg']}")
141
+
142
+ dismiss_cb = @app.register_callback(proc { |*|
143
+ @app.destroy(@top)
144
+ })
145
+ @app.tcl_eval("button #{btnframe}.dismiss -text Dismiss " \
146
+ "-bg #{@C['bg']} -activebackground #{@C['bg']} " \
147
+ "-command {ruby_callback #{dismiss_cb}}")
148
+ @app.tcl_eval("pack #{btnframe}.dismiss -side left")
149
+
150
+ show_cb = @app.register_callback(proc { |*| show_ctrl })
151
+ @show = "#{btnframe}.show"
152
+ @app.tcl_eval("button #{@show} -text >> " \
153
+ "-command {ruby_callback #{show_cb}} " \
154
+ "-bg #{@C['bg']} -activebackground #{@C['bg']}")
155
+ @app.tcl_eval("pack #{@show} -side left")
156
+
157
+ @app.tcl_eval("place #{btnframe} -in #{@canvas} -relx 1 -rely 0 -anchor ne")
158
+
159
+ @app.update
160
+ end
161
+
162
+ def do_ctrl_frame
163
+ # Create a bold font for the start button
164
+ @app.tcl_eval("font create GoldbergBold " \
165
+ "{*}[font configure TkDefaultFont] -weight bold")
166
+
167
+ cbs = {}
168
+ [0, 1, 2, 3, 4].each { |n|
169
+ cbs[n] = @app.register_callback(proc { |*| do_button(n) })
170
+ }
171
+ gui_cb = @app.register_callback(proc { |*| active_GUI })
172
+ about_cb = @app.register_callback(proc { |*| about })
173
+
174
+ @w_start = "#{@ctrl}.start"
175
+ @app.tcl_eval("button #{@w_start} -text Start -bd 6 " \
176
+ "-font GoldbergBold " \
177
+ "-command {ruby_callback #{cbs[0]}}")
178
+
179
+ @w_pause = "#{@ctrl}.pause"
180
+ @app.tcl_eval("checkbutton #{@w_pause} -text Pause " \
181
+ "-command {ruby_callback #{cbs[1]}} -relief raised " \
182
+ "-variable #{@tv_pause.name}")
183
+
184
+ @w_step = "#{@ctrl}.step"
185
+ @app.tcl_eval("button #{@w_step} -text {Single Step} " \
186
+ "-command {ruby_callback #{cbs[2]}}")
187
+
188
+ @w_bstep = "#{@ctrl}.bstep"
189
+ @app.tcl_eval("button #{@w_bstep} -text {Big Step} " \
190
+ "-command {ruby_callback #{cbs[4]}}")
191
+
192
+ @w_reset = "#{@ctrl}.reset"
193
+ @app.tcl_eval("button #{@w_reset} -text Reset " \
194
+ "-command {ruby_callback #{cbs[3]}}")
195
+
196
+ @w_details_frame = "#{@ctrl}.details"
197
+ @app.tcl_eval("frame #{@w_details_frame} -bd 2 -relief ridge")
198
+
199
+ @w_detail = "#{@w_details_frame}.detail"
200
+ @app.tcl_eval("checkbutton #{@w_detail} -text Details " \
201
+ "-relief raised -variable #{@tv_details.name} " \
202
+ "-command {ruby_callback #{gui_cb}}")
203
+
204
+ @w_msg_entry = "#{@ctrl}.msgentry"
205
+ @app.tcl_eval("entry #{@w_msg_entry} -textvariable #{@tv_message.name} " \
206
+ "-justify center")
207
+
208
+ @w_speed_scale = "#{@ctrl}.speedscale"
209
+ @app.tcl_eval("scale #{@w_speed_scale} -orient horizontal " \
210
+ "-from 1 -to 10 -bd 2 -relief ridge -showvalue 0 " \
211
+ "-variable #{@tv_speed.name} " \
212
+ "-command {ruby_callback #{gui_cb}}")
213
+
214
+ @w_about = "#{@ctrl}.about"
215
+ @app.tcl_eval("button #{@w_about} -text About " \
216
+ "-command {ruby_callback #{about_cb}}")
217
+
218
+ # Grid layout
219
+ @app.tcl_eval("grid #{@w_start} -in #{@ctrl} -row 0 -sticky ew")
220
+ @app.tcl_eval("grid rowconfigure #{@ctrl} 1 -minsize 10")
221
+ @app.tcl_eval("grid #{@w_pause} -in #{@ctrl} -row 2 -sticky ew")
222
+ @app.tcl_eval("grid #{@w_step} -in #{@ctrl} -sticky ew")
223
+ @app.tcl_eval("grid #{@w_bstep} -in #{@ctrl} -sticky ew")
224
+ @app.tcl_eval("grid #{@w_reset} -in #{@ctrl} -sticky ew")
225
+ @app.tcl_eval("grid rowconfigure #{@ctrl} 10 -minsize 20")
226
+ @app.tcl_eval("grid #{@w_details_frame} -in #{@ctrl} -row 11 -sticky ew")
227
+ @app.tcl_eval("grid #{@w_detail} -in #{@w_details_frame} -row 0 -sticky ew")
228
+ @app.tcl_eval("grid rowconfigure #{@ctrl} 50 -weight 1")
229
+
230
+ @app.tcl_eval("grid #{@w_msg_entry} -in #{@ctrl} -row 98 -sticky ew -pady 5")
231
+ @app.tcl_eval("grid #{@w_speed_scale} -in #{@ctrl} -row 99 -sticky ew")
232
+ @app.tcl_eval("grid #{@w_about} -in #{@ctrl} -row 100 -sticky ew")
233
+
234
+ # Debug: right-click reset to enter debug mode
235
+ @app.bind(@w_reset, 'Button-3') { @mode = :MDEBUG }
236
+ end
237
+
238
+ def do_detail_frame
239
+ @w_f_details = "#{@w_details_frame}.fd"
240
+ @app.tcl_eval("frame #{@w_f_details}")
241
+
242
+ lbl = "#{@w_f_details}.lbl"
243
+ @app.tcl_eval("label #{lbl} -textvariable #{@tv_cnt.name} " \
244
+ "-bd 1 -relief solid -bg white")
245
+ @app.tcl_eval("grid #{lbl} - - - -sticky ew -row 0")
246
+
247
+ idx = 1
248
+ loop {
249
+ break unless respond_to?("move#{idx}")
250
+ @step[idx] = 0
251
+ @tv_step[idx] = TclVar.new(@app, "step_#{idx}", 0)
252
+
253
+ l = "#{@w_f_details}.l#{idx}"
254
+ @app.tcl_eval("label #{l} -text #{idx} -anchor e " \
255
+ "-width 2 -bd 1 -relief solid -bg white")
256
+ ll = "#{@w_f_details}.ll#{idx}"
257
+ @app.tcl_eval("label #{ll} -textvariable #{@tv_step[idx].name} " \
258
+ "-width 5 -bd 1 -relief solid -bg white")
259
+
260
+ row = (idx + 1) / 2
261
+ col = ((idx + 1) & 1) * 2
262
+ @app.tcl_eval("grid #{l} -sticky ew -row #{row} -column #{col}")
263
+ @app.tcl_eval("grid #{ll} -sticky ew -row #{row} -column #{col + 1}")
264
+ idx += 1
265
+ }
266
+ @app.tcl_eval("grid columnconfigure #{@w_f_details} 1 -weight 1")
267
+ end
268
+
269
+ def show_ctrl
270
+ mapped = @app.tcl_eval("winfo ismapped #{@ctrl}")
271
+ if mapped != '0'
272
+ @app.tcl_eval("pack forget #{@ctrl}")
273
+ @app.tcl_eval("#{@show} configure -text >>")
274
+ else
275
+ @app.tcl_eval("pack #{@ctrl} -side right -fill both -ipady 5")
276
+ @app.tcl_eval("#{@show} configure -text <<")
277
+ end
278
+ end
279
+
280
+ # ----------------------------------------------------------------
281
+ # State management
282
+ # ----------------------------------------------------------------
283
+
284
+ def set_mode(m)
285
+ @mode = m
286
+ active_GUI
287
+ end
288
+
289
+ def toggle_pause
290
+ if @tv_pause.bool
291
+ set_mode(:MPAUSE)
292
+ else
293
+ set_mode(:MGO)
294
+ end
295
+ end
296
+
297
+ def draw_all
298
+ reset_step
299
+ cdel(:all)
300
+ idx = 0
301
+ loop {
302
+ m = "draw#{idx}"
303
+ break unless respond_to?(m)
304
+ send(m)
305
+ idx += 1
306
+ }
307
+ end
308
+
309
+ def active_GUI
310
+ st = { false => :disabled, true => :normal }
311
+
312
+ m = @mode
313
+ @tv_pause.set(m == :MPAUSE ? 1 : 0)
314
+ @app.tcl_eval("#{@w_start} configure -state #{st[m != :MGO]}")
315
+ @app.tcl_eval("#{@w_pause} configure -state #{st[m != :MSTART && m != :MDONE]}")
316
+ @app.tcl_eval("#{@w_step} configure -state #{st[m != :MGO && m != :MDONE]}")
317
+ @app.tcl_eval("#{@w_bstep} configure -state #{st[m != :MGO && m != :MDONE]}")
318
+ @app.tcl_eval("#{@w_reset} configure -state #{st[m != :MSTART]}")
319
+
320
+ if @tv_details.bool
321
+ @app.tcl_eval("grid #{@w_f_details} -in #{@w_details_frame} -row 2 -sticky ew")
322
+ else
323
+ @app.tcl_eval("grid forget #{@w_f_details}")
324
+ end
325
+ @app.tcl_eval("#{@w_speed_scale} configure -label {Speed: #{@tv_speed.to_i}}")
326
+ end
327
+
328
+ def start
329
+ set_mode(:MGO)
330
+ end
331
+
332
+ def do_button(what)
333
+ case what
334
+ when 0 # Start
335
+ reset if @mode == :MDONE
336
+ set_mode(:MGO)
337
+ when 1 # Pause
338
+ set_mode(@tv_pause.bool ? :MPAUSE : :MGO)
339
+ when 2 # Step
340
+ set_mode(:MSSTEP)
341
+ when 3 # Reset
342
+ reset
343
+ when 4 # Big step
344
+ set_mode(:MBSTEP)
345
+ end
346
+ end
347
+
348
+ def go(who = nil)
349
+ now = clock_ms
350
+ if who # Start here for debugging
351
+ @active = [who]
352
+ set_mode(:MGO)
353
+ end
354
+ return if @mode == :MDEBUG
355
+ n = next_step if @mode != :MPAUSE
356
+ set_mode(:MPAUSE) if @mode == :MSSTEP
357
+ set_mode(:MSSTEP) if @mode == :MBSTEP && n
358
+ elapsed = clock_ms - now
359
+ delay = @speed[@tv_speed.to_i] - elapsed
360
+ delay = 1 if delay <= 0
361
+ delay
362
+ end
363
+
364
+ def next_step
365
+ retval = false
366
+
367
+ if @mode != :MSTART && @mode != :MDONE
368
+ @cnt += 1
369
+ @tv_cnt.set(@cnt)
370
+ end
371
+
372
+ alive = []
373
+ @active.each { |who|
374
+ who = who.to_i
375
+ n = send("move#{who}")
376
+ if (n & 1).nonzero? # This guy still alive
377
+ alive << who
378
+ end
379
+ if (n & 2).nonzero? # Next guy is active
380
+ alive << (who + 1)
381
+ retval = true
382
+ end
383
+ if (n & 4).nonzero? # End of puzzle flag
384
+ set_mode(:MDONE)
385
+ @active = []
386
+ TeekDemo.finish if defined?(TeekDemo) && TeekDemo.recording?
387
+ return true
388
+ end
389
+ }
390
+ @active = alive
391
+ retval
392
+ end
393
+
394
+ def about
395
+ msg = "Teek Version ::\n"
396
+ msg += "Ported from Ruby/Tk by Hidetoshi NAGAI\n\n"
397
+ msg += "Original Version ::\n"
398
+ msg += "Tk Goldberg\nby Keith Vetter, March 2003\n"
399
+ msg += "(Reproduced by kind permission of the author)\n\n"
400
+ msg += "Man will always find a difficult means to perform a simple task"
401
+ msg += "\nRube Goldberg"
402
+ @app.tcl_eval("tk_messageBox -message {#{msg}} -title About")
403
+ end
404
+
405
+ ################################################################
406
+ #
407
+ # All the drawing and moving routines
408
+ #
409
+
410
+ # START HERE! banner
411
+ def draw0
412
+ color = @C['0']
413
+ ctext([579, 119], :text=>'START HERE!',
414
+ :fill=>color, :anchor=>:w,
415
+ :tag=>'I0', :font=>['Times Roman', 12, :italic, :bold])
416
+ cline([719, 119, 763, 119], :tag=>'I0', :fill=>color,
417
+ :width=>5, :arrow=>:last, :arrowshape=>[18, 18, 5])
418
+ cbind_item('I0', 'Button-1') { start }
419
+ end
420
+
421
+ def move0(step = nil)
422
+ step = get_step(0, step)
423
+
424
+ if @mode != :MSTART
425
+ move_abs('I0', [-100, -100])
426
+ return 2
427
+ end
428
+
429
+ pos = [
430
+ [673, 119], [678, 119], [683, 119], [688, 119],
431
+ [693, 119], [688, 119], [683, 119], [678, 119]
432
+ ]
433
+ step = step % pos.length
434
+ move_abs('I0', pos[step])
435
+ return 1
436
+ end
437
+
438
+ # Dropping ball
439
+ def draw1
440
+ color = @C['1a']
441
+ color2 = @C['1b']
442
+ cpoly([ 844, 133, 800, 133, 800, 346, 820, 346,
443
+ 820, 168, 844, 168, 844, 133 ],
444
+ :width=>3, :fill=>color, :outline=>'')
445
+ cpoly([ 771, 133, 685, 133, 685, 168, 751, 168,
446
+ 751, 346, 771, 346, 771, 133 ],
447
+ :width=>3, :fill=>color, :outline=>'')
448
+ coval(box(812, 122, 9),
449
+ :tag=>'I1', :fill=>color2, :outline=>'')
450
+
451
+ cbind_item('I1', 'Button-1') { start }
452
+ end
453
+
454
+ def move1(step = nil)
455
+ step = get_step(1, step)
456
+ pos = [
457
+ [807, 122], [802, 122], [797, 123], [793, 124], [789, 129], [785, 153],
458
+ [785, 203], [785, 278, :x], [785, 367], [810, 392], [816, 438],
459
+ [821, 503], [824, 585, :y], [838, 587], [848, 593], [857, 601],
460
+ [-100, -100]
461
+ ]
462
+ return 0 if step >= pos.length
463
+ where = pos[step]
464
+ move_abs('I1', where)
465
+ move15a if where[2] == :y
466
+ return 3 if where[2] == :x
467
+ return 1
468
+ end
469
+
470
+ # Lighting the match
471
+ def draw2
472
+ color = @C['2']
473
+
474
+ # Fulcrum
475
+ cpoly([750, 369, 740, 392, 760, 392],
476
+ :fill=>@C['fg'], :outline=>@C['fg'])
477
+
478
+ # Strike box
479
+ crect([628, 335, 660, 383],
480
+ :fill=>'', :outline=>@C['fg'])
481
+ (0..2).each { |y|
482
+ yy = 335 + y * 16
483
+ cbitmap([628, yy], :bitmap=>'gray25',
484
+ :anchor=>:nw, :foreground=>@C['fg'])
485
+ cbitmap([644, yy], :bitmap=>'gray25',
486
+ :anchor=>:nw, :foreground=>@C['fg'])
487
+ }
488
+
489
+ # Lever
490
+ cline([702, 366, 798, 366],
491
+ :fill=>@C['fg'], :width=>6, :tag=>'I2_0')
492
+ # R strap
493
+ cline([712, 363, 712, 355],
494
+ :fill=>@C['fg'], :width=>3, :tag=>'I2_1')
495
+ # L strap
496
+ cline([705, 363, 705, 355],
497
+ :fill=>@C['fg'], :width=>3, :tag=>'I2_2')
498
+ # Match stick
499
+ cline([679, 356, 679, 360, 717, 360, 717, 356, 679, 356],
500
+ :fill=>@C['fg'], :width=>3, :tag=>'I2_3')
501
+ # Match head
502
+ cpoly([ 671, 352, 677.4, 353.9, 680, 358.5, 677.4, 363.1,
503
+ 671, 365, 664.6, 363.1, 662, 358.5, 664.6, 353.9 ],
504
+ :fill=>color, :outline=>color, :tag=>'I2_4')
505
+ end
506
+
507
+ def move2(step = nil)
508
+ step = get_step(2, step)
509
+
510
+ stages = [0, 0, 1, 2, 0, 2, 1, 0, 1, 2, 0, 2, 1]
511
+ xy = []
512
+ xy[0] = [
513
+ 686, 333, 692, 323, 682, 316, 674, 309, 671, 295, 668, 307,
514
+ 662, 318, 662, 328, 671, 336
515
+ ]
516
+ xy[1] = [
517
+ 687, 331, 698, 322, 703, 295, 680, 320, 668, 297, 663, 311,
518
+ 661, 327, 671, 335
519
+ ]
520
+ xy[2] = [
521
+ 686, 331, 704, 322, 688, 300, 678, 283, 678, 283, 674, 298,
522
+ 666, 309, 660, 324, 672, 336
523
+ ]
524
+
525
+ if step >= stages.length
526
+ cdel('I2')
527
+ return 0
528
+ end
529
+
530
+ if step == 0 # Rotate the match
531
+ beta = 20
532
+ ox, oy = anchor('I2_0', :s)
533
+ i = 0
534
+ until cfind("I2_#{i}").empty?
535
+ rotate_item("I2_#{i}", ox, oy, beta)
536
+ i += 1
537
+ end
538
+ # For the flame
539
+ cpoly([], :tag=>'I2', :smooth=>true, :fill=>@C['2'])
540
+ return 1
541
+ end
542
+ ccoords('I2', xy[stages[step]])
543
+ return((step == 7) ? 3 : 1)
544
+ end
545
+
546
+ # Weight and pulleys
547
+ def draw3
548
+ color = @C['3a']
549
+ color2 = @C['3b']
550
+
551
+ xy = [ [602, 296], [577, 174], [518, 174] ]
552
+ xy.each { |x, y|
553
+ coval(box(x, y, 13),
554
+ :fill=>color, :outline=>@C['fg'], :width=>3)
555
+ coval(box(x, y, 2), :fill=>@C['fg'], :outline=>@C['fg'])
556
+ }
557
+
558
+ # Wall to flame
559
+ cline([750, 309, 670, 309], :tag=>'I3_s',
560
+ :width=>3, :fill=>@C['fg'], :smooth=>true)
561
+ # Flame to pulley 1
562
+ cline([670, 309, 650, 309], :tag=>'I3_0',
563
+ :width=>3, :fill=>@C['fg'], :smooth=>true)
564
+ cline([650, 309, 600, 309], :tag=>'I3_1',
565
+ :width=>3, :fill=>@C['fg'], :smooth=>true)
566
+ # Pulley 1 half way to 2
567
+ cline([589, 296, 589, 235], :tag=>'I3_2',
568
+ :width=>3, :fill=>@C['fg'])
569
+ # Pulley 1 other half to 2
570
+ cline([589, 235, 589, 174], :width=>3, :fill=>@C['fg'])
571
+ # Across the top
572
+ cline([577, 161, 518, 161], :width=>3, :fill=>@C['fg'])
573
+ # Down to weight
574
+ cline([505, 174, 505, 205], :tag=>'I3_w',
575
+ :width=>3, :fill=>@C['fg'])
576
+
577
+ # Draw the weight
578
+ x1, y1, x2, y2 = [515, 207, 495, 207]
579
+ coval(box(x1, y1, 6),
580
+ :tag=>'I3_', :fill=>color2, :outline=>color2)
581
+ coval(box(x2, y2, 6),
582
+ :tag=>'I3_', :fill=>color2, :outline=>color2)
583
+ crect(x1, y1 - 6, x2, y2 + 6,
584
+ :tag=>'I3_', :fill=>color2, :outline=>color2)
585
+ cpoly(round_rect([492, 220, 518, 263], 15),
586
+ :smooth=>true, :tag=>'I3_', :fill=>color2, :outline=>color2)
587
+ cline([500, 217, 511, 217],
588
+ :tag=>'I3_', :fill=>color2, :width=>10)
589
+
590
+ # Bottom weight target
591
+ cline([502, 393, 522, 393, 522, 465],
592
+ :tag=>'I3__', :fill=>@C['fg'], :joinstyle=>:miter, :width=>10)
593
+ end
594
+
595
+ def move3(step = nil)
596
+ step = get_step(3, step)
597
+
598
+ pos = [ [505, 247], [505, 297], [505, 386.5], [505, 386.5] ]
599
+ rope = []
600
+ rope[0] = [750, 309, 729, 301, 711, 324, 690, 300]
601
+ rope[1] = [750, 309, 737, 292, 736, 335, 717, 315, 712, 320]
602
+ rope[2] = [750, 309, 737, 309, 740, 343, 736, 351, 725, 340]
603
+ rope[3] = [750, 309, 738, 321, 746, 345, 742, 356]
604
+
605
+ return 0 if step >= pos.length
606
+
607
+ cdel("I3_#{step}")
608
+ move_abs('I3_', pos[step])
609
+ ccoords('I3_s', rope[step])
610
+ ccoords('I3_w', [505, 174].concat(pos[step]))
611
+ if step == 2
612
+ cmove('I3__', 0, 30)
613
+ return 2
614
+ end
615
+ return 1
616
+ end
617
+
618
+ # Cage and door
619
+ def draw4
620
+ color = @C['4']
621
+ x0, y0, x1, y1 = [527, 356, 611, 464]
622
+
623
+ y0.step(y1, 12) { |y| cline([x0, y, x1, y], :fill=>color, :width=>1) }
624
+ x0.step(x1, 12) { |x| cline([x, y0, x, y1], :fill=>color, :width=>1) }
625
+
626
+ # Swing gate
627
+ cline([518, 464, 518, 428], :tag=>'I4', :fill=>color, :width=>1)
628
+ end
629
+
630
+ def move4(step = nil)
631
+ step = get_step(4, step)
632
+ angles = [-10, -20, -30, -30]
633
+ return 0 if step >= angles.length
634
+ rotate_item('I4', 518, 464, angles[step])
635
+ craise('I4')
636
+ return((step == 3) ? 3 : 1)
637
+ end
638
+
639
+ # Mouse
640
+ def draw5
641
+ color = @C['5a']
642
+ color2 = @C['5b']
643
+
644
+ xy = [377, 248, 410, 248, 410, 465, 518, 465]
645
+ xy.concat [518, 428, 451, 428, 451, 212, 377, 212]
646
+ cpoly(xy, :fill=>color2, :outline=>@C['fg'], :width=>3)
647
+
648
+ xy = [
649
+ 534.5, 445.5, 541, 440, 552, 436, 560, 436, 569, 440, 574, 446,
650
+ 575, 452, 574, 454, 566, 456, 554, 456, 545, 456, 537, 454, 530, 452
651
+ ]
652
+ cpoly(xy, :tag=>['I5', 'I5_0'], :fill=>color)
653
+
654
+ cline([573, 452, 592, 458, 601, 460, 613, 456],
655
+ :tag=>['I5', 'I5_1'], :fill=>color, :smooth=>true, :width=>3)
656
+
657
+ xy = [540, 444, 541, 445, 541, 447, 540, 448, 538, 447, 538, 445]
658
+ cpoly(xy, :tag=>['I5', 'I5_2'], :fill=>@C['bg'],
659
+ :outline=>'', :smooth=>true)
660
+
661
+ cline([538, 454, 535, 461],
662
+ :tag=>['I5', 'I5_3'], :fill=>color, :width=>2)
663
+ cline([566, 455, 569, 462],
664
+ :tag=>['I5', 'I5_4'], :fill=>color, :width=>2)
665
+ cline([544, 455, 545, 460],
666
+ :tag=>['I5', 'I5_5'], :fill=>color, :width=>2)
667
+ cline([560, 455, 558, 460],
668
+ :tag=>['I5', 'I5_6'], :fill=>color, :width=>2)
669
+ end
670
+
671
+ def move5(step = nil)
672
+ step = get_step(5, step)
673
+
674
+ pos = [
675
+ [553, 452], [533, 452], [513, 452], [493, 452], [473, 452],
676
+ [463, 442, 30], [445.5, 441.5, 30], [425.5, 434.5, 30], [422, 414],
677
+ [422, 394], [422, 374], [422, 354], [422, 334], [422, 314], [422, 294],
678
+ [422, 274, -30], [422, 260.5, -30, :x], [422.5, 248.5, -28], [425, 237]
679
+ ]
680
+
681
+ return 0 if step >= pos.length
682
+
683
+ x, y, beta, nxt = pos[step]
684
+ move_abs('I5', [x, y])
685
+ if beta
686
+ ox, oy = centroid('I5_0')
687
+ (0..6).each { |id| rotate_item("I5_#{id}", ox, oy, beta) }
688
+ end
689
+ return 3 if nxt == :x
690
+ return 1
691
+ end
692
+
693
+ # Dropping gumballs
694
+ def draw6
695
+ color = @C['6']
696
+ xy = [324, 130, 391, 204]
697
+ xy = round_rect(xy, 10)
698
+ cpoly(xy, :smooth=>true,
699
+ :outline=>@C['fg'], :width=>3, :fill=>color)
700
+ crect([339, 204, 376, 253], :outline=>@C['fg'], :width=>3,
701
+ :fill=>color, :tag=>'I6c')
702
+ xy = box(346, 339, 28)
703
+ coval(xy, :fill=>color, :outline=>'')
704
+ carc(xy, :outline=>@C['fg'], :width=>2, :style=>:arc,
705
+ :start=>80, :extent=>205)
706
+ carc(xy, :outline=>@C['fg'], :width=>2, :style=>:arc,
707
+ :start=>-41, :extent=>85)
708
+
709
+ xy = box(346, 339, 15)
710
+ coval(xy, :outline=>@C['fg'], :fill=>@C['fg'], :tag=>'I6m')
711
+ xy = [352, 312, 352, 254, 368, 254, 368, 322]
712
+ cpoly(xy, :fill=>color, :outline=>'')
713
+ cline(xy, :fill=>@C['fg'], :width=>2)
714
+
715
+ crect([353, 240, 367, 300], :fill=>color, :outline=>'')
716
+ crect([341, 190, 375, 210], :fill=>color, :outline=>'')
717
+
718
+ xy = [
719
+ 368, 356, 368, 403, 389, 403, 389, 464, 320, 464, 320, 403,
720
+ 352, 403, 352, 366
721
+ ]
722
+ cpoly(xy, :fill=>color, :outline=>'', :width=>2)
723
+ cline(xy, :fill=>@C['fg'], :width=>2)
724
+ coval(box(275, 342, 7), :outline=>@C['fg'], :fill=>@C['fg'])
725
+ cline([276, 334, 342, 325], :fill=>@C['fg'], :width=>3)
726
+ cline([276, 349, 342, 353], :fill=>@C['fg'], :width=>3)
727
+
728
+ cline([337, 212, 337, 247], :fill=>@C['fg'], :width=>3, :tag=>'I6_')
729
+ cline([392, 212, 392, 247], :fill=>@C['fg'], :width=>3, :tag=>'I6_')
730
+ cline([337, 230, 392, 230], :fill=>@C['fg'], :width=>7, :tag=>'I6_')
731
+
732
+ colors = %w(red cyan orange green blue darkblue) * 3
733
+ (0..16).each { |i|
734
+ loc = -i
735
+ color = colors[i]
736
+ x, y = @XY6["#{loc}"]
737
+ coval(box(x, y, 5), :fill=>color, :outline=>color, :tag=>"I6_b#{i}")
738
+ }
739
+ draw6a(12)
740
+ end
741
+
742
+ def draw6a(beta)
743
+ cdel('I6_0')
744
+ ox, oy = [346, 339]
745
+ (0..3).each { |i|
746
+ b = beta + i * 45
747
+ x, y = rotate_c(28, 0, 0, 0, b)
748
+ xy = [ox + x, oy + y, ox - x, oy - y]
749
+ cline(xy, :tag=>'I6_0', :fill=>@C['fg'], :width=>2)
750
+ }
751
+ end
752
+
753
+ def move6(step = nil)
754
+ step = get_step(6, step)
755
+
756
+ return 0 if step > 62
757
+
758
+ if step < 2
759
+ cmove('I6_', -7, 0)
760
+ if step == 1
761
+ crect([348, 226, 365, 240], :fill=>citemcget('I6c', :fill),
762
+ :outline=>'')
763
+ end
764
+ return 1
765
+ end
766
+
767
+ s = step - 1
768
+ (0..(((s - 1) / 3).to_i)).each { |i|
769
+ tag = "I6_b#{i}"
770
+ break if cfind(tag).empty?
771
+ loc = s - 3 * i
772
+
773
+ if @XY6["#{loc},#{i}"]
774
+ move_abs(tag, @XY6["#{loc},#{i}"])
775
+ elsif @XY6["#{loc}"]
776
+ move_abs(tag, @XY6["#{loc}"])
777
+ end
778
+ }
779
+ if s % 3 == 1
780
+ first = (s + 2) / 3
781
+ i = first
782
+ loop {
783
+ tag = "I6_b#{i}"
784
+ break if cfind(tag).empty?
785
+ loc = first - i
786
+ move_abs(tag, @XY6["#{loc}"])
787
+ i += 1
788
+ }
789
+ end
790
+ draw6a(12 + s * 15) if s >= 3
791
+ return((s == 3) ? 3 : 1)
792
+ end
793
+
794
+ # On/off switch
795
+ def draw7
796
+ color = @C['7']
797
+ crect([198, 306, 277, 374], :outline=>@C['fg'], :width=>2,
798
+ :fill=>color, :tag=>'I7z')
799
+ clower('I7z')
800
+ cline([275, 343, 230, 349], :tag=>'I7', :fill=>@C['fg'], :arrow=>:last,
801
+ :arrowshape=>[23, 23, 8], :width=>6)
802
+ x, y = [225, 324]
803
+ coval(box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg'])
804
+ font = ['Times Roman', 8]
805
+ ctext([218, 323], :text=>'on', :anchor=>:e,
806
+ :fill=>@C['fg'], :font=>font)
807
+ x, y = [225, 350]
808
+ coval(box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg'])
809
+ ctext([218, 349], :text=>'off', :anchor=>:e,
810
+ :fill=>@C['fg'], :font=>font)
811
+ end
812
+
813
+ def move7(step = nil)
814
+ step = get_step(7, step)
815
+ numsteps = 30
816
+ return 0 if step > numsteps
817
+ beta = 30.0 / numsteps
818
+ rotate_item('I7', 275, 343, beta)
819
+ return((step == numsteps) ? 3 : 1)
820
+ end
821
+
822
+ # Electricity to the fan
823
+ def draw8
824
+ sine([271, 248, 271, 306], 5, 8, :tag=>'I8_s', :fill=>@C['8'], :width=>3)
825
+ end
826
+
827
+ def move8(step = nil)
828
+ step = get_step(8, step)
829
+ return 0 if step > 3
830
+ if step == 0
831
+ sparkle(anchor('I8_s', :s), 'I8')
832
+ return 1
833
+ elsif step == 1
834
+ move_abs('I8', anchor('I8_s', :c))
835
+ elsif step == 2
836
+ move_abs('I8', anchor('I8_s', :n))
837
+ else
838
+ cdel('I8')
839
+ end
840
+ return((step == 2) ? 3 : 1)
841
+ end
842
+
843
+ # Fan
844
+ def draw9
845
+ color = @C['9']
846
+ coval([266, 194, 310, 220], :outline=>color, :fill=>color)
847
+ coval([280, 209, 296, 248], :outline=>color, :fill=>color)
848
+ xy = [
849
+ 288, 249, 252, 249, 260, 240, 280, 234,
850
+ 296, 234, 316, 240, 324, 249, 288, 249
851
+ ]
852
+ cpoly(xy, :fill=>color, :smooth=>true)
853
+ cpoly([248, 205, 265, 214, 264, 205, 265, 196], :fill=>color)
854
+
855
+ coval([255, 206, 265, 234], :fill=>'', :outline=>@C['fg'],
856
+ :width=>3, :tag=>'I9_0')
857
+ coval([255, 176, 265, 204], :fill=>'', :outline=>@C['fg'],
858
+ :width=>3, :tag=>'I9_0')
859
+ coval([255, 206, 265, 220], :fill=>'', :outline=>@C['fg'],
860
+ :width=>1, :tag=>'I9_1')
861
+ coval([255, 190, 265, 204], :fill=>'', :outline=>@C['fg'],
862
+ :width=>1, :tag=>'I9_1')
863
+ end
864
+
865
+ def move9(step = nil)
866
+ step = get_step(9, step)
867
+ if (step & 1).nonzero?
868
+ citemconfig('I9_0', :width=>4)
869
+ citemconfig('I9_1', :width=>1)
870
+ clower('I9_1', 'I9_0')
871
+ else
872
+ citemconfig('I9_0', :width=>1)
873
+ citemconfig('I9_1', :width=>4)
874
+ clower('I9_0', 'I9_1')
875
+ end
876
+ return 3 if step == 0
877
+ return 1
878
+ end
879
+
880
+ # Boat
881
+ def draw10
882
+ color = @C['10a']
883
+ color2 = @C['10b']
884
+ cpoly([191, 230, 233, 230, 233, 178, 191, 178],
885
+ :fill=>color, :width=>3, :outline=>@C['fg'], :tag=>'I10')
886
+ xy = box(209, 204, 31)
887
+ carc(xy, :outline=>'', :fill=>color, :style=>:pie,
888
+ :start=>120, :extent=>120, :tag=>'I10')
889
+ carc(xy, :outline=>@C['fg'], :width=>3, :style=>:arc,
890
+ :start=>120, :extent=>120, :tag=>'I10')
891
+ xy = box(249, 204, 31)
892
+ carc(xy, :outline=>'', :fill=>@C['bg'], :width=>3,
893
+ :style=>:pie, :start=>120, :extent=>120, :tag=>'I10')
894
+ carc(xy, :outline=>@C['fg'], :width=>3, :style=>:arc,
895
+ :start=>120, :extent=>120, :tag=>'I10')
896
+
897
+ cline([200, 171, 200, 249], :fill=>@C['fg'], :width=>3, :tag=>'I10')
898
+ cline([159, 234, 182, 234], :fill=>@C['fg'], :width=>3, :tag=>'I10')
899
+ cline([180, 234, 180, 251, 220, 251], :fill=>@C['fg'], :width=>6, :tag=>'I10')
900
+
901
+ sine([92, 255, 221, 255], 2, 25, :fill=>color2, :width=>1, :tag=>'I10w')
902
+
903
+ xy = ccoords('I10w')[4..-5]
904
+ xy.concat([222, 266, 222, 277, 99, 277])
905
+ cpoly(xy, :fill=>color2, :outline=>color2)
906
+ cline([222, 266, 222, 277, 97, 277, 97, 266], :fill=>@C['fg'], :width=>3)
907
+
908
+ carc(box(239, 262, 17), :outline=>@C['fg'], :width=>3, :style=>:arc,
909
+ :start=>95, :extent=>103)
910
+ carc(box(76, 266, 21), :outline=>@C['fg'], :width=>3, :style=>:arc,
911
+ :extent=>190)
912
+ end
913
+
914
+ def move10(step = nil)
915
+ step = get_step(10, step)
916
+
917
+ pos = [
918
+ [195, 212], [193, 212], [190, 212], [186, 212], [181, 212], [176, 212],
919
+ [171, 212], [166, 212], [161, 212], [156, 212], [151, 212], [147, 212],
920
+ [142, 212], [137, 212], [132, 212, :x], [127, 212], [121, 212],
921
+ [116, 212], [111, 212]
922
+ ]
923
+ return 0 if step >= pos.length
924
+ where = pos[step]
925
+ move_abs('I10', where)
926
+ return 3 if where[2] == :x
927
+ return 1
928
+ end
929
+
930
+ # 2nd ball drop
931
+ def draw11
932
+ color = @C['11a']
933
+ color2 = @C['11b']
934
+ crect([23, 264, 55, 591], :fill=>color, :outline=>'')
935
+ coval(box(71, 460, 48), :fill=>color, :outline=>'')
936
+
937
+ cline([55, 264, 55, 458], :fill=>@C['fg'], :width=>3)
938
+ cline([55, 504, 55, 591], :fill=>@C['fg'], :width=>3)
939
+ carc(box(71, 460, 48), :outline=>@C['fg'], :width=>3, :style=>:arc,
940
+ :start=>110, :extent=>-290, :tag=>'I11i')
941
+ coval(box(71, 460, 16), :outline=>@C['fg'], :fill=>'',
942
+ :width=>3, :tag=>'I11i')
943
+ coval(box(71, 460, 16), :outline=>@C['fg'], :fill=>@C['bg'], :width=>3)
944
+
945
+ cline([23, 264, 23, 591], :fill=>@C['fg'], :width=>3)
946
+ carc(box(1, 266, 23), :outline=>@C['fg'], :width=>3,
947
+ :style=>:arc, :extent=>90)
948
+
949
+ coval(box(75, 235, 9), :fill=>color2, :outline=>'',
950
+ :width=>3, :tag=>'I11')
951
+ end
952
+
953
+ def move11(step = nil)
954
+ step = get_step(11, step)
955
+
956
+ pos = [
957
+ [75, 235], [70, 235], [65, 237], [56, 240], [46, 247], [38, 266],
958
+ [38, 296], [38, 333], [38, 399], [38, 475], [74, 496], [105, 472],
959
+ [100, 437], [65, 423], [-100, -100], [38, 505], [38, 527, :x], [38, 591]
960
+ ]
961
+ return 0 if step >= pos.length
962
+ where = pos[step]
963
+ move_abs('I11', where)
964
+ return 3 if where[2] == :x
965
+ return 1
966
+ end
967
+
968
+ # Hand
969
+ def draw12
970
+ xy = [
971
+ 20, 637, 20, 617, 20, 610, 20, 590, 40, 590, 40, 590,
972
+ 60, 590, 60, 610, 60, 610
973
+ ]
974
+ xy.concat([60, 610, 65, 620, 60, 631])
975
+ xy.concat([60, 631, 60, 637, 60, 662, 60, 669, 52, 669,
976
+ 56, 669, 50, 669, 50, 662, 50, 637])
977
+
978
+ y0 = 637; y1 = 645
979
+ 50.step(21, -10) { |x|
980
+ x1 = x - 5; x2 = x - 10
981
+ xy << x << y0 << x1 << y1 << x2 << y0
982
+ }
983
+ cpoly(xy, :fill=>@C['12'], :outline=>@C['fg'],
984
+ :smooth=>true, :tag=>'I12', :width=>3)
985
+ end
986
+
987
+ def move12(step = nil)
988
+ step = get_step(12, step)
989
+ pos = [[42.5, 641, :x]]
990
+ return 0 if step >= pos.length
991
+ where = pos[step]
992
+ move_abs('I12', where)
993
+ return 3 if where[2] == :x
994
+ return 1
995
+ end
996
+
997
+ # Fax
998
+ def draw13
999
+ color = @C['13a']
1000
+ xy = [86, 663, 149, 663, 149, 704, 50, 704, 50, 681, 64, 681, 86, 671]
1001
+ xy2 = [
1002
+ 784, 663, 721, 663, 721, 704, 820, 704, 820, 681, 806, 681, 784, 671
1003
+ ]
1004
+ radii = [2, 9, 9, 8, 5, 5, 2]
1005
+
1006
+ round_poly(xy, radii, :width=>3, :outline=>@C['fg'], :fill=>color)
1007
+ round_poly(xy2, radii, :width=>3, :outline=>@C['fg'], :fill=>color)
1008
+
1009
+ x, y = [56, 677]
1010
+ crect(box(x, y, 4), :fill=>'', :outline=>@C['fg'],
1011
+ :width=>3, :tag=>'I13')
1012
+ x, y = [809, 677]
1013
+ crect(box(x, y, 4), :fill=>'', :outline=>@C['fg'],
1014
+ :width=>3, :tag=>'I13R')
1015
+
1016
+ ctext([112, 687], :text=>'FAX', :fill=>@C['fg'],
1017
+ :font=>['Times Roman', 12, :bold])
1018
+ ctext([762, 687], :text=>'FAX', :fill=>@C['fg'],
1019
+ :font=>['Times Roman', 12, :bold])
1020
+
1021
+ cline([138, 663, 148, 636, 178, 636],
1022
+ :smooth=>true, :fill=>@C['fg'], :width=>3)
1023
+ cline([732, 663, 722, 636, 692, 636],
1024
+ :smooth=>true, :fill=>@C['fg'], :width=>3)
1025
+
1026
+ sine([149, 688, 720, 688], 5, 15,
1027
+ :tag=>'I13_s', :fill=>@C['fg'], :width=>3)
1028
+ end
1029
+
1030
+ def move13(step = nil)
1031
+ step = get_step(13, step)
1032
+ numsteps = 7
1033
+
1034
+ if step == numsteps + 2
1035
+ move_abs('I13_star', [-100, -100])
1036
+ citemconfig('I13R', :fill=>@C['13b'], :width=>2)
1037
+ return 2
1038
+ end
1039
+ if step == 0
1040
+ cdel('I13')
1041
+ sparkle([-100, -100], 'I13_star')
1042
+ return 1
1043
+ end
1044
+ x0, y0 = anchor('I13_s', :w)
1045
+ x1, y1 = anchor('I13_s', :e)
1046
+ x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f
1047
+ move_abs('I13_star', [x, y0])
1048
+ return 1
1049
+ end
1050
+
1051
+ # Paper in fax
1052
+ def draw14
1053
+ color = @C['14']
1054
+ cline([102, 661, 113, 632, 130, 618], :smooth=>true, :fill=>color,
1055
+ :width=>3, :tag=>'I14L_0')
1056
+ cline([148, 629, 125, 640, 124, 662], :smooth=>true, :fill=>color,
1057
+ :width=>3, :tag=>'I14L_1')
1058
+ draw14a('L')
1059
+
1060
+ cline([768.0, 662.5, 767.991316225, 662.433786215, 767.926187912, 662.396880171],
1061
+ :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_0')
1062
+ clower('I14R_0')
1063
+ cline([745.947897349, 662.428358855, 745.997829056, 662.452239237, 746.0, 662.5],
1064
+ :smooth=>true, :fill=>color, :width=>3, :tag=>'I14R_1')
1065
+ clower('I14R_1')
1066
+ end
1067
+
1068
+ def draw14a(side)
1069
+ color = @C['14']
1070
+ xy = ccoords("I14#{side}_0")
1071
+ xy2 = ccoords("I14#{side}_1")
1072
+ x0, y0, x1, y1, x2, y2 = xy
1073
+ x3, y3, x4, y4, x5, y5 = xy2
1074
+
1075
+ zz = [
1076
+ x0, y0, x0, y0, xy, x2, y2, x2, y2,
1077
+ x3, y3, x3, y3, xy2, x5, y5, x5, y5
1078
+ ].flatten
1079
+ cdel("I14#{side}")
1080
+ cpoly(zz, :tag=>"I14#{side}", :smooth=>true,
1081
+ :fill=>color, :outline=>color, :width=>3)
1082
+ clower("I14#{side}")
1083
+ end
1084
+
1085
+ def move14(step = nil)
1086
+ step = get_step(14, step)
1087
+
1088
+ sc = 0.9 - 0.05 * step
1089
+ if sc < 0.3
1090
+ cdel('I14L')
1091
+ return 0
1092
+ end
1093
+
1094
+ ox, oy = ccoords('I14L_0')
1095
+ cscale('I14L_0', ox, oy, sc, sc)
1096
+ ox, oy = ccoords('I14L_1')[-2..-1]
1097
+ cscale('I14L_1', ox, oy, sc, sc)
1098
+ draw14a('L')
1099
+
1100
+ sc = 0.35 + 0.05 * step
1101
+ sc = 1 / sc
1102
+
1103
+ ox, oy = ccoords('I14R_0')
1104
+ cscale('I14R_0', ox, oy, sc, sc)
1105
+ ox, oy = ccoords('I14R_1')[-2..-1]
1106
+ cscale('I14R_1', ox, oy, sc, sc)
1107
+ draw14a('R')
1108
+
1109
+ return((step == 10) ? 3 : 1)
1110
+ end
1111
+
1112
+ # Light beam
1113
+ def draw15
1114
+ color = @C['15a']
1115
+ cline([824, 599, 824, 585, 820, 585, 829, 585],
1116
+ :fill=>@C['fg'], :width=>3, :tag=>'I15a')
1117
+ crect([789, 599, 836, 643], :fill=>color, :outline=>@C['fg'], :width=>3)
1118
+ crect([778, 610, 788, 632], :fill=>color, :outline=>@C['fg'], :width=>3)
1119
+ crect([766, 617, 776, 625], :fill=>color, :outline=>@C['fg'], :width=>3)
1120
+
1121
+ crect([633, 600, 681, 640], :fill=>color, :outline=>@C['fg'], :width=>3)
1122
+ crect([635, 567, 657, 599], :fill=>color, :outline=>@C['fg'], :width=>2)
1123
+ crect([765, 557, 784, 583], :fill=>color, :outline=>@C['fg'], :width=>2)
1124
+
1125
+ sine([658, 580, 765, 580], 3, 15,
1126
+ :tag=>'I15_s', :fill=>@C['fg'], :width=>3)
1127
+ end
1128
+
1129
+ def move15a
1130
+ color = @C['15b']
1131
+ cscale('I15a', 824, 599, 1, 0.3)
1132
+ cline([765, 621, 681, 621], :dash=>'-', :width=>3, :fill=>color, :tag=>'I15')
1133
+ end
1134
+
1135
+ def move15(step = nil)
1136
+ step = get_step(15, step)
1137
+ numsteps = 6
1138
+
1139
+ if step == numsteps + 2
1140
+ move_abs('I15_star', [-100, -100])
1141
+ return 2
1142
+ end
1143
+ if step == 0
1144
+ sparkle([-100, -100], 'I15_star')
1145
+ ccoords('I15', [765, 621, 745, 621])
1146
+ return 1
1147
+ end
1148
+ x0, y0 = anchor('I15_s', :w)
1149
+ x1, y1 = anchor('I15_s', :e)
1150
+ x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f
1151
+ move_abs('I15_star', [x, y0])
1152
+ return 1
1153
+ end
1154
+
1155
+ # Bell
1156
+ def draw16
1157
+ color = @C['16']
1158
+ crect([722, 485, 791, 556], :fill=>'', :outline=>@C['fg'], :width=>3)
1159
+ coval(box(752, 515, 25), :fill=>color, :outline=>'black',
1160
+ :tag=>'I16b', :width=>2)
1161
+ coval(box(752, 515, 5), :fill=>'black', :outline=>'black', :tag=>'I16b')
1162
+
1163
+ cline([784, 523, 764, 549], :width=>3, :tag=>'I16c', :fill=>@C['fg'])
1164
+ coval(box(784, 523, 4), :fill=>@C['fg'], :outline=>@C['fg'], :tag=>'I16d')
1165
+ end
1166
+
1167
+ def move16(step = nil)
1168
+ step = get_step(16, step)
1169
+ ox, oy = [760, 553]
1170
+ if (step & 1).nonzero?
1171
+ beta = 12
1172
+ cmove('I16b', 3, 0)
1173
+ else
1174
+ beta = -12
1175
+ cmove('I16b', -3, 0)
1176
+ end
1177
+ rotate_item('I16c', ox, oy, beta)
1178
+ rotate_item('I16d', ox, oy, beta)
1179
+ return((step == 1) ? 3 : 1)
1180
+ end
1181
+
1182
+ # Cat
1183
+ def draw17
1184
+ color = @C['17']
1185
+
1186
+ cline([584, 556, 722, 556], :fill=>@C['fg'], :width=>3)
1187
+ cline([584, 485, 722, 485], :fill=>@C['fg'], :width=>3)
1188
+
1189
+ carc([664, 523, 717, 549], :outline=>@C['fg'], :fill=>color, :width=>3,
1190
+ :style=>:chord, :start=>128, :extent=>260, :tag=>'I17')
1191
+ coval([709, 554, 690, 543], :outline=>@C['fg'], :fill=>color,
1192
+ :width=>3, :tag=>'I17')
1193
+ coval([657, 544, 676, 555], :outline=>@C['fg'], :fill=>color,
1194
+ :width=>3, :tag=>'I17')
1195
+
1196
+ carc(box(660, 535, 15), :outline=>@C['fg'], :width=>3, :style=>:arc,
1197
+ :start=>150, :extent=>240, :tag=>'I17_')
1198
+ carc(box(660, 535, 15), :outline=>'', :fill=>color, :width=>1,
1199
+ :style=>:chord, :start=>150, :extent=>240, :tag=>'I17_')
1200
+ cline([674, 529, 670, 513, 662, 521, 658, 521, 650, 513, 647, 529],
1201
+ :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1202
+ cpoly([674, 529, 670, 513, 662, 521, 658, 521, 650, 513, 647, 529],
1203
+ :fill=>color, :outline=>'', :width=>1, :tag=>['I17_', 'I17_c'])
1204
+
1205
+ # Whiskers left
1206
+ cline([652, 542, 628, 539], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1207
+ cline([652, 543, 632, 545], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1208
+ cline([652, 546, 632, 552], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1209
+ # Whiskers right
1210
+ cline([668, 543, 687, 538], :fill=>@C['fg'], :width=>3,
1211
+ :tag=>['I17_', 'I17_w'])
1212
+ cline([668, 544, 688, 546], :fill=>@C['fg'], :width=>3,
1213
+ :tag=>['I17_', 'I17_w'])
1214
+ cline([668, 547, 688, 553], :fill=>@C['fg'], :width=>3,
1215
+ :tag=>['I17_', 'I17_w'])
1216
+
1217
+ # Eyes
1218
+ cline([649, 530, 654, 538, 659, 530], :fill=>@C['fg'], :width=>2,
1219
+ :smooth=>true, :tag=>'I17')
1220
+ cline([671, 530, 666, 538, 661, 530], :fill=>@C['fg'], :width=>2,
1221
+ :smooth=>true, :tag=>'I17')
1222
+ # Mouth
1223
+ cline([655, 543, 660, 551, 665, 543], :fill=>@C['fg'], :width=>2,
1224
+ :smooth=>true, :tag=>'I17')
1225
+ end
1226
+
1227
+ def move17(step = nil)
1228
+ step = get_step(17, step)
1229
+
1230
+ if step == 0
1231
+ cdel('I17')
1232
+ # Surprised mouth
1233
+ cline([655, 543, 660, 535, 665, 543], :fill=>@C['fg'], :width=>3,
1234
+ :smooth=>true, :tag=>'I17_')
1235
+ # Surprised eyes
1236
+ coval(box(654, 530, 4), :outline=>@C['fg'], :width=>3, :fill=>'',
1237
+ :tag=>'I17_')
1238
+ coval(box(666, 530, 4), :outline=>@C['fg'], :width=>3, :fill=>'',
1239
+ :tag=>'I17_')
1240
+
1241
+ cmove('I17_', 0, -20)
1242
+ cline([652, 528, 652, 554], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1243
+ cline([670, 528, 670, 554], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1244
+
1245
+ xy = [
1246
+ 675, 506, 694, 489, 715, 513, 715, 513, 715, 513, 716, 525,
1247
+ 716, 525, 716, 525, 706, 530, 695, 530, 679, 535, 668, 527,
1248
+ 668, 527, 668, 527, 675, 522, 676, 517, 677, 512
1249
+ ]
1250
+ cpoly(xy, :fill=>citemcget('I17_c', :fill),
1251
+ :outline=>@C['fg'], :width=>3, :smooth=>true, :tag=>'I17_')
1252
+ cline([716, 514, 716, 554], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1253
+ cline([694, 532, 694, 554], :fill=>@C['fg'], :width=>3, :tag=>'I17_')
1254
+ cline([715, 514, 718, 506, 719, 495, 716, 488], :fill=>@C['fg'],
1255
+ :width=>3, :smooth=>true, :tag=>'I17_')
1256
+
1257
+ craise('I17w')
1258
+ cmove('I17_', -5, 0)
1259
+ return 2
1260
+ end
1261
+ return 0
1262
+ end
1263
+
1264
+ # Sling shot
1265
+ def draw18
1266
+ cline([721, 506, 627, 506], :width=>4, :fill=>@C['fg'], :tag=>'I18')
1267
+ coval([607, 500, 628, 513], :fill=>@C['18'], :outline=>'', :tag=>'I18a')
1268
+ cline([526, 513, 606, 507, 494, 502], :fill=>@C['fg'], :width=>4, :tag=>'I18b')
1269
+ cline([485, 490, 510, 540, 510, 575, 510, 540, 535, 491],
1270
+ :fill=>@C['fg'], :width=>6)
1271
+ end
1272
+
1273
+ def move18(step = nil)
1274
+ step = get_step(18, step)
1275
+
1276
+ pos = [
1277
+ [587, 506], [537, 506], [466, 506], [376, 506], [266, 506, :x],
1278
+ [136, 506], [16, 506], [-100, -100]
1279
+ ]
1280
+ b = []
1281
+ b[0] = [490, 502, 719, 507, 524, 512]
1282
+ b[1] = [
1283
+ 491, 503, 524, 557, 563, 505, 559, 496, 546, 506, 551, 525,
1284
+ 553, 536, 538, 534, 532, 519, 529, 499
1285
+ ]
1286
+ b[2] = [
1287
+ 491, 503, 508, 563, 542, 533, 551, 526, 561, 539, 549, 550, 530, 500
1288
+ ]
1289
+ b[3] = [
1290
+ 491, 503, 508, 563, 530, 554, 541, 562, 525, 568, 519, 544, 530, 501
1291
+ ]
1292
+
1293
+ return 0 if step >= pos.length
1294
+
1295
+ if step == 0
1296
+ cdel('I18')
1297
+ citemconfig('I18b', :smooth=>true)
1298
+ end
1299
+ ccoords('I18b', b[step]) if b[step]
1300
+
1301
+ where = pos[step]
1302
+ move_abs('I18a', where)
1303
+ return 3 if where[2] == :x
1304
+ return 1
1305
+ end
1306
+
1307
+ # Water pipe
1308
+ def draw19
1309
+ color = @C['19']
1310
+ xx = [[249, 181], [155, 118], [86, 55], [22, 0]]
1311
+ xx.each { |x1, x2|
1312
+ crect(x1, 453, x2, 467, :fill=>color, :outline=>'', :tag=>'I19')
1313
+ cline([x1, 453, x2, 453], :fill=>@C['fg'], :width=>1)
1314
+ cline([x1, 467, x2, 467], :fill=>@C['fg'], :width=>1)
1315
+ }
1316
+ craise('I11i')
1317
+
1318
+ coval(box(168, 460, 16), :fill=>color, :outline=>'')
1319
+ carc(box(168, 460, 16), :outline=>@C['fg'], :width=>1, :style=>:arc,
1320
+ :start=>21, :extent=>136)
1321
+ carc(box(168, 460, 16), :outline=>@C['fg'], :width=>1, :style=>:arc,
1322
+ :start=>-21, :extent=>-130)
1323
+
1324
+ crect([249, 447, 255, 473], :fill=>color, :outline=>@C['fg'], :width=>1)
1325
+
1326
+ # Bends
1327
+ xy = box(257, 433, 34)
1328
+ carc(xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>-91)
1329
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90)
1330
+ xy = box(257, 433, 20)
1331
+ carc(xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>-92)
1332
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>-90)
1333
+ xy = box(257, 421, 34)
1334
+ carc(xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>0, :extent=>91)
1335
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90)
1336
+ xy = box(257, 421, 20)
1337
+ carc(xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>0, :extent=>90)
1338
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>0, :extent=>90)
1339
+ xy = box(243, 421, 34)
1340
+ carc(xy, :outline=>'', :fill=>color, :width=>1, :style=>:pie, :start=>90, :extent=>90)
1341
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90)
1342
+ xy = box(243, 421, 20)
1343
+ carc(xy, :outline=>'', :fill=>@C['bg'], :width=>1, :style=>:pie, :start=>90, :extent=>90)
1344
+ carc(xy, :outline=>@C['fg'], :width=>1, :style=>:arc, :start=>90, :extent=>90)
1345
+
1346
+ # Joints
1347
+ crect([270, 427, 296, 433], :fill=>color, :outline=>@C['fg'], :width=>1)
1348
+ crect([270, 421, 296, 427], :fill=>color, :outline=>@C['fg'], :width=>1)
1349
+ crect([249, 382, 255, 408], :fill=>color, :outline=>@C['fg'], :width=>1)
1350
+ crect([243, 382, 249, 408], :fill=>color, :outline=>@C['fg'], :width=>1)
1351
+ crect([203, 420, 229, 426], :fill=>color, :outline=>@C['fg'], :width=>1)
1352
+
1353
+ coval(box(168, 460, 6), :fill=>@C['fg'], :outline=>'', :tag=>'I19a')
1354
+ cline([168, 460, 168, 512], :fill=>@C['fg'], :width=>5, :tag=>'I19b')
1355
+ end
1356
+
1357
+ def move19(step = nil)
1358
+ step = get_step(19, step)
1359
+ angles = [30, 30, 30]
1360
+ return 2 if step == angles.length
1361
+ ox, oy = centroid('I19a')
1362
+ rotate_item('I19b', ox, oy, angles[step])
1363
+ return 1
1364
+ end
1365
+
1366
+ # Water pouring
1367
+ def draw20; end
1368
+
1369
+ def move20(step = nil)
1370
+ step = get_step(20, step)
1371
+ pos = [
1372
+ [451, 20], [462, 40], [473, 40], [484, 40], [496, 40],
1373
+ [504, 40], [513, 40], [523, 40], [532, 40, :x]
1374
+ ]
1375
+ return 0 if step >= pos.length
1376
+
1377
+ cdel('I20')
1378
+ where = pos[step]
1379
+ y, f = where
1380
+ h20(y, f)
1381
+ return 3 if where[2] == :x
1382
+ return 1
1383
+ end
1384
+
1385
+ def h20(y, f)
1386
+ cdel('I20')
1387
+ color = @C['20']
1388
+
1389
+ sine([208, 428, 208, y], 4, f, :tag=>['I20', 'I20s'],
1390
+ :width=>3, :fill=>color, :smooth=>true)
1391
+ cline(ccoords('I20s'), :width=>3, :fill=>color, :smooth=>true,
1392
+ :tag=>['I20', 'I20a'])
1393
+ cline(ccoords('I20s'), :width=>3, :fill=>color, :smooth=>true,
1394
+ :tag=>['I20', 'I20b'])
1395
+ cmove('I20a', 8, 0)
1396
+ cmove('I20b', 16, 0)
1397
+ end
1398
+
1399
+ # Bucket
1400
+ def draw21
1401
+ color = @C['21']
1402
+ cline([217, 451, 244, 490], :fill=>@C['fg'], :width=>2, :tag=>'I21_a')
1403
+ cline([201, 467, 182, 490], :fill=>@C['fg'], :width=>2, :tag=>'I21_a')
1404
+
1405
+ xy = [245, 490, 237, 535]
1406
+ xy2 = [189, 535, 181, 490]
1407
+ cpoly(xy + xy2, :fill=>color, :outline=>'', :tag=>['I21', 'I21f'])
1408
+ cline(xy, :fill=>@C['fg'], :width=>2, :tag=>'I21')
1409
+ cline(xy2, :fill=>@C['fg'], :width=>2, :tag=>'I21')
1410
+
1411
+ coval([182, 486, 244, 498], :fill=>color, :outline=>'', :width=>2,
1412
+ :tag=>['I21', 'I21f'])
1413
+ coval([182, 486, 244, 498], :fill=>'', :outline=>@C['fg'], :width=>2,
1414
+ :tag=>['I21', 'I21t'])
1415
+ coval([189, 532, 237, 540], :fill=>color, :outline=>@C['fg'], :width=>2,
1416
+ :tag=>['I21', 'I21b'])
1417
+ end
1418
+
1419
+ def move21(step = nil)
1420
+ step = get_step(21, step)
1421
+ numsteps = 30
1422
+ return 0 if step >= numsteps
1423
+
1424
+ x1, y1, x2, y2 = cbbox('I21b')
1425
+ lx1, ly1, lx2, ly2 = [183, 492, 243, 504]
1426
+
1427
+ f = step / numsteps.to_f
1428
+ y2 = y2 - 3
1429
+ xx1 = x1 + (lx1 - x1) * f
1430
+ yy1 = y1 + (ly1 - y1) * f
1431
+ xx2 = x2 + (lx2 - x2) * f
1432
+ yy2 = y2 + (ly2 - y2) * f
1433
+
1434
+ citemconfig('I21b', :fill=>@C['20'])
1435
+ cdel('I21w')
1436
+ cpoly(x2, y2, x1, y1, xx1, yy1, xx2, yy1,
1437
+ :tag=>['I21', 'I21w'], :outline=>'', :fill=>@C['20'])
1438
+ clower('I21w', 'I21')
1439
+ craise('I21b')
1440
+ clower('I21f')
1441
+
1442
+ return((step == numsteps - 1) ? 3 : 1)
1443
+ end
1444
+
1445
+ # Bucket drop
1446
+ def draw22; end
1447
+
1448
+ def move22(step = nil)
1449
+ step = get_step(22, step)
1450
+ pos = [[213, 513], [213, 523], [213, 543, :x], [213, 583], [213, 593]]
1451
+
1452
+ citemconfig('I21f', :fill=>@C['22']) if step == 0
1453
+ return 0 if step >= pos.length
1454
+ where = pos[step]
1455
+ move_abs('I21', where)
1456
+ h20(where[1], 40)
1457
+ cdel('I21_a')
1458
+ return 3 if where[2] == :x
1459
+ return 1
1460
+ end
1461
+
1462
+ # Blow dart
1463
+ def draw23
1464
+ color = @C['23a']
1465
+ color2 = @C['23b']
1466
+ color3 = @C['23c']
1467
+
1468
+ crect([185, 623, 253, 650], :fill=>'black', :outline=>@C['fg'],
1469
+ :width=>2, :tag=>'I23a')
1470
+ coval([187, 592, 241, 623], :outline=>'', :fill=>color, :tag=>'I23b')
1471
+ carc([187, 592, 241, 623], :outline=>@C['fg'], :width=>3, :tag=>'I23b',
1472
+ :style=>:arc, :start=>12, :extent=>336)
1473
+ cpoly([239, 604, 258, 589, 258, 625, 239, 610],
1474
+ :outline=>'', :fill=>color, :tag=>'I23b')
1475
+ cline([239, 604, 258, 589, 258, 625, 239, 610],
1476
+ :fill=>@C['fg'], :width=>3, :tag=>'I23b')
1477
+
1478
+ coval([285, 611, 250, 603], :fill=>color2, :outline=>@C['fg'],
1479
+ :width=>3, :tag=>'I23d')
1480
+ cpoly([249, 596, 249, 618, 264, 607, 249, 596],
1481
+ :fill=>color3, :outline=>@C['fg'], :width=>3, :tag=>'I23d')
1482
+ cline([249, 607, 268, 607], :fill=>@C['fg'], :width=>3, :tag=>'I23d')
1483
+ cline([285, 607, 305, 607], :fill=>@C['fg'], :width=>3, :tag=>'I23d')
1484
+ end
1485
+
1486
+ def move23(step = nil)
1487
+ step = get_step(23, step)
1488
+
1489
+ pos = [
1490
+ [277, 607], [287, 607], [307, 607, :x], [347, 607], [407, 607],
1491
+ [487, 607], [587, 607], [687, 607], [787, 607], [-100, -100]
1492
+ ]
1493
+ return 0 if step >= pos.length
1494
+ if step <= 1
1495
+ ox, oy = anchor('I23a', :n)
1496
+ cscale('I23b', ox, oy, 0.9, 0.5)
1497
+ end
1498
+ where = pos[step]
1499
+ move_abs('I23d', where)
1500
+ return 3 if where[2] == :x
1501
+ return 1
1502
+ end
1503
+
1504
+ # Balloon
1505
+ def draw24
1506
+ color = @C['24a']
1507
+ coval([366, 518, 462, 665], :fill=>color, :outline=>@C['fg'],
1508
+ :width=>3, :tag=>'I24')
1509
+ cline([414, 666, 414, 729], :fill=>@C['fg'], :width=>3, :tag=>'I24')
1510
+ cpoly([410, 666, 404, 673, 422, 673, 418, 666],
1511
+ :fill=>color, :outline=>@C['fg'], :width=>3, :tag=>'I24')
1512
+
1513
+ # Reflections
1514
+ cline([387, 567, 390, 549, 404, 542], :fill=>@C['fg'], :smooth=>true,
1515
+ :width=>2, :tag=>'I24')
1516
+ cline([395, 568, 399, 554, 413, 547], :fill=>@C['fg'], :smooth=>true,
1517
+ :width=>2, :tag=>'I24')
1518
+ cline([403, 570, 396, 555, 381, 553], :fill=>@C['fg'], :smooth=>true,
1519
+ :width=>2, :tag=>'I24')
1520
+ cline([408, 564, 402, 547, 386, 545], :fill=>@C['fg'], :smooth=>true,
1521
+ :width=>2, :tag=>'I24')
1522
+ end
1523
+
1524
+ def move24(step = nil)
1525
+ step = get_step(24, step)
1526
+ return 0 if step > 4
1527
+ return 2 if step == 4
1528
+
1529
+ if step == 0
1530
+ cdel('I24')
1531
+ xy = [
1532
+ 347, 465, 361, 557, 271, 503, 272, 503, 342, 574, 259, 594,
1533
+ 259, 593, 362, 626, 320, 737, 320, 740, 398, 691, 436, 738,
1534
+ 436, 739, 476, 679, 528, 701, 527, 702, 494, 627, 548, 613,
1535
+ 548, 613, 480, 574, 577, 473, 577, 473, 474, 538, 445, 508,
1536
+ 431, 441, 431, 440, 400, 502, 347, 465, 347, 465
1537
+ ]
1538
+ cpoly(xy, :tag=>'I24', :fill=>@C['24b'],
1539
+ :outline=>@C['24a'], :width=>10, :smooth=>true)
1540
+ msg = @tv_message.get.gsub("\\n", "\n")
1541
+ ctext(centroid('I24'), :text=>msg, :tag=>['I24', 'I24t'],
1542
+ :justify=>:center, :font=>['Times Roman', 18, :bold],
1543
+ :fill=>@C['fg'])
1544
+ return 1
1545
+ end
1546
+
1547
+ citemconfig('I24t', :font=>['Times Roman', 18 + 6 * step, :bold])
1548
+ cmove('I24', 0, -60)
1549
+ ox, oy = centroid('I24')
1550
+ cscale('I24', ox, oy, 1.25, 1.25)
1551
+ return 1
1552
+ end
1553
+
1554
+ # Displaying the message
1555
+ def move25(step = nil)
1556
+ step = get_step(25, step)
1557
+
1558
+ if step == 0
1559
+ @XY['25'] = clock_ms
1560
+ return 1
1561
+ end
1562
+ elapsed = clock_ms - @XY['25']
1563
+ return 1 if elapsed < 5000
1564
+ return 2
1565
+ end
1566
+
1567
+ # Collapsing balloon
1568
+ def move26(step = nil)
1569
+ step = get_step(26, step)
1570
+
1571
+ if step >= 3
1572
+ cdel('I24', 'I26')
1573
+ ctext(430, 740, :anchor=>:s, :tag=>'I26',
1574
+ :text=>'click to continue',
1575
+ :font=>['Times Roman', 24, :bold],
1576
+ :fill=>@C['fg'])
1577
+ canvas_bind('Button-1') { reset }
1578
+ return 4
1579
+ end
1580
+
1581
+ ox, oy = centroid('I24')
1582
+ cscale('I24', ox, oy, 0.8, 0.8)
1583
+ cmove('I24', 0, 60)
1584
+ citemconfig('I24t', :font=>['Times Roman', 30 - 6 * step, :bold])
1585
+ return 1
1586
+ end
1587
+
1588
+ ################################################################
1589
+ #
1590
+ # Helper functions
1591
+ #
1592
+ def box(x, y, r)
1593
+ [x - r, y - r, x + r, y + r]
1594
+ end
1595
+
1596
+ def move_abs(item, xy)
1597
+ x, y = xy
1598
+ ox, oy = centroid(item)
1599
+ dx = x - ox
1600
+ dy = y - oy
1601
+ cmove(item, dx, dy)
1602
+ end
1603
+
1604
+ def rotate_item(item, ox, oy, beta)
1605
+ xy = ccoords(item)
1606
+ xy2 = []
1607
+ 0.step(xy.length - 1, 2) { |idx|
1608
+ x, y = xy[idx, 2]
1609
+ xy2.concat(rotate_c(x, y, ox, oy, beta))
1610
+ }
1611
+ ccoords(item, xy2)
1612
+ end
1613
+
1614
+ def rotate_c(x, y, ox, oy, beta)
1615
+ x -= ox
1616
+ y -= oy
1617
+ beta = beta * Math.atan(1) * 4 / 180.0
1618
+ xx = x * Math.cos(beta) - y * Math.sin(beta)
1619
+ yy = x * Math.sin(beta) + y * Math.cos(beta)
1620
+ xx += ox
1621
+ yy += oy
1622
+ [xx, yy]
1623
+ end
1624
+
1625
+ def reset
1626
+ draw_all
1627
+ canvas_bind_remove('Button-1')
1628
+ set_mode(:MSTART)
1629
+ @active = [0]
1630
+ end
1631
+
1632
+ def get_step(who, step)
1633
+ if step
1634
+ @step[who] = step
1635
+ else
1636
+ if !@step.key?(who) || @step[who] == ''
1637
+ @step[who] = 0
1638
+ else
1639
+ @step[who] += 1
1640
+ end
1641
+ end
1642
+ @tv_step[who]&.set(@step[who])
1643
+ @step[who]
1644
+ end
1645
+
1646
+ def reset_step
1647
+ @cnt = 0
1648
+ @tv_cnt.set(0)
1649
+ @step.keys.each { |k| @step[k] = ''; @tv_step[k]&.set('') }
1650
+ end
1651
+
1652
+ def sine(xy0, amp, freq, **opts)
1653
+ x0, y0, x1, y1 = xy0
1654
+ step = 2
1655
+ xy = []
1656
+ if y0 == y1
1657
+ x0.step(x1, step) { |x|
1658
+ beta = (x - x0) * 2 * Math::PI / freq
1659
+ y = y0 + amp * Math.sin(beta)
1660
+ xy << x << y
1661
+ }
1662
+ else
1663
+ y0.step(y1, step) { |y|
1664
+ beta = (y - y0) * 2 * Math::PI / freq
1665
+ x = x0 + amp * Math.sin(beta)
1666
+ xy << x << y
1667
+ }
1668
+ end
1669
+ cline(xy, **opts)
1670
+ end
1671
+
1672
+ def round_rect(xy, radius)
1673
+ x0, y0, x3, y3 = xy
1674
+ r = winfo_pixels(radius)
1675
+ d = 2 * r
1676
+
1677
+ maxr = 0.75
1678
+ d = maxr * (x3 - x0) if d > maxr * (x3 - x0)
1679
+ d = maxr * (y3 - y0) if d > maxr * (y3 - y0)
1680
+
1681
+ x1 = x0 + d; x2 = x3 - d
1682
+ y1 = y0 + d; y2 = y3 - d
1683
+
1684
+ xy = [x0, y0, x1, y0, x2, y0, x3, y0, x3, y1, x3, y2]
1685
+ xy.concat([x3, y3, x2, y3, x1, y3, x0, y3, x0, y2, x0, y1])
1686
+ xy
1687
+ end
1688
+
1689
+ def round_poly(xy, radii, **opts)
1690
+ lenXY = xy.length
1691
+ lenR = radii.length
1692
+ raise "wrong number of vertices and radii" if lenXY != 2 * lenR
1693
+
1694
+ knots = []
1695
+ x0 = xy[-2]; y0 = xy[-1]
1696
+ x1 = xy[0]; y1 = xy[1]
1697
+ xy = xy + [xy[0], xy[1]]
1698
+
1699
+ 0.step(lenXY - 1, 2) { |i|
1700
+ radius = radii[i / 2]
1701
+ r = winfo_pixels(radius)
1702
+ x2 = xy[i + 2]; y2 = xy[i + 3]
1703
+ z = _round_poly2(x0, y0, x1, y1, x2, y2, r)
1704
+ knots.concat(z)
1705
+ x0 = x1; y0 = y1
1706
+ x1 = x2; y1 = y2
1707
+ }
1708
+ cpoly(knots, :smooth=>true, **opts)
1709
+ end
1710
+
1711
+ def _round_poly2(x0, y0, x1, y1, x2, y2, radius)
1712
+ d = 2 * radius
1713
+ maxr = 0.75
1714
+
1715
+ v1x = x0 - x1; v1y = y0 - y1
1716
+ v2x = x2 - x1; v2y = y2 - y1
1717
+
1718
+ vlen1 = Math.sqrt(v1x * v1x + v1y * v1y)
1719
+ vlen2 = Math.sqrt(v2x * v2x + v2y * v2y)
1720
+
1721
+ d = maxr * vlen1 if d > maxr * vlen1
1722
+ d = maxr * vlen2 if d > maxr * vlen2
1723
+
1724
+ xy = []
1725
+ xy << (x1 + d * v1x / vlen1) << (y1 + d * v1y / vlen1)
1726
+ xy << x1 << y1
1727
+ xy << (x1 + d * v2x / vlen2) << (y1 + d * v2y / vlen2)
1728
+ xy
1729
+ end
1730
+
1731
+ def sparkle(oxy, tag)
1732
+ xy = [
1733
+ [299, 283], [298, 302], [295, 314], [271, 331],
1734
+ [239, 310], [242, 292], [256, 274], [281, 273]
1735
+ ]
1736
+ xy.each { |x, y|
1737
+ cline([271, 304, x, y], :fill=>'white', :width=>3, :tag=>tag)
1738
+ }
1739
+ move_abs(tag, oxy)
1740
+ end
1741
+
1742
+ def centroid(item)
1743
+ anchor(item, :c)
1744
+ end
1745
+
1746
+ def anchor(item, where)
1747
+ x1, y1, x2, y2 = cbbox(item)
1748
+ case where
1749
+ when :n then y = y1
1750
+ when :s then y = y2
1751
+ else y = (y1 + y2) / 2.0
1752
+ end
1753
+ case where
1754
+ when :w then x = x1
1755
+ when :e then x = x2
1756
+ else x = (x1 + x2) / 2.0
1757
+ end
1758
+ [x, y]
1759
+ end
1760
+ end
1761
+
1762
+ # -- Main ------------------------------------------------------------------
1763
+
1764
+ app = Teek::App.new(track_widgets: false)
1765
+
1766
+ top = '.goldberg'
1767
+ app.tcl_eval("toplevel #{top}")
1768
+ app.set_window_title('Tk Goldberg (demonstration)', window: top)
1769
+ app.tcl_eval("wm iconname #{top} goldberg")
1770
+
1771
+ base = "#{top}.base"
1772
+ app.tcl_eval("frame #{base}")
1773
+ app.tcl_eval("pack #{base} -fill both -expand 1")
1774
+
1775
+ demo = TkGoldberg_Demo.new(app, base, top)
1776
+
1777
+ # Automated demo support (testing and recording)
1778
+ require_relative '../lib/teek/demo_support'
1779
+ TeekDemo.app = app
1780
+
1781
+ if TeekDemo.recording?
1782
+ app.set_window_geometry('+0+0', window: top) # Position at top-left for capture
1783
+ app.tcl_eval("#{top} configure -cursor none") # Hide cursor for recording
1784
+ TeekDemo.signal_recording_ready(window: top)
1785
+ app.after(500) { demo.start }
1786
+ elsif TeekDemo.testing?
1787
+ TeekDemo.after_idle {
1788
+ # Open the settings drawer (click >> button)
1789
+ app.tcl_eval("#{base}.btnf.show invoke")
1790
+ app.update
1791
+
1792
+ # Drag the speed slider to max (index 1 = fastest)
1793
+ app.tcl_eval("#{base}.ctrl.speedscale set 1")
1794
+ app.update
1795
+
1796
+ # Click the Start button
1797
+ app.tcl_eval("#{base}.ctrl.start invoke")
1798
+
1799
+ app.after(2000) { TeekDemo.finish }
1800
+ }
1801
+ end
1802
+
1803
+ app.mainloop