From 92cab44b85096f53acf46bee7c091b3bcceae670 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Fri, 4 May 2007 21:17:52 +0000 Subject: [PATCH] + added solitaire wizard to Tk-binding * improved solitaire wizard git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@158 efabe8c0-fbe8-4139-b769-b5e6d273206e --- pysollib/customgame.py | 140 +++++++++++++++++++++++++--------- pysollib/game.py | 21 +++++ pysollib/games/spider.py | 30 +------- pysollib/stack.py | 64 +++++++++++++++- pysollib/tile/wizarddialog.py | 14 ++-- pysollib/tk/menubar.py | 48 ++++++++++++ pysollib/tk/tabpage.py | 124 ++++++++++++++++++++++++++++++ pysollib/tk/wizarddialog.py | 108 ++++++++++++++++++++++++++ pysollib/wizardutil.py | 58 ++++++++------ 9 files changed, 511 insertions(+), 96 deletions(-) create mode 100644 pysollib/tk/tabpage.py create mode 100644 pysollib/tk/wizarddialog.py diff --git a/pysollib/customgame.py b/pysollib/customgame.py index caa38e22..059812b4 100644 --- a/pysollib/customgame.py +++ b/pysollib/customgame.py @@ -29,6 +29,7 @@ from hint import AbstractHint, DefaultHint, CautiousDefaultHint from wizardutil import WizardWidgets + # /*********************************************************************** # // # ************************************************************************/ @@ -48,59 +49,118 @@ class CustomGame(Game): v = ss[w.var_name] s[w.var_name] = v ##from pprint import pprint; pprint(s) - foundation = StackWrapper( - s['found_type'], - base_rank=s['found_base_card'], - dir=s['found_dir'], - max_move=s['found_max_move'], - ) - max_rounds = s['redeals'] - if max_rounds >= 0: - max_rounds += 1 - talon = StackWrapper( - s['talon'], - max_rounds=max_rounds, - ) - row = StackWrapper( - s['rows_type'], - base_rank=s['rows_base_card'], - dir=s['rows_dir'], - max_move=s['rows_max_move'], - ) - kw = {'rows' : s['rows_num'], + + # foundations + kw = { + 'dir': s['found_dir'], + 'base_rank': s['found_base_card'], + } + if s['found_type'] not in (Spider_SS_Foundation, + Spider_AC_Foundation,): + kw['max_move'] = s['found_max_move'] + else: + kw['dir'] = -kw['dir'] + if s['found_base_card'] == KING: + kw['base_rank'] = ACE + elif s['found_base_card'] == ACE: + kw['base_rank'] = KING + if s['found_wrap']: + kw['mod'] = 13 + foundation = StackWrapper(s['found_type'], **kw) + + # talon + kw = { + 'max_rounds': s['redeals'], + } + if s['redeals'] >= 0: + kw['max_rounds'] += 1 + talon = StackWrapper(s['talon'], **kw) + + # rows + kw = { + 'base_rank': s['rows_base_card'], + 'dir': s['rows_dir'], + 'max_move': s['rows_max_move'], + } + if s['rows_wrap']: + kw['mod'] = 13 + row = StackWrapper(s['rows_type'], **kw) + + # layout + layout_kw = {'rows' : s['rows_num'], 'waste' : False, 'texts' : True, } if s['talon'] is InitialDealTalonStack: - kw['texts'] = False - if s['talon'] is WasteTalonStack: - kw['waste'] = True - kw['waste_class'] = WasteStack - if int(s['reserves_num']): - kw['reserves'] = s['reserves_num'] - kw['reserve_class'] = s['reserves_type'] + layout_kw['texts'] = False + layout_kw['playcards'] = 12+s['deal_to_rows'] - kw['playcards'] = 12+s['deal_to_rows'] + # reserves + if s['reserves_num']: + layout_kw['reserves'] = s['reserves_num'] + kw = { + 'max_accept': s['reserves_max_accept'], + } + if s['reserves_max_accept']: + layout_kw['reserve_class'] = StackWrapper(ReserveStack, **kw) + else: + layout_kw['reserve_class'] = StackWrapper(OpenStack, **kw) + + # waste + if s['talon'] is WasteTalonStack: + layout_kw['waste'] = True + layout_kw['waste_class'] = WasteStack Layout(self).createGame(layout_method = s['layout'], talon_class = talon, foundation_class = foundation, row_class = row, - **kw + **layout_kw ) + # shallHighlightMatch for c, f in ( - ((AC_RowStack, UD_AC_RowStack), - self._shallHighlightMatch_AC), - ((SS_RowStack, UD_SS_RowStack), - self._shallHighlightMatch_SS), - ((RK_RowStack, UD_RK_RowStack), - self._shallHighlightMatch_RK), - ): + ((Spider_AC_RowStack, Spider_SS_RowStack), + (self._shallHighlightMatch_RK, + self._shallHighlightMatch_RKW)), + ((AC_RowStack, UD_AC_RowStack), + (self._shallHighlightMatch_AC, + self._shallHighlightMatch_ACW)), + ((SS_RowStack, UD_SS_RowStack), + (self._shallHighlightMatch_SS, + self._shallHighlightMatch_SSW)), + ((RK_RowStack, UD_RK_RowStack), + (self._shallHighlightMatch_RK, + self._shallHighlightMatch_RKW)), + ((SC_RowStack, UD_SC_RowStack), + (self._shallHighlightMatch_SC, + self._shallHighlightMatch_SCW)), + ((BO_RowStack,), + (self._shallHighlightMatch_BO, + self._shallHighlightMatch_BOW)), + ): if s['rows_type'] in c: - self.shallHighlightMatch = f + if s['rows_wrap']: + self.shallHighlightMatch = f[1] + else: + self.shallHighlightMatch = f[0] break + # getQuickPlayScore + if s['rows_type'] in (Spider_AC_RowStack, Spider_SS_RowStack): + self.getQuickPlayScore = self._getSpiderQuickPlayScore + + # canDropCards + if s['found_type'] in (Spider_SS_Foundation, + Spider_AC_Foundation,): + for stack in self.s.rows: + stack.canDropCards = stack.spiderCanDropCards + + if s['found_base_card'] == ANY_RANK: + for stack in self.s.foundations: + stack.acceptsCards = stack.varyAcceptsCards + stack.getBaseCard = stack.getVaryBaseCard + def startGame(self): frames = 0 @@ -115,7 +175,7 @@ class CustomGame(Game): self.startDealSample() # deal to rows - flip = self.SETTINGS['deal_faceup'] == 'All cards' + flip = (self.SETTINGS['deal_faceup'] == 'All cards') max_rows = self.SETTINGS['deal_to_rows'] if self.SETTINGS['deal_type'] == 'Triangle': # triangle @@ -140,12 +200,16 @@ class CustomGame(Game): if frames == 0: self.startDealSample() self.s.talon.dealRowAvail() + if isinstance(self.s.talon, InitialDealTalonStack): + while self.s.talon.cards: + self.s.talon.dealRowAvail() # deal to waste if self.s.waste: self.s.talon.dealCards() + def registerCustomGame(gameclass): s = gameclass.SETTINGS diff --git a/pysollib/game.py b/pysollib/game.py index ad0aaec1..6eff160d 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -2038,6 +2038,27 @@ for %d moves. return ((card1.rank + 1) % 13 == card2.rank or (card2.rank + 1) % 13 == card1.rank) + def _shallHighlightMatch_BO(self, stack1, card1, stack2, card2): + # by any suit but own + return card1.suit != card2.suit and abs(card1.rank-card2.rank) == 1 + + def _shallHighlightMatch_BOW(self, stack1, card1, stack2, card2): + # by any suit but own with wrapping (only for french games) + return (card1.suit != card2.suit + and ((card1.rank + 1) % 13 == card2.rank + or (card2.rank + 1) % 13 == card1.rank)) + + def _shallHighlightMatch_SC(self, stack1, card1, stack2, card2): + # by same color + return card1.color == card2.color and abs(card1.rank-card2.rank) == 1 + + def _shallHighlightMatch_SCW(self, stack1, card1, stack2, card2): + # by same color with wrapping (only for french games) + return (card1.color == card2.color + and ((card1.rank + 1) % 13 == card2.rank + or (card2.rank + 1) % 13 == card1.rank)) + + # # quick-play # diff --git a/pysollib/games/spider.py b/pysollib/games/spider.py index 557ec15e..876e3c2f 100644 --- a/pysollib/games/spider.py +++ b/pysollib/games/spider.py @@ -81,36 +81,8 @@ class Spider_Hint(SpiderType_Hint): # // # ************************************************************************/ -class Spider_SS_Foundation(AbstractFoundationStack): - def __init__(self, x, y, game, suit=ANY_SUIT, **cap): - kwdefault(cap, dir=-1, base_rank=KING, - min_accept=13, max_accept=13, max_move=0) - AbstractFoundationStack.__init__(self, x, y, game, suit, **cap) - - def acceptsCards(self, from_stack, cards): - if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): - return 0 - # now check the cards - return isSameSuitSequence(cards, self.cap.mod, self.cap.dir) - - -class Spider_AC_Foundation(Spider_SS_Foundation): - def acceptsCards(self, from_stack, cards): - if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): - return 0 - # now check the cards - return isAlternateColorSequence(cards, self.cap.mod, self.cap.dir) - - class Spider_RowStack(Spider_SS_RowStack): - def canDropCards(self, stacks): - if len(self.cards) < 13: - return (None, 0) - cards = self.cards[-13:] - for s in stacks: - if s is not self and s.acceptsCards(self, cards): - return (s, 13) - return (None, 0) + canDropCards = BasicRowStack.spiderCanDropCards class SuperMoveSpider_RowStack(SuperMoveStack_StackMethods, Spider_RowStack): diff --git a/pysollib/stack.py b/pysollib/stack.py index ade153f5..caae7224 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -58,6 +58,8 @@ __all__ = ['cardsFaceUp', 'RK_FoundationStack', 'AC_FoundationStack', 'SC_FoundationStack', + 'Spider_SS_Foundation', + 'Spider_AC_Foundation', #'SequenceStack_StackMethods', 'BasicRowStack', 'SequenceRowStack', @@ -1492,11 +1494,14 @@ class Stack: def getBaseCard(self): return '' - def _getBaseCard(self): + def _getBaseCard(self, rank=None): # FIXME: no-french games if self.cap.max_accept == 0: return '' - br = self.cap.base_rank + if rank is None: + br = self.cap.base_rank + else: + br = rank s = _('Base card - %s.') if br == NO_RANK: s = _('Empty row cannot be filled.') elif br == -1: s = s % _('any card') @@ -2068,6 +2073,28 @@ class AbstractFoundationStack(OpenStack): def getHelp(self): return _('Foundation.') + def varyAcceptsCards(self, from_stack, cards): + # if base rank of foundations is vary + subclass = self.__class__ # derived class (SS_FoundationStack, etc) + assert subclass is not AbstractFoundationStack + if self.cards: + return subclass.acceptsCards(self, from_stack, cards) + if not subclass.acceptsCards(self, from_stack, cards): + return False + # this stack don't have cards: check base rank of other stacks + for s in self.game.s.foundations: + if s.cards: + base_card = s.cards[0] + return base_card.rank == cards[0].rank + return True # all foundations is empty + + def getVaryBaseCard(self): + rank = None + for s in self.game.s.foundations: + if s.cards: + rank = s.cards[0].rank + return self._getBaseCard(rank=rank) + # A SameSuit_FoundationStack is the typical Foundation stack. # It builds up in rank and suit. @@ -2146,6 +2173,29 @@ class SC_FoundationStack(SS_FoundationStack): else: return _('Foundation. Build by same rank.') +# Spider-type foundations +class Spider_SS_Foundation(AbstractFoundationStack): + def __init__(self, x, y, game, suit=ANY_SUIT, **cap): + kwdefault(cap, dir=-1, base_rank=KING, + min_accept=13, max_accept=13, max_move=0) + AbstractFoundationStack.__init__(self, x, y, game, suit, **cap) + + def acceptsCards(self, from_stack, cards): + if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): + return 0 + # now check the cards + return isSameSuitSequence(cards, self.cap.mod, self.cap.dir) + + +class Spider_AC_Foundation(Spider_SS_Foundation): + def acceptsCards(self, from_stack, cards): + if not AbstractFoundationStack.acceptsCards(self, from_stack, cards): + return 0 + # now check the cards + return isAlternateColorSequence(cards, self.cap.mod, self.cap.dir) + + + # /*********************************************************************** # // Abstract classes for row stacks. # ************************************************************************/ @@ -2192,6 +2242,16 @@ class BasicRowStack(OpenStack): #def getBaseCard(self): # return self._getBaseCard() + def spiderCanDropCards(self, stacks): + # drop whole sequence + if len(self.cards) < 13: + return (None, 0) + cards = self.cards[-13:] + for s in stacks: + if s is not self and s.acceptsCards(self, cards): + return (s, 13) + return (None, 0) + # Abstract class. class SequenceRowStack(SequenceStack_StackMethods, BasicRowStack): diff --git a/pysollib/tile/wizarddialog.py b/pysollib/tile/wizarddialog.py index efae86f1..02fc377e 100644 --- a/pysollib/tile/wizarddialog.py +++ b/pysollib/tile/wizarddialog.py @@ -55,7 +55,8 @@ class WizardDialog(MfxDialog): for w in WizardWidgets: if isinstance(w, basestring): frame = Frame(notebook) - notebook.add(frame, text=w) + notebook.add(frame, text=w, sticky='nsew', padding=5) + frame.columnconfigure(1, weight=1) row = 0 continue @@ -64,12 +65,11 @@ class WizardDialog(MfxDialog): if w.widget == 'entry': w.variable = var = StringVar() en = Entry(frame, textvariable=var) - en.grid(row=row, column=1, sticky='ew') + en.grid(row=row, column=1, sticky='ew', padx=2, pady=2) elif w.widget == 'menu': w.variable = var = StringVar() - ##OptionMenu(frame, var, *w.values).grid(row=row, column=1) cb = Combobox(frame, values=tuple(w.values), textvariable=var, - state='readonly', width=20) + state='readonly', width=32) cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2) elif w.widget == 'spin': w.variable = var = IntVar() @@ -78,7 +78,11 @@ class WizardDialog(MfxDialog): s = PysolScale(frame, from_=from_, to=to, resolution=1, orient='horizontal', variable=var) - s.grid(row=row, column=1, sticky='ew') + s.grid(row=row, column=1, sticky='ew', padx=2, pady=2) + elif w.widget == 'check': + w.variable = var = BooleanVar() + ch = Checkbutton(frame, variable=var, takefocus=False) + ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2) if w.current_value is None: var.set(w.default) diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py index fbd44c38..f24a29b7 100644 --- a/pysollib/tk/menubar.py +++ b/pysollib/tk/menubar.py @@ -61,6 +61,7 @@ from selecttile import SelectTileDialogWithPreview from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog from solverdialog import connect_game_solver_dialog from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar +from wizarddialog import WizardDialog #from toolbar import TOOLBAR_BUTTONS from tkconst import TOOLBAR_BUTTONS @@ -401,6 +402,10 @@ class PysolMenubar(PysolMenubarActions): 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") @@ -1340,3 +1345,46 @@ class PysolMenubar(PysolMenubarActions): else: if self._cancelDrag(break_pause=True): return self.game.showStackDesc() + + + def wizardDialog(self, edit=False): + from pysollib.wizardutil import write_game, reset_wizard + if edit: + reset_wizard(self.game) + d = WizardDialog(self.top, _('Solitaire Wizard'), self.app) + if d.status == 0 and d.button == 0: + try: + if edit: + gameid = write_game(self.app, game=self.game) + else: + gameid = write_game(self.app) + except Exception, err: + if DEBUG: + traceback.print_exc() + d = MfxMessageDialog(self.top, title=_('Save game error'), + text=_(''' +Error while saving game. + +%s +''') % str(err), + bitmap='error') + return + if SELECT_GAME_MENU and not edit: + gi = self.app.getGameInfo(gameid) + label = gettext(gi.name) + menu = self.__menupath[".menubar.select.frenchgames.cusomgames"][2] + menu.add_radiobutton(command=self.mSelectGame, + variable=self.tkopt.gameid, + value=gameid, label=label, name=None) + self.tkopt.gameid.set(gameid) + self._mSelectGame(gameid, force=True) + + + def mWizard(self, *event): + if self._cancelDrag(break_pause=False): return + self.wizardDialog() + + def mWizardEdit(self, *event): + if self._cancelDrag(break_pause=False): return + self.wizardDialog(edit=True) + diff --git a/pysollib/tk/tabpage.py b/pysollib/tk/tabpage.py new file mode 100644 index 00000000..028bba84 --- /dev/null +++ b/pysollib/tk/tabpage.py @@ -0,0 +1,124 @@ +# +# This file is part of IDLE project - http://www.python.org/idle/ +# +""" +a couple of classes for implementing partial tabbed-page like behaviour +""" + +from Tkinter import * + +MYRIDGE, MYRAISED = RAISED, RIDGE +#MYRIDGE, MYRAISED = RIDGE, RAISED + +class InvalidTabPage(Exception): pass +class AlreadyExists(Exception): pass + +class PageTab(Frame): + """ + a 'page tab' like framed button + """ + def __init__(self,parent): + Frame.__init__(self, parent, borderwidth=2, relief=MYRIDGE) + self.button=Radiobutton(self, padx=5, pady=5, takefocus=FALSE, + indicatoron=FALSE, highlightthickness=0, + borderwidth=0, selectcolor=self.cget('bg')) + self.button.pack() + +class TabPageSet(Frame): + """ + a set of 'pages' with TabButtons for controlling their display + """ + def __init__(self,parent,pageNames=[],**kw): + """ + pageNames - a list of strings, each string will be the dictionary key + to a page's data, and the name displayed on the page's tab. Should be + specified in desired page order. The first page will be the default + and first active page. + """ + Frame.__init__(self, parent, kw) + self.grid_location(0,0) + self.columnconfigure(0,weight=1) + self.rowconfigure(1,weight=1) + self.tabBar=Frame(self) + self.tabBar.grid(row=0,column=0,sticky=EW) + self.activePage=StringVar(self) + self.defaultPage='' + self.pages={} + for name in pageNames: + self.AddPage(name) + + def ChangePage(self,pageName=None): + if pageName: + if pageName in self.pages.keys(): + self.activePage.set(pageName) + else: + raise InvalidTabPage, 'Invalid TabPage Name' + ## pop up the active 'tab' only + for page in self.pages.keys(): + self.pages[page]['tab'].config(relief=MYRIDGE) + self.pages[self.GetActivePage()]['tab'].config(relief=MYRAISED) + ## switch page + self.pages[self.GetActivePage()]['page'].lift() + + def GetActivePage(self): + return self.activePage.get() + + def AddPage(self,pageName): + if pageName in self.pages.keys(): + raise AlreadyExists, 'TabPage Name Already Exists' + self.pages[pageName]={ + 'tab': PageTab(self.tabBar), + 'page': Frame(self,borderwidth=2,relief=RAISED) + } + self.pages[pageName]['tab'].button.config( + text=pageName, + command=self.ChangePage, + variable=self.activePage, + value=pageName + ) + self.pages[pageName]['tab'].pack(side=LEFT) + self.pages[pageName]['page'].grid(row=1,column=0,sticky=NSEW) + if len(self.pages)==1: # adding first page + self.defaultPage=pageName + self.activePage.set(self.defaultPage) + self.ChangePage() + + def RemovePage(self,pageName): + if not pageName in self.pages.keys(): + raise InvalidTabPage, 'Invalid TabPage Name' + self.pages[pageName]['tab'].pack_forget() + self.pages[pageName]['page'].grid_forget() + self.pages[pageName]['tab'].destroy() + self.pages[pageName]['page'].destroy() + del(self.pages[pageName]) + # handle removing last remaining, or default, or active page + if not self.pages: # removed last remaining page + self.defaultPage='' + return + if pageName==self.defaultPage: # set a new default page + self.defaultPage=\ + self.tabBar.winfo_children()[0].button.cget('text') + if pageName==self.GetActivePage(): # set a new active page + self.activePage.set(self.defaultPage) + self.ChangePage() + +if __name__ == '__main__': + #test dialog + root=Tk() + tabPage=TabPageSet(root,pageNames=['Foobar','Baz']) + tabPage.pack(expand=TRUE,fill=BOTH) + Label(tabPage.pages['Foobar']['page'],text='Foo',pady=20).pack() + Label(tabPage.pages['Foobar']['page'],text='Bar',pady=20).pack() + Label(tabPage.pages['Baz']['page'],text='Baz').pack() + entryPgName=Entry(root) + buttonAdd=Button(root,text='Add Page', + command=lambda:tabPage.AddPage(entryPgName.get())) + buttonRemove=Button(root,text='Remove Page', + command=lambda:tabPage.RemovePage(entryPgName.get())) + labelPgName=Label(root,text='name of page to add/remove:') + buttonAdd.pack(padx=5,pady=5) + buttonRemove.pack(padx=5,pady=5) + labelPgName.pack(padx=5) + entryPgName.pack(padx=5) + tabPage.ChangePage() + root.mainloop() diff --git a/pysollib/tk/wizarddialog.py b/pysollib/tk/wizarddialog.py new file mode 100644 index 00000000..78c21f72 --- /dev/null +++ b/pysollib/tk/wizarddialog.py @@ -0,0 +1,108 @@ +##---------------------------------------------------------------------------## +## +## PySol -- a Python Solitaire game +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; see the file COPYING. +## If not, write to the Free Software Foundation, Inc., +## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +##---------------------------------------------------------------------------## + +__all__ = ['WizardDialog'] + + +# imports +from Tkinter import * +from tabpage import TabPageSet + +# PySol imports +from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct +from pysollib.wizardutil import WizardWidgets + +# Toolkit imports +from tkwidget import MfxDialog + + +# /*********************************************************************** +# // +# ************************************************************************/ + +class WizardDialog(MfxDialog): + def __init__(self, parent, title, app, **kw): + kw = self.initKw(kw) + MfxDialog.__init__(self, parent, title, kw.resizable, kw.default) + top_frame, bottom_frame = self.createFrames(kw) + self.createBitmaps(top_frame, kw) + + frame = Frame(top_frame) + frame.pack(expand=True, fill='both', padx=10, pady=10) + frame.columnconfigure(0, weight=1) + + notebook = TabPageSet(frame) + notebook.pack(expand=True, fill='both') + + for w in WizardWidgets: + if isinstance(w, basestring): + p = notebook.AddPage(w) + frame = Frame(notebook.pages[w]['page']) + frame.pack(expand=True, fill='both', padx=2, pady=4) + frame.columnconfigure(1, weight=1) + row = 0 + continue + + Label(frame, text=w.label).grid(row=row, column=0, padx=2) + + if w.widget == 'entry': + w.variable = var = StringVar() + en = Entry(frame, textvariable=var) + en.grid(row=row, column=1, sticky='ew', padx=2) + elif w.widget == 'menu': + w.variable = var = StringVar() + om = OptionMenu(frame, var, *w.values) + om.grid(row=row, column=1, sticky='ew', padx=2) + elif w.widget == 'spin': + w.variable = var = IntVar() + from_, to = w.values + s = Scale(frame, from_=from_, to=to, resolution=1, + orient='horizontal', + variable=var) + s.grid(row=row, column=1, sticky='ew', padx=2) + elif w.widget == 'check': + w.variable = var = BooleanVar() + ch = Checkbutton(frame, variable=var, + takefocus=False, anchor='w') + ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2) + + if w.current_value is None: + var.set(w.default) + else: + var.set(w.current_value) + + row += 1 + + notebook.ChangePage() + + focus = self.createButtons(bottom_frame, kw) + self.mainloop(focus, kw.timeout) + + + def initKw(self, kw): + kw = KwStruct(kw, + strings=(_('&OK'), _('&Cancel')), + default=0, + ) + return MfxDialog.initKw(self, kw) + + + diff --git a/pysollib/wizardutil.py b/pysollib/wizardutil.py index ca086af4..4e6e5200 100644 --- a/pysollib/wizardutil.py +++ b/pysollib/wizardutil.py @@ -117,17 +117,22 @@ Redeals = WizSetting( var_name = 'redeals', ) FoundType = WizSetting( - values_map = ((n_('Same suit'), SS_FoundationStack), - (n_('Alternate color'), AC_FoundationStack), - (n_('Same color'), SC_FoundationStack), - (n_('Rank'), RK_FoundationStack), + values_map = ((n_('Same suit'), SS_FoundationStack), + (n_('Alternate color'), AC_FoundationStack), + (n_('Same color'), SC_FoundationStack), + (n_('Rank'), RK_FoundationStack), + (n_('Spider same suit'), Spider_SS_Foundation), + (n_('Spider alternate color'), Spider_AC_Foundation), ), default = n_('Same suit'), label = _('Type:'), var_name = 'found_type', ) FoundBaseCard = WizSetting( - values_map = ((n_('Ace'), ACE), (n_('King'), KING)), + values_map = ((n_('Ace'), ACE), + (n_('King'), KING), + (n_('Any'), ANY_RANK), + ), default = n_('Ace'), label = _('Base card:'), var_name = 'found_base_card', @@ -139,10 +144,11 @@ FoundDir = WizSetting( var_name = 'found_dir', ) FoundWrap = WizSetting( - values_map = ((n_('Yes'), True), (n_('No'), False)), - default = n_('No'), + values_map = (True, False), + default = False, label = _('Wrapping:'), var_name = 'found_wrap', + widget = 'check', ) FoundMaxMove = WizSetting( values_map = ((n_('No move'), 0,), (n_('One card'), 1)), @@ -158,11 +164,17 @@ RowsNum = WizSetting( var_name = 'rows_num', ) RowsType = WizSetting( - values_map = ((n_('Same suit'), SS_RowStack), - (n_('Alternate color'), AC_RowStack), - (n_('Same color'), SC_RowStack), - (n_('Rank'), RK_RowStack), - (n_('Any suit but the same'), BO_RowStack), + values_map = ((n_('Same suit'), SS_RowStack), + (n_('Alternate color'), AC_RowStack), + (n_('Same color'), SC_RowStack), + (n_('Rank'), RK_RowStack), + (n_('Any suit but the same'), BO_RowStack), + (n_('Up or down by same suit'), UD_SS_RowStack), + (n_('Up or down by alternate color'), UD_AC_RowStack), + (n_('Up or down by rank'), UD_RK_RowStack), + (n_('Up or down by same color'), UD_SC_RowStack), + (n_('Spider same suit'), Spider_SS_RowStack), + (n_('Spider alternate color'), Spider_AC_RowStack), ), default = n_('Alternate color'), label = _('Type:'), @@ -185,10 +197,11 @@ RowsDir = WizSetting( var_name = 'rows_dir', ) RowsWrap = WizSetting( - values_map = ((n_('Yes'), True), (n_('No'), False)), - default = n_('No'), + values_map = (True, False), + default = False, label = _('Wrapping:'), var_name = 'rows_wrap', + widget = 'check', ) RowsMaxMove = WizSetting( values_map = ((n_('One card'), 1), (n_('Unlimited'), UNLIMITED_MOVES)), @@ -203,13 +216,12 @@ ReservesNum = WizSetting( label = _('Number of reserves:'), var_name = 'reserves_num', ) -ReservesType = WizSetting( - values_map = ((n_('FreeCell'), ReserveStack), - (n_('Reserve'), OpenStack), - ), - default = n_('FreeCell'), - label = n_('Type of reserves:'), - var_name = 'reserves_type', +ReservesMaxAccept = WizSetting( + values_map = (0, 20), + default = 1, + widget = 'spin', + label = _('Max accept:'), + var_name = 'reserves_max_accept', ) DealType = WizSetting( values_map = ((n_('Triangle'), 'triangle'), @@ -264,7 +276,7 @@ WizardWidgets = ( RowsMaxMove, _('Reserves'), ReservesNum, - ReservesType, + ReservesMaxAccept, _('Initial dealing'), DealType, DealFaceUp, @@ -320,6 +332,8 @@ class MyCustomGame(CustomGame): if isinstance(v, int): fd.write(" '%s': %i,\n" % (w.var_name, v)) else: + if w.var_name == 'name' and not v: + v = 'Invalid Game Name' fd.write(" '%s': '%s',\n" % (w.var_name, v)) fd.write(" 'gameid': %i,\n" % gameid) fd.write(" 'file': '%s',\n" % os.path.split(fn)[1])