mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
+ added solitaire wizard to Tk-binding
* improved solitaire wizard git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@158 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
parent
fb3b59bf3d
commit
4147a1ce20
9 changed files with 511 additions and 96 deletions
|
@ -29,6 +29,7 @@ from hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||||
|
|
||||||
from wizardutil import WizardWidgets
|
from wizardutil import WizardWidgets
|
||||||
|
|
||||||
|
|
||||||
# /***********************************************************************
|
# /***********************************************************************
|
||||||
# //
|
# //
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -48,59 +49,118 @@ class CustomGame(Game):
|
||||||
v = ss[w.var_name]
|
v = ss[w.var_name]
|
||||||
s[w.var_name] = v
|
s[w.var_name] = v
|
||||||
##from pprint import pprint; pprint(s)
|
##from pprint import pprint; pprint(s)
|
||||||
foundation = StackWrapper(
|
|
||||||
s['found_type'],
|
# foundations
|
||||||
base_rank=s['found_base_card'],
|
kw = {
|
||||||
dir=s['found_dir'],
|
'dir': s['found_dir'],
|
||||||
max_move=s['found_max_move'],
|
'base_rank': s['found_base_card'],
|
||||||
)
|
}
|
||||||
max_rounds = s['redeals']
|
if s['found_type'] not in (Spider_SS_Foundation,
|
||||||
if max_rounds >= 0:
|
Spider_AC_Foundation,):
|
||||||
max_rounds += 1
|
kw['max_move'] = s['found_max_move']
|
||||||
talon = StackWrapper(
|
else:
|
||||||
s['talon'],
|
kw['dir'] = -kw['dir']
|
||||||
max_rounds=max_rounds,
|
if s['found_base_card'] == KING:
|
||||||
)
|
kw['base_rank'] = ACE
|
||||||
row = StackWrapper(
|
elif s['found_base_card'] == ACE:
|
||||||
s['rows_type'],
|
kw['base_rank'] = KING
|
||||||
base_rank=s['rows_base_card'],
|
if s['found_wrap']:
|
||||||
dir=s['rows_dir'],
|
kw['mod'] = 13
|
||||||
max_move=s['rows_max_move'],
|
foundation = StackWrapper(s['found_type'], **kw)
|
||||||
)
|
|
||||||
kw = {'rows' : s['rows_num'],
|
# 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,
|
'waste' : False,
|
||||||
'texts' : True,
|
'texts' : True,
|
||||||
}
|
}
|
||||||
if s['talon'] is InitialDealTalonStack:
|
if s['talon'] is InitialDealTalonStack:
|
||||||
kw['texts'] = False
|
layout_kw['texts'] = False
|
||||||
if s['talon'] is WasteTalonStack:
|
layout_kw['playcards'] = 12+s['deal_to_rows']
|
||||||
kw['waste'] = True
|
|
||||||
kw['waste_class'] = WasteStack
|
|
||||||
if int(s['reserves_num']):
|
|
||||||
kw['reserves'] = s['reserves_num']
|
|
||||||
kw['reserve_class'] = s['reserves_type']
|
|
||||||
|
|
||||||
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'],
|
Layout(self).createGame(layout_method = s['layout'],
|
||||||
talon_class = talon,
|
talon_class = talon,
|
||||||
foundation_class = foundation,
|
foundation_class = foundation,
|
||||||
row_class = row,
|
row_class = row,
|
||||||
**kw
|
**layout_kw
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# shallHighlightMatch
|
||||||
for c, f in (
|
for c, f in (
|
||||||
((AC_RowStack, UD_AC_RowStack),
|
((Spider_AC_RowStack, Spider_SS_RowStack),
|
||||||
self._shallHighlightMatch_AC),
|
(self._shallHighlightMatch_RK,
|
||||||
((SS_RowStack, UD_SS_RowStack),
|
self._shallHighlightMatch_RKW)),
|
||||||
self._shallHighlightMatch_SS),
|
((AC_RowStack, UD_AC_RowStack),
|
||||||
((RK_RowStack, UD_RK_RowStack),
|
(self._shallHighlightMatch_AC,
|
||||||
self._shallHighlightMatch_RK),
|
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:
|
if s['rows_type'] in c:
|
||||||
self.shallHighlightMatch = f
|
if s['rows_wrap']:
|
||||||
|
self.shallHighlightMatch = f[1]
|
||||||
|
else:
|
||||||
|
self.shallHighlightMatch = f[0]
|
||||||
break
|
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):
|
def startGame(self):
|
||||||
frames = 0
|
frames = 0
|
||||||
|
@ -115,7 +175,7 @@ class CustomGame(Game):
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
|
|
||||||
# deal to rows
|
# deal to rows
|
||||||
flip = self.SETTINGS['deal_faceup'] == 'All cards'
|
flip = (self.SETTINGS['deal_faceup'] == 'All cards')
|
||||||
max_rows = self.SETTINGS['deal_to_rows']
|
max_rows = self.SETTINGS['deal_to_rows']
|
||||||
if self.SETTINGS['deal_type'] == 'Triangle':
|
if self.SETTINGS['deal_type'] == 'Triangle':
|
||||||
# triangle
|
# triangle
|
||||||
|
@ -140,12 +200,16 @@ class CustomGame(Game):
|
||||||
if frames == 0:
|
if frames == 0:
|
||||||
self.startDealSample()
|
self.startDealSample()
|
||||||
self.s.talon.dealRowAvail()
|
self.s.talon.dealRowAvail()
|
||||||
|
if isinstance(self.s.talon, InitialDealTalonStack):
|
||||||
|
while self.s.talon.cards:
|
||||||
|
self.s.talon.dealRowAvail()
|
||||||
|
|
||||||
# deal to waste
|
# deal to waste
|
||||||
if self.s.waste:
|
if self.s.waste:
|
||||||
self.s.talon.dealCards()
|
self.s.talon.dealCards()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def registerCustomGame(gameclass):
|
def registerCustomGame(gameclass):
|
||||||
|
|
||||||
s = gameclass.SETTINGS
|
s = gameclass.SETTINGS
|
||||||
|
|
|
@ -2038,6 +2038,27 @@ for %d moves.
|
||||||
return ((card1.rank + 1) % 13 == card2.rank
|
return ((card1.rank + 1) % 13 == card2.rank
|
||||||
or (card2.rank + 1) % 13 == card1.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
|
# quick-play
|
||||||
#
|
#
|
||||||
|
|
|
@ -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):
|
class Spider_RowStack(Spider_SS_RowStack):
|
||||||
def canDropCards(self, stacks):
|
canDropCards = BasicRowStack.spiderCanDropCards
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class SuperMoveSpider_RowStack(SuperMoveStack_StackMethods, Spider_RowStack):
|
class SuperMoveSpider_RowStack(SuperMoveStack_StackMethods, Spider_RowStack):
|
||||||
|
|
|
@ -58,6 +58,8 @@ __all__ = ['cardsFaceUp',
|
||||||
'RK_FoundationStack',
|
'RK_FoundationStack',
|
||||||
'AC_FoundationStack',
|
'AC_FoundationStack',
|
||||||
'SC_FoundationStack',
|
'SC_FoundationStack',
|
||||||
|
'Spider_SS_Foundation',
|
||||||
|
'Spider_AC_Foundation',
|
||||||
#'SequenceStack_StackMethods',
|
#'SequenceStack_StackMethods',
|
||||||
'BasicRowStack',
|
'BasicRowStack',
|
||||||
'SequenceRowStack',
|
'SequenceRowStack',
|
||||||
|
@ -1492,11 +1494,14 @@ class Stack:
|
||||||
def getBaseCard(self):
|
def getBaseCard(self):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _getBaseCard(self):
|
def _getBaseCard(self, rank=None):
|
||||||
# FIXME: no-french games
|
# FIXME: no-french games
|
||||||
if self.cap.max_accept == 0:
|
if self.cap.max_accept == 0:
|
||||||
return ''
|
return ''
|
||||||
br = self.cap.base_rank
|
if rank is None:
|
||||||
|
br = self.cap.base_rank
|
||||||
|
else:
|
||||||
|
br = rank
|
||||||
s = _('Base card - %s.')
|
s = _('Base card - %s.')
|
||||||
if br == NO_RANK: s = _('Empty row cannot be filled.')
|
if br == NO_RANK: s = _('Empty row cannot be filled.')
|
||||||
elif br == -1: s = s % _('any card')
|
elif br == -1: s = s % _('any card')
|
||||||
|
@ -2068,6 +2073,28 @@ class AbstractFoundationStack(OpenStack):
|
||||||
def getHelp(self):
|
def getHelp(self):
|
||||||
return _('Foundation.')
|
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.
|
# A SameSuit_FoundationStack is the typical Foundation stack.
|
||||||
# It builds up in rank and suit.
|
# It builds up in rank and suit.
|
||||||
|
@ -2146,6 +2173,29 @@ class SC_FoundationStack(SS_FoundationStack):
|
||||||
else: return _('Foundation. Build by same rank.')
|
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.
|
# // Abstract classes for row stacks.
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
@ -2192,6 +2242,16 @@ class BasicRowStack(OpenStack):
|
||||||
#def getBaseCard(self):
|
#def getBaseCard(self):
|
||||||
# return self._getBaseCard()
|
# 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.
|
# Abstract class.
|
||||||
class SequenceRowStack(SequenceStack_StackMethods, BasicRowStack):
|
class SequenceRowStack(SequenceStack_StackMethods, BasicRowStack):
|
||||||
|
|
|
@ -55,7 +55,8 @@ class WizardDialog(MfxDialog):
|
||||||
for w in WizardWidgets:
|
for w in WizardWidgets:
|
||||||
if isinstance(w, basestring):
|
if isinstance(w, basestring):
|
||||||
frame = Frame(notebook)
|
frame = Frame(notebook)
|
||||||
notebook.add(frame, text=w)
|
notebook.add(frame, text=w, sticky='nsew', padding=5)
|
||||||
|
frame.columnconfigure(1, weight=1)
|
||||||
row = 0
|
row = 0
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -64,12 +65,11 @@ class WizardDialog(MfxDialog):
|
||||||
if w.widget == 'entry':
|
if w.widget == 'entry':
|
||||||
w.variable = var = StringVar()
|
w.variable = var = StringVar()
|
||||||
en = Entry(frame, textvariable=var)
|
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':
|
elif w.widget == 'menu':
|
||||||
w.variable = var = StringVar()
|
w.variable = var = StringVar()
|
||||||
##OptionMenu(frame, var, *w.values).grid(row=row, column=1)
|
|
||||||
cb = Combobox(frame, values=tuple(w.values), textvariable=var,
|
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)
|
cb.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
|
||||||
elif w.widget == 'spin':
|
elif w.widget == 'spin':
|
||||||
w.variable = var = IntVar()
|
w.variable = var = IntVar()
|
||||||
|
@ -78,7 +78,11 @@ class WizardDialog(MfxDialog):
|
||||||
s = PysolScale(frame, from_=from_, to=to, resolution=1,
|
s = PysolScale(frame, from_=from_, to=to, resolution=1,
|
||||||
orient='horizontal',
|
orient='horizontal',
|
||||||
variable=var)
|
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:
|
if w.current_value is None:
|
||||||
var.set(w.default)
|
var.set(w.default)
|
||||||
|
|
|
@ -61,6 +61,7 @@ from selecttile import SelectTileDialogWithPreview
|
||||||
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
from findcarddialog import connect_game_find_card_dialog, destroy_find_card_dialog
|
||||||
from solverdialog import connect_game_solver_dialog
|
from solverdialog import connect_game_solver_dialog
|
||||||
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
from tkwrap import MfxRadioMenuItem, MfxCheckMenuItem, StringVar
|
||||||
|
from wizarddialog import WizardDialog
|
||||||
|
|
||||||
#from toolbar import TOOLBAR_BUTTONS
|
#from toolbar import TOOLBAR_BUTTONS
|
||||||
from tkconst 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_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 = MfxMenu(self.__menubar, label=n_("&Game"))
|
||||||
menu.add_command(label=n_("&Deal cards"), command=self.mDeal, accelerator="D")
|
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_("&Auto drop"), command=self.mDrop, accelerator="A")
|
||||||
|
@ -1340,3 +1345,46 @@ class PysolMenubar(PysolMenubarActions):
|
||||||
else:
|
else:
|
||||||
if self._cancelDrag(break_pause=True): return
|
if self._cancelDrag(break_pause=True): return
|
||||||
self.game.showStackDesc()
|
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)
|
||||||
|
|
||||||
|
|
124
pysollib/tk/tabpage.py
Normal file
124
pysollib/tk/tabpage.py
Normal file
|
@ -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()
|
108
pysollib/tk/wizarddialog.py
Normal file
108
pysollib/tk/wizarddialog.py
Normal file
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -117,17 +117,22 @@ Redeals = WizSetting(
|
||||||
var_name = 'redeals',
|
var_name = 'redeals',
|
||||||
)
|
)
|
||||||
FoundType = WizSetting(
|
FoundType = WizSetting(
|
||||||
values_map = ((n_('Same suit'), SS_FoundationStack),
|
values_map = ((n_('Same suit'), SS_FoundationStack),
|
||||||
(n_('Alternate color'), AC_FoundationStack),
|
(n_('Alternate color'), AC_FoundationStack),
|
||||||
(n_('Same color'), SC_FoundationStack),
|
(n_('Same color'), SC_FoundationStack),
|
||||||
(n_('Rank'), RK_FoundationStack),
|
(n_('Rank'), RK_FoundationStack),
|
||||||
|
(n_('Spider same suit'), Spider_SS_Foundation),
|
||||||
|
(n_('Spider alternate color'), Spider_AC_Foundation),
|
||||||
),
|
),
|
||||||
default = n_('Same suit'),
|
default = n_('Same suit'),
|
||||||
label = _('Type:'),
|
label = _('Type:'),
|
||||||
var_name = 'found_type',
|
var_name = 'found_type',
|
||||||
)
|
)
|
||||||
FoundBaseCard = WizSetting(
|
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'),
|
default = n_('Ace'),
|
||||||
label = _('Base card:'),
|
label = _('Base card:'),
|
||||||
var_name = 'found_base_card',
|
var_name = 'found_base_card',
|
||||||
|
@ -139,10 +144,11 @@ FoundDir = WizSetting(
|
||||||
var_name = 'found_dir',
|
var_name = 'found_dir',
|
||||||
)
|
)
|
||||||
FoundWrap = WizSetting(
|
FoundWrap = WizSetting(
|
||||||
values_map = ((n_('Yes'), True), (n_('No'), False)),
|
values_map = (True, False),
|
||||||
default = n_('No'),
|
default = False,
|
||||||
label = _('Wrapping:'),
|
label = _('Wrapping:'),
|
||||||
var_name = 'found_wrap',
|
var_name = 'found_wrap',
|
||||||
|
widget = 'check',
|
||||||
)
|
)
|
||||||
FoundMaxMove = WizSetting(
|
FoundMaxMove = WizSetting(
|
||||||
values_map = ((n_('No move'), 0,), (n_('One card'), 1)),
|
values_map = ((n_('No move'), 0,), (n_('One card'), 1)),
|
||||||
|
@ -158,11 +164,17 @@ RowsNum = WizSetting(
|
||||||
var_name = 'rows_num',
|
var_name = 'rows_num',
|
||||||
)
|
)
|
||||||
RowsType = WizSetting(
|
RowsType = WizSetting(
|
||||||
values_map = ((n_('Same suit'), SS_RowStack),
|
values_map = ((n_('Same suit'), SS_RowStack),
|
||||||
(n_('Alternate color'), AC_RowStack),
|
(n_('Alternate color'), AC_RowStack),
|
||||||
(n_('Same color'), SC_RowStack),
|
(n_('Same color'), SC_RowStack),
|
||||||
(n_('Rank'), RK_RowStack),
|
(n_('Rank'), RK_RowStack),
|
||||||
(n_('Any suit but the same'), BO_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'),
|
default = n_('Alternate color'),
|
||||||
label = _('Type:'),
|
label = _('Type:'),
|
||||||
|
@ -185,10 +197,11 @@ RowsDir = WizSetting(
|
||||||
var_name = 'rows_dir',
|
var_name = 'rows_dir',
|
||||||
)
|
)
|
||||||
RowsWrap = WizSetting(
|
RowsWrap = WizSetting(
|
||||||
values_map = ((n_('Yes'), True), (n_('No'), False)),
|
values_map = (True, False),
|
||||||
default = n_('No'),
|
default = False,
|
||||||
label = _('Wrapping:'),
|
label = _('Wrapping:'),
|
||||||
var_name = 'rows_wrap',
|
var_name = 'rows_wrap',
|
||||||
|
widget = 'check',
|
||||||
)
|
)
|
||||||
RowsMaxMove = WizSetting(
|
RowsMaxMove = WizSetting(
|
||||||
values_map = ((n_('One card'), 1), (n_('Unlimited'), UNLIMITED_MOVES)),
|
values_map = ((n_('One card'), 1), (n_('Unlimited'), UNLIMITED_MOVES)),
|
||||||
|
@ -203,13 +216,12 @@ ReservesNum = WizSetting(
|
||||||
label = _('Number of reserves:'),
|
label = _('Number of reserves:'),
|
||||||
var_name = 'reserves_num',
|
var_name = 'reserves_num',
|
||||||
)
|
)
|
||||||
ReservesType = WizSetting(
|
ReservesMaxAccept = WizSetting(
|
||||||
values_map = ((n_('FreeCell'), ReserveStack),
|
values_map = (0, 20),
|
||||||
(n_('Reserve'), OpenStack),
|
default = 1,
|
||||||
),
|
widget = 'spin',
|
||||||
default = n_('FreeCell'),
|
label = _('Max accept:'),
|
||||||
label = n_('Type of reserves:'),
|
var_name = 'reserves_max_accept',
|
||||||
var_name = 'reserves_type',
|
|
||||||
)
|
)
|
||||||
DealType = WizSetting(
|
DealType = WizSetting(
|
||||||
values_map = ((n_('Triangle'), 'triangle'),
|
values_map = ((n_('Triangle'), 'triangle'),
|
||||||
|
@ -264,7 +276,7 @@ WizardWidgets = (
|
||||||
RowsMaxMove,
|
RowsMaxMove,
|
||||||
_('Reserves'),
|
_('Reserves'),
|
||||||
ReservesNum,
|
ReservesNum,
|
||||||
ReservesType,
|
ReservesMaxAccept,
|
||||||
_('Initial dealing'),
|
_('Initial dealing'),
|
||||||
DealType,
|
DealType,
|
||||||
DealFaceUp,
|
DealFaceUp,
|
||||||
|
@ -320,6 +332,8 @@ class MyCustomGame(CustomGame):
|
||||||
if isinstance(v, int):
|
if isinstance(v, int):
|
||||||
fd.write(" '%s': %i,\n" % (w.var_name, v))
|
fd.write(" '%s': %i,\n" % (w.var_name, v))
|
||||||
else:
|
else:
|
||||||
|
if w.var_name == 'name' and not v:
|
||||||
|
v = 'Invalid Game Name'
|
||||||
fd.write(" '%s': '%s',\n" % (w.var_name, v))
|
fd.write(" '%s': '%s',\n" % (w.var_name, v))
|
||||||
fd.write(" 'gameid': %i,\n" % gameid)
|
fd.write(" 'gameid': %i,\n" % gameid)
|
||||||
fd.write(" 'file': '%s',\n" % os.path.split(fn)[1])
|
fd.write(" 'file': '%s',\n" % os.path.split(fn)[1])
|
||||||
|
|
Loading…
Add table
Reference in a new issue