1#!/usr/local/bin/wish8.6 -f 2 3###################################################################### 4# 5# table.tcl 6# 7# Copyright (C) 1993,1994 by John Heidemann <johnh@ficus.cs.ucla.edu> 8# All rights reserved. See the main klondike file for a full copyright 9# notice. 10# 11# $Id: table.tcl,v 2.16 1997/03/26 17:47:29 johnh Exp $ 12# 13###################################################################### 14 15# 16# generic card table routines 17# 18set rcsid(table.tcl) {$Id: table.tcl,v 2.16 1997/03/26 17:47:29 johnh Exp $} 19 20 21proc mkTableDefaults {} { 22 global table tk_version 23 24 if {$tk_version < 4.0} { 25 set table(colormodel) [tk colormodel .] 26 } else { 27 set table(colormodel) "color" 28 if {[winfo depth .] < 8} { 29 set table(colormodel) monochrome 30 } 31 } 32 set table(font) -*-Helvetica-Medium-R-*-140-* 33 if { $table(colormodel) == "monochrome" } { 34 set table(fg) Black 35 set table(bg) White 36 } else { 37 set table(fg) Black 38 set table(bg) #ffe4c4 39 } 40 41 set table(font) -*-Helvetica-Medium-R-*-140-* 42 43 set table(cardWidth) 54 44 set table(cardHeight) 69 45 # If necessary 46 # we will trim these values a little shorter in dontspace 47 # to make the window fit a 640x480 display. 48 set table(gutter) 12 49 set table(stackedCardOffset) 25 50} 51 52proc tableBell {} { 53 global tk_version 54 if {$tk_version < 4.0} { 55 puts -nonewline "\a" 56 } else { 57 bell 58 } 59 60} 61 62proc mkCardDefaults {} { 63 global table 64 65 # cards 66 # (see reface card for card colors) 67 68 set table(cardWidth) 52 69 set table(cardHeight) 67 70 # cardSpace -- reasonable amount of space between card bitmaps 71 set table(cardSpace) 8 72 # cardOverlap -- required overlap when dropping cards 73 set table(cardOverlap) 4 74 # padValue -- a good value for random padding (around text) 75 set table(padValue) 10 76 77 # coords of a place off the screen 78 set table(hiddenX) -1000 79 set table(hiddenY) -1000 80} 81 82# 83# init stuff 84# 85# table(preActionProc) = called before any action (used to start game) 86# 87proc mkTable {width height preActionProc} { 88 global table tk_version 89 90 set table(width) $width 91 set table(height) $height 92 set table(preActionProc) $preActionProc 93 set table(id) ".c" 94 95 mkCardDefaults 96 97 # random constants 98 set table(values) "a 2 3 4 5 6 7 8 9 t j q k" 99 set table(suits) "c d h s" 100 set table(cvalues) "xa23456789tjqkx" 101 set table(csuits) "xcdhsx" 102 set table(otherColorSuits,c) "dh" 103 set table(otherColorSuits,d) "cs" 104 set table(otherColorSuits,h) "cs" 105 set table(otherColorSuits,s) "dh" 106 107 canvas $table(id) -relief raised \ 108 -width $table(width) -height $table(height) \ 109 -background $table(bg) 110 if {$tk_version >= 4.0} { 111 focus $table(id) 112 $table(id) configure -takefocus 1 113 } 114 115 return $table(id) 116} 117 118 119# 120# card bitmap backgrounds 121# 122proc setBackBitmap {} { 123 global table 124 if { [info exists table(backFace)] } { 125 set oldBackFace $table(backFace) 126 } else { 127 set oldBackFace "xxx" 128 } 129 set table(backFace) "back_$table(backChoice)" 130 # 131 # Fix any cards with the old back. 132 # 133 if {[catch {$table(id) configure}] == 0} { 134 foreach i [$table(id) find withtag card] { 135 set itemBitmap [lindex [$table(id) itemconfigure $i -bitmap] 4] 136 if { [regexp $oldBackFace $itemBitmap] } { 137 refaceItem $i $table(id) $table(backFace) 138 } 139 } 140 } 141} 142 143proc chooseCardBackground {} { 144 global table 145 146 # 147 # get our choices 148 # 149 set choices "" 150 # Note: wish-4.1 under linux seems to have a bug 151 # with the glob failing. If so, take our 152 # known good cases. 153 if [catch { 154 set possibleChoices [glob [string trimleft "$table(bitmapdir)/c_back_*.xbm" "@"]] 155 }] { 156 set possibleChoices "c_back_crane.xbm c_back_pagoda.xbm c_back_plain.xbm" 157 } 158 foreach i $possibleChoices { 159 regexp {c_back_(.*)\.xbm$} $i trash token 160 lappend choices $token 161 } 162 if { $choices == "" } { 163 return -errorinfo "No background bitmap found." 164 } 165 set table(backChoices) $choices 166 167 # 168 # randomly pick one 169 # 170 set table(backChoice) [lindex $choices [random [llength $choices]]] 171 setBackBitmap 172} 173chooseCardBackground 174 175 176# 177# table stuff 178# 179 180 181proc refaceItem {itemId w face} { 182 global table items 183 # puts "refaceItem $itemId $w $face" 184 switch -glob $face { 185 [a23456789tjqk][cs] { 186 set items($itemId,normFg) Black 187 set items($itemId,normBg) White 188 if { $table(colormodel) == "monochrome" } { 189 set items($itemId,highFg) White 190 set items($itemId,highBg) Black 191 } else { 192 set items($itemId,highFg) Black 193 set items($itemId,highBg) Gray70 194 } 195 } 196 [a23456789tjqk][dh] { 197 set items($itemId,normFg) Red 198 set items($itemId,normBg) White 199 if { $table(colormodel) == "monochrome" } { 200 set items($itemId,highFg) White 201 set items($itemId,highBg) Black 202 } else { 203 set items($itemId,highFg) "#a00000" 204 set items($itemId,highBg) Gray70 205 } 206 } 207 back_* { 208 set items($itemId,normFg) Black 209 set items($itemId,normBg) White 210 if { $table(colormodel) == "monochrome" } { 211 set items($itemId,highFg) White 212 set items($itemId,highBg) Black 213 } else { 214 set items($itemId,highFg) Black 215 set items($itemId,highBg) Gray70 216 } 217 } 218 space - 219 warnspace { 220 set items($itemId,normFg) $table(fg) 221 set items($itemId,normBg) $table(bg) 222 if { $table(colormodel) == "monochrome" } { 223 set items($itemId,highFg) $table(bg) 224 set items($itemId,highBg) $table(fg) 225 } else { 226 set items($itemId,highFg) Black 227 set items($itemId,highBg) Gray70 228 } 229 } 230 default { puts "refaceItem: unkown face $face\n" } 231 } 232 $w itemconfigure $itemId \ 233 -bitmap "$table(bitmapdir)/c_$face.xbm" \ 234 -foreground $items($itemId,normFg) \ 235 -background $items($itemId,normBg) 236 237} 238 239proc createItemBitmap {x y face} { 240 global table 241 set c $table(id) 242 set itemId [ $c create bitmap $x $y -anchor nw] 243 refaceItem $itemId $c $face 244 # Remember the cards so we can change bitmaps as required. 245 $c addtag card withtag $itemId 246 # $c addtag debug withtag $itemId 247 return $itemId 248} 249 250 251# 252# null procs 253# 254proc recursiveFindFriendsProc {itemId w x y closure} { 255 global items 256 if { $closure == {} } { 257 return {} 258 } else { 259 return [linsert [recursiveFindFriendsProc $closure $w $x $y $items($closure,dragFindFriendsClosure)] 0 $closure] 260 } 261} 262proc defaultDragTargetAcceptProc {w target src srcFriends} { return 1 } 263 264proc defaultClickProc {item w x y closure} {} 265 266# 267# dropableCard 268# 269proc defaultDragTargetEnterProc {item w x y targetId} { 270 global items 271 $w itemconfig $targetId \ 272 -foreground $items($targetId,highFg) \ 273 -background $items($targetId,highBg) 274 } 275proc defaultDragTargetLeaveProc {item w x y targetId} { 276 global items 277 $w itemconfig $targetId \ 278 -foreground $items($targetId,normFg) \ 279 -background $items($targetId,normBg) 280} 281 282proc whereDroppedDragProc {itemId w x y src target} { 283} 284 285proc originalPlaceDragProc {itemId w x y src target} { 286 global table 287 # debugLog "originalPlaceDragProc $itemId $w $x $y $src $target" 288 if { $target == "" } { 289 # 290 # Put the card back where it started. 291 # This is a little trickey since we could be dragging a 292 # stack, so we compute the relative distance and 293 # move selected. 294 # 295 set oldCoords [$w coords $itemId] 296 moveAllRelatively $w $src \ 297 [lindex $oldCoords 0] [lindex $oldCoords 1] \ 298 $table(dragInitialX) $table(dragInitialY) 299 } else { 300 error "defaultDragAbortProc: called with target $target" 301 } 302} 303 304proc onCardPlaceDragProc {itemId w x y src target} { 305 global table items 306 if { $target != {} } { 307 # unhiligth other card by calling leave proc 308 defaultDragTargetLeaveProc $itemId $w $x $y $target 309 moveCardOnCard $w $itemId $target selected 310 } else { 311 error "defaultDragAbortProc: called with target $target" 312 } 313} 314 315proc samePlaceChildOffsetProc {} { 316 return [list 0 0] 317} 318proc offsetChildOffsetProc {} { 319 global table 320 return [list 0 $table(stackedCardOffset)] 321} 322 323 324 325# 326# map from id's to cards 327# 328proc memorizeCard {id vs} { 329 global cards 330 set cards($vs) $id 331} 332 333proc rememberCard {vs} { 334 global cards 335 return $cards($vs) 336} 337 338 339# 340# deck stuff 341# 342 343proc getCard {w id param} { 344 global items 345 return $items($id,[string trim $param "-"]) 346} 347 348proc setCard {w id args} { 349 global items 350 # puts "$id: $args" 351 while { [llength $args] } { 352 set a [lindex $args 0] 353 set args [lreplace $args 0 0] 354 if { $a != "-default" } { 355 if { [llength $args] == 0 } { 356 error "setCard: argument $a without parameter" 357 } 358 set b [lindex $args 0] 359 set args [lreplace $args 0 0] 360 361 switch -exact -- $a { 362 "-atag" { 363 $w addtag $b withtag $id 364 # Make sure that double clicking is allowed 365 # before clicking for dragging. 366 set tags [lindex [$w itemconf $id -tags] 4] 367 set doubleI [lsearch -exact $tags "doubleClickableCard"] 368 set dragableI [lsearch -exact $tags "dragableCard"] 369 if { $dragableI < $doubleI } { 370 # Redo dragableCard tag to make it last. 371 $w dtag $id dragableCard 372 $w addtag dragableCard withtag $id 373 } 374 } 375 "-dtag" { $w dtag $id $b } 376 default { 377 set a [string trim $a "-"] 378 set items($id,$a) $b 379 } 380 } 381 switch -exact -- $a { 382 "side" { 383 if { $b == "back" } { 384 set face $table(backFace) 385 } else { 386 set face $items($id,subtype) 387 } 388 refaceItem $id $w $face 389 } 390 "subtype" { 391 memorizeCard $id $b 392 } 393 } 394 } else { # -default 395 # kill tags 396 $w itemconf $id -tags card 397 398 set items($id,type) card 399 # values: card, place 400 if { [info exists items($id,subtype)] == 0 } { 401 set items($id,subtype) "" 402 # for cards: value/suit 403 } 404 set items($id,location) hidden 405 # values: hidden, deck, pile, 406 # tableau, foundation 407 set items($id,sublocation) "" 408 # values 409 set items($id,side) back 410 # values: face, back 411 set items($id,parent) {} 412 set items($id,child) {} 413 414 # items(id,normFg), items(id,normBg) 415 # items(id,highFg), items(id,highBg) 416 417 set items($id,childOffsetProc) samePlaceChildOffsetProc 418 # returns xy list of where 419 # a child should be placed 420 421 set items($id,dragableCardPress) defaultDragableCardPress 422 set items($id,dragableCardMove) defaultDragableCardMove 423 set items($id,dragableCardRelease) defaultDragableCardRelease 424 set items($id,dragFindFriendsProc) recursiveFindFriendsProc 425 set items($id,dragFindFriendsClosure) {} 426 # return a list of friends to be drug 427 set items($id,dragTargetEnterProc) \ 428 defaultDragTargetEnterProc 429 # when dropAccepting, called if a 430 # valid target is over us 431 set items($id,dragTargetLeaveProc) \ 432 defaultDragTargetLeaveProc 433 # when dropAccepting, called if a 434 # valid target was over us but left 435 set items($id,dragTargetAcceptGlob) "" 436 # globbing of cards that we take 437 set items($id,dragTargetAcceptProc) \ 438 defaultDragTargetAcceptProc 439 # second check after Accepts 440 set items($id,dragCommitProc) onCardPlaceDragProc 441 # Called when drag is released. 442 443 set items($id,clickProc) defaultClickProc 444 # Called when clicked on. 445 set items($id,clickClosure) {} 446 # passed to clickProc 447 set items($id,doubleClickProc) defaultClickProc 448 # Called when clicked on. 449 set items($id,doubleClickClosure) {} 450 # passed to doubleClickProc 451 452 set items($id,orphanChildProc) error 453 set items($id,orphanChildClosure) {} 454 455 set items($id,adoptChildProc) error 456 set items($id,adoptChildClosure) {} 457 } 458 } 459} 460 461proc tableRegisterDumbItem {id} { 462 global items 463 set items($id,dragTargetAcceptGlob) {} 464} 465 466proc mkDeck {} { 467 global table items deck 468 469 # 470 # Create each new card on the deck 471 # and add it to items. 472 # Initially cards are instantiated off-screen. 473 # 474 # 475 # Additionally, cards ids are listed in the deck list. 476 # 477 478 foreach v $table(values) { 479 foreach s $table(suits) { 480 # create the card 481 set id [createItemBitmap $table(hiddenX) $table(hiddenY) $table(backFace)] 482 lappend deck $id 483 setCard $table(id) $id -default -type card -subtype $v$s 484 } 485 } 486} 487 488 489 490proc shuffleDeck {} { 491 global deck 492 # Put the deck in a cannonical order so we 493 # can regenerate it with the same sequenece 494 # of random numbers. 495 set oldCards [lsort -integer $deck] 496 set newCards "" 497 while { [llength $oldCards] > 0 } { 498 # tclX 499 set i [random [llength $oldCards]] 500 lappend newCards [lindex $oldCards $i] 501 set oldCards [lreplace $oldCards $i $i] 502 } 503 set deck $newCards 504} 505 506 507 508 509# 510# bindings 511# 512proc mkBindings {w} { 513 global table items 514 515 # 516 # card clicking 517 # 518 $w bind clickableCard <ButtonRelease-1> { 519 global table 520 521 $table(preActionProc) click 522 523 set itemId [%W find withtag current] 524 # NEEDSWORK: Check to make sure release is still on card. 525 $items($itemId,clickProc) $itemId %W %x %y $items($itemId,clickClosure) 526 } 527 $w bind clickableCard <Enter> { enterHilightCard [%W find withtag current] %W %x %y } 528 $w bind clickableCard <Leave> { leaveUnhilightCard [%W find withtag current] %W %x %y } 529 530 # 531 # double clicking 532 # 533 $w bind doubleClickableCard <Double-ButtonRelease-1> { 534 global table 535 536 $table(preActionProc) doubleClick 537 set table(dragging) 0 538 539 set itemId [%W find withtag current] 540 # NEEDSWORK: Check to make sure release is still on card. 541 $items($itemId,doubleClickProc) $itemId %W %x %y $items($itemId,clickClosure) 542 } 543 # johnh: xxx 544 $w bind doubleClickableCard <ButtonRelease-3> { 545 global table 546 547 $table(preActionProc) doubleClick 548 549 set itemId [%W find withtag current] 550 # NEEDSWORK: Check to make sure release is still on card. 551 $items($itemId,doubleClickProc) $itemId %W %x %y $items($itemId,clickClosure) 552 } 553 $w bind doubleClickableCard <Enter> { enterHilightCard [%W find withtag current] %W %x %y } 554 $w bind doubleClickableCard <Leave> { leaveUnhilightCard [%W find withtag current] %W %x %y } 555 556 # 557 # dragableCard 558 # 559 $w bind dragableCard <ButtonPress-1> { 560 set id [%W find withtag current] 561 $items($id,dragableCardPress) $id %W %x %y 562 } 563 $w bind dragableCard <B1-Motion> { 564 set id [%W find withtag current] 565 $items($id,dragableCardMove) $id %W %x %y 566 } 567 $w bind dragableCard <ButtonRelease-1> { 568 set id [%W find withtag current] 569 $items($id,dragableCardRelease) $id %W %x %y 570 } 571 $w bind dragableCard <Enter> { enterHilightCard [%W find withtag current] %W %x %y } 572 $w bind dragableCard <Leave> { leaveUnhilightCard [%W find withtag current] %W %x %y } 573 574 # 575 # outlineableCard 576 # 577 $w bind outlineableCard <Enter> { enterHilightCard [%W find withtag current] %W %x %y } 578 $w bind outlineableCard <Leave> { leaveUnhilightCard [%W find withtag current] %W %x %y } 579 580 # this is for debugging 581 $w bind card <ButtonPress-2> { debugCard [%W find withtag current] %W %x %y} 582 583 # 584 # untouched stuff 585 # 586 $w bind untouchedCard <ButtonPress-1> { beginGame current %W %x %y } 587 # 588 $w bind pauseItems <ButtonRelease-1> { unpauseGame } 589 590 # 591 # Keyboard events 592 # 593 bind $w <Control-KeyPress> { # do nothing } 594 bind $w <Meta-KeyPress> { # do nothing } 595# bind $w <KeyPress> { keyPress "%A" %W } 596 resetKeyState 597} 598 599proc debugCard {id w x y } { 600 global items 601 puts -nonewline "dubugCard $id: " 602 foreach i {location sublocation parent child} { 603 puts -nonewline "$i=$items($id,$i) " 604 } 605 puts "" 606} 607 608 609# 610# keyPress 611# 612# Keypresses are managed by modes 613# submode: any-(special,suit,value)->(any,value,suit) 614# value-(suit)->any 615# suit-(value)->any 616# source---target 617# 618# 619proc keyPress {asc w} { 620 global table 621 622 if { "$asc" == "" } { return } 623 set asc [string tolower $asc] 624 switch -exact -- $table(keySubState) { 625 "any" { 626 switch -glob -- "$asc" { 627 [cdhs] { 628 set table(keySuit) $asc 629 set newSubState suit 630 } 631 [a23456789tjqk] { 632 set table(keyValue) $asc 633 set newSubState value 634 } 635 [\ ] { 636 set newSubState triple 637 } 638 [\n] { 639 set newSubState double 640 } 641 default { 642 set newSubState error 643 } 644 } 645 } 646 "value" { 647 switch -glob -- $asc { 648 [cdhs] { 649 set table(keySuit) $asc 650 set newSubState complete 651 } 652 [\b] { 653 set newSubState any 654 } 655 default { 656 set newSubState error 657 } 658 } 659 } 660 "suit" { 661 switch -glob -- $asc { 662 [a23456789tjqk] { 663 set table(keyValue) $asc 664 set newSubState complete 665 } 666 [\b] { 667 set newSubState any 668 } 669 default { 670 set newSubState error 671 } 672 } 673 } 674 } 675 # 676 # Handle larger state transitions. 677 # 678 switch -exact -- $table(keyState) { 679 "any" { 680 switch -exact -- $newSubState { 681 "double" { 682 set newState any 683 set newSubState any 684 } 685 "triple" { 686 set newState any 687 set newSubState any 688 } 689 "complete" { 690 set newState card 691 set newSubState any 692 } 693 "error" { 694 set newState error 695 set newSubState any 696 } 697 default { 698 set newState $table(keyState) 699 } 700 } 701 } 702 "card" { 703 switch -exact -- $newSubState { 704 "double" { 705 set newState double 706 set newSubState any 707 } 708 "triple" { 709 set newState triple 710 set newSubState any 711 } 712 "complete" { 713 set newState move 714 set newSubState any 715 } 716 "error" { 717 set newState error 718 set newSubState any 719 } 720 default { 721 set newState $table(keyState) 722 } 723 } 724 } 725 default { 726 set newState any 727 set newSubState any 728 } 729 } 730 # 731 # Take the action. 732 # 733 if { $table(keyState) == "card" && $newState != "card"} { 734 # Unhilight the card. 735 unhilightCard $table(keyFirstId) $w "" "" 736 } 737 switch -exact -- $newState { 738 "double" { 739 set newState any 740 } 741 "triple" { 742 set newState any 743 } 744 "card" { 745 # Check to make sure it's a card with actions. 746 set id [rememberCard "$table(keyValue)$table(keySuit)"] 747 set table(keyFirstId) $id 748 set goodCard 0 749 foreach i [lindex [$w itemconf $id -tags] 4] { 750 switch -exact -- $i { 751 "clickableCard" - 752 "doubleClickableCard" - 753 "dragableCard" { 754 set goodCard 1 755 break 756 } 757 } 758 } 759 if { $goodCard } { 760 # Hilight the selected card. 761 hilightCard $table(keyFirstId) $w "" "" 762 } else { 763 set newState any 764 } 765 } 766 "move" { 767# if { [cardHasTag $w $table(keyFirstId) dragableCard] } { 768# set newId [rememberCard "$table(keyValue)$table(keySuit)"] 769# } 770 set newState any 771 } 772 "error" { 773 tableBell 774 set newState any 775 } 776 } 777 # 778 # Commit the action. 779 # 780 set table(keyState) $newState 781 set table(keySubState) $newSubState 782} 783 784proc resetKeyState {} { 785 global table 786 787 set table(keySubState) any 788 set table(keyState) any 789 set table(keySuit) "x" 790 set table(keyValue) "x" 791 set table(keyFirstId) "x" 792} 793 794 795# 796# outlineableCard 797# 798proc enterHilightCard {itemId w x y} { 799 global game 800 # Avoid hilighting cards that will be obscured by other cards. 801 if { $game(status) == "dealing" } { return } 802 hilightCard $itemId $w $x $y 803} 804proc leaveUnhilightCard {itemId w x y} { 805 global table 806 807 if { $table(keyFirstId) == $itemId } { return } 808 # A bug was happening where sometimes we'd get a null itemId 809 # when redealing the tableau. It's not consistently repeatable. 810 # Avoid the problem 811 if { $itemId == "" } { return } 812 unhilightCard $itemId $w $x $y 813} 814 815proc hilightCard {itemId w x y} { 816 global table items 817 # puts "hilightCard $itemId $w $x $y" 818 if { [llength $itemId] != 1 } { error "hilightCard: called with list of items." } 819 $table(preActionProc) outlineEnter 820 $w itemconfig $itemId \ 821 -foreground $items($itemId,highFg) \ 822 -background $items($itemId,highBg) 823} 824proc unhilightCard {itemId w x y} { 825 global table items 826 827 if { [llength $itemId] < 1 } { error "unhilightCard: called with empty items." } 828 if { [llength $itemId] > 1 } { error "unhilightCard: called with list of items." } 829 $table(preActionProc) outlineLeave 830 $w itemconfig $itemId \ 831 -foreground $items($itemId,normFg) \ 832 -background $items($itemId,normBg) 833} 834proc checkHilighting {w x y} { 835 # Items come back to front, so reverse them. 836 set ids [lreverse [$w find overlapping $x $y $x $y]] 837 foreach id $ids { 838 set tags [lindex [$w itemconfig $id -tags] 4] 839 if { ([lsearch -exact $tags outlineableCard] != -1) || 840 ([lsearch -exact $tags dragableCard] != -1)} { 841 hilightCard $id $w $x $y 842 return 843 } 844 } 845} 846 847# 848# dragableCard 849# 850proc defaultDragableCardPress {itemId w x y} { 851 global table items 852 853 $table(preActionProc) dragPress 854 set table(dragging) 1 855 856 unhilightCard $itemId $w $x $y 857 858 $w dtag selected 859 $w addtag selected withtag $itemId 860 set friends [$items($itemId,dragFindFriendsProc) $itemId $w $x $y $items($itemId,dragFindFriendsClosure)] 861 set table(dragFriends) $friends 862 # NEEDSWORK: Tk3.2 bug. We shouldn't have to loop here, but 863 # it seems that "$w addtag selected withtag $friends" 864 # just adds one of the list. 865 foreach i $friends { 866 $w addtag selected withtag $i 867 } 868 $w raise selected 869 set table(dragLastX) $x 870 set table(dragLastY) $y 871 set table(dragLastHit) {} 872 set startXY [lrange [$w bbox $itemId] 0 1] 873 set table(dragInitialX) [lindex $startXY 0] 874 set table(dragInitialY) [lindex $startXY 1] 875} 876proc defaultDragableCardMove {itemId w x y} { 877 global table items 878 # debugLog "defaultDragableCardMove $itemId $w $x $y" 879 $w move selected [expr $x-$table(dragLastX)] [expr $y-$table(dragLastY)] 880 set table(dragLastX) $x 881 set table(dragLastY) $y 882 883 set hit [checkForDropableHit $itemId $w] 884 if { $hit != $table(dragLastHit) } { 885 if { $table(dragLastHit) != {} } { 886 $items($table(dragLastHit),dragTargetLeaveProc) $itemId $w $x $y $table(dragLastHit) 887 } 888 if { $hit != {} } { 889 $items($hit,dragTargetEnterProc) $itemId $w $x $y $hit 890 } 891 set table(dragLastHit) $hit 892 } 893} 894 895proc checkForDropableHit { itemId w } { 896 global table items 897 898 # 899 # Check for hit over possible dropableCard. 900 # 901 set bbox [$w bbox $itemId] 902 set bbox_t [expr [lindex $bbox 0]+$table(cardOverlap)] 903 set bbox_l [expr [lindex $bbox 1]+$table(cardOverlap)] 904 set bbox_b [expr [lindex $bbox 2]-$table(cardOverlap)] 905 set bbox_r [expr [lindex $bbox 3]-$table(cardOverlap)] 906 set hits [$w find overlapping $bbox_t $bbox_l $bbox_b $bbox_r] 907 # 908 # Go through the list of hits 909 # (in reverse order---we assume the list is sorted back-to-front). 910 # Quit if we get a good hit. 911 # 912 foreach hit [lreverse $hits] { 913 # 914 # Now check to see if we're over a dropableCard. 915 # (Sigh, there doesn't seem any way to query the tags 916 # of an object.) 917 # 918 if { ([string match $items($hit,dragTargetAcceptGlob) $items($itemId,subtype)] == 0) } { continue } 919 if { [$items($hit,dragTargetAcceptProc) $w $hit $itemId $table(dragFriends)] } { 920 # puts stderr "$itemId: $items($itemId,cardVS),$table(selectedCount) matches $hit: $table($hit,dropAccepts) of $hits" 921 return $hit; 922 } 923 } 924 return {} 925} 926 927proc defaultDragableCardRelease {itemId w x y} { 928 global items table 929 # debugLog "defaultDragableCardRelease $itemId $w $x $y" 930 # Dropping the card somewhere? 931 if { $table(dragLastHit) != {} } { 932 # yes 933 $items($table(dragLastHit),dragTargetLeaveProc) $itemId $w $x $y $table(dragLastHit) 934 playCardOnCard $w $itemId $table(dragFriends) $table(dragLastHit) 935 } elseif { $table(dragging) != 0 } { 936 # no, send it home 937 originalPlaceDragProc $itemId $w $x $y selected {} 938 } 939 # Redo the hilighting. 940 checkHilighting $w $x $y 941} 942 943 944# 945# playCardOnCard 946# 947proc playCardOnCard {w top topFriends newBottom} { 948 global items 949 # 950 # debugLog "playCardOnCard $w $top $topFriends $newBottom" 951 set oldBottom $items($top,parent) 952 if { $oldBottom != {} } { 953 $items($oldBottom,orphanChildProc) $w $oldBottom $top $topFriends $items($oldBottom,orphanChildClosure) 954 } 955 # 2. Connect top to bottom. 956 $items($newBottom,adoptChildProc) $w $newBottom $top $topFriends $items($newBottom,adoptChildClosure) 957} 958 959# 960# Unconditional position card on another card. 961# 962proc moveCardOnCard {w top bottom args} { 963 global items 964 965 # debugLog "moveCardOnCard $w $top $bottom $args" 966 if {[llength $args] == 0} { 967 set topTag $top 968 } else { 969 set topTag [lindex $args 0] 970 } 971 972 set oldCoords [$w coords $top] 973 set bottomCoords [$w bbox $bottom] 974 set bottomOffset [$items($bottom,childOffsetProc)] 975 moveAllRelatively $w $topTag \ 976 [lindex $oldCoords 0] [lindex $oldCoords 1] \ 977 [expr [lindex $bottomCoords 0]+[lindex $bottomOffset 0]] \ 978 [expr [lindex $bottomCoords 1]+[lindex $bottomOffset 1]] 979 980 $w raise $top 981} 982 983 984 985proc moveAllRelatively { w items oldX oldY newX newY } { 986 # debugLog "moveAllRelatively $w $items $oldX $oldY $newX $newY" 987 $w move $items [expr $newX-$oldX] [expr $newY-$oldY] 988} 989 990 991proc figureNextValue {oldValue inc} { 992 global table 993 return [string index $table(cvalues) \ 994 [expr [string first $oldValue $table(cvalues)]+$inc]] 995} 996 997proc globNextLowerOtherColor {vs} { 998 global table 999 1000 set v [string index $vs 0] 1001 set s [string index $vs 1] 1002 1003 return "[figureNextValue $v -1]\[$table(otherColorSuits,$s)\]" 1004} 1005 1006proc lreverse {lin} { 1007 set lout {} 1008 for {set i [expr [llength $lin]-1]} { $i >= 0 } {incr i -1} { 1009 lappend lout [lindex $lin $i] 1010 } 1011 return $lout 1012} 1013 1014proc obscureTable {} { 1015 global table 1016 set w $table(id) 1017 $w create rectangle 0 0 $table(width) $table(height) \ 1018 -fill $table(bg) -tag pauseItems 1019 $w create text [expr $table(width)/2] [expr $table(height)/2] \ 1020 -anchor center -fill $table(fg) \ 1021 -text "Game paused.\nClick to continue." \ 1022 -tag pauseItems 1023} 1024 1025proc unobscureTable {} { 1026 global table 1027 $table(id) delete pauseItems 1028} 1029