class Pile: """A group of graphical objects.""" def __init__(self, canvas, x, y, tag=None): self.canvas = canvas self.x = x self.y = y self.objects = [] self.bottom = Bottom(self.canvas, self.x, self.y) self.group = Group(self.canvas, tag=tag) self.group.addtag_withtag(self.bottom.group) self.bindhandlers() def bindhandlers(self): self.group.bind('<1>', self.clickhandler) self.group.bind('<Double-1>', self.doubleclickhandler) def add(self, object): self.objects.append(object) self.group.addtag_withtag(object.group) self.position(object) def delete(self, object): object.group.dtag(self.group) self.objects.remove(object) def position(self, object): object.tkraise() i = self.objects.index(object) object.moveto(self.x + i * 4, self.y + i * 8) def clickhandler(self, event): pass def doubleclickhandler(self, event): pass
class Pile: """A group of graphical objects.""" def __init__(self, canvas, x, y, tag=None): self.canvas = canvas self.x = x self.y = y self.objects = [] self.bottom = Bottom(self.canvas, self.x, self.y) self.group = Group(self.canvas, tag=tag) self.group.addtag_withtag(self.bottom.group) self.bindhandlers() def bindhandlers(self): self.group.bind('<1>', self.clickhandler) self.group.bind('<Double-1>', self.doubleclickhandler) def add(self, object): self.objects.append(object) self.group.addtag_withtag(object.group) self.position(object) def delete(self, object): object.group.dtag(self.group) self.objects.remove(object) def position(self, object): object.tkraise() i = self.objects.index(object) object.moveto(self.x + i*4, self.y + i*8) def clickhandler(self, event): pass def doubleclickhandler(self, event): pass
class Stack: """A generic stack of cards. This is used as a base class for all other stacks (e.g. the deck, the suit stacks, and the row stacks). Public methods: add(card) -- add a card to the stack delete(card) -- delete a card from the stack showtop() -- show the top card (if any) face up deal() -- delete and return the top card, or None if empty Method that subclasses may override: position(card) -- move the card to its proper (x, y) position The default position() method places all cards at the stack's own (x, y) position. userclickhandler(), userdoubleclickhandler() -- called to do subclass specific things on single and double clicks The default user (single) click handler shows the top card face up. The default user double click handler calls the user single click handler. usermovehandler(cards) -- called to complete a subpile move The default user move handler moves all moved cards back to their original position (by calling the position() method). Private methods: clickhandler(event), doubleclickhandler(event), motionhandler(event), releasehandler(event) -- event handlers The default event handlers turn the top card of the stack with its face up on a (single or double) click, and also support moving a subpile around. startmoving(event) -- begin a move operation finishmoving() -- finish a move operation """ def __init__(self, x, y, game=None): """Stack constructor. Arguments are the stack's nominal x and y position (the top left corner of the first card placed in the stack), and the game object (which is used to get the canvas; subclasses use the game object to find other stacks). """ self.x = x self.y = y self.game = game self.cards = [] self.group = Group(self.game.canvas) self.group.bind('<1>', self.clickhandler) self.group.bind('<Double-1>', self.doubleclickhandler) self.group.bind('<B1-Motion>', self.motionhandler) self.group.bind('<ButtonRelease-1>', self.releasehandler) self.makebottom() def makebottom(self): pass def __repr__(self): """Return a string for debug print statements.""" return "%s(%d, %d)" % (self.__class__.__name__, self.x, self.y) # Public methods def add(self, card): self.cards.append(card) card.tkraise() self.position(card) self.group.addtag_withtag(card.group) def delete(self, card): self.cards.remove(card) card.group.dtag(self.group) def showtop(self): if self.cards: self.cards[-1].showface() def deal(self): if not self.cards: return None card = self.cards[-1] self.delete(card) return card # Subclass overridable methods def position(self, card): card.moveto(self.x, self.y) def userclickhandler(self): self.showtop() def userdoubleclickhandler(self): self.userclickhandler() def usermovehandler(self, cards): for card in cards: self.position(card) # Event handlers def clickhandler(self, event): self.finishmoving() # In case we lost an event self.userclickhandler() self.startmoving(event) def motionhandler(self, event): self.keepmoving(event) def releasehandler(self, event): self.keepmoving(event) self.finishmoving() def doubleclickhandler(self, event): self.finishmoving() # In case we lost an event self.userdoubleclickhandler() self.startmoving(event) # Move internals moving = None def startmoving(self, event): self.moving = None tags = self.game.canvas.gettags('current') for i in range(len(self.cards)): card = self.cards[i] if card.group.tag in tags: break else: return if not card.face_shown: return self.moving = self.cards[i:] self.lastx = event.x self.lasty = event.y for card in self.moving: card.tkraise() def keepmoving(self, event): if not self.moving: return dx = event.x - self.lastx dy = event.y - self.lasty self.lastx = event.x self.lasty = event.y if dx or dy: for card in self.moving: card.moveby(dx, dy) def finishmoving(self): cards = self.moving self.moving = None if cards: self.usermovehandler(cards)
#! /usr/bin/env python