1# 2# Ruby/Tk Goldverg demo (called by 'widget') 3# 4# Based on Tcl/Tk8.5a2 widget demos. 5# The following is the original comment of TkGoldberg.tcl. 6# 7#>>##+################################################################# 8#>># 9#>># TkGoldberg.tcl 10#>># by Keith Vetter, March 13, 2003 11#>># 12#>># "Man will always find a difficult means to perform a simple task" 13#>># Rube Goldberg 14#>># 15#>># Reproduced here with permission. 16#>># 17#>>##+################################################################# 18#>># 19#>># Keith Vetter 2003-03-21: this started out as a simple little program 20#>># but was so much fun that it grew and grew. So I apologize about the 21#>># size but I just couldn't resist sharing it. 22#>># 23#>># This is a whizzlet that does a Rube Goldberg type animation, the 24#>># design of which comes from an New Years e-card from IncrediMail. 25#>># That version had nice sound effects which I eschewed. On the other 26#>># hand, that version was in black and white (actually dark blue and 27#>># light blue) and this one is fully colorized. 28#>># 29#>># One thing I learned from this project is that drawing filled complex 30#>># objects on a canvas is really hard. More often than not I had to 31#>># draw each item twice--once with the desired fill color but no 32#>># outline, and once with no fill but with the outline. Another trick 33#>># is erasing by drawing with the background color. Having a flood fill 34#>># command would have been extremely helpful. 35#>># 36#>># Two wiki pages were extremely helpful: Drawing rounded rectangles 37#>># which I generalized into Drawing rounded polygons, and regular 38#>># polygons which allowed me to convert ovals and arcs into polygons 39#>># which could then be rotated (see Canvas Rotation). I also wrote 40#>># Named Colors to aid in the color selection. 41#>># 42#>># I could comment on the code, but it's just 26 state machines with 43#>># lots of canvas create and move calls. 44 45if defined?($goldberg_demo) && $goldberg_demo 46 $goldberg_demo.destroy 47 $goldberg_demo = nil 48end 49 50# demo toplevel widget 51$goldberg_demo = TkToplevel.new {|w| 52 title("Tk Goldberg (demonstration)") 53 iconname("goldberg") 54# positionWindow(w) 55} 56 57base_frame = TkFrame.new($goldberg_demo).pack(:fill=>:both, :expand=>true) 58 59=begin 60# label 61msg = TkLabel.new($goldberg_demo) { 62 font 'Arial 10' 63 wraplength '4i' 64 justify 'left' 65 text "This is a demonstration of just how complex you can make your animations become. Click the ball to start things moving!\n\n\"Man will always find a difficult means to perform a simple task\"\n - Rube Goldberg" 66} 67msg.pack('side'=>'top') 68=end 69 70=begin 71# frame 72TkFrame.new($goldberg_demo) {|frame| 73 TkButton.new(frame) { 74 text 'Dismiss' 75 command proc{ 76 tmppath = $goldberg_demo 77 $goldberg_demo = nil 78 tmppath.destroy 79 } 80 }.pack('side'=>'left', 'expand'=>'yes') 81 82 TkButton.new(frame) { 83 text 'See Code' 84 command proc{showCode 'goldberg'} 85 }.pack('side'=>'left', 'expand'=>'yes') 86 87}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') 88=end 89 90######################################### 91 92class TkGoldberg_Demo 93 def initialize(parent) 94 @parent = parent 95 96 @S = {} 97 @S['title'] = 'Tk Goldberg' 98 @S['speed'] = TkVariable.new(5) 99 @S['cnt'] = TkVariable.new(0) 100 @S['message'] = TkVariable.new("\\nWelcome\\nto\\nRuby/Tk") 101 @S['pause'] = TkVariable.new 102 @S['details'] = TkVariable.new(true) 103 104 @S['mode'] = TkVariable.new(:MSTART, :symbol) 105 # :MSTART, :MGO, :MPAUSE, :MSSTEP, :MBSTEP, :MDONE, :MDEBUG 106 107 # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 108 @speed = [1, 10, 20, 50, 80, 100, 150, 200, 300, 400, 500] 109 110 # colors 111 @C = {} 112 @C['fg'] = 'black' 113 # @C['bg'] = 'gray75' 114 @C['bg'] = 'cornflowerblue' 115 116 @C['0'] = 'white'; @C['1a'] = 'darkgreen'; @C['1b'] = 'yellow' 117 @C['2'] = 'red'; @C['3a'] = 'green'; @C['3b'] = 'darkblue' 118 @C['4'] = @C['fg']; @C['5a'] = 'brown'; @C['5b'] = 'white' 119 @C['6'] = 'magenta'; @C['7'] = 'green'; @C['8'] = @C['fg'] 120 @C['9'] = 'blue4'; @C['10a'] = 'white'; @C['10b'] = 'cyan' 121 @C['11a'] = 'yellow'; @C['11b'] = 'mediumblue'; @C['12'] = 'tan2' 122 @C['13a'] = 'yellow'; @C['13b'] = 'red'; @C['14'] = 'white' 123 @C['15a'] = 'green'; @C['15b'] = 'yellow'; @C['16'] = 'gray65' 124 @C['17'] = '#A65353'; @C['18'] = @C['fg']; @C['19'] = 'gray50' 125 @C['20'] = 'cyan'; @C['21'] = 'gray65'; @C['22'] = @C['20'] 126 @C['23a'] = 'blue'; @C['23b'] = 'red'; @C['23c'] = 'yellow' 127 @C['24a'] = 'red'; @C['24b'] = 'white'; 128 129 @STEP = TkVariable.new_hash 130 @STEP.default_value_type = :numeric 131 132 @XY = {} 133 134 @XY6 = { 135 '-1'=>[366, 207], '-2'=>[349, 204], '-3'=>[359, 193], '-4'=>[375, 192], 136 '-5'=>[340, 190], '-6'=>[349, 177], '-7'=>[366, 177], '-8'=>[380, 176], 137 '-9'=>[332, 172], '-10'=>[342, 161], '-11'=>[357, 164], 138 '-12'=>[372, 163], '-13'=>[381, 149], '-14'=>[364, 151], 139 '-15'=>[349, 146], '-16'=>[333, 148], '0'=>[357, 219], 140 '1'=>[359, 261], '2'=>[359, 291], '3'=>[359, 318], '4'=>[361, 324], 141 '5'=>[365, 329], '6'=>[367, 334], '7'=>[367, 340], '8'=>[366, 346], 142 '9'=>[364, 350], '10'=>[361, 355], '11'=>[359, 370], '12'=>[359, 391], 143 '13,0'=>[360, 456], '13,1'=>[376, 456], '13,2'=>[346, 456], 144 '13,3'=>[330, 456], '13,4'=>[353, 444], '13,5'=>[368, 443], 145 '13,6'=>[339, 442], '13,7'=>[359, 431], '13,8'=>[380, 437], 146 '13,9'=>[345, 428], '13,10'=>[328, 434], '13,11'=>[373, 424], 147 '13,12'=>[331, 420], '13,13'=>[360, 417], '13,14'=>[345, 412], 148 '13,15'=>[376, 410], '13,16'=>[360, 403] 149 } 150 151 @timer = TkTimer.new(@speed[@S['speed'].numeric]){|timer| 152 timer.set_interval(go) 153 } 154 155 do_display 156 reset 157 158 # Start everything going 159 @timer.start 160 end 161 162 def do_display() 163 @ctrl = TkFrame.new(@parent, :relief=>:ridge, :bd=>2, :padx=>5, :pady=>5) 164 @screen = TkFrame.new(@parent, :bd=>2, 165 :relief=>:raised).pack(:side=>:left, :fill=>:both, 166 :expand=>true) 167 168 @canvas = TkCanvas.new(@parent, :width=>850, :height=>700, 169 :bg=>@C['bg'], :highlightthickness=>0){ 170 scrollregion([0, 0, 1000, 1000]) # Kludge to move everything up 171 yview_moveto(0.05) 172 }.pack(:in=>@screen, :side=>:top, :fill=>:both, :expand=>true) 173 174 @canvas.bind('3'){ @pause.invoke } 175 @canvas.bind('Destroy'){ @timer.stop } 176 177 do_ctrl_frame 178 do_detail_frame 179 180 # msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') { 181 msg = Tk::Label.new(@parent, :bg=>@C['bg'], :fg=>'white') { 182 font 'Arial 10' 183 wraplength 600 184 justify 'left' 185 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" 186 } 187 msg.place(:in=>@canvas, :relx=>0, :rely=>0, :anchor=>:nw) 188 189 frame = TkFrame.new(@parent, :bg=>@C['bg']) 190 191 # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { 192 Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { 193 text 'Dismiss' 194 command proc{ 195 tmppath = $goldberg_demo 196 $goldberg_demo = nil 197 tmppath.destroy 198 } 199 }.pack('side'=>'left') 200 201 # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { 202 Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) { 203 text 'See Code' 204 command proc{showCode 'goldberg'} 205 }.pack('side'=>'left', 'padx'=>5) 206 207 # @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl}, 208 @show = Tk::Button.new(frame, :text=>'>>', :command=>proc{show_ctrl}, 209 :bg=>@C['bg'], :activebackground=>@C['bg']) 210 @show.pack('side'=>'left') 211 frame.place(:in=>@canvas, :relx=>1, :rely=>0, :anchor=>:ne) 212 213 Tk.update 214 end 215 216 def do_ctrl_frame 217 @start = Tk::Button.new(@parent, :text=>'Start', :bd=>6, 218 :command=>proc{do_button(0)}) 219 if font = @start['font'] 220 @start.font(font.weight('bold')) 221 end 222 223 @pause = TkCheckbutton.new(@parent, :text=>'Pause', :font=>font, 224 :command=>proc{do_button(1)}, :relief=>:raised, 225 :variable=>@S['pause']) 226 227 @step = TkButton.new(@parent, :text=>'Single Step', :font=>font, 228 :command=>proc{do_button(2)}) 229 @bstep = TkButton.new(@parent, :text=>'Big Step', :font=>font, 230 :command=>proc{do_button(4)}) 231 @reset = TkButton.new(@parent, :text=>'Reset', :font=>font, 232 :command=>proc{do_button(3)}) 233 234 @details = TkFrame.new(@parent, :bd=>2, :relief=>:ridge) 235 @detail = TkCheckbutton.new(@parent, :text=>'Details', :font=>font, 236 :relief=>:raised, :variable=>@S['details']) 237 238 @msg_entry = TkEntry.new(@parent, :textvariable=>@S['message'], 239 :justify=>:center) 240 @speed_scale = TkScale.new(@parent, :orient=>:horizontal, 241 :from=>1, :to=>10, :font=>font, 242 :variable=>@S['speed'], :bd=>2, 243 :relief=>:ridge, :showvalue=>false) 244 @about = TkButton.new(@parent, :text=>'About', 245 :command=>proc{about}, :font=>font) 246 247 Tk.grid(@start, :in=>@ctrl, :row=>0, :sticky=>:ew) 248 @ctrl.grid_rowconfigure(1, :minsize=>10) 249 Tk.grid(@pause, :in=>@ctrl, :row=>2, :sticky=>:ew) 250 Tk.grid(@step, :in=>@ctrl, :sticky=>:ew) 251 Tk.grid(@bstep, :in=>@ctrl, :sticky=>:ew) 252 Tk.grid(@reset, :in=>@ctrl, :sticky=>:ew) 253 @ctrl.grid_rowconfigure(10, :minsize=>20) 254 Tk.grid(@details, :in=>@ctrl, :row=>11, :sticky=>:ew) 255 Tk.grid(@detail, :in=>@details, :row=>0, :sticky=>:ew) 256 @ctrl.grid_rowconfigure(50, :weight=>1) 257 258 @S['mode'].trace('w', proc{|*args| active_GUI(*args)}) 259 @S['details'].trace('w', proc{|*args| active_GUI(*args)}) 260 @S['speed'].trace('w', proc{|*args| active_GUI(*args)}) 261 262 Tk.grid(@msg_entry, :in=>@ctrl, :row=>98, :sticky=>:ew, :pady=>5) 263 Tk.grid(@speed_scale, :in=>@ctrl, :row=>99, :sticky=>:ew) 264 Tk.grid(@about, :in=>@ctrl, :row=>100, :sticky=>:ew) 265 266 @reset.bind('3'){@S['mode'].value = -1} # Debugging 267 end 268 269 def do_detail_frame 270 @f_details = TkFrame.new(@details) 271 272 @label = TkLabel.new(@f_details, :textvariable=>@S['cnt'], 273 :bd=>1, :relief=>:solid, :bg=>'white') 274 Tk.grid(@label, '-', '-', '-', :sticky=>:ew, :row=>0) 275 276 idx = 1 277 loop { 278 break unless respond_to?("move#{idx}") 279 l = TkLabel.new(@f_details, :text=>idx, :anchor=>:e, 280 :width=>2, :bd=>1, :relief=>:solid, :bg=>'white') 281 @STEP[idx] = 0 282 ll = TkLabel.new(@f_details, :textvariable=>@STEP.ref(idx), 283 :width=>5, :bd=>1, :relief=>:solid, :bg=>'white') 284 row = (idx + 1)/2 285 col = ((idx + 1) & 1) * 2 286 Tk.grid(l, :sticky=>:ew, :row=>row, :column=>col) 287 Tk.grid(ll, :sticky=>:ew, :row=>row, :column=>(col + 1)) 288 idx += 1 289 } 290 @f_details.grid_columnconfigure(1, :weight=>1) 291 end 292 293 def show_ctrl 294 if @ctrl.winfo_mapped? 295 @ctrl.pack_forget 296 @show.text('>>') 297 else 298 @ctrl.pack(:side=>:right, :fill=>:both, :ipady=>5) 299 @show.text('<<') 300 end 301 end 302 303 def draw_all 304 reset_step 305 @canvas.delete(:all) 306 idx = 0 307 loop{ 308 m = "draw#{idx}" 309 break unless respond_to?(m) 310 send(m) 311 idx += 1 312 } 313 end 314 315 def active_GUI(var1, var2, op) 316 st = {false=>:disabled, true=>:normal} 317 318 m = @S['mode'].to_sym 319 @S['pause'].value = (m == :MPAUSE) 320 @start.state(st[m != :MGO]) 321 @pause.state(st[m != :MSTART && m != :MDONE]) 322 @step.state(st[m != :MGO && m != :MDONE]) 323 @bstep.state(st[m != :MGO && m != :MDONE]) 324 @reset.state(st[m != :MSTART]) 325 326 if @S['details'].bool 327 Tk.grid(@f_details, :in=>@details, :row=>2, :sticky=>:ew) 328 else 329 Tk.grid_forget(@f_details) 330 end 331 @speed_scale.label("Speed: #{@S['speed'].value}") 332 end 333 334 def start 335 @S['mode'].value = :MGO 336 end 337 338 def do_button(what) 339 case what 340 when 0 # Start 341 reset if @S['mode'].to_sym == :MDONE 342 @S['mode'].value = :MGO 343 344 when 1 # Pause 345 @S['mode'].value = ((@S['pause'].bool)? :MPAUSE: :MGO) 346 347 when 2 # Step 348 @S['mode'].value = :MSSTEP 349 350 when 3 # Reset 351 reset 352 353 when 4 # Big step 354 @S['mode'].value = :MBSTEP 355 end 356 end 357 358 def go(who = nil) 359 now = Tk::Clock.clicks(:miliseconds) 360 if who # Start here for debugging 361 @S['active'] = [who] 362 @S['mode'].value = :MGO 363 end 364 return if @S['mode'].to_sym == :MDEBUG # Debugging 365 # If not paused, do the next move 366 n = next_step if @S['mode'].to_sym != :MPAUSE 367 @S['mode'].value = :MPAUSE if @S['mode'].to_sym == :MSSTEP # Single step 368 @S['mode'].value = :MSSTEP if @S['mode'].to_sym == :MBSTEP && n # big step 369 elapsed = Tk::Clock.clicks(:miliseconds) - now 370 delay = @speed[@S['speed'].to_i] - elapsed 371 delay = 1 if delay <= 0 372 return delay 373 end 374 375 def next_step 376 retval = false # Return value 377 378 if @S['mode'].to_sym != :MSTART && @S['mode'].to_sym != :MDONE 379 @S['cnt'].numeric += 1 380 end 381 alive = [] 382 @S['active'].each{|who| 383 who = who.to_i 384 n = send("move#{who}") 385 if (n & 1).nonzero? # This guy still alive 386 alive << who 387 end 388 if (n & 2).nonzero? # Next guy is active 389 alive << (who + 1) 390 retval = true 391 end 392 if (n & 4).nonzero? # End of puzzle flag 393 @S['mode'].value = :MDONE # Done mode 394 @S['active'] = [] # No more animation 395 return true 396 end 397 } 398 @S['active'] = alive 399 return retval 400 end 401 402 def about 403 msg = "Ruby/Tk Version ::\nby Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)\n\n" 404 msg += "Original Version ::\n" 405 msg += "#{@S['title']}\nby Keith Vetter, March 2003\n(Reproduced by kind permission of the author)\n\n" 406 msg += "Man will always find a difficult means to perform a simple task" 407 msg += "\nRube Goldberg" 408 Tk.messageBox(:message=>msg, :title=>'About') 409 end 410 411 ################################################################ 412 # 413 # All the drawing and moving routines 414 # 415 416 # START HERE! banner 417 def draw0 418 color = @C['0'] 419 TkcText.new(@canvas, [579, 119], :text=>'START HERE!', 420 :fill=>color, :anchor=>:w, 421 :tag=>'I0', :font=>['Times Roman', 12, :italic, :bold]) 422 TkcLine.new(@canvas, [719, 119, 763, 119], :tag=>'I0', :fill=>color, 423 :width=>5, :arrow=>:last, :arrowshape=>[18, 18, 5]) 424 @canvas.itembind('I0', '1'){ start } 425 end 426 427 def move0(step = nil) 428 step = get_step(0, step) 429 430 if @S['mode'].to_sym != :MSTART # Start the ball rolling 431 move_abs('I0', [-100, -100]) # Hide the banner 432 return 2 433 end 434 435 pos = [ 436 [673, 119], [678, 119], [683, 119], [688, 119], 437 [693, 119], [688, 119], [683, 119], [678, 119] 438 ] 439 step = step % pos.length 440 move_abs('I0', pos[step]) 441 return 1 442 end 443 444 # Dropping ball 445 def draw1 446 color = @C['1a'] 447 color2 = @C['1b'] 448 TkcPolygon.new(@canvas, 449 [ 844, 133, 800, 133, 800, 346, 820, 346, 450 820, 168, 844, 168, 844, 133 ], 451 :width=>3, :fill=>color, :outline=>'') 452 TkcPolygon.new(@canvas, 453 [ 771, 133, 685, 133, 685, 168, 751, 168, 454 751, 346, 771, 346, 771, 133 ], 455 :width=>3, :fill=>color, :outline=>'') 456 TkcOval.new(@canvas, box(812, 122, 9), 457 :tag=>'I1', :fill=>color2, :outline=>'') 458 459 @canvas.itembind('I1', '1'){ start } 460 end 461 462 def move1(step = nil) 463 step = get_step(1, step) 464 pos = [ 465 [807, 122], [802, 122], [797, 123], [793, 124], [789, 129], [785, 153], 466 [785, 203], [785, 278, :x], [785, 367], [810, 392], [816, 438], 467 [821, 503], [824, 585, :y], [838, 587], [848, 593], [857, 601], 468 [-100, -100] 469 ] 470 return 0 if step >= pos.length 471 where = pos[step] 472 move_abs('I1', where) 473 move15a if where[2] == :y 474 return 3 if where[2] == :x 475 return 1 476 end 477 478 # Lighting the match 479 def draw2 480 color = @C['2'] 481 482 # Fulcrum 483 TkcPolygon.new(@canvas, [750, 369, 740, 392, 760, 392], 484 :fill=>@C['fg'], :outline=>@C['fg']) 485 486 # Strike box 487 TkcRectangle.new(@canvas, [628, 335, 660, 383], 488 :fill=>'', :outline=>@C['fg']) 489 (0..2).each{|y| 490 yy = 335 + y*16 491 TkcBitmap.new(@canvas, [628, yy], :bitmap=>'gray25', 492 :anchor=>:nw, :foreground=>@C['fg']) 493 TkcBitmap.new(@canvas, [644, yy], :bitmap=>'gray25', 494 :anchor=>:nw, :foreground=>@C['fg']) 495 } 496 497 # Lever 498 TkcLine.new(@canvas, [702, 366, 798, 366], 499 :fill=>@C['fg'], :width=>6, :tag=>'I2_0') 500 501 # R strap 502 TkcLine.new(@canvas, [712, 363, 712, 355], 503 :fill=>@C['fg'], :width=>3, :tag=>'I2_1') 504 505 # L strap 506 TkcLine.new(@canvas, [705, 363, 705, 355], 507 :fill=>@C['fg'], :width=>3, :tag=>'I2_2') 508 509 # Match stick 510 TkcLine.new(@canvas, [679, 356, 679, 360, 717, 360, 717, 356, 679, 356], 511 :fill=>@C['fg'], :width=>3, :tag=>'I2_3') 512 513 # Match head 514 TkcPolygon.new(@canvas, 515 [ 671, 352, 677.4, 353.9, 680, 358.5, 677.4, 363.1, 516 671, 365, 664.6, 363.1, 662, 358.5, 664.6, 353.9 ], 517 :fill=>color, :outline=>color, :tag=>'I2_4') 518 end 519 520 def move2(step = nil) 521 step = get_step(2, step) 522 523 stages = [0, 0, 1, 2, 0, 2, 1, 0, 1, 2, 0, 2, 1] 524 xy = [] 525 xy[0] = [ 526 686, 333, 692, 323, 682, 316, 674, 309, 671, 295, 668, 307, 527 662, 318, 662, 328, 671, 336 528 ] 529 xy[1] = [ 530 687, 331, 698, 322, 703, 295, 680, 320, 668, 297, 663, 311, 531 661, 327, 671, 335 532 ] 533 xy[2] = [ 534 686, 331, 704, 322, 688, 300, 678, 283, 678, 283, 674, 298, 535 666, 309, 660, 324, 672, 336 536 ] 537 538 if step >= stages.length 539 @canvas.delete('I2') 540 return 0 541 end 542 543 if step == 0 # Rotate the match 544 beta = 20 545 546 ox, oy = anchor('I2_0', :s) # Where to pivot 547 548 i = 0 549 until @canvas.find_withtag("I2_#{i}").empty? 550 rotate_item("I2_#{i}", ox, oy, beta) 551 i += 1 552 end 553 554 # For the flame 555 TkcPolygon.new(@canvas, [], :tag=>'I2', :smooth=>true, :fill=>@C['2']) 556 557 return 1 558 end 559 @canvas.coords('I2', xy[stages[step]]) 560 return ((step == 7)? 3: 1) 561 end 562 563 # Weight and pulleys 564 def draw3 565 color = @C['3a'] 566 color2 = @C['3b'] 567 568 xy = [ [602, 296], [577, 174], [518, 174] ] 569 xy.each{|x, y| # 3 Pulleys 570 TkcOval.new(@canvas, box(x, y, 13), 571 :fill=>color, :outline=>@C['fg'], :width=>3) 572 TkcOval.new(@canvas, box(x, y, 2), :fill=>@C['fg'], :outline=>@C['fg']) 573 } 574 575 # Wall to flame 576 TkcLine.new(@canvas, [750, 309, 670, 309], :tag=>'I3_s', 577 :width=>3, :fill=>@C['fg'], :smooth=>true) 578 579 # Flame to pulley 1 580 TkcLine.new(@canvas, [670, 309, 650, 309], :tag=>'I3_0', 581 :width=>3, :fill=>@C['fg'], :smooth=>true) 582 TkcLine.new(@canvas, [650, 309, 600, 309], :tag=>'I3_1', 583 :width=>3, :fill=>@C['fg'], :smooth=>true) 584 585 # Pulley 1 half way to 2 586 TkcLine.new(@canvas, [589, 296, 589, 235], :tag=>'I3_2', 587 :width=>3, :fill=>@C['fg']) 588 589 # Pulley 1 other half to 2 590 TkcLine.new(@canvas, [589, 235, 589, 174], :width=>3, :fill=>@C['fg']) 591 592 # Across the top 593 TkcLine.new(@canvas, [577, 161, 518, 161], :width=>3, :fill=>@C['fg']) 594 595 # Down to weight 596 TkcLine.new(@canvas, [505, 174, 505, 205], :tag=>'I3_w', 597 :width=>3, :fill=>@C['fg']) 598 599 # Draw the weight as 2 circles, two rectangles and 1 rounded rectangle 600 x1, y1, x2, y2 = [515, 207, 495, 207] 601 TkcOval.new(@canvas, box(x1, y1, 6), 602 :tag=>'I3_', :fill=>color2, :outline=>color2) 603 TkcOval.new(@canvas, box(x2, y2, 6), 604 :tag=>'I3_', :fill=>color2, :outline=>color2) 605 TkcRectangle.new(@canvas, x1, y1 - 6, x2, y2 + 6, 606 :tag=>'I3_', :fill=>color2, :outline=>color2) 607 608 TkcPolygon.new(@canvas, round_rect([492, 220, 518, 263], 15), 609 :smooth=>true, :tag=>'I3_', :fill=>color2, :outline=>color2) 610 611 TkcLine.new(@canvas, [500, 217, 511, 217], 612 :tag=>'I3_', :fill=>color2, :width=>10) 613 614 # Bottom weight target 615 TkcLine.new(@canvas, [502, 393, 522, 393, 522, 465], 616 :tag=>'I3__', :fill=>@C['fg'], :joinstyle=>:miter, :width=>10) 617 end 618 619 def move3(step = nil) 620 step = get_step(3, step) 621 622 pos = [ [505, 247], [505, 297], [505, 386.5], [505, 386.5] ] 623 rope = [] 624 rope[0] = [750, 309, 729, 301, 711, 324, 690, 300] 625 rope[1] = [750, 309, 737, 292, 736, 335, 717, 315, 712, 320] 626 rope[2] = [750, 309, 737, 309, 740, 343, 736, 351, 725, 340] 627 rope[3] = [750, 309, 738, 321, 746, 345, 742, 356] 628 629 return 0 if step >= pos.length 630 631 @canvas.delete("I3_#{step}") # Delete part of the rope 632 move_abs('I3_', pos[step]) # Move weight down 633 @canvas.coords('I3_s', rope[step]) # Flapping rope end 634 @canvas.coords('I3_w', [505, 174].concat(pos[step])) 635 if step == 2 636 @canvas.move('I3__', 0, 30) 637 return 2 638 end 639 return 1 640 end 641 642 # Cage and door 643 def draw4 644 color = @C['4'] 645 x0, y0, x1, y1 = [527, 356, 611, 464] 646 647 # Horizontal bars 648 y0.step(y1, 12){|y| 649 TkcLine.new(@canvas, [x0, y, x1, y], :fill=>color, :width=>1) 650 } 651 652 # Vertical bars 653 x0.step(x1, 12){|x| 654 TkcLine.new(@canvas, [x, y0, x, y1], :fill=>color, :width=>1) 655 } 656 657 # Swing gate 658 TkcLine.new(@canvas, [518, 464, 518, 428], 659 :tag=>'I4', :fill=>color, :width=>1) 660 end 661 662 def move4(step = nil) 663 step = get_step(4, step) 664 665 angles = [-10, -20, -30, -30] 666 return 0 if step >= angles.length 667 668 rotate_item('I4', 518, 464, angles[step]) 669 @canvas.raise('I4') 670 671 return((step == 3)? 3: 1) 672 end 673 674 # Mouse 675 def draw5 676 color = @C['5a'] 677 color2 = @C['5b'] 678 679 xy = [377, 248, 410, 248, 410, 465, 518, 465] # Mouse course 680 xy.concat [518, 428, 451, 428, 451, 212, 377, 212] 681 682 TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], :width=>3) 683 684 xy = [ 685 534.5, 445.5, 541, 440, 552, 436, 560, 436, 569, 440, 574, 446, 686 575, 452, 574, 454, 566, 456, 554, 456, 545, 456, 537, 454, 530, 452 687 ] 688 TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_0'], :fill=>color) 689 690 TkcLine.new(@canvas, [573, 452, 592, 458, 601, 460, 613, 456], # Tail 691 :tag=>['I5', 'I5_1'], :fill=>color, :smooth=>true, :width=>3) 692 693 xy = box(540, 446, 2) # Eye 694 xy = [540, 444, 541, 445, 541, 447, 540, 448, 538, 447, 538, 445] 695 TkcPolygon.new(@canvas, xy, :tag=>['I5', 'I5_2'], :fill=>@C['bg'], 696 :outline=>'', :smooth=>true) 697 698 xy = [538, 454, 535, 461] # Front leg 699 TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_3'], :fill=>color, :width=>2) 700 701 xy = [566, 455, 569, 462] # Back leg 702 TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_4'], :fill=>color, :width=>2) 703 704 xy = [544, 455, 545, 460] # 2nd front leg 705 TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_5'], :fill=>color, :width=>2) 706 707 xy = [560, 455, 558, 460] # 2nd back leg 708 TkcLine.new(@canvas, xy, :tag=>['I5', 'I5_6'], :fill=>color, :width=>2) 709 end 710 711 def move5(step = nil) 712 step = get_step(5, step) 713 714 pos = [ 715 [553, 452], [533, 452], [513, 452], [493, 452], [473, 452], 716 [463, 442, 30], [445.5, 441.5, 30], [425.5, 434.5, 30], [422, 414], 717 [422, 394], [422, 374], [422, 354], [422, 334], [422, 314], [422, 294], 718 [422, 274, -30], [422, 260.5, -30, :x], [422.5, 248.5, -28], [425, 237] 719 ] 720 721 return 0 if step >= pos.length 722 723 x, y, beta, nxt = pos[step] 724 move_abs('I5', [x, y]) 725 if beta 726 ox, oy = centroid('I5_0') 727 (0..6).each{|id| rotate_item("I5_#{id}", ox, oy, beta) } 728 end 729 return 3 if nxt == :x 730 return 1 731 end 732 733 # Dropping gumballs 734 def draw6 735 color = @C['6'] 736 xy = [324, 130, 391, 204] # Ball holder 737 xy = round_rect(xy, 10) 738 TkcPolygon.new(@canvas, xy, :smooth=>true, 739 :outline=>@C['fg'], :width=>3, :fill=>color) 740 xy = [339, 204, 376, 253] # Below the ball holder 741 TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>3, 742 :fill=>color, :tag=>'I6c') 743 xy = box(346, 339, 28) 744 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') # Roter 745 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, 746 :start=>80, :extent=>205) 747 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>2, :style=>:arc, 748 :start=>-41, :extent=>85) 749 750 xy = box(346, 339, 15) # Center of rotor 751 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg'], :tag=>'I6m') 752 xy = [352, 312, 352, 254, 368, 254, 368, 322] # Top drop to rotor 753 TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'') 754 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) 755 756 xy = [353, 240, 367, 300] # Poke bottom hole 757 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') 758 xy = [341, 190, 375, 210] # Poke another hole 759 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') 760 761 xy = [ 762 368, 356, 368, 403, 389, 403, 389, 464, 320, 464, 320, 403, 763 352, 403, 352, 366 764 ] 765 TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', 766 :width=>2) # Below rotor 767 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2) 768 xy = box(275, 342, 7) # On/off rotor 769 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['fg']) 770 xy = [276, 334, 342, 325] # Fan belt top 771 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 772 xy = [276, 349, 342, 353] # Fan belt bottom 773 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 774 775 xy = [337, 212, 337, 247] # What the mouse pushes 776 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') 777 xy = [392, 212, 392, 247] 778 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I6_') 779 xy = [337, 230, 392, 230] 780 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>7, :tag=>'I6_') 781 782 who = -1 # All the balls 783 colors = %w(red cyan orange green blue darkblue) 784 colors *= 3 785 786 (0..16).each{|i| 787 loc = -i 788 color = colors[i] 789 x, y = @XY6["#{loc}"] 790 TkcOval.new(@canvas, box(x, y, 5), 791 :fill=>color, :outline=>color, :tag=>"I6_b#{i}") 792 } 793 draw6a(12) # The wheel 794 end 795 796 def draw6a(beta) 797 @canvas.delete('I6_0') 798 ox, oy = [346, 339] 799 (0..3).each{|i| 800 b = beta + i * 45 801 x, y = rotate_c(28, 0, 0, 0, b) 802 xy = [ox + x, oy + y, ox - x, oy - y] 803 TkcLine.new(@canvas, xy, :tag=>'I6_0', :fill=>@C['fg'], :width=>2) 804 } 805 end 806 807 def move6(step = nil) 808 step = get_step(6, step) 809 810 return 0 if step > 62 811 812 if step < 2 # Open gate for balls to drop 813 @canvas.move('I6_', -7, 0) 814 if step == 1 # Poke a hole 815 xy = [348, 226, 365, 240] 816 TkcRectangle.new(@canvas, xy, :fill=>@canvas.itemcget('I6c', :fill), 817 :outline=>'') 818 end 819 return 1 820 end 821 822 s = step - 1 # Do the gumball drop dance 823 (0..(((s - 1)/3).to_i)).each{|i| 824 tag = "I6_b#{i}" 825 break if @canvas.find_withtag(tag).empty? 826 loc = s - 3*i 827 828 if @XY6["#{loc},#{i}"] 829 move_abs(tag, @XY6["#{loc},#{i}"]) 830 elsif @XY6["#{loc}"] 831 move_abs(tag, @XY6["#{loc}"]) 832 end 833 } 834 if s % 3 == 1 835 first = (s + 2)/3 836 i = first 837 loop { 838 tag = "I6_b#{i}" 839 break if @canvas.find_withtag(tag).empty? 840 loc = first - i 841 move_abs(tag, @XY6["#{loc}"]) 842 i += 1 843 } 844 end 845 if s >= 3 # Rotate the motor 846 idx = s % 3 847 draw6a(12 + s * 15) 848 end 849 return((s == 3)? 3 : 1) 850 end 851 852 # On/off switch 853 def draw7 854 color = @C['7'] 855 xy = [198, 306, 277, 374] # Box 856 TkcRectangle.new(@canvas, xy, :outline=>@C['fg'], :width=>2, 857 :fill=>color, :tag=>'I7z') 858 @canvas.lower('I7z') 859 xy = [275, 343, 230, 349] 860 TkcLine.new(@canvas, xy, :tag=>'I7', :fill=>@C['fg'], :arrow=>:last, 861 :arrowshape=>[23, 23, 8], :width=>6) 862 xy = [225, 324] # On button 863 x, y = xy 864 TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) 865 xy = [218, 323] # On text 866 font = ['Times Roman', 8] 867 TkcText.new(@canvas, xy, :text=>'on', :anchor=>:e, 868 :fill=>@C['fg'], :font=>font) 869 xy = [225, 350] # Off button 870 x, y = xy 871 TkcOval.new(@canvas, box(x, y, 3), :fill=>@C['fg'], :outline=>@C['fg']) 872 xy = [218, 349] # Off text 873 TkcText.new(@canvas, xy, :text=>'off', :anchor=>:e, 874 :fill=>@C['fg'], :font=>font) 875 end 876 877 def move7(step = nil) 878 step = get_step(7, step) 879 880 numsteps = 30 881 return 0 if step > numsteps 882 beta = 30.0 / numsteps 883 rotate_item('I7', 275, 343, beta) 884 885 return((step == numsteps)? 3: 1) 886 end 887 888 # Electricity to the fan 889 def draw8 890 sine([271, 248, 271, 306], 5, 8, :tag=>'I8_s', :fill=>@C['8'], :width=>3) 891 end 892 893 def move8(step = nil) 894 step = get_step(8, step) 895 896 return 0 if step > 3 897 if step == 0 898 sparkle(anchor('I8_s', :s), 'I8') 899 return 1 900 elsif step == 1 901 move_abs('I8', anchor('I8_s', :c)) 902 elsif step == 2 903 move_abs('I8', anchor('I8_s', :n)) 904 else 905 @canvas.delete('I8') 906 end 907 return((step == 2)? 3: 1) 908 end 909 910 # Fan 911 def draw9 912 color = @C['9'] 913 xy = [266, 194, 310, 220] 914 TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) 915 xy = [280, 209, 296, 248] 916 TkcOval.new(@canvas, xy, :outline=>color, :fill=>color) 917 xy = [ 918 288, 249, 252, 249, 260, 240, 280, 234, 919 296, 234, 316, 240, 324, 249, 288, 249 920 ] 921 TkcPolygon.new(@canvas, xy, :fill=>color, :smooth=>true) 922 923 xy = [248, 205, 265, 214, 264, 205, 265, 196] # Spinner 924 TkcPolygon.new(@canvas, xy, :fill=>color) 925 926 xy = [255, 206, 265, 234] # Fan blades 927 TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], 928 :width=>3, :tag=>'I9_0') 929 xy = [255, 176, 265, 204] 930 TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], 931 :width=>3, :tag=>'I9_0') 932 xy = [255, 206, 265, 220] 933 TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], 934 :width=>1, :tag=>'I9_1') 935 xy = [255, 190, 265, 204] 936 TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], 937 :width=>1, :tag=>'I9_1') 938 end 939 940 def move9(step = nil) 941 step = get_step(9, step) 942 943 if (step & 1).nonzero? 944 @canvas.itemconfigure('I9_0', :width=>4) 945 @canvas.itemconfigure('I9_1', :width=>1) 946 @canvas.lower('I9_1', 'I9_0') 947 else 948 @canvas.itemconfigure('I9_0', :width=>1) 949 @canvas.itemconfigure('I9_1', :width=>4) 950 @canvas.lower('I9_0', 'I9_1') 951 end 952 return 3 if step == 0 953 return 1 954 end 955 956 # Boat 957 def draw10 958 color = @C['10a'] 959 color2 = @C['10b'] 960 xy = [191, 230, 233, 230, 233, 178, 191, 178] # Sail 961 TkcPolygon.new(@canvas, xy, :fill=>color, :width=>3, :outline=>@C['fg'], 962 :tag=>'I10') 963 xy = box(209, 204, 31) # Front 964 TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :style=>:pie, 965 :start=>120, :extent=>120, :tag=>'I10') 966 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 967 :start=>120, :extent=>120, :tag=>'I10') 968 xy = box(249, 204, 31) # Back 969 TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>3, 970 :style=>:pie, :start=>120, :extent=>120, :tag=>'I10') 971 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 972 :start=>120, :extent=>120, :tag=>'I10') 973 974 xy = [200, 171, 200, 249] # Mast 975 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') 976 xy = [159, 234, 182, 234] # Bow sprit 977 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I10') 978 xy = [180, 234, 180, 251, 220, 251] # Hull 979 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6, :tag=>'I10') 980 981 xy = [92, 255, 221, 255] # Waves 982 sine(xy, 2, 25, :fill=>color2, :width=>1, :tag=>'I10w') 983 984 xy = @canvas.coords('I10w')[4..-5] # Water 985 xy.concat([222, 266, 222, 277, 99, 277]) 986 TkcPolygon.new(@canvas, xy, :fill=>color2, :outline=>color2) 987 xy = [222, 266, 222, 277, 97, 277, 97, 266] # Water bottom 988 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 989 990 xy = box(239, 262, 17) 991 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 992 :start=>95, :extent=>103) 993 xy = box(76, 266, 21) 994 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 995 :extent=>190) 996 end 997 998 def move10(step = nil) 999 step = get_step(10, step) 1000 1001 pos = [ 1002 [195, 212], [193, 212], [190, 212], [186, 212], [181, 212], [176, 212], 1003 [171, 212], [166, 212], [161, 212], [156, 212], [151, 212], [147, 212], 1004 [142, 212], [137, 212], [132, 212, :x], [127, 212], [121, 212], 1005 [116, 212], [111, 212] 1006 ] 1007 1008 return 0 if step >= pos.length 1009 1010 where = pos[step] 1011 move_abs('I10', where) 1012 1013 return 3 if where[2] == :x 1014 return 1 1015 end 1016 1017 # 2nd ball drop 1018 def draw11 1019 color = @C['11a'] 1020 color2 = @C['11b'] 1021 xy = [23, 264, 55, 591] # Color the down tube 1022 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>'') 1023 xy = box(71, 460, 48) # Color the outer loop 1024 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') 1025 1026 xy = [55, 264, 55, 458] # Top right side 1027 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 1028 xy = [55, 504, 55, 591] # Bottom right side 1029 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 1030 xy = box(71, 460, 48) # Outer loop 1031 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 1032 :start=>110, :extent=>-290, :tag=>'I11i') 1033 xy = box(71, 460, 16) # Inner loop 1034 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>'', 1035 :width=>3, :tag=>'I11i') 1036 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>@C['bg'], :width=>3) 1037 1038 xy = [23, 264, 23, 591] # Left side 1039 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 1040 xy = box(1, 266, 23) # Top left curve 1041 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, 1042 :style=>:arc, :extent=>90) 1043 1044 xy = box(75, 235, 9) # The ball 1045 TkcOval.new(@canvas, xy, :fill=>color2, :outline=>'', 1046 :width=>3, :tag=>'I11') 1047 end 1048 1049 def move11(step = nil) 1050 step = get_step(11, step) 1051 1052 pos = [ 1053 [75, 235], [70, 235], [65, 237], [56, 240], [46, 247], [38, 266], 1054 [38, 296], [38, 333], [38, 399], [38, 475], [74, 496], [105, 472], 1055 [100, 437], [65, 423], [-100, -100], [38, 505], [38, 527, :x], [38, 591] 1056 ] 1057 1058 return 0 if step >= pos.length 1059 where = pos[step] 1060 move_abs('I11', where) 1061 return 3 if where[2] == :x 1062 return 1 1063 end 1064 1065 # Hand 1066 def draw12 1067 xy = [ 1068 20, 637, 20, 617, 20, 610, 20, 590, 40, 590, 40, 590, 1069 60, 590, 60, 610, 60, 610 1070 ] 1071 xy.concat([60, 610, 65, 620, 60, 631]) # Thumb 1072 xy.concat([60, 631, 60, 637, 60, 662, 60, 669, 52, 669, 1073 56, 669, 50, 669, 50, 662, 50, 637]) 1074 1075 y0 = 637 # Bumps for fingers 1076 y1 = 645 1077 50.step(21, -10){|x| 1078 x1 = x - 5 1079 x2 = x - 10 1080 xy << x << y0 << x1 << y1 << x2 << y0 1081 } 1082 TkcPolygon.new(@canvas, xy, :fill=>@C['12'], :outline=>@C['fg'], 1083 :smooth=>true, :tag=>'I12', :width=>3) 1084 end 1085 1086 def move12(step = nil) 1087 step = get_step(12, step) 1088 1089 pos = [[42.5, 641, :x]] 1090 return 0 if step >= pos.length 1091 where = pos[step] 1092 move_abs('I12', where) 1093 return 3 if where[2] == :x 1094 return 1 1095 end 1096 1097 # Fax 1098 def draw13 1099 color = @C['13a'] 1100 xy = [86, 663, 149, 663, 149, 704, 50, 704, 50, 681, 64, 681, 86, 671] 1101 xy2 = [ 1102 784, 663, 721, 663, 721, 704, 820, 704, 820, 681, 806, 681, 784, 671 1103 ] 1104 radii = [2, 9, 9, 8, 5, 5, 2] 1105 1106 round_poly(@canvas, xy, radii, :width=>3, 1107 :outline=>@C['fg'], :fill=>color) 1108 round_poly(@canvas, xy2, radii, :width=>3, 1109 :outline=>@C['fg'], :fill=>color) 1110 1111 xy = [56, 677] 1112 x, y = xy 1113 TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], 1114 :width=>3, :tag=>'I13') 1115 xy = [809, 677] 1116 x, y = xy 1117 TkcRectangle.new(@canvas, box(x, y, 4), :fill=>'', :outline=>@C['fg'], 1118 :width=>3, :tag=>'I13R') 1119 1120 xy = [112, 687] # Label 1121 TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], 1122 :font=>['Times Roman', 12, :bold]) 1123 xy = [762, 687] 1124 TkcText.new(@canvas, xy, :text=>'FAX', :fill=>@C['fg'], 1125 :font=>['Times Roman', 12, :bold]) 1126 1127 xy = [138, 663, 148, 636, 178, 636] # Paper guide 1128 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) 1129 xy = [732, 663, 722, 636, 692, 636] 1130 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>@C['fg'], :width=>3) 1131 1132 sine([149, 688, 720, 688], 5, 15, 1133 :tag=>'I13_s', :fill=>@C['fg'], :width=>3) 1134 end 1135 1136 def move13(step = nil) 1137 step = get_step(13, step) 1138 1139 numsteps = 7 1140 1141 if step == numsteps + 2 1142 move_abs('I13_star', [-100, -100]) 1143 @canvas.itemconfigure('I13R', :fill=>@C['13b'], :width=>2) 1144 return 2 1145 end 1146 if step == 0 # Button down 1147 @canvas.delete('I13') 1148 sparkle([-100, -100], 'I13_star') # Create off screen 1149 return 1 1150 end 1151 x0, y0 = anchor('I13_s', :w) 1152 x1, y1 = anchor('I13_s', :e) 1153 x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f 1154 move_abs('I13_star', [x, y0]) 1155 return 1 1156 end 1157 1158 # Paper in fax 1159 def draw14 1160 color = @C['14'] 1161 xy = [102, 661, 113, 632, 130, 618] # Left paper edge 1162 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, 1163 :width=>3, :tag=>'I14L_0') 1164 xy = [148, 629, 125, 640, 124, 662] # Right paper edge 1165 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, 1166 :width=>3, :tag=>'I14L_1') 1167 draw14a('L') 1168 1169 xy = [ 1170 768.0, 662.5, 767.991316225, 662.433786215, 767.926187912, 662.396880171 1171 ] 1172 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, 1173 :width=>3, :tag=>'I14R_0') 1174 @canvas.lower('I14R_0') 1175 # NB. these numbers are VERY sensitive, you must start with final size 1176 # and shrink down to get the values 1177 xy = [ 1178 745.947897349, 662.428358855, 745.997829056, 662.452239237, 746.0, 662.5 1179 ] 1180 TkcLine.new(@canvas, xy, :smooth=>true, :fill=>color, 1181 :width=>3, :tag=>'I14R_1') 1182 @canvas.lower('I14R_1') 1183 end 1184 1185 def draw14a(side) 1186 color = @C['14'] 1187 xy = @canvas.coords("I14#{side}_0") 1188 xy2 = @canvas.coords("I14#{side}_1") 1189 x0, y0, x1, y1, x2, y2 = xy 1190 x3, y3, x4, y4, x5, y5 = xy2 1191 1192 zz = [ 1193 x0, y0, x0, y0, xy, x2, y2, x2, y2, 1194 x3, y3, x3, y3, xy2, x5, y5, x5, y5 1195 ].flatten 1196 @canvas.delete("I14#{side}") 1197 TkcPolygon.new(@canvas, zz, :tag=>"I14#{side}", :smooth=>true, 1198 :fill=>color, :outline=>color, :width=>3) 1199 @canvas.lower("I14#{side}") 1200 end 1201 1202 def move14(step = nil) 1203 step = get_step(14, step) 1204 1205 # Paper going down 1206 sc = 0.9 - 0.05*step 1207 if sc < 0.3 1208 @canvas.delete('I14L') 1209 return 0 1210 end 1211 1212 ox, oy = @canvas.coords('I14L_0') 1213 @canvas.scale('I14L_0', ox, oy, sc, sc) 1214 ox, oy = @canvas.coords('I14L_1')[-2..-1] 1215 @canvas.scale('I14L_1', ox, oy, sc, sc) 1216 draw14a('L') 1217 1218 # Paper going up 1219 sc = 0.35 + 0.05*step 1220 sc = 1/sc 1221 1222 ox, oy = @canvas.coords('I14R_0') 1223 @canvas.scale('I14R_0', ox, oy, sc, sc) 1224 ox, oy = @canvas.coords('I14R_1')[-2..-1] 1225 @canvas.scale('I14R_1', ox, oy, sc, sc) 1226 draw14a('R') 1227 1228 return((step == 10)? 3: 1) 1229 end 1230 1231 # Light beam 1232 def draw15 1233 color = @C['15a'] 1234 xy = [824, 599, 824, 585, 820, 585, 829, 585] 1235 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I15a') 1236 xy = [789, 599, 836, 643] 1237 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) 1238 xy = [778, 610, 788, 632] 1239 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) 1240 xy = [766, 617, 776, 625] 1241 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) 1242 1243 xy = [633, 600, 681, 640] 1244 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>3) 1245 xy = [635, 567, 657, 599] 1246 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) 1247 xy = [765, 557, 784, 583] 1248 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2) 1249 1250 sine([658, 580, 765, 580], 3, 15, 1251 :tag=>'I15_s', :fill=>@C['fg'], :width=>3) 1252 end 1253 1254 def move15a 1255 color = @C['15b'] 1256 @canvas.scale('I15a', 824, 599, 1, 0.3) # Button down 1257 xy = [765, 621, 681, 621] 1258 TkcLine.new(@canvas, xy, :dash=>'-', :width=>3, :fill=>color, :tag=>'I15') 1259 end 1260 1261 def move15(step = nil) 1262 step = get_step(15, step) 1263 1264 numsteps = 6 1265 1266 if step == numsteps + 2 1267 move_abs('I15_star', [-100, -100]) 1268 return 2 1269 end 1270 if step == 0 # Break the light beam 1271 sparkle([-100, -100], 'I15_star') 1272 xy = [765, 621, 745, 621] 1273 @canvas.coords('I15', xy) 1274 return 1 1275 end 1276 x0, y0 = anchor('I15_s', :w) 1277 x1, y1 = anchor('I15_s', :e) 1278 x = x0 + (x1 - x0) * (step - 1) / numsteps.to_f 1279 move_abs('I15_star', [x, y0]) 1280 return 1 1281 end 1282 1283 # Bell 1284 def draw16 1285 color = @C['16'] 1286 xy = [722, 485, 791, 556] 1287 TkcRectangle.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>3) 1288 xy = box(752, 515, 25) # Bell 1289 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'black', 1290 :tag=>'I16b', :width=>2) 1291 xy = box(752, 515, 5) # Bell button 1292 TkcOval.new(@canvas, xy, :fill=>'black', :outline=>'black', :tag=>'I16b') 1293 1294 xy = [784, 523, 764, 549] # Clapper 1295 TkcLine.new(@canvas, xy, :width=>3, :tag=>'I16c', :fill=>@C['fg']) 1296 xy = box(784, 523, 4) 1297 TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>@C['fg'], :tag=>'I16d') 1298 end 1299 1300 def move16(step = nil) 1301 step = get_step(16, step) 1302 1303 # Note: we never stop 1304 ox, oy = [760, 553] 1305 if (step & 1).nonzero? 1306 beta = 12 1307 @canvas.move('I16b', 3, 0) 1308 else 1309 beta = -12 1310 @canvas.move('I16b', -3, 0) 1311 end 1312 rotate_item('I16c', ox, oy, beta) 1313 rotate_item('I16d', ox, oy, beta) 1314 1315 return ((step == 1)? 3: 1) 1316 end 1317 1318 # Cat 1319 def draw17 1320 color = @C['17'] 1321 1322 xy = [584, 556, 722, 556] 1323 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 1324 xy = [584, 485, 722, 485] 1325 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3) 1326 1327 xy = [664, 523, 717, 549] # Body 1328 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, :width=>3, 1329 :style=>:chord, :start=>128, :extent=>260, :tag=>'I17') 1330 1331 xy = [709, 554, 690, 543] # Paw 1332 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, 1333 :width=>3, :tag=>'I17') 1334 xy = [657, 544, 676, 555] 1335 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :fill=>color, 1336 :width=>3, :tag=>'I17') 1337 1338 xy = box(660, 535, 15) # Lower face 1339 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :style=>:arc, 1340 :start=>150, :extent=>240, :tag=>'I17_') 1341 TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, 1342 :style=>:chord, :start=>150, :extent=>240, :tag=>'I17_') 1343 xy = [674, 529, 670, 513, 662, 521, 658, 521, 650, 513, 647, 529] # Ears 1344 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1345 TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>'', :width=>1, 1346 :tag=>['I17_', 'I17_c']) 1347 xy = [652, 542, 628, 539] # Whiskers 1348 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1349 xy = [652, 543, 632, 545] 1350 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1351 xy = [652, 546, 632, 552] 1352 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1353 1354 xy = [668, 543, 687, 538] 1355 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, 1356 :tag=>['I17_', 'I17_w']) 1357 xy = [668, 544, 688, 546] 1358 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, 1359 :tag=>['I17_', 'I17_w']) 1360 xy = [668, 547, 688, 553] 1361 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, 1362 :tag=>['I17_', 'I17_w']) 1363 1364 xy = [649, 530, 654, 538, 659, 530] # Left eye 1365 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, 1366 :smooth=>true, :tag=>'I17') 1367 xy = [671, 530, 666, 538, 661, 530] # Right eye 1368 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, 1369 :smooth=>true, :tag=>'I17') 1370 xy = [655, 543, 660, 551, 665, 543] # Mouth 1371 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, 1372 :smooth=>true, :tag=>'I17') 1373 end 1374 1375 def move17(step = nil) 1376 step = get_step(17, step) 1377 1378 if step == 0 1379 @canvas.delete('I17') # Delete most of the cat 1380 xy = [655, 543, 660, 535, 665, 543] # Mouth 1381 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, 1382 :smooth=>true, :tag=>'I17_') 1383 xy = box(654, 530, 4) # Left eye 1384 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', 1385 :tag=>'I17_') 1386 xy = box(666, 530, 4) # Right eye 1387 TkcOval.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :fill=>'', 1388 :tag=>'I17_') 1389 1390 @canvas.move('I17_', 0, -20) # Move face up 1391 xy = [652, 528, 652, 554] # Front leg 1392 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1393 xy = [670, 528, 670, 554] # 2nd front leg 1394 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1395 1396 xy = [ # Body 1397 675, 506, 694, 489, 715, 513, 715, 513, 715, 513, 716, 525, 1398 716, 525, 716, 525, 706, 530, 695, 530, 679, 535, 668, 527, 1399 668, 527, 668, 527, 675, 522, 676, 517, 677, 512 1400 ] 1401 TkcPolygon.new(@canvas, xy, :fill=>@canvas.itemcget('I17_c', :fill), 1402 :outline=>@C['fg'], :width=>3, :smooth=>true, 1403 :tag=>'I17_') 1404 xy = [716, 514, 716, 554] # Back leg 1405 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1406 xy = [694, 532, 694, 554] # 2nd back leg 1407 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I17_') 1408 xy = [715, 514, 718, 506, 719, 495, 716, 488] # Tail 1409 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, 1410 :smooth=>true, :tag=>'I17_') 1411 1412 @canvas.raise('I17w') # Make whiskers visible 1413 @canvas.move('I17_', -5, 0) # Move away from the wall a bit 1414 return 2 1415 end 1416 return 0 1417 end 1418 1419 # Sling shot 1420 def draw18 1421 color = @C['18'] 1422 xy = [721, 506, 627, 506] # Sling hold 1423 TkcLine.new(@canvas, xy, :width=>4, :fill=>@C['fg'], :tag=>'I18') 1424 1425 xy = [607, 500, 628, 513] # Sling rock 1426 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :tag=>'I18a') 1427 1428 xy = [526, 513, 606, 507, 494, 502] # Sling band 1429 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>4, :tag=>'I18b') 1430 xy = [485, 490, 510, 540, 510, 575, 510, 540, 535, 491] # Sling 1431 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>6) 1432 end 1433 1434 def move18(step = nil) 1435 step = get_step(18, step) 1436 1437 pos = [ 1438 [587, 506], [537, 506], [466, 506], [376, 506], [266, 506, :x], 1439 [136, 506], [16, 506], [-100, -100] 1440 ] 1441 1442 b = [] 1443 b[0] = [490, 502, 719, 507, 524, 512] # Band collapsing 1444 b[1] = [ 1445 491, 503, 524, 557, 563, 505, 559, 496, 546, 506, 551, 525, 1446 553, 536, 538, 534, 532, 519, 529, 499 1447 ] 1448 b[2] = [ 1449 491, 503, 508, 563, 542, 533, 551, 526, 561, 539, 549, 550, 530, 500 1450 ] 1451 b[3] = [ 1452 491, 503, 508, 563, 530, 554, 541, 562, 525, 568, 519, 544, 530, 501 1453 ] 1454 1455 return 0 if step >= pos.length 1456 1457 if step == 0 1458 @canvas.delete('I18') 1459 @canvas.itemconfigure('I18b', :smooth=>true) 1460 end 1461 if b[step] 1462 @canvas.coords('I18b', b[step]) 1463 end 1464 1465 where = pos[step] 1466 move_abs('I18a', where) 1467 return 3 if where[2] == :x 1468 return 1 1469 end 1470 1471 # Water pipe 1472 def draw19 1473 color = @C['19'] 1474 xx = [[249, 181], [155, 118], [86, 55], [22, 0]] 1475 xx.each{|x1, x2| 1476 TkcRectangle.new(@canvas, x1, 453, x2, 467, 1477 :fill=>color, :outline=>'', :tag=>'I19') 1478 TkcLine.new(@canvas, x1, 453, x2, 453, 1479 :fill=>@C['fg'], :width=>1) # Pipe top 1480 TkcLine.new(@canvas, x1, 467, x2, 467, 1481 :fill=>@C['fg'], :width=>1) # Pipe bottom 1482 } 1483 @canvas.raise('I11i') 1484 1485 xy = box(168, 460, 16) # Bulge by the joint 1486 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'') 1487 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, 1488 :start=>21, :extent=>136) 1489 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, :style=>:arc, 1490 :start=>-21, :extent=>-130) 1491 1492 xy = [249, 447, 255, 473] # First joint 26x6 1493 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1494 1495 xy = box(257, 433, 34) # Bend up 1496 TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, 1497 :style=>:pie, :start=>0, :extent=>-91) 1498 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1499 :style=>:arc, :start=>0, :extent=>-90) 1500 xy = box(257, 433, 20) 1501 TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, 1502 :style=>:pie, :start=>0, :extent=>-92) 1503 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1504 :style=>:arc, :start=>0, :extent=>-90) 1505 xy = box(257, 421, 34) # Bend left 1506 TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, 1507 :style=>:pie, :start=>0, :extent=>91) 1508 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1509 :style=>:arc, :start=>0, :extent=>90) 1510 xy = box(257, 421, 20) 1511 TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, 1512 :style=>:pie, :start=>0, :extent=>90) 1513 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1514 :style=>:arc, :start=>0, :extent=>90) 1515 xy = box(243, 421, 34) # Bend down 1516 TkcArc.new(@canvas, xy, :outline=>'', :fill=>color, :width=>1, 1517 :style=>:pie, :start=>90, :extent=>90) 1518 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1519 :style=>:arc, :start=>90, :extent=>90) 1520 xy = box(243, 421, 20) 1521 TkcArc.new(@canvas, xy, :outline=>'', :fill=>@C['bg'], :width=>1, 1522 :style=>:pie, :start=>90, :extent=>90) 1523 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>1, 1524 :style=>:arc, :start=>90, :extent=>90) 1525 1526 xy = [270, 427, 296, 433] # 2nd joint bottom 1527 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1528 xy = [270, 421, 296, 427] # 2nd joint top 1529 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1530 xy = [249, 382, 255, 408] # Third joint right 1531 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1532 xy = [243, 382, 249, 408] # Third joint left 1533 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1534 xy = [203, 420, 229, 426] # Last joint 1535 TkcRectangle.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>1) 1536 1537 xy = box(168, 460, 6) # Handle joint 1538 TkcOval.new(@canvas, xy, :fill=>@C['fg'], :outline=>'', :tag=>'I19a') 1539 xy = [168, 460, 168, 512] # Handle bar 1540 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>5, :tag=>'I19b') 1541 end 1542 1543 def move19(step = nil) 1544 step = get_step(19, step) 1545 1546 angles = [30, 30, 30] 1547 return 2 if step == angles.length 1548 ox, oy = centroid('I19a') 1549 rotate_item('I19b', ox, oy, angles[step]) 1550 1551 return 1 1552 end 1553 1554 # Water pouring 1555 def draw20 1556 # do nothing 1557 end 1558 1559 def move20(step = nil) 1560 step = get_step(20, step) 1561 1562 pos = [451, 462, 473, 484, 496, 504, 513, 523, 532] 1563 freq = [20, 40, 40, 40, 40, 40, 40, 40, 40] 1564 pos = [ 1565 [451, 20], [462, 40], [473, 40], [484, 40], [496, 40], 1566 [504, 40], [513, 40], [523, 40], [532, 40, :x] 1567 ] 1568 return 0 if step >= pos.length 1569 1570 @canvas.delete('I20') 1571 where = pos[step] 1572 y, f = where 1573 h20(y, f) 1574 return 3 if where[2] == :x 1575 return 1 1576 end 1577 1578 def h20(y, f) 1579 color = @C['20'] 1580 @canvas.delete('I20') 1581 1582 sine([208, 428, 208, y], 4, f, :tag=>['I20', 'I20s'], 1583 :width=>3, :fill=>color, :smooth=>true) 1584 TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, 1585 :fill=>color, :smooth=>1, :tag=>['I20', 'I20a']) 1586 TkcLine.new(@canvas, @canvas.coords('I20s'), :width=>3, 1587 :fill=>color, :smooth=>1, :tag=>['I20', 'I20b']) 1588 @canvas.move('I20a', 8, 0) 1589 @canvas.move('I20b', 16, 0) 1590 end 1591 1592 # Bucket 1593 def draw21 1594 color = @C['21'] 1595 xy = [217, 451, 244, 490] # Right handle 1596 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') 1597 xy = [201, 467, 182, 490] # Left handle 1598 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21_a') 1599 1600 xy = [245, 490, 237, 535] # Right side 1601 xy2 = [189, 535, 181, 490] # Left side 1602 TkcPolygon.new(@canvas, xy + xy2, :fill=>color, :outline=>'', 1603 :tag=>['I21', 'I21f']) 1604 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>2, :tag=>'I21') 1605 TkcLine.new(@canvas, xy2, :fill=>@C['fg'], :width=>2, :tag=>'I21') 1606 1607 xy = [182, 486, 244, 498] # Top 1608 TkcOval.new(@canvas, xy, :fill=>color, :outline=>'', :width=>2, 1609 :tag=>['I21', 'I21f']) 1610 TkcOval.new(@canvas, xy, :fill=>'', :outline=>@C['fg'], :width=>2, 1611 :tag=>['I21', 'I21t']) 1612 xy = [189, 532, 237, 540] # Bottom 1613 TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], :width=>2, 1614 :tag=>['I21', 'I21b']) 1615 end 1616 1617 def move21(step = nil) 1618 step = get_step(21, step) 1619 1620 numsteps = 30 1621 return 0 if step >= numsteps 1622 1623 x1, y1, x2, y2 = @canvas.coords('I21b') 1624 # lx1, ly1, lx2, ly2 = @canvas.coords('I21t') 1625 lx1, ly1, lx2, ly2 = [183, 492, 243, 504] 1626 1627 f = step / numsteps.to_f 1628 y2 = y2 - 3 1629 xx1 = x1 + (lx1 - x1) * f 1630 yy1 = y1 + (ly1 - y1) * f 1631 xx2 = x2 + (lx2 - x2) * f 1632 yy2 = y2 + (ly2 - y2) * f 1633 1634 @canvas.itemconfigure('I21b', :fill=>@C['20']) 1635 @canvas.delete('I21w') 1636 TkcPolygon.new(@canvas, x2, y2, x1, y1, xx1, yy1, xx2, yy1, 1637 :tag=>['I21', 'I21w'], :outline=>'', :fill=>@C['20']) 1638 @canvas.lower('I21w', 'I21') 1639 @canvas.raise('I21b') 1640 @canvas.lower('I21f') 1641 1642 return((step == numsteps - 1)? 3: 1) 1643 end 1644 1645 # Bucket drop 1646 def draw22 1647 # do nothing 1648 end 1649 1650 def move22(step = nil) 1651 step = get_step(22, step) 1652 pos = [[213, 513], [213, 523], [213, 543, :x], [213, 583], [213, 593]] 1653 1654 @canvas.itemconfigure('I21f', :fill=>@C['22']) if step == 0 1655 return 0 if step >= pos.length 1656 where = pos[step] 1657 move_abs('I21', where) 1658 h20(where[1], 40) 1659 @canvas.delete('I21_a') # Delete handles 1660 1661 return 3 if where[2] == :x 1662 return 1 1663 end 1664 1665 # Blow dart 1666 def draw23 1667 color = @C['23a'] 1668 color2 = @C['23b'] 1669 color3 = @C['23c'] 1670 1671 xy = [185, 623, 253, 650] # Block 1672 TkcRectangle.new(@canvas, xy, :fill=>'black', :outline=>@C['fg'], 1673 :width=>2, :tag=>'I23a') 1674 xy = [187, 592, 241, 623] # Balloon 1675 TkcOval.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') 1676 TkcArc.new(@canvas, xy, :outline=>@C['fg'], :width=>3, :tag=>'I23b', 1677 :style=>:arc, :start=>12, :extent=>336) 1678 xy = [239, 604, 258, 589, 258, 625, 239, 610] # Balloon nozzle 1679 TkcPolygon.new(@canvas, xy, :outline=>'', :fill=>color, :tag=>'I23b') 1680 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23b') 1681 1682 xy = [285, 611, 250, 603] # Dart body 1683 TkcOval.new(@canvas, xy, :fill=>color2, :outline=>@C['fg'], 1684 :width=>3, :tag=>'I23d') 1685 xy = [249, 596, 249, 618, 264, 607, 249, 596] # Dart tail 1686 TkcPolygon.new(@canvas, xy, :fill=>color3, :outline=>@C['fg'], 1687 :width=>3, :tag=>'I23d') 1688 xy = [249, 607, 268, 607] # Dart detail 1689 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') 1690 xy = [285, 607, 305, 607] # Dart needle 1691 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I23d') 1692 end 1693 1694 def move23(step = nil) 1695 step = get_step(23, step) 1696 1697 pos = [ 1698 [277, 607], [287, 607], [307, 607, :x], [347, 607], [407, 607], 1699 [487, 607], [587, 607], [687, 607], [787, 607], [-100, -100] 1700 ] 1701 1702 return 0 if step >= pos.length 1703 if step <= 1 1704 ox, oy = anchor('I23a', :n) 1705 @canvas.scale('I23b', ox, oy, 0.9, 0.5) 1706 end 1707 where = pos[step] 1708 move_abs('I23d', where) 1709 1710 return 3 if where[2] == :x 1711 return 1 1712 end 1713 1714 # Balloon 1715 def draw24 1716 color = @C['24a'] 1717 xy = [366, 518, 462, 665] # Balloon 1718 TkcOval.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], 1719 :width=>3, :tag=>'I24') 1720 xy = [414, 666, 414, 729] # String 1721 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :width=>3, :tag=>'I24') 1722 xy = [410, 666, 404, 673, 422, 673, 418, 666] # Nozzle 1723 TkcPolygon.new(@canvas, xy, :fill=>color, :outline=>@C['fg'], 1724 :width=>3, :tag=>'I24') 1725 1726 xy = [387, 567, 390, 549, 404, 542] # Reflections 1727 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, 1728 :width=>2, :tag=>'I24') 1729 xy = [395, 568, 399, 554, 413, 547] 1730 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, 1731 :width=>2, :tag=>'I24') 1732 xy = [403, 570, 396, 555, 381, 553] 1733 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, 1734 :width=>2, :tag=>'I24') 1735 xy = [408, 564, 402, 547, 386, 545] 1736 TkcLine.new(@canvas, xy, :fill=>@C['fg'], :smooth=>true, 1737 :width=>2, :tag=>'I24') 1738 end 1739 1740 def move24(step = nil) 1741 step = get_step(24, step) 1742 1743 return 0 if step > 4 1744 return 2 if step == 4 1745 1746 if step == 0 1747 @canvas.delete('I24') # Exploding balloon 1748 xy = [ 1749 347, 465, 361, 557, 271, 503, 272, 503, 342, 574, 259, 594, 1750 259, 593, 362, 626, 320, 737, 320, 740, 398, 691, 436, 738, 1751 436, 739, 476, 679, 528, 701, 527, 702, 494, 627, 548, 613, 1752 548, 613, 480, 574, 577, 473, 577, 473, 474, 538, 445, 508, 1753 431, 441, 431, 440, 400, 502, 347, 465, 347, 465 1754 ] 1755 TkcPolygon.new(@canvas, xy, :tag=>'I24', :fill=>@C['24b'], 1756 :outline=>@C['24a'], :width=>10, :smooth=>true) 1757 msg = Tk.subst(@S['message'].value) 1758 TkcText.new(@canvas, centroid('I24'), :text=>msg, :tag=>['I24', 'I24t'], 1759 :justify=>:center, :font=>['Times Roman', 18, :bold]) 1760 return 1 1761 end 1762 1763 @canvas.itemconfigure('I24t', :font=>['Times Roman', 18 + 6*step, :bold]) 1764 @canvas.move('I24', 0, -60) 1765 ox, oy = centroid('I24') 1766 @canvas.scale('I24', ox, oy, 1.25, 1.25) 1767 return 1 1768 end 1769 1770 # Displaying the message 1771 def move25(step = nil) 1772 step = get_step(25, step) 1773 1774 if step == 0 1775 @XY['25'] = Tk::Clock.clicks(:miliseconds) 1776 return 1 1777 end 1778 elapsed = Tk::Clock.clicks(:miliseconds) - @XY['25'] 1779 return 1 if elapsed < 5000 1780 return 2 1781 end 1782 1783 # Collapsing balloon 1784 def move26(step = nil) 1785 step = get_step(26, step) 1786 1787 if step >= 3 1788 @canvas.delete('I24', 'I26') 1789 TkcText.new(@canvas, 430, 740, :anchor=>:s, :tag=>'I26', 1790 :text=>'click to continue', 1791 :font=>['Times Roman', 24, :bold]) 1792 @canvas.bind('1', proc{reset}) 1793 return 4 1794 end 1795 1796 ox, oy = centroid('I24') 1797 @canvas.scale('I24', ox, oy, 0.8, 0.8) 1798 @canvas.move('I24', 0, 60) 1799 @canvas.itemconfigure('I24t', :font=>['Times Roman', 30 - 6*step, :bold]) 1800 return 1 1801 end 1802 1803 ################################################################ 1804 # 1805 # Helper functions 1806 # 1807 def box(x, y, r) 1808 [x - r, y - r, x + r, y + r] 1809 end 1810 1811 def move_abs(item, xy) 1812 x, y = xy 1813 ox, oy = centroid(item) 1814 dx = x - ox 1815 dy = y - oy 1816 @canvas.move(item, dx, dy) 1817 end 1818 1819 def rotate_item(item, ox, oy, beta) 1820 xy = @canvas.coords(item) 1821 xy2 = [] 1822 0.step(xy.length - 1, 2){|idx| 1823 x, y = xy[idx, 2] 1824 xy2.concat(rotate_c(x, y, ox, oy, beta)) 1825 } 1826 @canvas.coords(item, xy2) 1827 end 1828 1829 def rotate_c(x, y, ox, oy, beta) 1830 # rotates vector (ox,oy)->(x,y) by beta degrees clockwise 1831 1832 x -= ox # Shift to origin 1833 y -= oy 1834 1835 beta = beta * Math.atan(1) * 4 / 180.0 # Radians 1836 xx = x * Math.cos(beta) - y * Math.sin(beta) # Rotate 1837 yy = x * Math.sin(beta) + y * Math.cos(beta) 1838 1839 xx += ox # Shift back 1840 yy += oy 1841 1842 [xx, yy] 1843 end 1844 1845 def reset 1846 draw_all 1847 @canvas.bind_remove('1') 1848 @S['mode'].value = :MSTART 1849 @S['active'] = [0] 1850 end 1851 1852 # Each Move## keeps its state info in STEP, this retrieves and increments it 1853 def get_step(who, step) 1854 if step 1855 @STEP[who] = step 1856 else 1857 if !@STEP.exist?(who) || @STEP[who] == "" 1858 @STEP[who] = 0 1859 else 1860 @STEP[who] += 1 1861 end 1862 end 1863 @STEP[who] 1864 end 1865 1866 def reset_step 1867 @S['cnt'].value = 0 1868 @STEP.keys.each{|k| @STEP[k] = ''} 1869 end 1870 1871 def sine(xy0, amp, freq, opts = {}) 1872 x0, y0, x1, y1 = xy0 1873 step = 2 1874 xy = [] 1875 if y0 == y1 # Horizontal 1876 x0.step(x1, step){|x| 1877 beta = (x - x0) * 2 * Math::PI / freq 1878 y = y0 + amp * Math.sin(beta) 1879 xy << x << y 1880 } 1881 else 1882 y0.step(y1, step){|y| 1883 beta = (y - y0) * 2 * Math::PI / freq 1884 x = x0 + amp * Math.sin(beta) 1885 xy << x << y 1886 } 1887 end 1888 TkcLine.new(@canvas, xy, opts) 1889 end 1890 1891 def round_rect(xy, radius, opts={}) 1892 x0, y0, x3, y3 = xy 1893 r = @canvas.winfo_pixels(radius) 1894 d = 2 * r 1895 1896 # Make sure that the radius of the curve is less than 3/8 size of the box! 1897 maxr = 0.75 1898 if d > maxr * (x3 - x0) 1899 d = maxr * (x3 - x0) 1900 end 1901 if d > maxr * (y3 - y0) 1902 d = maxr * (y3 - y0) 1903 end 1904 1905 x1 = x0 + d 1906 x2 = x3 - d 1907 y1 = y0 + d 1908 y2 = y3 - d 1909 1910 xy = [x0, y0, x1, y0, x2, y0, x3, y0, x3, y1, x3, y2] 1911 xy.concat([x3, y3, x2, y3, x1, y3, x0, y3, x0, y2, x0, y1]) 1912 return xy 1913 end 1914 1915 def round_poly(canv, xy, radii, opts) 1916 lenXY = xy.length 1917 lenR = radii.length 1918 if lenXY != 2*lenR 1919 raise "wrong number of vertices and radii" 1920 end 1921 1922 knots = [] 1923 x0 = xy[-2]; y0 = xy[-1] 1924 x1 = xy[0]; y1 = xy[1] 1925 xy << xy[0] << xy[1] 1926 1927 0.step(lenXY - 1, 2){|i| 1928 radius = radii[i/2] 1929 r = canv.winfo_pixels(radius) 1930 1931 x2 = xy[i+2]; y2 = xy[i+3] 1932 z = _round_poly2(x0, y0, x1, y1, x2, y2, r) 1933 knots.concat(z) 1934 1935 x0 = x1; y0 = y1 1936 x1 = x2; y1 = y2 1937 } 1938 TkcPolygon.new(canv, knots, {:smooth=>true}.update(opts)) 1939 end 1940 1941 def _round_poly2(x0, y0, x1, y1, x2, y2, radius) 1942 d = 2 * radius 1943 maxr = 0.75 1944 1945 v1x = x0 - x1 1946 v1y = y0 - y1 1947 v2x = x2 - x1 1948 v2y = y2 - y1 1949 1950 vlen1 = Math.sqrt(v1x*v1x + v1y*v1y) 1951 vlen2 = Math.sqrt(v2x*v2x + v2y*v2y) 1952 1953 if d > maxr * vlen1 1954 d = maxr * vlen1 1955 end 1956 if d > maxr * vlen2 1957 d = maxr * vlen2 1958 end 1959 1960 xy = [] 1961 xy << (x1 + d * v1x / vlen1) << (y1 + d * v1y / vlen1) 1962 xy << x1 << y1 1963 xy << (x1 + d * v2x / vlen2) << (y1 + d * v2y / vlen2) 1964 1965 return xy 1966 end 1967 1968 def sparkle(oxy, tag) 1969 xy = [ 1970 [299, 283], [298, 302], [295, 314], [271, 331], 1971 [239, 310], [242, 292], [256, 274], [281, 273] 1972 ] 1973 xy.each{|x, y| 1974 TkcLine.new(@canvas, 271, 304, x, y, 1975 :fill=>'white', :width=>3, :tag=>tag) 1976 } 1977 move_abs(tag, oxy) 1978 end 1979 1980 def centroid(item) 1981 anchor(item, :c) 1982 end 1983 1984 def anchor(item, where) 1985 x1, y1, x2, y2 = @canvas.bbox(item) 1986 case(where) 1987 when :n 1988 y = y1 1989 when :s 1990 y = y2 1991 else 1992 y = (y1 + y2) / 2.0 1993 end 1994 case(where) 1995 when :w 1996 x = x1 1997 when :e 1998 x = x2 1999 else 2000 x = (x1 + x2) / 2.0 2001 end 2002 return [x, y] 2003 end 2004end 2005 2006TkGoldberg_Demo.new(base_frame) 2007