From 8fcb8116086a732b4b22716852f89e6a83affee4 Mon Sep 17 00:00:00 2001 From: Shlomi Fish Date: Fri, 19 Feb 2016 17:55:30 +0200 Subject: [PATCH] Move duplicate code to the menuar base class. --- pysollib/tile/menubar.py | 908 --------------------------------- pysollib/tk/menubar.py | 908 --------------------------------- pysollib/ui/tktile/menubar.py | 917 ++++++++++++++++++++++++++++++++++ 3 files changed, 917 insertions(+), 1816 deletions(-) diff --git a/pysollib/tile/menubar.py b/pysollib/tile/menubar.py index 15967942..7104db5f 100644 --- a/pysollib/tile/menubar.py +++ b/pysollib/tile/menubar.py @@ -82,914 +82,6 @@ class PysolMenubarTk(PysolMenubarTkCommon): # create the menubar # - def _createMenubar(self): - MfxMenubar.addPath = self._addPath - kw = { "name": "menubar" } - self.menubar = MfxMenubar(self.top, **kw) - - # init keybindings - bind(self.top, "", self._keyPressHandler) - - m = "Ctrl-" - if sys.platform == "darwin": m = "Cmd-" - - if WIN_SYSTEM == "aqua": - applemenu=MfxMenu(self.menubar, "apple") - applemenu.add_command(label=_("&About ")+TITLE, command=self.mHelpAbout) - - menu = MfxMenu(self.menubar, n_("&File")) - menu.add_command(label=n_("&New game"), command=self.mNewGame, accelerator="N") - submenu = MfxMenu(menu, label=n_("R&ecent games")) - ##menu.add_command(label=n_("Select &random game"), command=self.mSelectRandomGame, accelerator=m+"R") - submenu = MfxMenu(menu, label=n_("Select &random game")) - submenu.add_command(label=n_("&All games"), command=lambda : self.mSelectRandomGame('all'), accelerator=m+"R") - submenu.add_command(label=n_("Games played and &won"), command=lambda : self.mSelectRandomGame('won')) - submenu.add_command(label=n_("Games played and ¬ won"), command=lambda : self.mSelectRandomGame('not won')) - submenu.add_command(label=n_("Games not &played"), command=lambda : self.mSelectRandomGame('not played')) - menu.add_command(label=n_("Select game by nu&mber..."), command=self.mSelectGameById, accelerator=m+"M") - menu.add_separator() - submenu = MfxMenu(menu, label=n_("Fa&vorite games")) - menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor) - menu.add_command(label=n_("Remove &from favorites"), command=self.mDelFavor) - menu.add_separator() - menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O") - menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S") - menu.add_command(label=n_("Save &as..."), command=self.mSaveAs) - menu.add_command(label=n_("E&xport current layout..."), command=self.mExportCurrentLayout) - menu.add_separator() - menu.add_command(label=n_("&Hold and quit"), command=self.mHoldAndQuit, accelerator=m+"X") - if WIN_SYSTEM != "aqua": - menu.add_command(label=n_("&Quit"), command=self.mQuit, accelerator=m+"Q") - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Select")) - self._addSelectGameMenu(menu) - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Edit")) - menu.add_command(label=n_("&Undo"), command=self.mUndo, accelerator="Z") - menu.add_command(label=n_("&Redo"), command=self.mRedo, accelerator="R") - menu.add_command(label=n_("Redo &all"), command=self.mRedoAll) - - menu.add_separator() - submenu = MfxMenu(menu, label=n_("&Set bookmark")) - for i in range(9): - label = _("Bookmark %d") % (i + 1) - submenu.add_command(label=label, command=lambda i=i: self.mSetBookmark(i)) - submenu = MfxMenu(menu, label=n_("Go&to bookmark")) - for i in range(9): - label = _("Bookmark %d") % (i + 1) - acc = m + "%d" % (i + 1) - submenu.add_command(label=label, command=lambda i=i: self.mGotoBookmark(i), accelerator=acc) - menu.add_command(label=n_("&Clear bookmarks"), command=self.mClearBookmarks) - menu.add_separator() - - menu.add_command(label=n_("Restart"), command=self.mRestart, accelerator=m+"G") - - menu.add_separator() - menu.add_command(label=n_("Solitaire &Wizard"), command=self.mWizard) - menu.add_command(label=n_("&Edit current game"), command=self.mWizardEdit) - - menu = MfxMenu(self.menubar, label=n_("&Game")) - menu.add_command(label=n_("&Deal cards"), command=self.mDeal, accelerator="D") - menu.add_command(label=n_("&Auto drop"), command=self.mDrop, accelerator="A") - menu.add_command(label=n_("Shu&ffle tiles"), command=self.mShuffle, accelerator="F") - menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P") - #menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P") - menu.add_separator() - menu.add_command(label=n_("S&tatus..."), command=lambda : self.mPlayerStats(mode=100), accelerator=m+"Y") - menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment) - menu.add_separator() - menu.add_command(label=n_("&Statistics..."), command=self.mPlayerStats, accelerator=m+"T") - menu.add_command(label=n_("Log..."), command=lambda : self.mPlayerStats(mode=103)) - menu.add_separator() - menu.add_command(label=n_("D&emo statistics"), command=lambda : self.mPlayerStats(mode=1101)) - - 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="F3") - 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) - if USE_FREECELL_SOLVER: - menu.add_command(label=n_("&Solver"), command=self.mSolver) - else: - menu.add_command(label=n_("&Solver"), state='disabled') - menu.add_separator() - menu.add_command(label=n_("&Piles description"), command=self.mStackDesk, accelerator="F2") - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Options")) - menu.add_command(label=n_("&Player options..."), command=self.mOptPlayerOptions) - submenu = MfxMenu(menu, label=n_("&Automatic play")) - submenu.add_checkbutton(label=n_("Auto &face up"), variable=self.tkopt.autofaceup, command=self.mOptAutoFaceUp) - submenu.add_checkbutton(label=n_("A&uto drop"), variable=self.tkopt.autodrop, command=self.mOptAutoDrop) - submenu.add_checkbutton(label=n_("Auto &deal"), variable=self.tkopt.autodeal, command=self.mOptAutoDeal) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Quick play"), variable=self.tkopt.quickplay, command=self.mOptQuickPlay) - submenu = MfxMenu(menu, label=n_("Assist &level")) - submenu.add_checkbutton(label=n_("Enable &undo"), variable=self.tkopt.undo, command=self.mOptEnableUndo) - submenu.add_checkbutton(label=n_("Enable &bookmarks"), variable=self.tkopt.bookmarks, command=self.mOptEnableBookmarks) - submenu.add_checkbutton(label=n_("Enable &hint"), variable=self.tkopt.hint, command=self.mOptEnableHint) - submenu.add_checkbutton(label=n_("Enable shu&ffle"), variable=self.tkopt.shuffle, command=self.mOptEnableShuffle) - submenu.add_checkbutton(label=n_("Enable highlight p&iles"), variable=self.tkopt.highlight_piles, command=self.mOptEnableHighlightPiles) - submenu.add_checkbutton(label=n_("Enable highlight &cards"), variable=self.tkopt.highlight_cards, command=self.mOptEnableHighlightCards) - submenu.add_checkbutton(label=n_("Enable highlight same &rank"), variable=self.tkopt.highlight_samerank, command=self.mOptEnableHighlightSameRank) - submenu.add_checkbutton(label=n_("Highlight &no matching"), variable=self.tkopt.highlight_not_matching, command=self.mOptEnableHighlightNotMatching) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Show removed tiles (in Mahjongg games)"), variable=self.tkopt.mahjongg_show_removed, command=self.mOptMahjonggShowRemoved) - submenu.add_checkbutton(label=n_("Show hint &arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint) - menu.add_separator() - label = n_("&Sound...") - if not self.app.audio.CAN_PLAY_SOUND: - menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog, state='disabled') - else: - menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog) - # cardsets - if USE_PIL: - submenu = MfxMenu(menu, label=n_("Card si&ze")) - submenu.add_command(label=n_("&Increase the card size"), command=self.mIncreaseCardset, accelerator=m+"+") - submenu.add_command(label=n_("&Decrease the card size"), command=self.mDecreaseCardset, accelerator=m+"-") - submenu.add_checkbutton(label=n_("&Auto scaling"), variable=self.tkopt.auto_scale, command=self.mOptAutoScale, accelerator=m+'0') - #manager = self.app.cardset_manager - #n = manager.len() - menu.add_command(label=n_("Cards&et..."), command=self.mSelectCardsetDialog, accelerator=m+"E") - menu.add_command(label=n_("Table t&ile..."), command=self.mSelectTileDialog) - # this submenu will get set by updateBackgroundImagesMenu() - submenu = MfxMenu(menu, label=n_("Card &background")) - submenu = MfxMenu(menu, label=n_("Card &view")) - submenu.add_checkbutton(label=n_("Card shado&w"), variable=self.tkopt.shadow, command=self.mOptShadow) - submenu.add_checkbutton(label=n_("Shade &legal moves"), variable=self.tkopt.shade, command=self.mOptShade) - submenu.add_checkbutton(label=n_("&Negative cards bottom"), variable=self.tkopt.negative_bottom, command=self.mOptNegativeBottom) - submenu.add_checkbutton(label=n_("Shrink face-down cards"), variable=self.tkopt.shrink_face_down, command=self.mOptShrinkFaceDown) - submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks) - submenu = MfxMenu(menu, label=n_("A&nimations")) - submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Very fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Medium"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("V&ery slow"), variable=self.tkopt.animations, value=5, command=self.mOptAnimations) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation) - if Image: - submenu.add_checkbutton(label=n_("&Winning animation"), variable=self.tkopt.win_animation, command=self.mWinAnimation) - submenu = MfxMenu(menu, label=n_("&Mouse")) - submenu.add_radiobutton(label=n_("&Drag-and-Drop"), variable=self.tkopt.mouse_type, value='drag-n-drop', command=self.mOptMouseType) - submenu.add_radiobutton(label=n_("&Point-and-Click"), variable=self.tkopt.mouse_type, value='point-n-click', command=self.mOptMouseType) - submenu.add_radiobutton(label=n_("&Sticky mouse"), variable=self.tkopt.mouse_type, value='sticky-mouse', command=self.mOptMouseType) - submenu.add_separator() - submenu.add_checkbutton(label=n_("Use mouse for undo/redo"), variable=self.tkopt.mouse_undo, command=self.mOptMouseUndo) - menu.add_separator() - menu.add_command(label=n_("&Fonts..."), command=self.mOptFonts) - menu.add_command(label=n_("&Colors..."), command=self.mOptColors) - menu.add_command(label=n_("Time&outs..."), command=self.mOptTimeouts) - menu.add_separator() - self.createThemesMenu(menu) - submenu = MfxMenu(menu, label=n_("&Toolbar")) - createToolbarMenu(self, submenu) - submenu = MfxMenu(menu, label=n_("Stat&usbar")) - submenu.add_checkbutton(label=n_("Show &statusbar"), variable=self.tkopt.statusbar, command=self.mOptStatusbar) - submenu.add_checkbutton(label=n_("Show &number of cards"), variable=self.tkopt.num_cards, command=self.mOptNumCards) - submenu.add_checkbutton(label=n_("Show &help bar"), variable=self.tkopt.helpbar, command=self.mOptHelpbar) - if not USE_PIL: - menu.add_checkbutton(label=n_("Save games &geometry"), variable=self.tkopt.save_games_geometry, command=self.mOptSaveGamesGeometry) - menu.add_checkbutton(label=n_("&Demo logo"), variable=self.tkopt.demo_logo, command=self.mOptDemoLogo) - menu.add_checkbutton(label=n_("Startup splash sc&reen"), variable=self.tkopt.splashscreen, command=self.mOptSplashscreen) -### menu.add_separator() -### menu.add_command(label="Save options", command=self.mOptSave) - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Help")) - menu.add_command(label=n_("&Contents"), command=self.mHelp, accelerator=m+"F1") - menu.add_command(label=n_("&How to play"), command=self.mHelpHowToPlay) - menu.add_command(label=n_("&Rules for this game"), command=self.mHelpRules, accelerator="F1") - menu.add_command(label=n_("&License terms"), command=self.mHelpLicense) - ##menu.add_command(label=n_("What's &new ?"), command=self.mHelpNews) - if WIN_SYSTEM != "aqua": - menu.add_separator() - menu.add_command(label=n_("&About ")+TITLE+"...", command=self.mHelpAbout) - - MfxMenubar.addPath = None - - ### FIXME: all key bindings should be *added* to keyPressHandler - ctrl = "Control-" - if sys.platform == "darwin": ctrl = "Command-" - self._bindKey("", "n", self.mNewGame) - self._bindKey(ctrl, "w", self.mSelectGameDialog) - self._bindKey(ctrl, "v", self.mSelectGameDialogWithPreview) - self._bindKey(ctrl, "r", lambda e: self.mSelectRandomGame()) - self._bindKey(ctrl, "m", self.mSelectGameById) - self._bindKey(ctrl, "n", self.mNewGameWithNextId) - self._bindKey(ctrl, "o", self.mOpen) - self._bindKey(ctrl, "s", self.mSave) - self._bindKey(ctrl, "x", self.mHoldAndQuit) - self._bindKey(ctrl, "q", self.mQuit) - self._bindKey("", "z", self.mUndo) - self._bindKey("", "BackSpace", self.mUndo) # undocumented - self._bindKey("", "KP_Enter", self.mUndo) # undocumented - self._bindKey("", "r", self.mRedo) - self._bindKey(ctrl, "g", self.mRestart) - self._bindKey("", "space", self.mDeal) # undocumented - self._bindKey(ctrl, "y", lambda e: self.mPlayerStats(mode=100)) - self._bindKey(ctrl, "t", lambda e: self.mPlayerStats(mode=105)) - self._bindKey("", "h", self.mHint) - self._bindKey(ctrl, "h", self.mHint1) # undocumented - ##self._bindKey("", "Shift_L", self.mHighlightPiles) - ##self._bindKey("", "Shift_R", self.mHighlightPiles) - self._bindKey("", "i", self.mHighlightPiles) - self._bindKey("", "F3", self.mFindCard) - self._bindKey(ctrl, "d", self.mDemo) - self._bindKey(ctrl, "e", self.mSelectCardsetDialog) - if USE_PIL: - self._bindKey(ctrl, "plus", self.mIncreaseCardset) - self._bindKey(ctrl, "equal", self.mIncreaseCardset) - self._bindKey(ctrl, "minus", self.mDecreaseCardset) - self._bindKey(ctrl, "0", self.mOptAutoScale) - self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented - self._bindKey(ctrl, "i", self.mOptChangeTableTile) # undocumented - self._bindKey(ctrl, "p", self.mOptPlayerOptions) # undocumented - self._bindKey(ctrl, "F1", self.mHelp) - self._bindKey("", "F1", self.mHelpRules) - self._bindKey("", "Print", self.mScreenshot) - self._bindKey(ctrl, "u", self.mPlayNextMusic) # undocumented - self._bindKey("", "p", self.mPause) - self._bindKey("", "Pause", self.mPause) # undocumented - self._bindKey("", "Escape", self.mIconify) # undocumented - # ASD and LKJ - self._bindKey("", "a", self.mDrop) - self._bindKey(ctrl, "a", self.mDrop1) - self._bindKey("", "s", self.mUndo) - self._bindKey("", "d", self.mDeal) - self._bindKey("", "l", self.mDrop) - self._bindKey(ctrl, "l", self.mDrop1) - self._bindKey("", "k", self.mUndo) - self._bindKey("", "j", self.mDeal) - - self._bindKey("", "F2", self.mStackDesk) - # - self._bindKey("", "slash", lambda e: self.mPlayerStats(mode=106)) # undocumented, devel - # - self._bindKey("", "f", self.mShuffle) - - for i in range(9): - self._bindKey(ctrl, str(i+1), lambda e, i=i: self.mGotoBookmark(i, confirm=0)) - - # undocumented, devel - self._bindKey(ctrl, "End", self.mPlayNextMusic) - self._bindKey(ctrl, "Prior", self.mSelectPrevGameByName) - self._bindKey(ctrl, "Next", self.mSelectNextGameByName) - self._bindKey(ctrl, "Up", self.mSelectPrevGameById) - self._bindKey(ctrl, "Down", self.mSelectNextGameById) - - - # - # key binding utility - # - - def _bindKey(self, modifier, key, func): -## if 0 and not modifier and len(key) == 1: -## self.keybindings[key.lower()] = func -## self.keybindings[key.upper()] = func -## return - if not modifier and len(key) == 1: - # ignore Ctrl/Shift/Alt - # but don't ignore NumLock (state == 16) - func = lambda e, func=func: e.state in (0, 16) and func(e) - sequence = "<" + modifier + "KeyPress-" + key + ">" - bind(self.top, sequence, func) - if len(key) == 1 and key != key.upper(): - key = key.upper() - sequence = "<" + modifier + "KeyPress-" + key + ">" - bind(self.top, sequence, func) - - - def _keyPressHandler(self, event): - r = EVENT_PROPAGATE - if event and self.game: - ##print event.__dict__ - if self.game.demo: - # stop the demo by setting self.game.demo.keypress - if event.char: # ignore Ctrl/Shift/etc. - self.game.demo.keypress = event.char - r = EVENT_HANDLED -## func = self.keybindings.get(event.char) -## if func and (event.state & ~2) == 0: -## func(event) -## r = EVENT_HANDLED - return r - - # - # Select Game menu creation - # - - def _addSelectGameMenu(self, menu): - #games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByShortName()) - games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName()) - ##games = tuple(games) - ###menu = MfxMenu(menu, label="Select &game") - m = "Ctrl-" - if sys.platform == "darwin": m = "Cmd-" - menu.add_command(label=n_("All &games..."), accelerator=m+"W", - command=self.mSelectGameDialog) - menu.add_command(label=n_("Playable pre&view..."), accelerator=m+"V", - command=self.mSelectGameDialogWithPreview) - if not SELECT_GAME_MENU: - return - menu.add_separator() - self._addSelectPopularGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectFrenchGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - if self.progress: self.progress.update(step=1) - self._addSelectMahjonggGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectOrientalGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectSpecialGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectCustomGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - menu.add_separator() - if self.progress: self.progress.update(step=1) - self._addSelectAllGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - - - def _addSelectGameSubMenu(self, games, menu, select_data, - command, variable): - ##print select_data - need_sep = 0 - for label, select_func in select_data: - if label is None: - need_sep = 1 - continue - g = filter(select_func, games) - if not g: - continue - if need_sep: - menu.add_separator() - need_sep = 0 - submenu = MfxMenu(menu, label=label) - self._addSelectGameSubSubMenu(g, submenu, command, variable) - - def _getNumGames(self, games, select_data): - ngames = 0 - for label, select_func in select_data: - ngames += len(filter(select_func, games)) - return ngames - - def _addSelectMahjonggGameSubMenu(self, games, menu, command, variable): - select_func = lambda gi: gi.si.game_type == GI.GT_MAHJONGG - mahjongg_games = filter(select_func, games) - if len(mahjongg_games) == 0: - return - # - menu = MfxMenu(menu, label=n_("&Mahjongg games")) - - def add_menu(games, c0, c1, menu=menu, - variable=variable, command=command): - if not games: - return - label = c0 + ' - ' + c1 - if c0 == c1: - label = c0 - submenu = MfxMenu(menu, label=label, name=None) - self._addSelectGameSubSubMenu(games, submenu, command, - variable, short_name=True) - - games = {} - for gi in mahjongg_games: - c = gi.short_name.strip()[0] - if c in games: - games[c].append(gi) - else: - games[c] = [gi] - games = games.items() - games.sort() - g0 = [] - c0 = c1 = games[0][0] - for c, g1 in games: - if len(g0)+len(g1) >= self.cb_max: - add_menu(g0, c0, c1) - g0 = g1 - c0 = c1 = c - else: - g0 += g1 - c1 = c - add_menu(g0, c0, c1) - - def _addSelectPopularGameSubMenu(self, games, menu, command, variable): - select_func = lambda gi: gi.si.game_flags & GI.GT_POPULAR - if len(filter(select_func, games)) == 0: - return - data = (n_("&Popular games"), select_func) - self._addSelectGameSubMenu(games, menu, (data, ), - self.mSelectGamePopular, - self.tkopt.gameid_popular) - - def _addSelectFrenchGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&French games")) - self._addSelectGameSubMenu(games, submenu, GI.SELECT_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectOrientalGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&Oriental games")) - self._addSelectGameSubMenu(games, submenu, - GI.SELECT_ORIENTAL_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectSpecialGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&Special games")) - self._addSelectGameSubMenu(games, submenu, - GI.SELECT_SPECIAL_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectCustomGameSubMenu(self, games, menu, command, variable): - submenu = MfxMenu(menu, label=n_("&Custom games")) - select_func = lambda gi: gi.si.game_type == GI.GT_CUSTOM - games = filter(select_func, games) - self.updateGamesMenu(submenu, games) - - def _addSelectAllGameSubMenu(self, games, menu, command, variable): - menu = MfxMenu(menu, label=n_("&All games by name")) - n, d = 0, self.cb_max - i = 0 - while True: - if self.progress: self.progress.update(step=1) - columnbreak = i > 0 and (i % d) == 0 - i += 1 - if not games[n:n+d]: - break - m = min(n+d-1, len(games)-1) - label = games[n].name[:3] + ' - ' + games[m].name[:3] - submenu = MfxMenu(menu, label=label, name=None) - self._addSelectGameSubSubMenu(games[n:n+d], submenu, - command, variable) - n += d - if columnbreak: - menu.entryconfigure(i, columnbreak=columnbreak) - - def _addSelectGameSubSubMenu(self, games, menu, command, variable, - short_name=False): - ##cb = (25, self.cb_max) [ len(g) > 4 * 25 ] - ##cb = min(cb, self.cb_max) - cb = self.cb_max - for i in range(len(games)): - gi = games[i] - columnbreak = i > 0 and (i % cb) == 0 - if short_name: - label = gi.short_name - else: - label = gi.name - # optimized by inlining - menu.tk.call((menu._w, 'add', 'radiobutton') + - menu._options({'command': command, - 'variable': variable, - 'columnbreak': columnbreak, - 'value': gi.id, - 'label': label})) - - def updateGamesMenu(self, menu, games): - menu.delete(0, 'last') - if len(games) == 0: - menu.add_radiobutton(label='', name=None, state='disabled') - elif len(games) > self.cb_max*4: - games.sort(lambda a, b: cmp(a.name, b.name)) - self._addSelectAllGameSubMenu(games, menu, - command=self.mSelectGame, - variable=self.tkopt.gameid) - else: - self._addSelectGameSubSubMenu(games, menu, - command=self.mSelectGame, - variable=self.tkopt.gameid) - - # - # Select Game menu actions - # - - def mSelectGame(self, *args): - self._mSelectGame(self.tkopt.gameid.get()) - - def mSelectGamePopular(self, *args): - self._mSelectGame(self.tkopt.gameid_popular.get()) - - def _mSelectGameDialog(self, d): - if d.status == 0 and d.button == 0 and d.gameid != self.game.id: - self.tkopt.gameid.set(d.gameid) - self.tkopt.gameid_popular.set(d.gameid) - if 0: - self._mSelectGame(d.gameid, random=d.random) - else: - # don't ask areYouSure() - self._cancelDrag() - self.game.endGame() - self.game.quitGame(d.gameid, random=d.random) - return EVENT_HANDLED - - def __restoreCursor(self, *event): - self.game.setCursor(cursor=self.app.top_cursor) - - def mSelectGameDialog(self, *event): - if self._cancelDrag(break_pause=False): return - self.game.setCursor(cursor=CURSOR_WATCH) - after_idle(self.top, self.__restoreCursor) - d = SelectGameDialog(self.top, title=_("Select game"), - app=self.app, gameid=self.game.id) - return self._mSelectGameDialog(d) - - def mSelectGameDialogWithPreview(self, *event): - if self._cancelDrag(break_pause=False): return - self.game.setCursor(cursor=CURSOR_WATCH) - bookmark = None - if 0: - # use a bookmark for our preview game - if self.game.setBookmark(-2, confirm=0): - bookmark = self.game.gsaveinfo.bookmarks[-2][0] - del self.game.gsaveinfo.bookmarks[-2] - after_idle(self.top, self.__restoreCursor) - d = SelectGameDialogWithPreview(self.top, title=_("Select game"), - app=self.app, gameid=self.game.id, - bookmark=bookmark) - return self._mSelectGameDialog(d) - - - # - # menubar overrides - # - - def updateFavoriteGamesMenu(self): - gameids = self.app.opt.favorite_gameid - submenu = self.menupath[".menubar.file.favoritegames"][2] - games = [] - for id in gameids: - gi = self.app.getGameInfo(id) - if gi: - games.append(gi) - self.updateGamesMenu(submenu, games) - state = self._getEnabledState - in_favor = self.app.game.id in gameids - menu, index, submenu = self.menupath[".menubar.file.addtofavorites"] - menu.entryconfig(index, state=state(not in_favor)) - menu, index, submenu = self.menupath[".menubar.file.removefromfavorites"] - menu.entryconfig(index, state=state(in_favor)) - - - def updateRecentGamesMenu(self, gameids): - submenu = self.menupath[".menubar.file.recentgames"][2] - games = [] - for id in gameids: - gi = self.app.getGameInfo(id) - if gi: - games.append(gi) - self.updateGamesMenu(submenu, games) - - def updateBookmarkMenuState(self): - state = self._getEnabledState - mp1 = self.menupath.get(".menubar.edit.setbookmark") - mp2 = self.menupath.get(".menubar.edit.gotobookmark") - mp3 = self.menupath.get(".menubar.edit.clearbookmarks") - if mp1 is None or mp2 is None or mp3 is None: - return - x = self.app.opt.bookmarks and self.game.canSetBookmark() - # - menu, index, submenu = mp1 - for i in range(9): - submenu.entryconfig(i, state=state(x)) - menu.entryconfig(index, state=state(x)) - # - menu, index, submenu = mp2 - ms = 0 - for i in range(9): - s = self.game.gsaveinfo.bookmarks.get(i) is not None - submenu.entryconfig(i, state=state(s and x)) - ms = ms or s - menu.entryconfig(index, state=state(ms and x)) - # - menu, index, submenu = mp3 - menu.entryconfig(index, state=state(ms and x)) - - def updateBackgroundImagesMenu(self): - mp = self.menupath.get(".menubar.options.cardbackground") - # delete all entries - submenu = mp[2] - submenu.delete(0, "last") - # insert new cardbacks - mbacks = self.app.images.getCardbacks() - cb = int(math.ceil(math.sqrt(len(mbacks)))) - for i in range(len(mbacks)): - columnbreak = i > 0 and (i % cb) == 0 - submenu.add_radiobutton(label=mbacks[i].name, image=mbacks[i].menu_image, variable=self.tkopt.cardback, value=i, - command=self.mOptCardback, columnbreak=columnbreak, indicatoron=0, hidemargin=0) - - - # - # menu updates - # - - def setMenuState(self, state, path): - #print state, path - path = ".menubar." + path - mp = self.menupath.get(path) - menu, index, submenu = mp - s = self._getEnabledState(state) - menu.entryconfig(index, state=s) - - def setToolbarState(self, state, path): - #print state, path - s = self._getEnabledState(state) - w = getattr(self.app.toolbar, path + "_button") - w["state"] = s - - def _setCommentMenu(self, v): - self.tkopt.comment.set(v) - - def _setPauseMenu(self, v): - self.tkopt.pause.set(v) - - - # - # menu actions - # - - DEFAULTEXTENSION = ".pso" - FILETYPES = ((TITLE+" files", "*"+DEFAULTEXTENSION), ("All files", "*")) - - def mAddFavor(self, *event): - gameid = self.app.game.id - if gameid not in self.app.opt.favorite_gameid: - self.app.opt.favorite_gameid.append(gameid) - self.updateFavoriteGamesMenu() - - def mDelFavor(self, *event): - gameid = self.app.game.id - if gameid in self.app.opt.favorite_gameid: - self.app.opt.favorite_gameid.remove(gameid) - self.updateFavoriteGamesMenu() - - def mOpen(self, *event): - if self._cancelDrag(break_pause=False): return - filename = self.game.filename - if filename: - idir, ifile = os.path.split(os.path.normpath(filename)) - else: - idir, ifile = "", "" - if not idir: - idir = self.app.dn.savegames - d = tkFileDialog.Open() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - if os.path.isfile(filename): - self.game.loadGame(filename) - - def mExportCurrentLayout(self, *event): - if self._cancelDrag(break_pause=False): return - game = self.game - if not self.menustate.save_as: - return - if not game.Solver_Class: - d = MfxMessageDialog(self.top, title=_('Export game error'), - text=_(''' -Unsupported game for export. -'''), - bitmap='error') - return - - filename = game.filename - if not filename: - filename = self.app.getGameSaveName(self.game.id) - if os.name == "posix" or os.path.supports_unicode_filenames: - filename += "-" + self.game.getGameNumber(format=0) - else: - filename += "-01" - filename += ".board" - idir, ifile = os.path.split(os.path.normpath(filename)) - if not idir: - idir = self.app.dn.savegames - ##print self.game.filename, ifile - d = tkFileDialog.SaveAs() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - with open(filename, 'w') as fh: - game = self.game - fh.write(game.Solver_Class(game, self).calcBoardString()) - self.updateMenus() - - def mSaveAs(self, *event): - if self._cancelDrag(break_pause=False): return - if not self.menustate.save_as: - return - filename = self.game.filename - if not filename: - filename = self.app.getGameSaveName(self.game.id) - if os.name == "posix": - filename = filename + "-" + self.game.getGameNumber(format=0) - elif os.path.supports_unicode_filenames: # new in python 2.3 - filename = filename + "-" + self.game.getGameNumber(format=0) - else: - filename = filename + "-01" - filename = filename + self.DEFAULTEXTENSION - idir, ifile = os.path.split(os.path.normpath(filename)) - if not idir: - idir = self.app.dn.savegames - ##print self.game.filename, ifile - d = tkFileDialog.SaveAs() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - self.game.saveGame(filename) - self.updateMenus() - - def mPause(self, *args): - if not self.game: - return - if not self.game.pause: - if self._cancelDrag(): return - self.game.doPause() - self.tkopt.pause.set(self.game.pause) - - def mOptSoundDialog(self, *args): - if self._cancelDrag(break_pause=False): return - d = SoundOptionsDialog(self.top, _("Sound settings"), self.app) - self.tkopt.sound.set(self.app.opt.sound) - - def mOptAutoFaceUp(self, *args): - if self._cancelDrag(): return - self.app.opt.autofaceup = self.tkopt.autofaceup.get() - if self.app.opt.autofaceup: - self.game.autoPlay() - - def mOptAutoDrop(self, *args): - if self._cancelDrag(): return - self.app.opt.autodrop = self.tkopt.autodrop.get() - if self.app.opt.autodrop: - self.game.autoPlay() - - def mOptAutoDeal(self, *args): - if self._cancelDrag(): return - self.app.opt.autodeal = self.tkopt.autodeal.get() - if self.app.opt.autodeal: - self.game.autoPlay() - - def mOptQuickPlay(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.quickplay = self.tkopt.quickplay.get() - - def mOptEnableUndo(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.undo = self.tkopt.undo.get() - self.game.updateMenus() - - def mOptEnableBookmarks(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.bookmarks = self.tkopt.bookmarks.get() - self.game.updateMenus() - - def mOptEnableHint(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.hint = self.tkopt.hint.get() - self.game.updateMenus() - - def mOptEnableShuffle(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shuffle = self.tkopt.shuffle.get() - self.game.updateMenus() - - def mOptEnableHighlightPiles(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_piles = self.tkopt.highlight_piles.get() - self.game.updateMenus() - - def mOptEnableHighlightCards(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_cards = self.tkopt.highlight_cards.get() - self.game.updateMenus() - - def mOptEnableHighlightSameRank(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_samerank = self.tkopt.highlight_samerank.get() - ##self.game.updateMenus() - - def mOptEnableHighlightNotMatching(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_not_matching = self.tkopt.highlight_not_matching.get() - ##self.game.updateMenus() - - def mOptAnimations(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.animations = self.tkopt.animations.get() - - def mRedealAnimation(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.redeal_animation = self.tkopt.redeal_animation.get() - - def mWinAnimation(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.win_animation = self.tkopt.win_animation.get() - - def mOptShadow(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shadow = self.tkopt.shadow.get() - - def mOptShade(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shade = self.tkopt.shade.get() - - def mOptShrinkFaceDown(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shrink_face_down = self.tkopt.shrink_face_down.get() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptShadeFilledStacks(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shade_filled_stacks = self.tkopt.shade_filled_stacks.get() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptMahjonggShowRemoved(self, *args): - if self._cancelDrag(): return - self.app.opt.mahjongg_show_removed = self.tkopt.mahjongg_show_removed.get() - ##self.game.updateMenus() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptShisenShowHint(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shisen_show_hint = self.tkopt.shisen_show_hint.get() - ##self.game.updateMenus() - - def _updateCardSize(self): - geom = (self.app.canvas.winfo_width(), - self.app.canvas.winfo_height()) - self.app.opt.game_geometry = geom - self.app.game.resizeGame() - if self.app.opt.auto_scale: - w, h = self.app.opt.game_geometry - self.app.canvas.setInitialSize(w, h, scrollregion=False) - else: - w = int(round(self.app.game.width * self.app.opt.scale_x)) - h = int(round(self.app.game.height * self.app.opt.scale_y)) - self.app.canvas.setInitialSize(w, h) - self.app.top.wm_geometry("") # cancel user-specified geometry - ##self.app.top.update_idletasks() - - def mIncreaseCardset(self, *event): - if self._cancelDrag(break_pause=True): return - if self.app.opt.scale_x < 4: - self.app.opt.scale_x += 0.1 - else: - return - if self.app.opt.scale_y < 4: - self.app.opt.scale_y += 0.1 - else: - return - self.app.opt.auto_scale = False - self.tkopt.auto_scale.set(False) - self._updateCardSize() - - def mDecreaseCardset(self, *event): - if self._cancelDrag(break_pause=True): return - if self.app.opt.scale_x > 0.5: - self.app.opt.scale_x -= 0.1 - else: - return - if self.app.opt.scale_y > 0.5: - self.app.opt.scale_y -= 0.1 - else: - return - self.app.opt.auto_scale = False - self.tkopt.auto_scale.set(False) - self._updateCardSize() - - def mOptAutoScale(self, *event): - if self._cancelDrag(break_pause=True): return - auto_scale = not self.app.opt.auto_scale - self.app.opt.auto_scale = auto_scale - self.tkopt.auto_scale.set(auto_scale) - self._updateCardSize() def mSelectCardsetDialog(self, *event): if self._cancelDrag(break_pause=False): return diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py index 80f740fc..710b8350 100644 --- a/pysollib/tk/menubar.py +++ b/pysollib/tk/menubar.py @@ -81,914 +81,6 @@ class PysolMenubarTk(PysolMenubarTkCommon): def createThemesMenu(self, menu): return - def _createMenubar(self): - MfxMenubar.addPath = self._addPath - kw = { "name": "menubar" } - self.menubar = MfxMenubar(self.top, **kw) - - # init keybindings - bind(self.top, "", self._keyPressHandler) - - m = "Ctrl-" - if sys.platform == "darwin": m = "Cmd-" - - if WIN_SYSTEM == "aqua": - applemenu=MfxMenu(self.menubar, "apple") - applemenu.add_command(label=_("&About ")+TITLE, command=self.mHelpAbout) - - menu = MfxMenu(self.menubar, n_("&File")) - menu.add_command(label=n_("&New game"), command=self.mNewGame, accelerator="N") - submenu = MfxMenu(menu, label=n_("R&ecent games")) - ##menu.add_command(label=n_("Select &random game"), command=self.mSelectRandomGame, accelerator=m+"R") - submenu = MfxMenu(menu, label=n_("Select &random game")) - submenu.add_command(label=n_("&All games"), command=lambda : self.mSelectRandomGame('all'), accelerator=m+"R") - submenu.add_command(label=n_("Games played and &won"), command=lambda : self.mSelectRandomGame('won')) - submenu.add_command(label=n_("Games played and ¬ won"), command=lambda : self.mSelectRandomGame('not won')) - submenu.add_command(label=n_("Games not &played"), command=lambda : self.mSelectRandomGame('not played')) - menu.add_command(label=n_("Select game by nu&mber..."), command=self.mSelectGameById, accelerator=m+"M") - menu.add_separator() - submenu = MfxMenu(menu, label=n_("Fa&vorite games")) - menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor) - menu.add_command(label=n_("Remove &from favorites"), command=self.mDelFavor) - menu.add_separator() - menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O") - menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S") - menu.add_command(label=n_("Save &as..."), command=self.mSaveAs) - menu.add_command(label=n_("E&xport current layout..."), command=self.mExportCurrentLayout) - menu.add_separator() - menu.add_command(label=n_("&Hold and quit"), command=self.mHoldAndQuit, accelerator=m+"X") - if WIN_SYSTEM != "aqua": - menu.add_command(label=n_("&Quit"), command=self.mQuit, accelerator=m+"Q") - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Select")) - self._addSelectGameMenu(menu) - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Edit")) - menu.add_command(label=n_("&Undo"), command=self.mUndo, accelerator="Z") - menu.add_command(label=n_("&Redo"), command=self.mRedo, accelerator="R") - menu.add_command(label=n_("Redo &all"), command=self.mRedoAll) - - menu.add_separator() - submenu = MfxMenu(menu, label=n_("&Set bookmark")) - for i in range(9): - label = _("Bookmark %d") % (i + 1) - submenu.add_command(label=label, command=lambda i=i: self.mSetBookmark(i)) - submenu = MfxMenu(menu, label=n_("Go&to bookmark")) - for i in range(9): - label = _("Bookmark %d") % (i + 1) - acc = m + "%d" % (i + 1) - submenu.add_command(label=label, command=lambda i=i: self.mGotoBookmark(i), accelerator=acc) - menu.add_command(label=n_("&Clear bookmarks"), command=self.mClearBookmarks) - menu.add_separator() - - menu.add_command(label=n_("Restart"), command=self.mRestart, accelerator=m+"G") - - menu.add_separator() - menu.add_command(label=n_("Solitaire &Wizard"), command=self.mWizard) - menu.add_command(label=n_("&Edit current game"), command=self.mWizardEdit) - - menu = MfxMenu(self.menubar, label=n_("&Game")) - menu.add_command(label=n_("&Deal cards"), command=self.mDeal, accelerator="D") - menu.add_command(label=n_("&Auto drop"), command=self.mDrop, accelerator="A") - menu.add_command(label=n_("Shu&ffle tiles"), command=self.mShuffle, accelerator="F") - menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P") - #menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P") - menu.add_separator() - menu.add_command(label=n_("S&tatus..."), command=lambda : self.mPlayerStats(mode=100), accelerator=m+"Y") - menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment) - menu.add_separator() - menu.add_command(label=n_("&Statistics..."), command=self.mPlayerStats, accelerator=m+"T") - menu.add_command(label=n_("Log..."), command=lambda : self.mPlayerStats(mode=103)) - menu.add_separator() - menu.add_command(label=n_("D&emo statistics"), command=lambda : self.mPlayerStats(mode=1101)) - - 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="F3") - 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) - if USE_FREECELL_SOLVER: - menu.add_command(label=n_("&Solver"), command=self.mSolver) - else: - menu.add_command(label=n_("&Solver"), state='disabled') - menu.add_separator() - menu.add_command(label=n_("&Piles description"), command=self.mStackDesk, accelerator="F2") - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Options")) - menu.add_command(label=n_("&Player options..."), command=self.mOptPlayerOptions) - submenu = MfxMenu(menu, label=n_("&Automatic play")) - submenu.add_checkbutton(label=n_("Auto &face up"), variable=self.tkopt.autofaceup, command=self.mOptAutoFaceUp) - submenu.add_checkbutton(label=n_("A&uto drop"), variable=self.tkopt.autodrop, command=self.mOptAutoDrop) - submenu.add_checkbutton(label=n_("Auto &deal"), variable=self.tkopt.autodeal, command=self.mOptAutoDeal) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Quick play"), variable=self.tkopt.quickplay, command=self.mOptQuickPlay) - submenu = MfxMenu(menu, label=n_("Assist &level")) - submenu.add_checkbutton(label=n_("Enable &undo"), variable=self.tkopt.undo, command=self.mOptEnableUndo) - submenu.add_checkbutton(label=n_("Enable &bookmarks"), variable=self.tkopt.bookmarks, command=self.mOptEnableBookmarks) - submenu.add_checkbutton(label=n_("Enable &hint"), variable=self.tkopt.hint, command=self.mOptEnableHint) - submenu.add_checkbutton(label=n_("Enable shu&ffle"), variable=self.tkopt.shuffle, command=self.mOptEnableShuffle) - submenu.add_checkbutton(label=n_("Enable highlight p&iles"), variable=self.tkopt.highlight_piles, command=self.mOptEnableHighlightPiles) - submenu.add_checkbutton(label=n_("Enable highlight &cards"), variable=self.tkopt.highlight_cards, command=self.mOptEnableHighlightCards) - submenu.add_checkbutton(label=n_("Enable highlight same &rank"), variable=self.tkopt.highlight_samerank, command=self.mOptEnableHighlightSameRank) - submenu.add_checkbutton(label=n_("Highlight &no matching"), variable=self.tkopt.highlight_not_matching, command=self.mOptEnableHighlightNotMatching) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Show removed tiles (in Mahjongg games)"), variable=self.tkopt.mahjongg_show_removed, command=self.mOptMahjonggShowRemoved) - submenu.add_checkbutton(label=n_("Show hint &arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint) - menu.add_separator() - label = n_("&Sound...") - if not self.app.audio.CAN_PLAY_SOUND: - menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog, state='disabled') - else: - menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog) - # cardsets - if USE_PIL: - submenu = MfxMenu(menu, label=n_("Card si&ze")) - submenu.add_command(label=n_("&Increase the card size"), command=self.mIncreaseCardset, accelerator=m+"+") - submenu.add_command(label=n_("&Decrease the card size"), command=self.mDecreaseCardset, accelerator=m+"-") - submenu.add_checkbutton(label=n_("&Auto scaling"), variable=self.tkopt.auto_scale, command=self.mOptAutoScale, accelerator=m+'0') - #manager = self.app.cardset_manager - #n = manager.len() - menu.add_command(label=n_("Cards&et..."), command=self.mSelectCardsetDialog, accelerator=m+"E") - menu.add_command(label=n_("Table t&ile..."), command=self.mSelectTileDialog) - # this submenu will get set by updateBackgroundImagesMenu() - submenu = MfxMenu(menu, label=n_("Card &background")) - submenu = MfxMenu(menu, label=n_("Card &view")) - submenu.add_checkbutton(label=n_("Card shado&w"), variable=self.tkopt.shadow, command=self.mOptShadow) - submenu.add_checkbutton(label=n_("Shade &legal moves"), variable=self.tkopt.shade, command=self.mOptShade) - submenu.add_checkbutton(label=n_("&Negative cards bottom"), variable=self.tkopt.negative_bottom, command=self.mOptNegativeBottom) - submenu.add_checkbutton(label=n_("Shrink face-down cards"), variable=self.tkopt.shrink_face_down, command=self.mOptShrinkFaceDown) - submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks) - submenu = MfxMenu(menu, label=n_("A&nimations")) - submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Very fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Medium"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations) - submenu.add_radiobutton(label=n_("V&ery slow"), variable=self.tkopt.animations, value=5, command=self.mOptAnimations) - submenu.add_separator() - submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation) - if Image: - submenu.add_checkbutton(label=n_("&Winning animation"), variable=self.tkopt.win_animation, command=self.mWinAnimation) - submenu = MfxMenu(menu, label=n_("&Mouse")) - submenu.add_radiobutton(label=n_("&Drag-and-Drop"), variable=self.tkopt.mouse_type, value='drag-n-drop', command=self.mOptMouseType) - submenu.add_radiobutton(label=n_("&Point-and-Click"), variable=self.tkopt.mouse_type, value='point-n-click', command=self.mOptMouseType) - submenu.add_radiobutton(label=n_("&Sticky mouse"), variable=self.tkopt.mouse_type, value='sticky-mouse', command=self.mOptMouseType) - submenu.add_separator() - submenu.add_checkbutton(label=n_("Use mouse for undo/redo"), variable=self.tkopt.mouse_undo, command=self.mOptMouseUndo) - menu.add_separator() - menu.add_command(label=n_("&Fonts..."), command=self.mOptFonts) - menu.add_command(label=n_("&Colors..."), command=self.mOptColors) - menu.add_command(label=n_("Time&outs..."), command=self.mOptTimeouts) - menu.add_separator() - self.createThemesMenu(menu) - submenu = MfxMenu(menu, label=n_("&Toolbar")) - createToolbarMenu(self, submenu) - submenu = MfxMenu(menu, label=n_("Stat&usbar")) - submenu.add_checkbutton(label=n_("Show &statusbar"), variable=self.tkopt.statusbar, command=self.mOptStatusbar) - submenu.add_checkbutton(label=n_("Show &number of cards"), variable=self.tkopt.num_cards, command=self.mOptNumCards) - submenu.add_checkbutton(label=n_("Show &help bar"), variable=self.tkopt.helpbar, command=self.mOptHelpbar) - if not USE_PIL: - menu.add_checkbutton(label=n_("Save games &geometry"), variable=self.tkopt.save_games_geometry, command=self.mOptSaveGamesGeometry) - menu.add_checkbutton(label=n_("&Demo logo"), variable=self.tkopt.demo_logo, command=self.mOptDemoLogo) - menu.add_checkbutton(label=n_("Startup splash sc&reen"), variable=self.tkopt.splashscreen, command=self.mOptSplashscreen) -### menu.add_separator() -### menu.add_command(label="Save options", command=self.mOptSave) - - if self.progress: self.progress.update(step=1) - - menu = MfxMenu(self.menubar, label=n_("&Help")) - menu.add_command(label=n_("&Contents"), command=self.mHelp, accelerator=m+"F1") - menu.add_command(label=n_("&How to play"), command=self.mHelpHowToPlay) - menu.add_command(label=n_("&Rules for this game"), command=self.mHelpRules, accelerator="F1") - menu.add_command(label=n_("&License terms"), command=self.mHelpLicense) - ##menu.add_command(label=n_("What's &new ?"), command=self.mHelpNews) - if WIN_SYSTEM != "aqua": - menu.add_separator() - menu.add_command(label=n_("&About ")+TITLE+"...", command=self.mHelpAbout) - - MfxMenubar.addPath = None - - ### FIXME: all key bindings should be *added* to keyPressHandler - ctrl = "Control-" - if sys.platform == "darwin": ctrl = "Command-" - self._bindKey("", "n", self.mNewGame) - self._bindKey(ctrl, "w", self.mSelectGameDialog) - self._bindKey(ctrl, "v", self.mSelectGameDialogWithPreview) - self._bindKey(ctrl, "r", lambda e: self.mSelectRandomGame()) - self._bindKey(ctrl, "m", self.mSelectGameById) - self._bindKey(ctrl, "n", self.mNewGameWithNextId) - self._bindKey(ctrl, "o", self.mOpen) - self._bindKey(ctrl, "s", self.mSave) - self._bindKey(ctrl, "x", self.mHoldAndQuit) - self._bindKey(ctrl, "q", self.mQuit) - self._bindKey("", "z", self.mUndo) - self._bindKey("", "BackSpace", self.mUndo) # undocumented - self._bindKey("", "KP_Enter", self.mUndo) # undocumented - self._bindKey("", "r", self.mRedo) - self._bindKey(ctrl, "g", self.mRestart) - self._bindKey("", "space", self.mDeal) # undocumented - self._bindKey(ctrl, "y", lambda e: self.mPlayerStats(mode=100)) - self._bindKey(ctrl, "t", lambda e: self.mPlayerStats(mode=105)) - self._bindKey("", "h", self.mHint) - self._bindKey(ctrl, "h", self.mHint1) # undocumented - ##self._bindKey("", "Shift_L", self.mHighlightPiles) - ##self._bindKey("", "Shift_R", self.mHighlightPiles) - self._bindKey("", "i", self.mHighlightPiles) - self._bindKey("", "F3", self.mFindCard) - self._bindKey(ctrl, "d", self.mDemo) - self._bindKey(ctrl, "e", self.mSelectCardsetDialog) - if USE_PIL: - self._bindKey(ctrl, "plus", self.mIncreaseCardset) - self._bindKey(ctrl, "equal", self.mIncreaseCardset) - self._bindKey(ctrl, "minus", self.mDecreaseCardset) - self._bindKey(ctrl, "0", self.mOptAutoScale) - self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented - self._bindKey(ctrl, "i", self.mOptChangeTableTile) # undocumented - self._bindKey(ctrl, "p", self.mOptPlayerOptions) # undocumented - self._bindKey(ctrl, "F1", self.mHelp) - self._bindKey("", "F1", self.mHelpRules) - self._bindKey("", "Print", self.mScreenshot) - self._bindKey(ctrl, "u", self.mPlayNextMusic) # undocumented - self._bindKey("", "p", self.mPause) - self._bindKey("", "Pause", self.mPause) # undocumented - self._bindKey("", "Escape", self.mIconify) # undocumented - # ASD and LKJ - self._bindKey("", "a", self.mDrop) - self._bindKey(ctrl, "a", self.mDrop1) - self._bindKey("", "s", self.mUndo) - self._bindKey("", "d", self.mDeal) - self._bindKey("", "l", self.mDrop) - self._bindKey(ctrl, "l", self.mDrop1) - self._bindKey("", "k", self.mUndo) - self._bindKey("", "j", self.mDeal) - - self._bindKey("", "F2", self.mStackDesk) - # - self._bindKey("", "slash", lambda e: self.mPlayerStats(mode=106)) # undocumented, devel - # - self._bindKey("", "f", self.mShuffle) - - for i in range(9): - self._bindKey(ctrl, str(i+1), lambda e, i=i: self.mGotoBookmark(i, confirm=0)) - - # undocumented, devel - self._bindKey(ctrl, "End", self.mPlayNextMusic) - self._bindKey(ctrl, "Prior", self.mSelectPrevGameByName) - self._bindKey(ctrl, "Next", self.mSelectNextGameByName) - self._bindKey(ctrl, "Up", self.mSelectPrevGameById) - self._bindKey(ctrl, "Down", self.mSelectNextGameById) - - - # - # key binding utility - # - - def _bindKey(self, modifier, key, func): -## if 0 and not modifier and len(key) == 1: -## self.keybindings[key.lower()] = func -## self.keybindings[key.upper()] = func -## return - if not modifier and len(key) == 1: - # ignore Ctrl/Shift/Alt - # but don't ignore NumLock (state == 16) - func = lambda e, func=func: e.state in (0, 16) and func(e) - sequence = "<" + modifier + "KeyPress-" + key + ">" - bind(self.top, sequence, func) - if len(key) == 1 and key != key.upper(): - key = key.upper() - sequence = "<" + modifier + "KeyPress-" + key + ">" - bind(self.top, sequence, func) - - - def _keyPressHandler(self, event): - r = EVENT_PROPAGATE - if event and self.game: - ##print event.__dict__ - if self.game.demo: - # stop the demo by setting self.game.demo.keypress - if event.char: # ignore Ctrl/Shift/etc. - self.game.demo.keypress = event.char - r = EVENT_HANDLED -## func = self.keybindings.get(event.char) -## if func and (event.state & ~2) == 0: -## func(event) -## r = EVENT_HANDLED - return r - - # - # Select Game menu creation - # - - def _addSelectGameMenu(self, menu): - #games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByShortName()) - games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName()) - ##games = tuple(games) - ###menu = MfxMenu(menu, label="Select &game") - m = "Ctrl-" - if sys.platform == "darwin": m = "Cmd-" - menu.add_command(label=n_("All &games..."), accelerator=m+"W", - command=self.mSelectGameDialog) - menu.add_command(label=n_("Playable pre&view..."), accelerator=m+"V", - command=self.mSelectGameDialogWithPreview) - if not SELECT_GAME_MENU: - return - menu.add_separator() - self._addSelectPopularGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectFrenchGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - if self.progress: self.progress.update(step=1) - self._addSelectMahjonggGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectOrientalGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectSpecialGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - self._addSelectCustomGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - menu.add_separator() - if self.progress: self.progress.update(step=1) - self._addSelectAllGameSubMenu(games, menu, self.mSelectGame, - self.tkopt.gameid) - - - def _addSelectGameSubMenu(self, games, menu, select_data, - command, variable): - ##print select_data - need_sep = 0 - for label, select_func in select_data: - if label is None: - need_sep = 1 - continue - g = filter(select_func, games) - if not g: - continue - if need_sep: - menu.add_separator() - need_sep = 0 - submenu = MfxMenu(menu, label=label) - self._addSelectGameSubSubMenu(g, submenu, command, variable) - - def _getNumGames(self, games, select_data): - ngames = 0 - for label, select_func in select_data: - ngames += len(filter(select_func, games)) - return ngames - - def _addSelectMahjonggGameSubMenu(self, games, menu, command, variable): - select_func = lambda gi: gi.si.game_type == GI.GT_MAHJONGG - mahjongg_games = filter(select_func, games) - if len(mahjongg_games) == 0: - return - # - menu = MfxMenu(menu, label=n_("&Mahjongg games")) - - def add_menu(games, c0, c1, menu=menu, - variable=variable, command=command): - if not games: - return - label = c0 + ' - ' + c1 - if c0 == c1: - label = c0 - submenu = MfxMenu(menu, label=label, name=None) - self._addSelectGameSubSubMenu(games, submenu, command, - variable, short_name=True) - - games = {} - for gi in mahjongg_games: - c = gi.short_name.strip()[0] - if c in games: - games[c].append(gi) - else: - games[c] = [gi] - games = games.items() - games.sort() - g0 = [] - c0 = c1 = games[0][0] - for c, g1 in games: - if len(g0)+len(g1) >= self.cb_max: - add_menu(g0, c0, c1) - g0 = g1 - c0 = c1 = c - else: - g0 += g1 - c1 = c - add_menu(g0, c0, c1) - - def _addSelectPopularGameSubMenu(self, games, menu, command, variable): - select_func = lambda gi: gi.si.game_flags & GI.GT_POPULAR - if len(filter(select_func, games)) == 0: - return - data = (n_("&Popular games"), select_func) - self._addSelectGameSubMenu(games, menu, (data, ), - self.mSelectGamePopular, - self.tkopt.gameid_popular) - - def _addSelectFrenchGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&French games")) - self._addSelectGameSubMenu(games, submenu, GI.SELECT_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectOrientalGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&Oriental games")) - self._addSelectGameSubMenu(games, submenu, - GI.SELECT_ORIENTAL_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectSpecialGameSubMenu(self, games, menu, command, variable): - if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: - return - submenu = MfxMenu(menu, label=n_("&Special games")) - self._addSelectGameSubMenu(games, submenu, - GI.SELECT_SPECIAL_GAME_BY_TYPE, - self.mSelectGame, self.tkopt.gameid) - - def _addSelectCustomGameSubMenu(self, games, menu, command, variable): - submenu = MfxMenu(menu, label=n_("&Custom games")) - select_func = lambda gi: gi.si.game_type == GI.GT_CUSTOM - games = filter(select_func, games) - self.updateGamesMenu(submenu, games) - - def _addSelectAllGameSubMenu(self, games, menu, command, variable): - menu = MfxMenu(menu, label=n_("&All games by name")) - n, d = 0, self.cb_max - i = 0 - while True: - if self.progress: self.progress.update(step=1) - columnbreak = i > 0 and (i % d) == 0 - i += 1 - if not games[n:n+d]: - break - m = min(n+d-1, len(games)-1) - label = games[n].name[:3] + ' - ' + games[m].name[:3] - submenu = MfxMenu(menu, label=label, name=None) - self._addSelectGameSubSubMenu(games[n:n+d], submenu, - command, variable) - n += d - if columnbreak: - menu.entryconfigure(i, columnbreak=columnbreak) - - def _addSelectGameSubSubMenu(self, games, menu, command, variable, - short_name=False): - ##cb = (25, self.cb_max) [ len(g) > 4 * 25 ] - ##cb = min(cb, self.cb_max) - cb = self.cb_max - for i in range(len(games)): - gi = games[i] - columnbreak = i > 0 and (i % cb) == 0 - if short_name: - label = gi.short_name - else: - label = gi.name - # optimized by inlining - menu.tk.call((menu._w, 'add', 'radiobutton') + - menu._options({'command': command, - 'variable': variable, - 'columnbreak': columnbreak, - 'value': gi.id, - 'label': label})) - - def updateGamesMenu(self, menu, games): - menu.delete(0, 'last') - if len(games) == 0: - menu.add_radiobutton(label='', name=None, state='disabled') - elif len(games) > self.cb_max*4: - games.sort(lambda a, b: cmp(a.name, b.name)) - self._addSelectAllGameSubMenu(games, menu, - command=self.mSelectGame, - variable=self.tkopt.gameid) - else: - self._addSelectGameSubSubMenu(games, menu, - command=self.mSelectGame, - variable=self.tkopt.gameid) - - # - # Select Game menu actions - # - - def mSelectGame(self, *args): - self._mSelectGame(self.tkopt.gameid.get()) - - def mSelectGamePopular(self, *args): - self._mSelectGame(self.tkopt.gameid_popular.get()) - - def _mSelectGameDialog(self, d): - if d.status == 0 and d.button == 0 and d.gameid != self.game.id: - self.tkopt.gameid.set(d.gameid) - self.tkopt.gameid_popular.set(d.gameid) - if 0: - self._mSelectGame(d.gameid, random=d.random) - else: - # don't ask areYouSure() - self._cancelDrag() - self.game.endGame() - self.game.quitGame(d.gameid, random=d.random) - return EVENT_HANDLED - - def __restoreCursor(self, *event): - self.game.setCursor(cursor=self.app.top_cursor) - - def mSelectGameDialog(self, *event): - if self._cancelDrag(break_pause=False): return - self.game.setCursor(cursor=CURSOR_WATCH) - after_idle(self.top, self.__restoreCursor) - d = SelectGameDialog(self.top, title=_("Select game"), - app=self.app, gameid=self.game.id) - return self._mSelectGameDialog(d) - - def mSelectGameDialogWithPreview(self, *event): - if self._cancelDrag(break_pause=False): return - self.game.setCursor(cursor=CURSOR_WATCH) - bookmark = None - if 0: - # use a bookmark for our preview game - if self.game.setBookmark(-2, confirm=0): - bookmark = self.game.gsaveinfo.bookmarks[-2][0] - del self.game.gsaveinfo.bookmarks[-2] - after_idle(self.top, self.__restoreCursor) - d = SelectGameDialogWithPreview(self.top, title=_("Select game"), - app=self.app, gameid=self.game.id, - bookmark=bookmark) - return self._mSelectGameDialog(d) - - - # - # menubar overrides - # - - def updateFavoriteGamesMenu(self): - gameids = self.app.opt.favorite_gameid - submenu = self.menupath[".menubar.file.favoritegames"][2] - games = [] - for id in gameids: - gi = self.app.getGameInfo(id) - if gi: - games.append(gi) - self.updateGamesMenu(submenu, games) - state = self._getEnabledState - in_favor = self.app.game.id in gameids - menu, index, submenu = self.menupath[".menubar.file.addtofavorites"] - menu.entryconfig(index, state=state(not in_favor)) - menu, index, submenu = self.menupath[".menubar.file.removefromfavorites"] - menu.entryconfig(index, state=state(in_favor)) - - - def updateRecentGamesMenu(self, gameids): - submenu = self.menupath[".menubar.file.recentgames"][2] - games = [] - for id in gameids: - gi = self.app.getGameInfo(id) - if gi: - games.append(gi) - self.updateGamesMenu(submenu, games) - - def updateBookmarkMenuState(self): - state = self._getEnabledState - mp1 = self.menupath.get(".menubar.edit.setbookmark") - mp2 = self.menupath.get(".menubar.edit.gotobookmark") - mp3 = self.menupath.get(".menubar.edit.clearbookmarks") - if mp1 is None or mp2 is None or mp3 is None: - return - x = self.app.opt.bookmarks and self.game.canSetBookmark() - # - menu, index, submenu = mp1 - for i in range(9): - submenu.entryconfig(i, state=state(x)) - menu.entryconfig(index, state=state(x)) - # - menu, index, submenu = mp2 - ms = 0 - for i in range(9): - s = self.game.gsaveinfo.bookmarks.get(i) is not None - submenu.entryconfig(i, state=state(s and x)) - ms = ms or s - menu.entryconfig(index, state=state(ms and x)) - # - menu, index, submenu = mp3 - menu.entryconfig(index, state=state(ms and x)) - - def updateBackgroundImagesMenu(self): - mp = self.menupath.get(".menubar.options.cardbackground") - # delete all entries - submenu = mp[2] - submenu.delete(0, "last") - # insert new cardbacks - mbacks = self.app.images.getCardbacks() - cb = int(math.ceil(math.sqrt(len(mbacks)))) - for i in range(len(mbacks)): - columnbreak = i > 0 and (i % cb) == 0 - submenu.add_radiobutton(label=mbacks[i].name, image=mbacks[i].menu_image, variable=self.tkopt.cardback, value=i, - command=self.mOptCardback, columnbreak=columnbreak, indicatoron=0, hidemargin=0) - - - # - # menu updates - # - - def setMenuState(self, state, path): - #print state, path - path = ".menubar." + path - mp = self.menupath.get(path) - menu, index, submenu = mp - s = self._getEnabledState(state) - menu.entryconfig(index, state=s) - - def setToolbarState(self, state, path): - #print state, path - s = self._getEnabledState(state) - w = getattr(self.app.toolbar, path + "_button") - w["state"] = s - - def _setCommentMenu(self, v): - self.tkopt.comment.set(v) - - def _setPauseMenu(self, v): - self.tkopt.pause.set(v) - - - # - # menu actions - # - - DEFAULTEXTENSION = ".pso" - FILETYPES = ((TITLE+" files", "*"+DEFAULTEXTENSION), ("All files", "*")) - - def mAddFavor(self, *event): - gameid = self.app.game.id - if gameid not in self.app.opt.favorite_gameid: - self.app.opt.favorite_gameid.append(gameid) - self.updateFavoriteGamesMenu() - - def mDelFavor(self, *event): - gameid = self.app.game.id - if gameid in self.app.opt.favorite_gameid: - self.app.opt.favorite_gameid.remove(gameid) - self.updateFavoriteGamesMenu() - - def mOpen(self, *event): - if self._cancelDrag(break_pause=False): return - filename = self.game.filename - if filename: - idir, ifile = os.path.split(os.path.normpath(filename)) - else: - idir, ifile = "", "" - if not idir: - idir = self.app.dn.savegames - d = tkFileDialog.Open() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - if os.path.isfile(filename): - self.game.loadGame(filename) - - def mExportCurrentLayout(self, *event): - if self._cancelDrag(break_pause=False): return - game = self.game - if not self.menustate.save_as: - return - if not game.Solver_Class: - d = MfxMessageDialog(self.top, title=_('Export game error'), - text=_(''' -Unsupported game for export. -'''), - bitmap='error') - return - - filename = game.filename - if not filename: - filename = self.app.getGameSaveName(self.game.id) - if os.name == "posix" or os.path.supports_unicode_filenames: - filename += "-" + self.game.getGameNumber(format=0) - else: - filename += "-01" - filename += ".board" - idir, ifile = os.path.split(os.path.normpath(filename)) - if not idir: - idir = self.app.dn.savegames - ##print self.game.filename, ifile - d = tkFileDialog.SaveAs() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - with open(filename, 'w') as fh: - game = self.game - fh.write(game.Solver_Class(game, self).calcBoardString()) - self.updateMenus() - - def mSaveAs(self, *event): - if self._cancelDrag(break_pause=False): return - if not self.menustate.save_as: - return - filename = self.game.filename - if not filename: - filename = self.app.getGameSaveName(self.game.id) - if os.name == "posix": - filename = filename + "-" + self.game.getGameNumber(format=0) - elif os.path.supports_unicode_filenames: # new in python 2.3 - filename = filename + "-" + self.game.getGameNumber(format=0) - else: - filename = filename + "-01" - filename = filename + self.DEFAULTEXTENSION - idir, ifile = os.path.split(os.path.normpath(filename)) - if not idir: - idir = self.app.dn.savegames - ##print self.game.filename, ifile - d = tkFileDialog.SaveAs() - filename = d.show(filetypes=self.FILETYPES, - defaultextension=self.DEFAULTEXTENSION, - initialdir=idir, initialfile=ifile) - if filename: - filename = os.path.normpath(filename) - ##filename = os.path.normcase(filename) - self.game.saveGame(filename) - self.updateMenus() - - def mPause(self, *args): - if not self.game: - return - if not self.game.pause: - if self._cancelDrag(): return - self.game.doPause() - self.tkopt.pause.set(self.game.pause) - - def mOptSoundDialog(self, *args): - if self._cancelDrag(break_pause=False): return - d = SoundOptionsDialog(self.top, _("Sound settings"), self.app) - self.tkopt.sound.set(self.app.opt.sound) - - def mOptAutoFaceUp(self, *args): - if self._cancelDrag(): return - self.app.opt.autofaceup = self.tkopt.autofaceup.get() - if self.app.opt.autofaceup: - self.game.autoPlay() - - def mOptAutoDrop(self, *args): - if self._cancelDrag(): return - self.app.opt.autodrop = self.tkopt.autodrop.get() - if self.app.opt.autodrop: - self.game.autoPlay() - - def mOptAutoDeal(self, *args): - if self._cancelDrag(): return - self.app.opt.autodeal = self.tkopt.autodeal.get() - if self.app.opt.autodeal: - self.game.autoPlay() - - def mOptQuickPlay(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.quickplay = self.tkopt.quickplay.get() - - def mOptEnableUndo(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.undo = self.tkopt.undo.get() - self.game.updateMenus() - - def mOptEnableBookmarks(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.bookmarks = self.tkopt.bookmarks.get() - self.game.updateMenus() - - def mOptEnableHint(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.hint = self.tkopt.hint.get() - self.game.updateMenus() - - def mOptEnableShuffle(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shuffle = self.tkopt.shuffle.get() - self.game.updateMenus() - - def mOptEnableHighlightPiles(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_piles = self.tkopt.highlight_piles.get() - self.game.updateMenus() - - def mOptEnableHighlightCards(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_cards = self.tkopt.highlight_cards.get() - self.game.updateMenus() - - def mOptEnableHighlightSameRank(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_samerank = self.tkopt.highlight_samerank.get() - ##self.game.updateMenus() - - def mOptEnableHighlightNotMatching(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.highlight_not_matching = self.tkopt.highlight_not_matching.get() - ##self.game.updateMenus() - - def mOptAnimations(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.animations = self.tkopt.animations.get() - - def mRedealAnimation(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.redeal_animation = self.tkopt.redeal_animation.get() - - def mWinAnimation(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.win_animation = self.tkopt.win_animation.get() - - def mOptShadow(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shadow = self.tkopt.shadow.get() - - def mOptShade(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shade = self.tkopt.shade.get() - - def mOptShrinkFaceDown(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shrink_face_down = self.tkopt.shrink_face_down.get() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptShadeFilledStacks(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shade_filled_stacks = self.tkopt.shade_filled_stacks.get() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptMahjonggShowRemoved(self, *args): - if self._cancelDrag(): return - self.app.opt.mahjongg_show_removed = self.tkopt.mahjongg_show_removed.get() - ##self.game.updateMenus() - self.game.endGame(bookmark=1) - self.game.quitGame(bookmark=1) - - def mOptShisenShowHint(self, *args): - if self._cancelDrag(break_pause=False): return - self.app.opt.shisen_show_hint = self.tkopt.shisen_show_hint.get() - ##self.game.updateMenus() - - def _updateCardSize(self): - geom = (self.app.canvas.winfo_width(), - self.app.canvas.winfo_height()) - self.app.opt.game_geometry = geom - self.app.game.resizeGame() - if self.app.opt.auto_scale: - w, h = self.app.opt.game_geometry - self.app.canvas.setInitialSize(w, h, scrollregion=False) - else: - w = int(round(self.app.game.width * self.app.opt.scale_x)) - h = int(round(self.app.game.height * self.app.opt.scale_y)) - self.app.canvas.setInitialSize(w, h) - self.app.top.wm_geometry("") # cancel user-specified geometry - ##self.app.top.update_idletasks() - - def mIncreaseCardset(self, *event): - if self._cancelDrag(break_pause=True): return - if self.app.opt.scale_x < 4: - self.app.opt.scale_x += 0.1 - else: - return - if self.app.opt.scale_y < 4: - self.app.opt.scale_y += 0.1 - else: - return - self.app.opt.auto_scale = False - self.tkopt.auto_scale.set(False) - self._updateCardSize() - - def mDecreaseCardset(self, *event): - if self._cancelDrag(break_pause=True): return - if self.app.opt.scale_x > 0.5: - self.app.opt.scale_x -= 0.1 - else: - return - if self.app.opt.scale_y > 0.5: - self.app.opt.scale_y -= 0.1 - else: - return - self.app.opt.auto_scale = False - self.tkopt.auto_scale.set(False) - self._updateCardSize() - - def mOptAutoScale(self, *event): - if self._cancelDrag(break_pause=True): return - auto_scale = not self.app.opt.auto_scale - self.app.opt.auto_scale = auto_scale - self.tkopt.auto_scale.set(auto_scale) - self._updateCardSize() def mSelectCardsetDialog(self, *event): if self._cancelDrag(break_pause=False): return diff --git a/pysollib/ui/tktile/menubar.py b/pysollib/ui/tktile/menubar.py index b2729388..7e79de6d 100644 --- a/pysollib/ui/tktile/menubar.py +++ b/pysollib/ui/tktile/menubar.py @@ -1,11 +1,20 @@ +import math import re +import sys + import Tkinter from pysollib.mfxutil import Struct, kwdefault +from pysollib.mfxutil import Image, USE_PIL from pysollib.mygettext import _, n_ +from pysollib.settings import TITLE, WIN_SYSTEM +from pysollib.settings import SELECT_GAME_MENU +from pysollib.gamedb import GI +from pysollib.settings import USE_FREECELL_SOLVER from pysollib.ui.tktile.tkconst import EVENT_HANDLED, EVENT_PROPAGATE, CURSOR_WATCH, COMPOUNDS from pysollib.ui.tktile.tkconst import TOOLBAR_BUTTONS +from pysollib.ui.tktile.tkutil import bind, after_idle def createToolbarMenu(menubar, menu): tearoff = menu.cget('tearoff') @@ -261,3 +270,911 @@ class PysolMenubarTkCommon: def updateProgress(self): if self.progress: self.progress.update(step=1) + def _createMenubar(self): + MfxMenubar.addPath = self._addPath + kw = { "name": "menubar" } + self.menubar = MfxMenubar(self.top, **kw) + + # init keybindings + bind(self.top, "", self._keyPressHandler) + + m = "Ctrl-" + if sys.platform == "darwin": m = "Cmd-" + + if WIN_SYSTEM == "aqua": + applemenu=MfxMenu(self.menubar, "apple") + applemenu.add_command(label=_("&About ")+TITLE, command=self.mHelpAbout) + + menu = MfxMenu(self.menubar, n_("&File")) + menu.add_command(label=n_("&New game"), command=self.mNewGame, accelerator="N") + submenu = MfxMenu(menu, label=n_("R&ecent games")) + ##menu.add_command(label=n_("Select &random game"), command=self.mSelectRandomGame, accelerator=m+"R") + submenu = MfxMenu(menu, label=n_("Select &random game")) + submenu.add_command(label=n_("&All games"), command=lambda : self.mSelectRandomGame('all'), accelerator=m+"R") + submenu.add_command(label=n_("Games played and &won"), command=lambda : self.mSelectRandomGame('won')) + submenu.add_command(label=n_("Games played and ¬ won"), command=lambda : self.mSelectRandomGame('not won')) + submenu.add_command(label=n_("Games not &played"), command=lambda : self.mSelectRandomGame('not played')) + menu.add_command(label=n_("Select game by nu&mber..."), command=self.mSelectGameById, accelerator=m+"M") + menu.add_separator() + submenu = MfxMenu(menu, label=n_("Fa&vorite games")) + menu.add_command(label=n_("A&dd to favorites"), command=self.mAddFavor) + menu.add_command(label=n_("Remove &from favorites"), command=self.mDelFavor) + menu.add_separator() + menu.add_command(label=n_("&Open..."), command=self.mOpen, accelerator=m+"O") + menu.add_command(label=n_("&Save"), command=self.mSave, accelerator=m+"S") + menu.add_command(label=n_("Save &as..."), command=self.mSaveAs) + menu.add_command(label=n_("E&xport current layout..."), command=self.mExportCurrentLayout) + menu.add_separator() + menu.add_command(label=n_("&Hold and quit"), command=self.mHoldAndQuit, accelerator=m+"X") + if WIN_SYSTEM != "aqua": + menu.add_command(label=n_("&Quit"), command=self.mQuit, accelerator=m+"Q") + + if self.progress: self.progress.update(step=1) + + menu = MfxMenu(self.menubar, label=n_("&Select")) + self._addSelectGameMenu(menu) + + if self.progress: self.progress.update(step=1) + + menu = MfxMenu(self.menubar, label=n_("&Edit")) + menu.add_command(label=n_("&Undo"), command=self.mUndo, accelerator="Z") + menu.add_command(label=n_("&Redo"), command=self.mRedo, accelerator="R") + menu.add_command(label=n_("Redo &all"), command=self.mRedoAll) + + menu.add_separator() + submenu = MfxMenu(menu, label=n_("&Set bookmark")) + for i in range(9): + label = _("Bookmark %d") % (i + 1) + submenu.add_command(label=label, command=lambda i=i: self.mSetBookmark(i)) + submenu = MfxMenu(menu, label=n_("Go&to bookmark")) + for i in range(9): + label = _("Bookmark %d") % (i + 1) + acc = m + "%d" % (i + 1) + submenu.add_command(label=label, command=lambda i=i: self.mGotoBookmark(i), accelerator=acc) + menu.add_command(label=n_("&Clear bookmarks"), command=self.mClearBookmarks) + menu.add_separator() + + menu.add_command(label=n_("Restart"), command=self.mRestart, accelerator=m+"G") + + menu.add_separator() + menu.add_command(label=n_("Solitaire &Wizard"), command=self.mWizard) + menu.add_command(label=n_("&Edit current game"), command=self.mWizardEdit) + + menu = MfxMenu(self.menubar, label=n_("&Game")) + menu.add_command(label=n_("&Deal cards"), command=self.mDeal, accelerator="D") + menu.add_command(label=n_("&Auto drop"), command=self.mDrop, accelerator="A") + menu.add_command(label=n_("Shu&ffle tiles"), command=self.mShuffle, accelerator="F") + menu.add_checkbutton(label=n_("&Pause"), variable=self.tkopt.pause, command=self.mPause, accelerator="P") + #menu.add_command(label=n_("&Pause"), command=self.mPause, accelerator="P") + menu.add_separator() + menu.add_command(label=n_("S&tatus..."), command=lambda : self.mPlayerStats(mode=100), accelerator=m+"Y") + menu.add_checkbutton(label=n_("&Comments..."), variable=self.tkopt.comment, command=self.mEditGameComment) + menu.add_separator() + menu.add_command(label=n_("&Statistics..."), command=self.mPlayerStats, accelerator=m+"T") + menu.add_command(label=n_("Log..."), command=lambda : self.mPlayerStats(mode=103)) + menu.add_separator() + menu.add_command(label=n_("D&emo statistics"), command=lambda : self.mPlayerStats(mode=1101)) + + 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="F3") + 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) + if USE_FREECELL_SOLVER: + menu.add_command(label=n_("&Solver"), command=self.mSolver) + else: + menu.add_command(label=n_("&Solver"), state='disabled') + menu.add_separator() + menu.add_command(label=n_("&Piles description"), command=self.mStackDesk, accelerator="F2") + + if self.progress: self.progress.update(step=1) + + menu = MfxMenu(self.menubar, label=n_("&Options")) + menu.add_command(label=n_("&Player options..."), command=self.mOptPlayerOptions) + submenu = MfxMenu(menu, label=n_("&Automatic play")) + submenu.add_checkbutton(label=n_("Auto &face up"), variable=self.tkopt.autofaceup, command=self.mOptAutoFaceUp) + submenu.add_checkbutton(label=n_("A&uto drop"), variable=self.tkopt.autodrop, command=self.mOptAutoDrop) + submenu.add_checkbutton(label=n_("Auto &deal"), variable=self.tkopt.autodeal, command=self.mOptAutoDeal) + submenu.add_separator() + submenu.add_checkbutton(label=n_("&Quick play"), variable=self.tkopt.quickplay, command=self.mOptQuickPlay) + submenu = MfxMenu(menu, label=n_("Assist &level")) + submenu.add_checkbutton(label=n_("Enable &undo"), variable=self.tkopt.undo, command=self.mOptEnableUndo) + submenu.add_checkbutton(label=n_("Enable &bookmarks"), variable=self.tkopt.bookmarks, command=self.mOptEnableBookmarks) + submenu.add_checkbutton(label=n_("Enable &hint"), variable=self.tkopt.hint, command=self.mOptEnableHint) + submenu.add_checkbutton(label=n_("Enable shu&ffle"), variable=self.tkopt.shuffle, command=self.mOptEnableShuffle) + submenu.add_checkbutton(label=n_("Enable highlight p&iles"), variable=self.tkopt.highlight_piles, command=self.mOptEnableHighlightPiles) + submenu.add_checkbutton(label=n_("Enable highlight &cards"), variable=self.tkopt.highlight_cards, command=self.mOptEnableHighlightCards) + submenu.add_checkbutton(label=n_("Enable highlight same &rank"), variable=self.tkopt.highlight_samerank, command=self.mOptEnableHighlightSameRank) + submenu.add_checkbutton(label=n_("Highlight &no matching"), variable=self.tkopt.highlight_not_matching, command=self.mOptEnableHighlightNotMatching) + submenu.add_separator() + submenu.add_checkbutton(label=n_("&Show removed tiles (in Mahjongg games)"), variable=self.tkopt.mahjongg_show_removed, command=self.mOptMahjonggShowRemoved) + submenu.add_checkbutton(label=n_("Show hint &arrow (in Shisen-Sho games)"), variable=self.tkopt.shisen_show_hint, command=self.mOptShisenShowHint) + menu.add_separator() + label = n_("&Sound...") + if not self.app.audio.CAN_PLAY_SOUND: + menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog, state='disabled') + else: + menu.add_checkbutton(label=label, variable=self.tkopt.sound, command=self.mOptSoundDialog) + # cardsets + if USE_PIL: + submenu = MfxMenu(menu, label=n_("Card si&ze")) + submenu.add_command(label=n_("&Increase the card size"), command=self.mIncreaseCardset, accelerator=m+"+") + submenu.add_command(label=n_("&Decrease the card size"), command=self.mDecreaseCardset, accelerator=m+"-") + submenu.add_checkbutton(label=n_("&Auto scaling"), variable=self.tkopt.auto_scale, command=self.mOptAutoScale, accelerator=m+'0') + #manager = self.app.cardset_manager + #n = manager.len() + menu.add_command(label=n_("Cards&et..."), command=self.mSelectCardsetDialog, accelerator=m+"E") + menu.add_command(label=n_("Table t&ile..."), command=self.mSelectTileDialog) + # this submenu will get set by updateBackgroundImagesMenu() + submenu = MfxMenu(menu, label=n_("Card &background")) + submenu = MfxMenu(menu, label=n_("Card &view")) + submenu.add_checkbutton(label=n_("Card shado&w"), variable=self.tkopt.shadow, command=self.mOptShadow) + submenu.add_checkbutton(label=n_("Shade &legal moves"), variable=self.tkopt.shade, command=self.mOptShade) + submenu.add_checkbutton(label=n_("&Negative cards bottom"), variable=self.tkopt.negative_bottom, command=self.mOptNegativeBottom) + submenu.add_checkbutton(label=n_("Shrink face-down cards"), variable=self.tkopt.shrink_face_down, command=self.mOptShrinkFaceDown) + submenu.add_checkbutton(label=n_("Shade &filled stacks"), variable=self.tkopt.shade_filled_stacks, command=self.mOptShadeFilledStacks) + submenu = MfxMenu(menu, label=n_("A&nimations")) + submenu.add_radiobutton(label=n_("&None"), variable=self.tkopt.animations, value=0, command=self.mOptAnimations) + submenu.add_radiobutton(label=n_("&Very fast"), variable=self.tkopt.animations, value=1, command=self.mOptAnimations) + submenu.add_radiobutton(label=n_("&Fast"), variable=self.tkopt.animations, value=2, command=self.mOptAnimations) + submenu.add_radiobutton(label=n_("&Medium"), variable=self.tkopt.animations, value=3, command=self.mOptAnimations) + submenu.add_radiobutton(label=n_("&Slow"), variable=self.tkopt.animations, value=4, command=self.mOptAnimations) + submenu.add_radiobutton(label=n_("V&ery slow"), variable=self.tkopt.animations, value=5, command=self.mOptAnimations) + submenu.add_separator() + submenu.add_checkbutton(label=n_("&Redeal animation"), variable=self.tkopt.redeal_animation, command=self.mRedealAnimation) + if Image: + submenu.add_checkbutton(label=n_("&Winning animation"), variable=self.tkopt.win_animation, command=self.mWinAnimation) + submenu = MfxMenu(menu, label=n_("&Mouse")) + submenu.add_radiobutton(label=n_("&Drag-and-Drop"), variable=self.tkopt.mouse_type, value='drag-n-drop', command=self.mOptMouseType) + submenu.add_radiobutton(label=n_("&Point-and-Click"), variable=self.tkopt.mouse_type, value='point-n-click', command=self.mOptMouseType) + submenu.add_radiobutton(label=n_("&Sticky mouse"), variable=self.tkopt.mouse_type, value='sticky-mouse', command=self.mOptMouseType) + submenu.add_separator() + submenu.add_checkbutton(label=n_("Use mouse for undo/redo"), variable=self.tkopt.mouse_undo, command=self.mOptMouseUndo) + menu.add_separator() + menu.add_command(label=n_("&Fonts..."), command=self.mOptFonts) + menu.add_command(label=n_("&Colors..."), command=self.mOptColors) + menu.add_command(label=n_("Time&outs..."), command=self.mOptTimeouts) + menu.add_separator() + self.createThemesMenu(menu) + submenu = MfxMenu(menu, label=n_("&Toolbar")) + createToolbarMenu(self, submenu) + submenu = MfxMenu(menu, label=n_("Stat&usbar")) + submenu.add_checkbutton(label=n_("Show &statusbar"), variable=self.tkopt.statusbar, command=self.mOptStatusbar) + submenu.add_checkbutton(label=n_("Show &number of cards"), variable=self.tkopt.num_cards, command=self.mOptNumCards) + submenu.add_checkbutton(label=n_("Show &help bar"), variable=self.tkopt.helpbar, command=self.mOptHelpbar) + if not USE_PIL: + menu.add_checkbutton(label=n_("Save games &geometry"), variable=self.tkopt.save_games_geometry, command=self.mOptSaveGamesGeometry) + menu.add_checkbutton(label=n_("&Demo logo"), variable=self.tkopt.demo_logo, command=self.mOptDemoLogo) + menu.add_checkbutton(label=n_("Startup splash sc&reen"), variable=self.tkopt.splashscreen, command=self.mOptSplashscreen) +### menu.add_separator() +### menu.add_command(label="Save options", command=self.mOptSave) + + if self.progress: self.progress.update(step=1) + + menu = MfxMenu(self.menubar, label=n_("&Help")) + menu.add_command(label=n_("&Contents"), command=self.mHelp, accelerator=m+"F1") + menu.add_command(label=n_("&How to play"), command=self.mHelpHowToPlay) + menu.add_command(label=n_("&Rules for this game"), command=self.mHelpRules, accelerator="F1") + menu.add_command(label=n_("&License terms"), command=self.mHelpLicense) + ##menu.add_command(label=n_("What's &new ?"), command=self.mHelpNews) + if WIN_SYSTEM != "aqua": + menu.add_separator() + menu.add_command(label=n_("&About ")+TITLE+"...", command=self.mHelpAbout) + + MfxMenubar.addPath = None + + ### FIXME: all key bindings should be *added* to keyPressHandler + ctrl = "Control-" + if sys.platform == "darwin": ctrl = "Command-" + self._bindKey("", "n", self.mNewGame) + self._bindKey(ctrl, "w", self.mSelectGameDialog) + self._bindKey(ctrl, "v", self.mSelectGameDialogWithPreview) + self._bindKey(ctrl, "r", lambda e: self.mSelectRandomGame()) + self._bindKey(ctrl, "m", self.mSelectGameById) + self._bindKey(ctrl, "n", self.mNewGameWithNextId) + self._bindKey(ctrl, "o", self.mOpen) + self._bindKey(ctrl, "s", self.mSave) + self._bindKey(ctrl, "x", self.mHoldAndQuit) + self._bindKey(ctrl, "q", self.mQuit) + self._bindKey("", "z", self.mUndo) + self._bindKey("", "BackSpace", self.mUndo) # undocumented + self._bindKey("", "KP_Enter", self.mUndo) # undocumented + self._bindKey("", "r", self.mRedo) + self._bindKey(ctrl, "g", self.mRestart) + self._bindKey("", "space", self.mDeal) # undocumented + self._bindKey(ctrl, "y", lambda e: self.mPlayerStats(mode=100)) + self._bindKey(ctrl, "t", lambda e: self.mPlayerStats(mode=105)) + self._bindKey("", "h", self.mHint) + self._bindKey(ctrl, "h", self.mHint1) # undocumented + ##self._bindKey("", "Shift_L", self.mHighlightPiles) + ##self._bindKey("", "Shift_R", self.mHighlightPiles) + self._bindKey("", "i", self.mHighlightPiles) + self._bindKey("", "F3", self.mFindCard) + self._bindKey(ctrl, "d", self.mDemo) + self._bindKey(ctrl, "e", self.mSelectCardsetDialog) + if USE_PIL: + self._bindKey(ctrl, "plus", self.mIncreaseCardset) + self._bindKey(ctrl, "equal", self.mIncreaseCardset) + self._bindKey(ctrl, "minus", self.mDecreaseCardset) + self._bindKey(ctrl, "0", self.mOptAutoScale) + self._bindKey(ctrl, "b", self.mOptChangeCardback) # undocumented + self._bindKey(ctrl, "i", self.mOptChangeTableTile) # undocumented + self._bindKey(ctrl, "p", self.mOptPlayerOptions) # undocumented + self._bindKey(ctrl, "F1", self.mHelp) + self._bindKey("", "F1", self.mHelpRules) + self._bindKey("", "Print", self.mScreenshot) + self._bindKey(ctrl, "u", self.mPlayNextMusic) # undocumented + self._bindKey("", "p", self.mPause) + self._bindKey("", "Pause", self.mPause) # undocumented + self._bindKey("", "Escape", self.mIconify) # undocumented + # ASD and LKJ + self._bindKey("", "a", self.mDrop) + self._bindKey(ctrl, "a", self.mDrop1) + self._bindKey("", "s", self.mUndo) + self._bindKey("", "d", self.mDeal) + self._bindKey("", "l", self.mDrop) + self._bindKey(ctrl, "l", self.mDrop1) + self._bindKey("", "k", self.mUndo) + self._bindKey("", "j", self.mDeal) + + self._bindKey("", "F2", self.mStackDesk) + # + self._bindKey("", "slash", lambda e: self.mPlayerStats(mode=106)) # undocumented, devel + # + self._bindKey("", "f", self.mShuffle) + + for i in range(9): + self._bindKey(ctrl, str(i+1), lambda e, i=i: self.mGotoBookmark(i, confirm=0)) + + # undocumented, devel + self._bindKey(ctrl, "End", self.mPlayNextMusic) + self._bindKey(ctrl, "Prior", self.mSelectPrevGameByName) + self._bindKey(ctrl, "Next", self.mSelectNextGameByName) + self._bindKey(ctrl, "Up", self.mSelectPrevGameById) + self._bindKey(ctrl, "Down", self.mSelectNextGameById) + + + # + # key binding utility + # + + def _bindKey(self, modifier, key, func): +## if 0 and not modifier and len(key) == 1: +## self.keybindings[key.lower()] = func +## self.keybindings[key.upper()] = func +## return + if not modifier and len(key) == 1: + # ignore Ctrl/Shift/Alt + # but don't ignore NumLock (state == 16) + func = lambda e, func=func: e.state in (0, 16) and func(e) + sequence = "<" + modifier + "KeyPress-" + key + ">" + bind(self.top, sequence, func) + if len(key) == 1 and key != key.upper(): + key = key.upper() + sequence = "<" + modifier + "KeyPress-" + key + ">" + bind(self.top, sequence, func) + + + def _keyPressHandler(self, event): + r = EVENT_PROPAGATE + if event and self.game: + ##print event.__dict__ + if self.game.demo: + # stop the demo by setting self.game.demo.keypress + if event.char: # ignore Ctrl/Shift/etc. + self.game.demo.keypress = event.char + r = EVENT_HANDLED +## func = self.keybindings.get(event.char) +## if func and (event.state & ~2) == 0: +## func(event) +## r = EVENT_HANDLED + return r + + # + # Select Game menu creation + # + + def _addSelectGameMenu(self, menu): + #games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByShortName()) + games = map(self.app.gdb.get, self.app.gdb.getGamesIdSortedByName()) + ##games = tuple(games) + ###menu = MfxMenu(menu, label="Select &game") + m = "Ctrl-" + if sys.platform == "darwin": m = "Cmd-" + menu.add_command(label=n_("All &games..."), accelerator=m+"W", + command=self.mSelectGameDialog) + menu.add_command(label=n_("Playable pre&view..."), accelerator=m+"V", + command=self.mSelectGameDialogWithPreview) + if not SELECT_GAME_MENU: + return + menu.add_separator() + self._addSelectPopularGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + self._addSelectFrenchGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + if self.progress: self.progress.update(step=1) + self._addSelectMahjonggGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + self._addSelectOrientalGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + self._addSelectSpecialGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + self._addSelectCustomGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + menu.add_separator() + if self.progress: self.progress.update(step=1) + self._addSelectAllGameSubMenu(games, menu, self.mSelectGame, + self.tkopt.gameid) + + + def _addSelectGameSubMenu(self, games, menu, select_data, + command, variable): + ##print select_data + need_sep = 0 + for label, select_func in select_data: + if label is None: + need_sep = 1 + continue + g = filter(select_func, games) + if not g: + continue + if need_sep: + menu.add_separator() + need_sep = 0 + submenu = MfxMenu(menu, label=label) + self._addSelectGameSubSubMenu(g, submenu, command, variable) + + def _getNumGames(self, games, select_data): + ngames = 0 + for label, select_func in select_data: + ngames += len(filter(select_func, games)) + return ngames + + def _addSelectMahjonggGameSubMenu(self, games, menu, command, variable): + select_func = lambda gi: gi.si.game_type == GI.GT_MAHJONGG + mahjongg_games = filter(select_func, games) + if len(mahjongg_games) == 0: + return + # + menu = MfxMenu(menu, label=n_("&Mahjongg games")) + + def add_menu(games, c0, c1, menu=menu, + variable=variable, command=command): + if not games: + return + label = c0 + ' - ' + c1 + if c0 == c1: + label = c0 + submenu = MfxMenu(menu, label=label, name=None) + self._addSelectGameSubSubMenu(games, submenu, command, + variable, short_name=True) + + games = {} + for gi in mahjongg_games: + c = gi.short_name.strip()[0] + if c in games: + games[c].append(gi) + else: + games[c] = [gi] + games = games.items() + games.sort() + g0 = [] + c0 = c1 = games[0][0] + for c, g1 in games: + if len(g0)+len(g1) >= self.cb_max: + add_menu(g0, c0, c1) + g0 = g1 + c0 = c1 = c + else: + g0 += g1 + c1 = c + add_menu(g0, c0, c1) + + def _addSelectPopularGameSubMenu(self, games, menu, command, variable): + select_func = lambda gi: gi.si.game_flags & GI.GT_POPULAR + if len(filter(select_func, games)) == 0: + return + data = (n_("&Popular games"), select_func) + self._addSelectGameSubMenu(games, menu, (data, ), + self.mSelectGamePopular, + self.tkopt.gameid_popular) + + def _addSelectFrenchGameSubMenu(self, games, menu, command, variable): + if self._getNumGames(games, GI.SELECT_GAME_BY_TYPE) == 0: + return + submenu = MfxMenu(menu, label=n_("&French games")) + self._addSelectGameSubMenu(games, submenu, GI.SELECT_GAME_BY_TYPE, + self.mSelectGame, self.tkopt.gameid) + + def _addSelectOrientalGameSubMenu(self, games, menu, command, variable): + if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: + return + submenu = MfxMenu(menu, label=n_("&Oriental games")) + self._addSelectGameSubMenu(games, submenu, + GI.SELECT_ORIENTAL_GAME_BY_TYPE, + self.mSelectGame, self.tkopt.gameid) + + def _addSelectSpecialGameSubMenu(self, games, menu, command, variable): + if self._getNumGames(games, GI.SELECT_ORIENTAL_GAME_BY_TYPE) == 0: + return + submenu = MfxMenu(menu, label=n_("&Special games")) + self._addSelectGameSubMenu(games, submenu, + GI.SELECT_SPECIAL_GAME_BY_TYPE, + self.mSelectGame, self.tkopt.gameid) + + def _addSelectCustomGameSubMenu(self, games, menu, command, variable): + submenu = MfxMenu(menu, label=n_("&Custom games")) + select_func = lambda gi: gi.si.game_type == GI.GT_CUSTOM + games = filter(select_func, games) + self.updateGamesMenu(submenu, games) + + def _addSelectAllGameSubMenu(self, games, menu, command, variable): + menu = MfxMenu(menu, label=n_("&All games by name")) + n, d = 0, self.cb_max + i = 0 + while True: + if self.progress: self.progress.update(step=1) + columnbreak = i > 0 and (i % d) == 0 + i += 1 + if not games[n:n+d]: + break + m = min(n+d-1, len(games)-1) + label = games[n].name[:3] + ' - ' + games[m].name[:3] + submenu = MfxMenu(menu, label=label, name=None) + self._addSelectGameSubSubMenu(games[n:n+d], submenu, + command, variable) + n += d + if columnbreak: + menu.entryconfigure(i, columnbreak=columnbreak) + + def _addSelectGameSubSubMenu(self, games, menu, command, variable, + short_name=False): + ##cb = (25, self.cb_max) [ len(g) > 4 * 25 ] + ##cb = min(cb, self.cb_max) + cb = self.cb_max + for i in range(len(games)): + gi = games[i] + columnbreak = i > 0 and (i % cb) == 0 + if short_name: + label = gi.short_name + else: + label = gi.name + # optimized by inlining + menu.tk.call((menu._w, 'add', 'radiobutton') + + menu._options({'command': command, + 'variable': variable, + 'columnbreak': columnbreak, + 'value': gi.id, + 'label': label})) + + def updateGamesMenu(self, menu, games): + menu.delete(0, 'last') + if len(games) == 0: + menu.add_radiobutton(label='', name=None, state='disabled') + elif len(games) > self.cb_max*4: + games.sort(lambda a, b: cmp(a.name, b.name)) + self._addSelectAllGameSubMenu(games, menu, + command=self.mSelectGame, + variable=self.tkopt.gameid) + else: + self._addSelectGameSubSubMenu(games, menu, + command=self.mSelectGame, + variable=self.tkopt.gameid) + + # + # Select Game menu actions + # + + def mSelectGame(self, *args): + self._mSelectGame(self.tkopt.gameid.get()) + + def mSelectGamePopular(self, *args): + self._mSelectGame(self.tkopt.gameid_popular.get()) + + def _mSelectGameDialog(self, d): + if d.status == 0 and d.button == 0 and d.gameid != self.game.id: + self.tkopt.gameid.set(d.gameid) + self.tkopt.gameid_popular.set(d.gameid) + if 0: + self._mSelectGame(d.gameid, random=d.random) + else: + # don't ask areYouSure() + self._cancelDrag() + self.game.endGame() + self.game.quitGame(d.gameid, random=d.random) + return EVENT_HANDLED + + def __restoreCursor(self, *event): + self.game.setCursor(cursor=self.app.top_cursor) + + def mSelectGameDialog(self, *event): + if self._cancelDrag(break_pause=False): return + self.game.setCursor(cursor=CURSOR_WATCH) + after_idle(self.top, self.__restoreCursor) + d = SelectGameDialog(self.top, title=_("Select game"), + app=self.app, gameid=self.game.id) + return self._mSelectGameDialog(d) + + def mSelectGameDialogWithPreview(self, *event): + if self._cancelDrag(break_pause=False): return + self.game.setCursor(cursor=CURSOR_WATCH) + bookmark = None + if 0: + # use a bookmark for our preview game + if self.game.setBookmark(-2, confirm=0): + bookmark = self.game.gsaveinfo.bookmarks[-2][0] + del self.game.gsaveinfo.bookmarks[-2] + after_idle(self.top, self.__restoreCursor) + d = SelectGameDialogWithPreview(self.top, title=_("Select game"), + app=self.app, gameid=self.game.id, + bookmark=bookmark) + return self._mSelectGameDialog(d) + + + # + # menubar overrides + # + + def updateFavoriteGamesMenu(self): + gameids = self.app.opt.favorite_gameid + submenu = self.menupath[".menubar.file.favoritegames"][2] + games = [] + for id in gameids: + gi = self.app.getGameInfo(id) + if gi: + games.append(gi) + self.updateGamesMenu(submenu, games) + state = self._getEnabledState + in_favor = self.app.game.id in gameids + menu, index, submenu = self.menupath[".menubar.file.addtofavorites"] + menu.entryconfig(index, state=state(not in_favor)) + menu, index, submenu = self.menupath[".menubar.file.removefromfavorites"] + menu.entryconfig(index, state=state(in_favor)) + + + def updateRecentGamesMenu(self, gameids): + submenu = self.menupath[".menubar.file.recentgames"][2] + games = [] + for id in gameids: + gi = self.app.getGameInfo(id) + if gi: + games.append(gi) + self.updateGamesMenu(submenu, games) + + def updateBookmarkMenuState(self): + state = self._getEnabledState + mp1 = self.menupath.get(".menubar.edit.setbookmark") + mp2 = self.menupath.get(".menubar.edit.gotobookmark") + mp3 = self.menupath.get(".menubar.edit.clearbookmarks") + if mp1 is None or mp2 is None or mp3 is None: + return + x = self.app.opt.bookmarks and self.game.canSetBookmark() + # + menu, index, submenu = mp1 + for i in range(9): + submenu.entryconfig(i, state=state(x)) + menu.entryconfig(index, state=state(x)) + # + menu, index, submenu = mp2 + ms = 0 + for i in range(9): + s = self.game.gsaveinfo.bookmarks.get(i) is not None + submenu.entryconfig(i, state=state(s and x)) + ms = ms or s + menu.entryconfig(index, state=state(ms and x)) + # + menu, index, submenu = mp3 + menu.entryconfig(index, state=state(ms and x)) + + def updateBackgroundImagesMenu(self): + mp = self.menupath.get(".menubar.options.cardbackground") + # delete all entries + submenu = mp[2] + submenu.delete(0, "last") + # insert new cardbacks + mbacks = self.app.images.getCardbacks() + cb = int(math.ceil(math.sqrt(len(mbacks)))) + for i in range(len(mbacks)): + columnbreak = i > 0 and (i % cb) == 0 + submenu.add_radiobutton(label=mbacks[i].name, image=mbacks[i].menu_image, variable=self.tkopt.cardback, value=i, + command=self.mOptCardback, columnbreak=columnbreak, indicatoron=0, hidemargin=0) + + + # + # menu updates + # + + def setMenuState(self, state, path): + #print state, path + path = ".menubar." + path + mp = self.menupath.get(path) + menu, index, submenu = mp + s = self._getEnabledState(state) + menu.entryconfig(index, state=s) + + def setToolbarState(self, state, path): + #print state, path + s = self._getEnabledState(state) + w = getattr(self.app.toolbar, path + "_button") + w["state"] = s + + def _setCommentMenu(self, v): + self.tkopt.comment.set(v) + + def _setPauseMenu(self, v): + self.tkopt.pause.set(v) + + + # + # menu actions + # + + DEFAULTEXTENSION = ".pso" + FILETYPES = ((TITLE+" files", "*"+DEFAULTEXTENSION), ("All files", "*")) + + def mAddFavor(self, *event): + gameid = self.app.game.id + if gameid not in self.app.opt.favorite_gameid: + self.app.opt.favorite_gameid.append(gameid) + self.updateFavoriteGamesMenu() + + def mDelFavor(self, *event): + gameid = self.app.game.id + if gameid in self.app.opt.favorite_gameid: + self.app.opt.favorite_gameid.remove(gameid) + self.updateFavoriteGamesMenu() + + def mOpen(self, *event): + if self._cancelDrag(break_pause=False): return + filename = self.game.filename + if filename: + idir, ifile = os.path.split(os.path.normpath(filename)) + else: + idir, ifile = "", "" + if not idir: + idir = self.app.dn.savegames + d = tkFileDialog.Open() + filename = d.show(filetypes=self.FILETYPES, + defaultextension=self.DEFAULTEXTENSION, + initialdir=idir, initialfile=ifile) + if filename: + filename = os.path.normpath(filename) + ##filename = os.path.normcase(filename) + if os.path.isfile(filename): + self.game.loadGame(filename) + + def mExportCurrentLayout(self, *event): + if self._cancelDrag(break_pause=False): return + game = self.game + if not self.menustate.save_as: + return + if not game.Solver_Class: + d = MfxMessageDialog(self.top, title=_('Export game error'), + text=_(''' +Unsupported game for export. +'''), + bitmap='error') + return + + filename = game.filename + if not filename: + filename = self.app.getGameSaveName(self.game.id) + if os.name == "posix" or os.path.supports_unicode_filenames: + filename += "-" + self.game.getGameNumber(format=0) + else: + filename += "-01" + filename += ".board" + idir, ifile = os.path.split(os.path.normpath(filename)) + if not idir: + idir = self.app.dn.savegames + ##print self.game.filename, ifile + d = tkFileDialog.SaveAs() + filename = d.show(filetypes=self.FILETYPES, + defaultextension=self.DEFAULTEXTENSION, + initialdir=idir, initialfile=ifile) + if filename: + filename = os.path.normpath(filename) + ##filename = os.path.normcase(filename) + with open(filename, 'w') as fh: + game = self.game + fh.write(game.Solver_Class(game, self).calcBoardString()) + self.updateMenus() + + def mSaveAs(self, *event): + if self._cancelDrag(break_pause=False): return + if not self.menustate.save_as: + return + filename = self.game.filename + if not filename: + filename = self.app.getGameSaveName(self.game.id) + if os.name == "posix": + filename = filename + "-" + self.game.getGameNumber(format=0) + elif os.path.supports_unicode_filenames: # new in python 2.3 + filename = filename + "-" + self.game.getGameNumber(format=0) + else: + filename = filename + "-01" + filename = filename + self.DEFAULTEXTENSION + idir, ifile = os.path.split(os.path.normpath(filename)) + if not idir: + idir = self.app.dn.savegames + ##print self.game.filename, ifile + d = tkFileDialog.SaveAs() + filename = d.show(filetypes=self.FILETYPES, + defaultextension=self.DEFAULTEXTENSION, + initialdir=idir, initialfile=ifile) + if filename: + filename = os.path.normpath(filename) + ##filename = os.path.normcase(filename) + self.game.saveGame(filename) + self.updateMenus() + + def mPause(self, *args): + if not self.game: + return + if not self.game.pause: + if self._cancelDrag(): return + self.game.doPause() + self.tkopt.pause.set(self.game.pause) + + def mOptSoundDialog(self, *args): + if self._cancelDrag(break_pause=False): return + d = SoundOptionsDialog(self.top, _("Sound settings"), self.app) + self.tkopt.sound.set(self.app.opt.sound) + + def mOptAutoFaceUp(self, *args): + if self._cancelDrag(): return + self.app.opt.autofaceup = self.tkopt.autofaceup.get() + if self.app.opt.autofaceup: + self.game.autoPlay() + + def mOptAutoDrop(self, *args): + if self._cancelDrag(): return + self.app.opt.autodrop = self.tkopt.autodrop.get() + if self.app.opt.autodrop: + self.game.autoPlay() + + def mOptAutoDeal(self, *args): + if self._cancelDrag(): return + self.app.opt.autodeal = self.tkopt.autodeal.get() + if self.app.opt.autodeal: + self.game.autoPlay() + + def mOptQuickPlay(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.quickplay = self.tkopt.quickplay.get() + + def mOptEnableUndo(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.undo = self.tkopt.undo.get() + self.game.updateMenus() + + def mOptEnableBookmarks(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.bookmarks = self.tkopt.bookmarks.get() + self.game.updateMenus() + + def mOptEnableHint(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.hint = self.tkopt.hint.get() + self.game.updateMenus() + + def mOptEnableShuffle(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shuffle = self.tkopt.shuffle.get() + self.game.updateMenus() + + def mOptEnableHighlightPiles(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.highlight_piles = self.tkopt.highlight_piles.get() + self.game.updateMenus() + + def mOptEnableHighlightCards(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.highlight_cards = self.tkopt.highlight_cards.get() + self.game.updateMenus() + + def mOptEnableHighlightSameRank(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.highlight_samerank = self.tkopt.highlight_samerank.get() + ##self.game.updateMenus() + + def mOptEnableHighlightNotMatching(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.highlight_not_matching = self.tkopt.highlight_not_matching.get() + ##self.game.updateMenus() + + def mOptAnimations(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.animations = self.tkopt.animations.get() + + def mRedealAnimation(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.redeal_animation = self.tkopt.redeal_animation.get() + + def mWinAnimation(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.win_animation = self.tkopt.win_animation.get() + + def mOptShadow(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shadow = self.tkopt.shadow.get() + + def mOptShade(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shade = self.tkopt.shade.get() + + def mOptShrinkFaceDown(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shrink_face_down = self.tkopt.shrink_face_down.get() + self.game.endGame(bookmark=1) + self.game.quitGame(bookmark=1) + + def mOptShadeFilledStacks(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shade_filled_stacks = self.tkopt.shade_filled_stacks.get() + self.game.endGame(bookmark=1) + self.game.quitGame(bookmark=1) + + def mOptMahjonggShowRemoved(self, *args): + if self._cancelDrag(): return + self.app.opt.mahjongg_show_removed = self.tkopt.mahjongg_show_removed.get() + ##self.game.updateMenus() + self.game.endGame(bookmark=1) + self.game.quitGame(bookmark=1) + + def mOptShisenShowHint(self, *args): + if self._cancelDrag(break_pause=False): return + self.app.opt.shisen_show_hint = self.tkopt.shisen_show_hint.get() + ##self.game.updateMenus() + + def _updateCardSize(self): + geom = (self.app.canvas.winfo_width(), + self.app.canvas.winfo_height()) + self.app.opt.game_geometry = geom + self.app.game.resizeGame() + if self.app.opt.auto_scale: + w, h = self.app.opt.game_geometry + self.app.canvas.setInitialSize(w, h, scrollregion=False) + else: + w = int(round(self.app.game.width * self.app.opt.scale_x)) + h = int(round(self.app.game.height * self.app.opt.scale_y)) + self.app.canvas.setInitialSize(w, h) + self.app.top.wm_geometry("") # cancel user-specified geometry + ##self.app.top.update_idletasks() + + def mIncreaseCardset(self, *event): + if self._cancelDrag(break_pause=True): return + if self.app.opt.scale_x < 4: + self.app.opt.scale_x += 0.1 + else: + return + if self.app.opt.scale_y < 4: + self.app.opt.scale_y += 0.1 + else: + return + self.app.opt.auto_scale = False + self.tkopt.auto_scale.set(False) + self._updateCardSize() + + def mDecreaseCardset(self, *event): + if self._cancelDrag(break_pause=True): return + if self.app.opt.scale_x > 0.5: + self.app.opt.scale_x -= 0.1 + else: + return + if self.app.opt.scale_y > 0.5: + self.app.opt.scale_y -= 0.1 + else: + return + self.app.opt.auto_scale = False + self.tkopt.auto_scale.set(False) + self._updateCardSize() + + def mOptAutoScale(self, *event): + if self._cancelDrag(break_pause=True): return + auto_scale = not self.app.opt.auto_scale + self.app.opt.auto_scale = auto_scale + self.tkopt.auto_scale.set(auto_scale) + self._updateCardSize()