diff --git a/pysollib/actions.py b/pysollib/actions.py index c6c87109..93668e6b 100644 --- a/pysollib/actions.py +++ b/pysollib/actions.py @@ -45,6 +45,7 @@ from pysolrandom import constructRandom from version import VERSION from settings import PACKAGE, PACKAGE_URL from settings import TOP_TITLE +from gamedb import GI # stats imports from stats import PysolStatsFormatter @@ -66,6 +67,7 @@ from pysoltk import ColorsDialog from pysoltk import FontsDialog from pysoltk import EditTextDialog from pysoltk import TOOLBAR_BUTTONS +from pysoltk import create_find_card_dialog, connect_game_find_card_dialog, destroy_find_card_dialog from help import helpAbout, helpHTML gettext = _ @@ -95,6 +97,7 @@ class PysolMenubarActions: quickplay = 0, demo = 0, highlight_piles = 0, + find_card = 0, rules = 0, pause = 0, ) @@ -188,9 +191,12 @@ class PysolMenubarActions: tkopt.splashscreen.set(opt.splashscreen) tkopt.sticky_mouse.set(opt.sticky_mouse) tkopt.negative_bottom.set(opt.negative_bottom) - for w in TOOLBAR_BUTTONS: tkopt.toolbar_vars[w].set(opt.toolbar_vars[w]) + if game.gameinfo.category == GI.GC_FRENCH: + connect_game_find_card_dialog(game) + else: + destroy_find_card_dialog() # will get called after connectGame() def updateRecentGamesMenu(self, gameids): @@ -274,6 +280,8 @@ class PysolMenubarActions: ms.quickplay = 1 if opt.highlight_piles and game.getHighlightPilesStacks(): ms.highlight_piles = 1 + if game.gameinfo.category == GI.GC_FRENCH: + ms.find_card = 1 if game.app.getGameRulesFilename(game.id): # note: this may return "" ms.rules = 1 if not game.finished: @@ -301,6 +309,7 @@ class PysolMenubarActions: # Assist menu self.setMenuState(ms.hint, "assist.hint") self.setMenuState(ms.highlight_piles, "assist.highlightpiles") + self.setMenuState(ms.find_card, "assist.findcard") self.setMenuState(ms.demo, "assist.demo") self.setMenuState(ms.demo, "assist.demoallgames") # Options menu @@ -589,6 +598,10 @@ class PysolMenubarActions: if self._cancelDrag(break_pause=False): return self.mPlayerStats(mode=106) + def mFindCard(self, *args): + create_find_card_dialog(self.game.top, self.game, + self.app.getFindCardImagesDir()) + def mEditGameComment(self, *args): if self._cancelDrag(break_pause=False): return game, gi = self.game, self.game.gameinfo diff --git a/pysollib/app.py b/pysollib/app.py index 94fd8d07..ca587f9e 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -892,6 +892,9 @@ class Application: return None return d + def getFindCardImagesDir(self): + return self._getImagesDir('cards') + def getToolbarImagesDir(self): if self.opt.toolbar_size: size = 'large' diff --git a/pysollib/game.py b/pysollib/game.py index 8b050dd5..e352d447 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -142,6 +142,7 @@ class Game: # data = [], # raw data ) + self.event_handled = False # if click event handled by Stack (???) self.reset() # main constructor @@ -214,9 +215,13 @@ class Game: def initBindings(self): # note: a Game is only allowed to bind self.canvas and not to self.top - bind(self.canvas, "<1>", self.clickHandler) + ##bind(self.canvas, "<1>", self.clickHandler) bind(self.canvas, "<2>", self.clickHandler) - bind(self.canvas, "<3>", self.clickHandler) + ##bind(self.canvas, "<3>", self.clickHandler) + ##bind(self.canvas, "", self.undoHandler) + ##bind(self.canvas, "", self.undoHandler) + bind(self.canvas, "<1>", self.undoHandler) + bind(self.canvas, "<3>", self.redoHandler) bind(self.top, '', self._unmapHandler) def __createCommon(self, app): @@ -721,12 +726,29 @@ class Game: # # UI & graphics support # - - def clickHandler(self, *args): + def _defaultHandler(self): self.interruptSleep() self.deleteStackDesc() if self.demo: self.stopDemo() + + def clickHandler(self, event): + self._defaultHandler() + self.event_handled = False + return EVENT_PROPAGATE + + def undoHandler(self, event): + self._defaultHandler() + if not self.event_handled: + self.app.menubar.mUndo() + self.event_handled = False + return EVENT_PROPAGATE + + def redoHandler(self, event): + self._defaultHandler() + if not self.event_handled: + self.app.menubar.mRedo() + self.event_handled = False return EVENT_PROPAGATE def updateStatus(self, **kw): @@ -1392,6 +1414,16 @@ for %d moves. return self.dealCards(sound=sound) return 0 + ## for find_card_dialog + def highlightCard(self, suit, rank): + col = self.app.opt.highlight_samerank_colors[3] + info = [] + for s in self.allstacks: + for c in s.cards: + if c.suit == suit and c.rank == rank: + if s.basicShallHighlightSameRank(c): + info.append((s, c, c, col)) + return self._highlightCards(info, 0) ### highlight all moveable piles def getHighlightPilesStacks(self): @@ -1429,12 +1461,15 @@ for %d moves. if not items: return 0 self.canvas.update_idletasks() - self.sleep(sleep) - items.reverse() - for r in items: - r.delete() - self.canvas.update_idletasks() - return EVENT_HANDLED + if sleep: + self.sleep(sleep) + items.reverse() + for r in items: + r.delete() + self.canvas.update_idletasks() + return EVENT_HANDLED + else: + return items def highlightNotMatching(self): if self.demo: diff --git a/pysollib/games/harp.py b/pysollib/games/harp.py index e0d244db..37ed6028 100644 --- a/pysollib/games/harp.py +++ b/pysollib/games/harp.py @@ -108,12 +108,17 @@ class DoubleKlondikeByThrees(DoubleKlondike): # /*********************************************************************** # // Gargantua (Double Klondike with one redeal) +# // Pantagruel # ************************************************************************/ class Gargantua(DoubleKlondike): def createGame(self): DoubleKlondike.createGame(self, max_rounds=2) +class Pantagruel(DoubleKlondike): + RowStack_Class = AC_RowStack + def createGame(self): + DoubleKlondike.createGame(self, max_rounds=1) # /*********************************************************************** # // Harp (Double Klondike with 10 non-king rows and no redeal) @@ -311,5 +316,7 @@ registerGame(GameInfo(562, Delivery, "Delivery", registerGame(GameInfo(590, ChineseKlondike, "Chinese Klondike", GI.GT_KLONDIKE, 3, -1, GI.SL_BALANCED, suits=(0, 1, 2) )) +registerGame(GameInfo(591, Pantagruel, "Pantagruel", + GI.GT_KLONDIKE, 2, 0, GI.SL_BALANCED)) diff --git a/pysollib/games/mahjongg/mahjongg.py b/pysollib/games/mahjongg/mahjongg.py index 3f542d74..c994ce7d 100644 --- a/pysollib/games/mahjongg/mahjongg.py +++ b/pysollib/games/mahjongg/mahjongg.py @@ -112,6 +112,9 @@ class Mahjongg_Foundation(OpenStack): fnds[n].group.tkraise() return + def getHelp(self): + return '' + # /*********************************************************************** # // @@ -211,6 +214,7 @@ class Mahjongg_RowStack(OpenStack): bind(group, "", self.__controlclickEventHandler) def __defaultClickEventHandler(self, event, handler): + self.game.event_handled = True # for Game.undoHandler if self.game.demo: self.game.stopDemo(event) if self.game.busy: @@ -527,7 +531,7 @@ class AbstractMahjonggGame(Game): # i = factorial(len(free_stacks))/2/factorial(len(free_stacks)-2) old_pairs = [] - for _ in xrange(i): + for j in xrange(i): nc = new_cards[:] while True: # create uniq pair diff --git a/pysollib/games/picturegallery.py b/pysollib/games/picturegallery.py index 4cf31271..b1582fbe 100644 --- a/pysollib/games/picturegallery.py +++ b/pysollib/games/picturegallery.py @@ -394,6 +394,7 @@ class MountOlympus_RowStack(SS_RowStack): class MountOlympus(Game): + RowStack_Class = MountOlympus_RowStack def createGame(self): # create layout @@ -415,7 +416,7 @@ class MountOlympus(Game): x += l.XS x, y = l.XM, l.YM+2*l.YS for i in range(9): - s.rows.append(MountOlympus_RowStack(x, y, self, dir=-2)) + s.rows.append(self.RowStack_Class(x, y, self, dir=-2)) x += l.XS s.talon=DealRowTalonStack(l.XM, l.YM, self) l.createText(s.talon, 's') @@ -446,7 +447,16 @@ class MountOlympus(Game): (card1.rank + 2 == card2.rank or card2.rank + 2 == card1.rank)) +class Zeus_RowStack(MountOlympus_RowStack): + def acceptsCards(self, from_stack, cards): + if not MountOlympus_RowStack.acceptsCards(self, from_stack, cards): + return False + if not self.cards: + return cards[0].rank in (QUEEN, KING) + return True + class Zeus(MountOlympus): + RowStack_Class = Zeus_RowStack def startGame(self): self.s.talon.dealRow(rows=self.s.foundations, frames=0) self.startDealSample() diff --git a/pysollib/games/pyramid.py b/pysollib/games/pyramid.py index aad9d9af..68908e76 100644 --- a/pysollib/games/pyramid.py +++ b/pysollib/games/pyramid.py @@ -183,7 +183,7 @@ class Pyramid(Game): w = l.XM + max_rows*l.XS h = l.YM + 4*l.YS if reserves: - h += l.YS+4*l.YOFFSET + h += l.YS+2*l.YOFFSET self.setSize(w, h) # create stacks @@ -331,6 +331,53 @@ class Thirteen(Pyramid): self.s.talon.dealCards() # deal first card to WasteStack +# /*********************************************************************** +# // Thirteens +# ************************************************************************/ + +class Thirteens(Pyramid): + + + def createGame(self): + # create layout + l, s = Layout(self), self.s + + # set window + self.setSize(l.XM+5*l.XS, l.YM+4*l.YS) + + # create stacks + x, y = l.XM, l.YM + for i in range(2): + x = l.XM + for j in range(5): + s.rows.append(Giza_Reserve(x, y, self, max_accept=1)) + x += l.XS + y += l.YS + x, y = l.XM, self.height-l.YS + s.talon = TalonStack(x, y, self) + l.createText(s.talon, 'n') + x, y = self.width-l.XS, self.height-l.YS + s.foundations.append(Pyramid_Foundation(x, y, self, + suit=ANY_SUIT, dir=0, base_rank=ANY_RANK, + max_move=0, max_cards=52)) + + # define stack-groups + l.defaultStackGroups() + + def startGame(self): + self.startDealSample() + self.s.talon.dealRow() + + def fillStack(self, stack): + if stack in self.s.rows: + if not stack.cards and self.s.talon.cards: + old_state = self.enterState(self.S_FILL) + self.s.talon.flipMove() + self.s.talon.moveMove(1, stack) + self.leaveState(old_state) + + + # register the game registerGame(GameInfo(38, Pyramid, "Pyramid", GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK)) @@ -338,8 +385,10 @@ registerGame(GameInfo(193, RelaxedPyramid, "Relaxed Pyramid", GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2, GI.SL_MOSTLY_LUCK)) ##registerGame(GameInfo(44, Thirteen, "Thirteen", ## GI.GT_PAIRING_TYPE, 1, 0)) -registerGame(GameInfo(591, Giza, "Giza", +registerGame(GameInfo(592, Giza, "Giza", GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED)) +registerGame(GameInfo(593, Thirteens, "Thirteens", + GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK)) diff --git a/pysollib/games/sultan.py b/pysollib/games/sultan.py index 19bf83dd..b1c2930e 100644 --- a/pysollib/games/sultan.py +++ b/pysollib/games/sultan.py @@ -334,6 +334,7 @@ class IdleAces(Game): # /*********************************************************************** # // Lady of the Manor +# // Archway # ************************************************************************/ class LadyOfTheManor_RowStack(BasicRowStack): diff --git a/pysollib/pysolrandom.py b/pysollib/pysolrandom.py index ff2c793a..c3178ea4 100644 --- a/pysollib/pysolrandom.py +++ b/pysollib/pysolrandom.py @@ -38,9 +38,12 @@ import sys, os, re, time, types import random -##---------------------------------------------------------------------- -class PysolRandom(random.Random): +# /*********************************************************************** +# // system based random (need python >= 2.3) +# ************************************************************************/ + +class SysRandom(random.Random): #MAX_SEED = 0L #MAX_SEED = 0xffffffffffffffffL # 64 bits MAX_SEED = 100000000000000000000L # 20 digits @@ -91,7 +94,7 @@ class PysolRandom(random.Random): # // We use a seed of type long in the range [0, MAX_SEED]. # ************************************************************************/ -class PysolRandomMFX: +class MFXRandom: MAX_SEED = 0L ORIGIN_UNKNOWN = 0 @@ -188,12 +191,36 @@ class PysolRandomMFX: seq[n], seq[j] = seq[j], seq[n] n = n - 1 + +# /*********************************************************************** +# // Linear Congruential random generator +# // +# // Knuth, Donald.E., "The Art of Computer Programming,", Vol 2, +# // Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998, +# // p. 106 (line 26) & p. 108 +# ************************************************************************/ + +class LCRandom64(MFXRandom): + MAX_SEED = 0xffffffffffffffffL # 64 bits + + def str(self, seed): + s = repr(long(seed)) + if s[-1:] == "L": + s = s[:-1] + s = "0"*(20-len(s)) + s + return s + + def random(self): + self.seed = (self.seed*6364136223846793005L + 1L) & self.MAX_SEED + return ((self.seed >> 21) & 0x7fffffffL) / 2147483648.0 + + # /*********************************************************************** # // Linear Congruential random generator # // In PySol this is only used for 0 <= seed <= 32000. # ************************************************************************/ -class LCRandom31(PysolRandomMFX): +class LCRandom31(MFXRandom): MAX_SEED = 0x7fffffffL # 31 bits def str(self, seed): @@ -207,6 +234,9 @@ class LCRandom31(PysolRandomMFX): self.seed = (self.seed*214013L + 2531011L) & self.MAX_SEED return a + (int(self.seed >> 16) % (b+1-a)) +# select +##PysolRandom = LCRandom64 +PysolRandom = SysRandom # /*********************************************************************** # // PySol support code diff --git a/pysollib/stack.py b/pysollib/stack.py index 5f6a223b..10d386aa 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -895,6 +895,7 @@ class Stack: # def __defaultClickEventHandler(self, event, handler, start_drag=0, cancel_drag=1): + self.game.event_handled = True # for Game.clickHandler if self.game.demo: self.game.stopDemo(event) self.game.interruptSleep() diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py index 34076b81..ea820be5 100644 --- a/pysollib/tk/menubar.py +++ b/pysollib/tk/menubar.py @@ -315,6 +315,7 @@ class PysolMenubar(PysolMenubarActions): menu = MfxMenu(self.__menubar, label=n_("&Assist")) menu.add_command(label=n_("&Hint"), command=self.mHint, accelerator="H") menu.add_command(label=n_("Highlight p&iles"), command=self.mHighlightPiles, accelerator="I") + menu.add_command(label=n_("Find card"), command=self.mFindCard, accelerator="F") menu.add_separator() menu.add_command(label=n_("&Demo"), command=self.mDemo, accelerator=m+"D") menu.add_command(label=n_("Demo (&all games)"), command=self.mMixedDemo) @@ -417,6 +418,7 @@ class PysolMenubar(PysolMenubarActions): ##self._bindKey("", "Shift_L", self.mHighlightPiles) ##self._bindKey("", "Shift_R", self.mHighlightPiles) self._bindKey("", "i", self.mHighlightPiles) + self._bindKey("", "f", self.mFindCard) self._bindKey(ctrl, "d", self.mDemo) self._bindKey(ctrl, "e", self.mSelectCardsetDialog) self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented diff --git a/pysollib/tk/tkwidget.py b/pysollib/tk/tkwidget.py index 1b24da9c..916553e0 100644 --- a/pysollib/tk/tkwidget.py +++ b/pysollib/tk/tkwidget.py @@ -39,6 +39,9 @@ __all__ = ['MfxMessageDialog', 'MfxTooltip', 'MfxScrolledCanvas', 'StackDesc', + 'create_find_card_dialog', + 'connect_game_find_card_dialog', + 'destroy_find_card_dialog', ] # imports @@ -55,7 +58,7 @@ from tkconst import EVENT_HANDLED, EVENT_PROPAGATE from tkutil import after, after_idle, after_cancel from tkutil import bind, unbind_destroy, makeImage from tkutil import makeToplevel, setTransient -from tkcanvas import MfxCanvas +from tkcanvas import MfxCanvas, MfxCanvasGroup, MfxCanvasImage, MfxCanvasRectangle # /*********************************************************************** @@ -78,23 +81,24 @@ class MfxDialog: # ex. _ToplevelDialog bind(self.top, "WM_DELETE_WINDOW", self.wmDeleteWindow) # - def mainloop(self, focus=None, timeout=0): + def mainloop(self, focus=None, timeout=0, transient=True): bind(self.top, "", self.mCancel) bind(self.top, '', self.altKeyEvent) # for accelerators if focus is not None: focus.focus() - setTransient(self.top, self.parent) - try: - self.top.grab_set() - except Tkinter.TclError: - if traceback: traceback.print_exc() - pass - if timeout > 0: - self.timer = after(self.top, timeout, self.mTimeout) - try: self.top.mainloop() - except SystemExit: - pass - self.destroy() + if transient: + setTransient(self.top, self.parent) + try: + self.top.grab_set() + except Tkinter.TclError: + if traceback: traceback.print_exc() + pass + if timeout > 0: + self.timer = after(self.top, timeout, self.mTimeout) + try: self.top.mainloop() + except SystemExit: + pass + self.destroy() def destroy(self): after_cancel(self.timer) @@ -716,5 +720,203 @@ class StackDesc: self.label.unbind('', b) +# /*********************************************************************** +# // +# ************************************************************************/ + +class FindCardDialog(MfxDialog): + SUIT_IMAGES = {} # key: (suit, color) + RANK_IMAGES = {} # key: (rank, color) + + def __init__(self, parent, game, dir, title='Find card', **kw): + kw = self.initKw(kw) + MfxDialog.__init__(self, parent, title, kw.resizable, kw.default) + top_frame, bottom_frame = self.createFrames(kw) + self.createBitmaps(top_frame, kw) + self.images_dir = dir + #self.default_color = top_frame['bg'] + #self.bg_colors = ('#f9e3d2', '#c9e3d2') + #self.highlight_color = 'white' + self.label_width, self.label_height = 36, 30 + self.top_frame = top_frame + self.canvas = MfxCanvas(top_frame, bg='white') + self.canvas.pack(expand=True, fill='both') + # + self.button = kw.default + self.labels = [] + self.tk_images = [] + self.highlight_items = None + self.last_card = None + self.connectGame(game) + # + focus = self.createButtons(bottom_frame, kw) + ##self.mainloop(focus, kw.timeout, transient=False) + + def initKw(self, kw): + kw = KwStruct(kw, + strings=(_("&Close"),), default=0, + resizable=0, + padx=4, pady=4, + separatorwidth=0, + ) + return MfxDialog.initKw(self, kw) + + def createCardLabel(self, suit, rank, x0, y0): + dx, dy = self.label_width, self.label_height + dir = self.images_dir + images = self.tk_images + canvas = self.canvas + group = MfxCanvasGroup(canvas) + s = 'cshd'[suit] + if suit >= 2: c = 'red' + else: c = 'black' + x1, y1 = x0+dx-2, y0+dy-2 + rect = MfxCanvasRectangle(self.canvas, x0, y0, x1, y1, + width=2, fill='white', outline='white') + rect.addtag(group) + # + fn = os.path.join(dir, c+'-'+str(rank)+'.gif') + rim = FindCardDialog.RANK_IMAGES.get((rank, c)) + if not rim: + rim = Tkinter.PhotoImage(file=fn) + FindCardDialog.RANK_IMAGES[(rank, c)] = rim + fn = os.path.join(dir, 'large-'+s+'.gif') + sim = FindCardDialog.SUIT_IMAGES.get((suit, c)) + if not sim: + sim = Tkinter.PhotoImage(file=fn) + FindCardDialog.SUIT_IMAGES[(suit, c)] = sim + # + x0 = x0+(dx-rim.width()-sim.width())/2 + x, y = x0, y0+(dy-rim.height())/2 + im = MfxCanvasImage(canvas, x, y, image=rim, anchor='nw') + im.addtag(group) + x, y = x0+rim.width(), y0+(dy-sim.height())/2 + im = MfxCanvasImage(canvas, x, y, image=sim, anchor='nw') + im.addtag(group) + bind(group, '', + lambda e, suit=suit, rank=rank, rect=rect: + self.enterEvent(suit, rank, rect)) + bind(group, '', + lambda e, suit=suit, rank=rank, rect=rect: + self.leaveEvent(suit, rank, rect)) + self.labels.append(group) + def connectGame(self, game): + self.game = game + suits = game.gameinfo.suits + ranks = game.gameinfo.ranks + dx, dy = self.label_width, self.label_height + i = 0 + for suit in suits: + j = 0 + for rank in ranks: + x, y = dx*j+2, dy*i+2 + self.createCardLabel(suit=suit, rank=rank, x0=x, y0=y) + j += 1 + i += 1 + w, h = dx*j, dy*i + self.canvas.config(width=w, height=h) + + +## if self.labels: +## for l in self.labels: +## unbind_destroy(l) +## l.grid_forget() +## frame = self.top_frame +## from pysollib.util import SUITS, RANKS +## suits = game.gameinfo.suits +## ranks = game.gameinfo.ranks +## ns = 0 +## for i in suits: +## color = self.bg_colors[ns%2] +## suit = SUITS[i] +## suit_label = Tkinter.Label(frame, text=suit, bg=color) +## suit_label.grid(row=i, column=0, sticky='ew') +## self.labels.append(suit_label) +## ns += 1 +## nk = 0 +## for j in ranks: +## color = self.bg_colors[(ns+nk)%2] +## rank = RANKS[j] +## rank_label = Tkinter.Label(frame, text=rank, bg=color) +## bind(rank_label, '', lambda e, label=rank_label, suit=i, rank=j: self.enterEvent(label, suit, rank)) +## bind(rank_label, '', lambda e, label=rank_label, suit=i, rank=j: self.leaveEvent(label, suit, rank)) +## self.labels.append(rank_label) +## #rank_label.config(highlightthickness=1, +## # highlightbackground='black') +## rank_label.grid(row=i, column=j+1, sticky='ew') +## nk += 1 + +## def showCard(self, suit, rank, rect): +## print suit, rank + + def enterEvent(self, suit, rank, rect): + #print 'enterEvent', suit, rank + #if (suit, rank) == self.last_card: return + self.last_card = (suit, rank) + self.highlight_items = self.game.highlightCard(suit, rank) + if not self.highlight_items: + self.highlight_items = [] +## dx, dy = self.label_width, self.label_height +## x0, y0 = dx*rank, dy*suit +## x1, y1 = dx*(rank+1), dy*(suit+1) + rect.config(outline='red') + #item = MfxCanvasRectangle(self.canvas, x0, y0, x1, y1, + # width=2, fill=None, outline='red') + #self.highlight_items.append(item) + + def leaveEvent(self, suit, rank, rect): + #print 'leaveEvent', suit, rank + #if (suit, rank) == self.last_card: return + for i in self.highlight_items: + i.delete() + #self.game.canvas.update_idletasks() + #self.canvas.update_idletasks() + rect.config(outline='white') + self.last_card = None + + def destroy(self): + for l in self.labels: + unbind_destroy(l) + unbind_destroy(self.top) + self.top.wm_withdraw() + self.top.destroy() + + def tkraise(self): + self.top.tkraise() + + def mDone(self, button): + self.destroy() + pass + + def wmDeleteWindow(self, *event): + self.destroy() + pass + + +find_card_dialog = None + +def create_find_card_dialog(parent, game, dir): + global find_card_dialog + try: + find_card_dialog.tkraise() + except: + ##traceback.print_exc() + find_card_dialog = FindCardDialog(parent, game, dir) + +def connect_game_find_card_dialog(game): + try: + find_card_dialog.connectGame(game) + except: + pass + +def destroy_find_card_dialog(): + global find_card_dialog + try: + find_card_dialog.destroy() + except: + ##traceback.print_exc() + pass + find_card_dialog = None +