mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
* scalable cards (req: PIL >= 1.1.7)
git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@263 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
parent
d812df8b35
commit
0e3dccb247
36 changed files with 857 additions and 304 deletions
7
AUTHORS
7
AUTHORS
|
@ -22,3 +22,10 @@ Matthew Hohlfeld <hohlfeld@cs.ucsd.edu>
|
|||
Nicola Larosa
|
||||
John Stoneham <obijohn99@aol.com>
|
||||
David Svoboda <svoboda@users.sourceforge.net>
|
||||
|
||||
|
||||
Translations
|
||||
============
|
||||
|
||||
Holger Schäkel <Holger@Schaekel-row.de> (de)
|
||||
Jerzy Trzeciak <artusek@wp.pl> (pl)
|
||||
|
|
|
@ -31,6 +31,7 @@ from mfxutil import destruct, Struct
|
|||
from mfxutil import pickle, unpickle, UnpicklingError
|
||||
from mfxutil import getusername, getprefdir
|
||||
from mfxutil import latin1_to_ascii, print_err
|
||||
from mfxutil import USE_PIL
|
||||
from util import CARDSET, IMAGE_EXTENSIONS
|
||||
from settings import PACKAGE, VERSION_TUPLE, WIN_SYSTEM
|
||||
from resource import CSI, CardsetConfig, Cardset, CardsetManager
|
||||
|
@ -536,11 +537,10 @@ class Application:
|
|||
pass
|
||||
self.wm_save_state()
|
||||
# save game geometry
|
||||
geom = (self.canvas.winfo_width(), self.canvas.winfo_height())
|
||||
if self.opt.save_games_geometry and not self.opt.wm_maximized:
|
||||
w = self.canvas.winfo_width()
|
||||
h = self.canvas.winfo_height()
|
||||
geom = (w, h)
|
||||
self.opt.games_geometry[self.game.id] = geom
|
||||
self.opt.game_geometry = geom
|
||||
self.freeGame()
|
||||
#
|
||||
if self.nextgame.id <= 0:
|
||||
|
@ -1020,8 +1020,18 @@ Please select a %s type %s.
|
|||
if d.status != 0 or d.button != 1:
|
||||
return None
|
||||
cs = self.cardset_manager.get(d.key)
|
||||
if cs is None or d.key == key:
|
||||
changed = (self.opt.scale_x,
|
||||
self.opt.scale_y,
|
||||
self.opt.auto_scale,
|
||||
self.opt.preserve_aspect_ratio) != d.scale_values
|
||||
if cs is None:
|
||||
return None
|
||||
if d.key == key and not changed:
|
||||
return None
|
||||
(self.opt.scale_x,
|
||||
self.opt.scale_y,
|
||||
self.opt.auto_scale,
|
||||
self.opt.preserve_aspect_ratio) = d.scale_values
|
||||
return cs
|
||||
|
||||
|
||||
|
|
227
pysollib/game.py
227
pysollib/game.py
|
@ -31,7 +31,7 @@ from cStringIO import StringIO
|
|||
|
||||
# PySol imports
|
||||
from mfxutil import Pickler, Unpickler, UnpicklingError
|
||||
from mfxutil import Image, ImageTk
|
||||
from mfxutil import Image, ImageTk, USE_PIL
|
||||
from mfxutil import destruct, Struct, SubclassResponsibility
|
||||
from mfxutil import uclock, usleep
|
||||
from mfxutil import format_time, print_err
|
||||
|
@ -135,12 +135,15 @@ class Game:
|
|||
remaining = [], # list of stacks in no region
|
||||
#
|
||||
data = [], # raw data
|
||||
init_info = [], # init info (at the start)
|
||||
)
|
||||
self.init_size = (0,0)
|
||||
self.event_handled = False # if click event handled by Stack (???)
|
||||
self.reset()
|
||||
|
||||
# main constructor
|
||||
def create(self, app):
|
||||
#print 'Game.create'
|
||||
old_busy = self.busy
|
||||
self.__createCommon(app)
|
||||
self.setCursor(cursor=CURSOR_WATCH)
|
||||
|
@ -186,13 +189,46 @@ class Game:
|
|||
##self.top.bind('<3>', self.top._sleepEvent)
|
||||
# update display properties
|
||||
self.canvas.busy = True
|
||||
self.canvas.setInitialSize(self.width, self.height)
|
||||
if self.app.opt.save_games_geometry and \
|
||||
# geometry
|
||||
if not USE_PIL and self.app.opt.save_games_geometry and \
|
||||
self.id in self.app.opt.games_geometry:
|
||||
# restore game geometry
|
||||
w, h = self.app.opt.games_geometry[self.id]
|
||||
self.canvas.config(width=w, height=h)
|
||||
self.top.wm_geometry("") # cancel user-specified geometry
|
||||
if USE_PIL:
|
||||
if self.app.opt.auto_scale:
|
||||
w, h = self.app.opt.game_geometry
|
||||
self.canvas.setInitialSize(w, h, margins=False,
|
||||
scrollregion=False)
|
||||
## self.canvas.config(width=w, height=h)
|
||||
## dx, dy = self.canvas.xmargin, self.canvas.ymargin
|
||||
## self.canvas.config(scrollregion=(-dx, -dy, dx, dy))
|
||||
else:
|
||||
w = int(round(self.width * self.app.opt.scale_x))
|
||||
h = int(round(self.height * self.app.opt.scale_y))
|
||||
self.canvas.setInitialSize(w, h)
|
||||
self.top.wm_geometry("") # cancel user-specified geometry
|
||||
# preserve texts positions
|
||||
for t in ('info', 'help', 'misc', 'score', 'base_rank'):
|
||||
item = getattr(self.texts, t)
|
||||
if item:
|
||||
coords = self.canvas.coords(item)
|
||||
setattr(self.init_texts, t, coords)
|
||||
#
|
||||
for item in self.texts.list:
|
||||
coords = self.canvas.coords(item)
|
||||
self.init_texts.list.append(coords)
|
||||
# resize
|
||||
self.resizeGame()
|
||||
# fix coords of cards (see self.createCards)
|
||||
x, y = self.s.talon.x, self.s.talon.y
|
||||
for c in self.cards:
|
||||
c.moveTo(x, y)
|
||||
else:
|
||||
# no PIL
|
||||
self.canvas.setInitialSize(self.width, self.height)
|
||||
self.top.wm_geometry("") # cancel user-specified geometry
|
||||
# done; update view
|
||||
self.top.update_idletasks()
|
||||
self.canvas.busy = False
|
||||
if DEBUG >= 4:
|
||||
|
@ -200,12 +236,11 @@ class Game:
|
|||
width=2, fill=None, outline='green')
|
||||
#
|
||||
self.stats.update_time = time.time()
|
||||
self.busy = old_busy
|
||||
self.showHelp() # just in case
|
||||
hint_class = self.getHintClass()
|
||||
if hint_class is not None:
|
||||
self.Stuck_Class = hint_class(self, 0)
|
||||
##self.reallocateStacks()
|
||||
self.busy = old_busy
|
||||
|
||||
|
||||
def _checkGame(self):
|
||||
|
@ -262,7 +297,8 @@ class Game:
|
|||
bind(self.canvas, "<2>", self.dropHandler)
|
||||
bind(self.canvas, "<3>", self.redoHandler)
|
||||
bind(self.canvas, '<Unmap>', self._unmapHandler)
|
||||
bind(self.canvas, '<Configure>', self.configureHandler, add=True)
|
||||
bind(self.canvas, '<Configure>', self._configureHandler, add=True)
|
||||
|
||||
|
||||
def __createCommon(self, app):
|
||||
self.busy = 1
|
||||
|
@ -293,6 +329,16 @@ class Game:
|
|||
misc = None, #
|
||||
score = None, # for displaying the score
|
||||
base_rank = None, # for displaying the base_rank
|
||||
list = [], # list of texts (if we use many text)
|
||||
)
|
||||
# initial position of the texts
|
||||
self.init_texts = Struct(
|
||||
info = None, # misc info text
|
||||
help = None, # a static help text
|
||||
misc = None, #
|
||||
score = None, # for displaying the score
|
||||
base_rank = None, # for displaying the base_rank
|
||||
list = [],
|
||||
)
|
||||
|
||||
def createPreview(self, app):
|
||||
|
@ -409,6 +455,8 @@ class Game:
|
|||
# this is called from within createGame()
|
||||
def setSize(self, w, h):
|
||||
self.width, self.height = int(round(w)), int(round(h))
|
||||
dx, dy = self.canvas.xmargin, self.canvas.ymargin
|
||||
self.init_size = self.width+2*dx, self.height+2*dy
|
||||
|
||||
def setCursor(self, cursor):
|
||||
if self.canvas:
|
||||
|
@ -424,6 +472,7 @@ class Game:
|
|||
|
||||
# start a new name
|
||||
def newGame(self, random=None, restart=0, autoplay=1):
|
||||
#print 'Game.newGame'
|
||||
self.finished = False
|
||||
old_busy, self.busy = self.busy, 1
|
||||
self.setCursor(cursor=CURSOR_WATCH)
|
||||
|
@ -538,8 +587,8 @@ class Game:
|
|||
self.stats.update_time = time.time()
|
||||
self.busy = old_busy
|
||||
#
|
||||
##self.configureHandler() # reallocateCards
|
||||
after(self.top, 200, self.configureHandler) # wait for canvas is mapped
|
||||
##self._configureHandler() # reallocateCards
|
||||
after(self.top, 200, self._configureHandler) # wait for canvas is mapped
|
||||
#
|
||||
if TOOLKIT == 'gtk':
|
||||
## FIXME
|
||||
|
@ -561,6 +610,7 @@ class Game:
|
|||
self.busy = old_busy
|
||||
|
||||
def resetGame(self):
|
||||
#print 'Game.resetGame'
|
||||
self.hints.list = None
|
||||
self.s.talon.removeAllCards()
|
||||
for stack in self.allstacks:
|
||||
|
@ -638,22 +688,73 @@ class Game:
|
|||
self.endGame(restart=1)
|
||||
self.newGame(restart=1, random=self.random)
|
||||
|
||||
def reallocateStacks(self):
|
||||
w0, h0 = self.width, self.height
|
||||
iw = int(self.canvas.cget('width'))
|
||||
ih = int(self.canvas.cget('height'))
|
||||
vw = self.canvas.winfo_width()
|
||||
vh = self.canvas.winfo_height()
|
||||
if vw <= iw or vh <= ih:
|
||||
def resizeImages(self):
|
||||
# resizing images and cards
|
||||
if self.app.opt.auto_scale:
|
||||
if self.canvas.winfo_ismapped():
|
||||
# apparent size of canvas
|
||||
vw = self.canvas.winfo_width()
|
||||
vh = self.canvas.winfo_height()
|
||||
else:
|
||||
# we have no a real size of canvas (winfo_width / winfo_reqwidth)
|
||||
# so we use a saved size
|
||||
vw, vh = self.app.opt.game_geometry
|
||||
if not vw:
|
||||
# first run of the game
|
||||
return 1, 1
|
||||
iw, ih = self.init_size # requested size of canvas (createGame -> setSize)
|
||||
# calculate factor of resizing
|
||||
xf = float(vw)/iw
|
||||
yf = float(vh)/ih
|
||||
if self.app.opt.preserve_aspect_ratio:
|
||||
xf = yf = min(xf, yf)
|
||||
else:
|
||||
xf, yf = self.app.opt.scale_x, self.app.opt.scale_y
|
||||
# images
|
||||
self.app.images.resize(xf, yf)
|
||||
# cards
|
||||
for card in self.cards:
|
||||
card.update(card.id, card.deck, card.suit, card.rank, self)
|
||||
return xf, yf
|
||||
|
||||
def resizeGame(self):
|
||||
#if self.busy:
|
||||
# return
|
||||
if not USE_PIL:
|
||||
return
|
||||
xf = float(vw)/iw
|
||||
yf = float(vh)/ih
|
||||
self.deleteStackDesc()
|
||||
xf, yf = self.resizeImages()
|
||||
#print 'resizeGame', xf, yf
|
||||
# stacks
|
||||
for stack in self.allstacks:
|
||||
x0, y0 = stack.init_coord
|
||||
x, y = int(x0*xf), int(y0*yf)
|
||||
if x == stack.x and y == stack.y:
|
||||
continue
|
||||
stack.moveTo(x, y)
|
||||
x, y = int(round(x0*xf)), int(round(y0*yf))
|
||||
#if x == stack.x and y == stack.y:
|
||||
# continue
|
||||
stack.resize(xf, yf)
|
||||
stack.updatePositions()
|
||||
# regions
|
||||
info = []
|
||||
for stacks, rect in self.regions.init_info:
|
||||
rect = (int(round(rect[0]*xf)), int(round(rect[1]*yf)),
|
||||
int(round(rect[2]*xf)), int(round(rect[3]*yf)))
|
||||
info.append((stacks, rect))
|
||||
self.regions.info = tuple(info)
|
||||
# texts
|
||||
for t in ('info', 'help', 'misc', 'score', 'base_rank'):
|
||||
init_coord = getattr(self.init_texts, t)
|
||||
if init_coord:
|
||||
item = getattr(self.texts, t)
|
||||
x, y = int(round(init_coord[0]*xf)), int(round(init_coord[1]*yf))
|
||||
self.canvas.coords(item, x, y)
|
||||
for i in range(len(self.texts.list)):
|
||||
init_coord = self.init_texts.list[i]
|
||||
item = self.texts.list[i]
|
||||
x, y = int(round(init_coord[0]*xf)), int(round(init_coord[1]*yf))
|
||||
self.canvas.coords(item, x, y)
|
||||
#
|
||||
#self.canvas.update()
|
||||
#self.canvas.update_idletasks()
|
||||
|
||||
def createRandom(self, random):
|
||||
if random is None:
|
||||
|
@ -985,11 +1086,27 @@ class Game:
|
|||
if self.app and not self.pause:
|
||||
self.app.menubar.mPause()
|
||||
|
||||
def configureHandler(self, event=None):
|
||||
_resizeHandlerID = None
|
||||
def _resizeHandler(self):
|
||||
#print '_resizeHandler'
|
||||
self._resizeHandlerID = None
|
||||
self.resizeGame()
|
||||
|
||||
def _configureHandler(self, event=None):
|
||||
#print 'configureHandler'
|
||||
if not USE_PIL:
|
||||
return
|
||||
if not self.app:
|
||||
return
|
||||
if not self.canvas:
|
||||
return
|
||||
for stack in self.allstacks:
|
||||
stack.updatePositions()
|
||||
if not self.app.opt.auto_scale:
|
||||
return
|
||||
if self.preview:
|
||||
return
|
||||
if self._resizeHandlerID:
|
||||
self.canvas.after_cancel(self._resizeHandlerID)
|
||||
self._resizeHandlerID = self.canvas.after(250, self._resizeHandler)
|
||||
|
||||
#
|
||||
# sound support
|
||||
|
@ -1504,13 +1621,20 @@ class Game:
|
|||
assert len(stacks) > 0
|
||||
assert len(rect) == 4 and rect[0] < rect[2] and rect[1] < rect[3]
|
||||
if DEBUG >= 2:
|
||||
MfxCanvasRectangle(self.canvas, rect[0], rect[1], rect[2], rect[3],
|
||||
xf, yf = self.app.images._xfactor, self.app.images._yfactor
|
||||
MfxCanvasRectangle(self.canvas,
|
||||
xf*rect[0], yf*rect[1], xf*rect[2], yf*rect[3],
|
||||
width=2, fill=None, outline='red')
|
||||
for s in stacks:
|
||||
assert s and s in self.allstacks
|
||||
# verify that the stack lies within the rectangle
|
||||
x, y, r = s.x, s.y, rect
|
||||
##print x, y, r
|
||||
r = rect
|
||||
if USE_PIL:
|
||||
x, y = s.init_coord
|
||||
#print 'setRegion:', x, y, r
|
||||
else:
|
||||
x, y = s.x, s.y
|
||||
#print 'setRegion:', x, y, r
|
||||
assert r[0] <= x <= r[2] and r[1] <= y <= r[3]
|
||||
# verify that the stack is not already in another region
|
||||
# with the same priority
|
||||
|
@ -1538,7 +1662,7 @@ class Game:
|
|||
while stack in remaining:
|
||||
remaining.remove(stack)
|
||||
self.regions.remaining = tuple(remaining)
|
||||
##print self.regions.info
|
||||
self.regions.init_info = self.regions.info
|
||||
|
||||
def getInvisibleCoords(self):
|
||||
# for InvisibleStack, etc
|
||||
|
@ -1917,6 +2041,7 @@ Congratulations, you did it !
|
|||
if self.pause:
|
||||
return 0
|
||||
self.stopWinAnimation()
|
||||
cw, ch = self.app.images.getSize()
|
||||
items = []
|
||||
for s, c1, c2, color in info:
|
||||
assert c1 in s.cards and c2 in s.cards
|
||||
|
@ -1943,33 +2068,33 @@ Congratulations, you did it !
|
|||
x2, y2 = s.getPositionFor(c2)
|
||||
if sx0 != 0 and sy0 == 0:
|
||||
# horizontal stack
|
||||
y2 = y2 + self.app.images.CARDH
|
||||
y2 += ch
|
||||
if c2 is s.cards[-1]: # top card
|
||||
x2 = x2 + self.app.images.CARDW
|
||||
x2 += cw
|
||||
else:
|
||||
if sx0 > 0:
|
||||
# left to right
|
||||
x2 = x2 + sx0
|
||||
x2 += sx0
|
||||
else:
|
||||
# right to left
|
||||
x1 = x1 + self.app.images.CARDW
|
||||
x2 = x2 + self.app.images.CARDW + sx0
|
||||
x1 += cw
|
||||
x2 += cw + sx0
|
||||
elif sx0 == 0 and sy0 != 0:
|
||||
# vertical stack
|
||||
x2 = x2 + self.app.images.CARDW
|
||||
x2 += cw
|
||||
if c2 is s.cards[-1]: # top card
|
||||
y2 = y2 + self.app.images.CARDH
|
||||
y2 += ch
|
||||
else:
|
||||
if sy0 > 0:
|
||||
# up to down
|
||||
y2 = y2 + sy0
|
||||
else:
|
||||
# down to up
|
||||
y1 = y1 + self.app.images.CARDH
|
||||
y2 = y2 + self.app.images.CARDH + sy0
|
||||
y1 += ch
|
||||
y2 += ch + sy0
|
||||
else:
|
||||
x2 = x2 + self.app.images.CARDW
|
||||
y2 = y2 + self.app.images.CARDH
|
||||
x2 += cw
|
||||
y2 += ch
|
||||
tkraise = True
|
||||
##print c1, c2, x1, y1, x2, y2
|
||||
x1, x2 = x1-delta[0], x2+delta[1]
|
||||
|
@ -2237,19 +2362,21 @@ Congratulations, you did it !
|
|||
images = self.app.images
|
||||
x1, y1 = from_stack.getPositionFor(from_stack.cards[-ncards])
|
||||
x2, y2 = to_stack.getPositionFor(to_stack.getCard())
|
||||
x1, y1 = x1 + images.CARD_DX, y1 + images.CARD_DY
|
||||
x2, y2 = x2 + images.CARD_DX, y2 + images.CARD_DY
|
||||
cw, ch = images.getSize()
|
||||
dx, dy = images.getDelta()
|
||||
x1, y1 = x1 + dx, y1 + dy
|
||||
x2, y2 = x2 + dx, y2 + dy
|
||||
if ncards == 1:
|
||||
x1 = x1 + images.CARDW / 2
|
||||
y1 = y1 + images.CARDH / 2
|
||||
x1 += cw / 2
|
||||
y1 += ch / 2
|
||||
elif from_stack.CARD_XOFFSET[0]:
|
||||
x1 = x1 + from_stack.CARD_XOFFSET[0] / 2
|
||||
y1 = y1 + images.CARDH / 2
|
||||
x1 += from_stack.CARD_XOFFSET[0] / 2
|
||||
y1 += ch / 2
|
||||
else:
|
||||
x1 = x1 + images.CARDW / 2
|
||||
y1 = y1 + from_stack.CARD_YOFFSET[0] / 2
|
||||
x2 = x2 + images.CARDW / 2
|
||||
y2 = y2 + images.CARDH / 2
|
||||
x1 += cw / 2
|
||||
y1 += from_stack.CARD_YOFFSET[0] / 2
|
||||
x2 += cw / 2
|
||||
y2 += ch / 2
|
||||
# draw the hint
|
||||
arrow = MfxCanvasLine(self.canvas, x1, y1, x2, y2, width=7,
|
||||
fill=self.app.opt.colors['hintarrow'],
|
||||
|
|
|
@ -32,7 +32,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from numerica import Numerica_Hint
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -33,7 +33,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from fortythieves import FortyThieves_Hint
|
||||
from spider import Spider_Hint
|
||||
|
|
|
@ -32,7 +32,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from gypsy import DieRussische_Foundation
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -35,7 +35,6 @@ from pysollib.game import Game
|
|||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.hint import KlondikeType_Hint, YukonType_Hint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from spider import Spider_SS_Foundation, Spider_RowStack, Spider_Hint
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ from pysollib.game import Game
|
|||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.hint import KlondikeType_Hint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from spider import Spider_RowStack, Spider_SS_Foundation, Spider_Hint
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -276,7 +276,7 @@ class Mahjongg_RowStack(OpenStack):
|
|||
drag.shade_img.delete()
|
||||
#game.canvas.delete(drag.shade_img)
|
||||
drag.shade_img = None
|
||||
img = game.app.images.getShadowCard(card.deck, card.suit, card.rank)
|
||||
img = game.app.images.getHighlightedCard(card.deck, card.suit, card.rank)
|
||||
if img is None:
|
||||
return 1
|
||||
img = MfxCanvasImage(game.canvas, self.x, self.y, image=img,
|
||||
|
@ -896,7 +896,7 @@ a solvable configuration.'''),
|
|||
assert c1 in s.cards
|
||||
tkraise = False
|
||||
x, y = s.x, s.y
|
||||
img = self.app.images.getHighlightCard(c1.deck, c1.suit, c1.rank)
|
||||
img = self.app.images.getHighlightedCard(c1.deck, c1.suit, c1.rank, 'black')
|
||||
if img is None:
|
||||
continue
|
||||
img = MfxCanvasImage(self.canvas, x, y, image=img,
|
||||
|
|
|
@ -123,7 +123,7 @@ r(5078, "Squaring", layout="0caaacaceaciaakacmacqaasacuacyaaAacCaaacaecaicdkcamc
|
|||
r(5079, "Stairs", layout="0aoaaebaybeacdccagcaicakcbmccocbqcascaucawcdAceCcaedayddaeaieaoeauedCebefbyfaagaigaogaugaCgbchcehbghakhbmhbqhashbwhcyhbAhaaiaiiaoiauiaCibejbyjdakaikaokaukdCkaelayleamdcmagmaimakmbmmcombqmasmaumawmdAmeCmaenaynaoohechychofhahkohhChhojhemhym")
|
||||
r(5080, "Star Ship", layout="0eoaaabdmbdqbaCbaccckccscaAcaadbidbudaCdbceagecoeawebAeaafaefamfaqfayfaCfecgaggaigbkgdogbsgaugawgeAgaahaehamhaqhayhaChbciagicoiawibAiaajbijbujaCjackckkcskaAkaaldmldqlaCleomhachCchaehCehaghegimgiqghyghCghaihCihakhCkoadoCdoafoCfoahoChoajoCjvaevCevagvCgvaivCiCafCCfCahCCh")
|
||||
#
|
||||
r(5081, "Step Pyramid", layout="0aaaacaaeaagaaiaakaamaaoaaqaaacaccaecagcaicakcamcaocaqcaaeaceaoeaqeaagacgaogaqgaaiaciaoiaqiaakackaekagkaikakkamkaokaqkaamacmaemagmaimakmammaomaqmhbbhdbhfbhhbhjbhlbhnbhpbhbdhddhfdhhdhjdhldhndhpdhbfhdfhnfhpfhbhhdhhnhhphhbjhdjhfjhhjhjjhljhnjhpjhblhdlhflhhlhjlhllhnlhplpccoecogcoicokcomcpococepeepgepiepkepmeooeocgpegpmgoogocipeipgipiipkipmiooipckoekogkoikokkomkpokCffChfCjfClfCfhChhCjhClh")
|
||||
r(5081, "Steps Pyramid", layout="0aaaacaaeaagaaiaakaamaaoaaqaaacaccaecagcaicakcamcaocaqcaaeaceaoeaqeaagacgaogaqgaaiaciaoiaqiaakackaekagkaikakkamkaokaqkaamacmaemagmaimakmammaomaqmhbbhdbhfbhhbhjbhlbhnbhpbhbdhddhfdhhdhjdhldhndhpdhbfhdfhnfhpfhbhhdhhnhhphhbjhdjhfjhhjhjjhljhnjhpjhblhdlhflhhlhjlhllhnlhplpccoecogcoicokcomcpococepeepgepiepkepmeooeocgpegpmgoogocipeipgipiipkipmiooipckoekogkoikokkomkpokCffChfCjfClfCfhChhCjhClh")
|
||||
r(5082, "Stonehenge", layout="0cdachackacoacracvacyacCacaccFcajeaneareavecagcFgddhdhhdlhdphdthdxhdBhcajcFjajkankarkavkcancFncdpchpckpcopcrpcvpcypcCpveavgavlavnavsavuavzavBavadvFdvafvFfvakvFkvamvFmvepvgpvlpvnpvspvupvzpvBpCehCghCihCkhCmhCohCqhCshCuhCwhCyhCAh")
|
||||
r(5083, "SunMoon", layout="0dgaciabkaamabyadebbrbbBbdccbvccaddcecheckecnebDecafbtfbAfdcgdjgdlgbxgcahchhcnhdcidjidlibribDicajbvjdckchkckkcnkbAkcalbsldcmbxmdenbBndgociobkoamobuovaevagvaivakCkh")
|
||||
r(5084, "Temple", layout="0baaacaaeaalaanaapaaraataaAaaCabEaaacaccalcbncbpcbrcatcaCcaEcajdavdaaeblebnebpebrebteaEeaffahfajfavfaxfazfblgbngbpgbrgbtgadhafhahhajhavhaxhazhaBhblibnibpibribtiafjahjajjavjaxjazjaakblkbnkbpkbrkbtkaEkajlavlaamacmalmbnmbpmbrmatmaCmaEmbaoacoaeoaloanoapoaroatoaAoaCobEohhghjghvghxghhihjihvihxiooeoqeokgomgoogoqgosgougokiomiooioqiosiouiookoqkvpgvpi")
|
||||
|
|
|
@ -250,33 +250,31 @@ class Shisen_RowStack(Mahjongg_RowStack):
|
|||
|
||||
def drawArrow(self, other_stack, sleep):
|
||||
game = self.game
|
||||
images = game.app.images
|
||||
cs = game.app.cardset
|
||||
path = self.acceptsCards(other_stack, [other_stack.cards[-1]])
|
||||
#print path
|
||||
x0, y0 = game.XMARGIN, game.YMARGIN
|
||||
#print x0, y0
|
||||
images = game.app.images
|
||||
cs = game.app.cardset
|
||||
cardw, cardh = images.CARDW, images.CARDH
|
||||
if cs.version >= 6:
|
||||
cardw = images.CARDW-cs.SHADOW_XOFFSET
|
||||
cardh = images.CARDH-cs.SHADOW_YOFFSET
|
||||
else:
|
||||
cardw = images.CARDW
|
||||
cardh = images.CARDH
|
||||
cardw -= cs.SHADOW_XOFFSET
|
||||
cardh -= cs.SHADOW_YOFFSET
|
||||
coords = []
|
||||
dx, dy = game._delta_x, game._delta_y
|
||||
xf, yf = images._xfactor, images._yfactor
|
||||
for x, y in path:
|
||||
if x == 0:
|
||||
coords.append(6)
|
||||
elif x == game.L[0]+1:
|
||||
coords.append(x0+cardw*(x-1)+10+dx)
|
||||
coords.append(int(round(xf * (x0+cardw*(x-1)+10+dx))))
|
||||
else:
|
||||
coords.append(x0+cardw/2+cardw*(x-1)+dx)
|
||||
coords.append(int(round(xf * (x0+cardw/2+cardw*(x-1)+dx))))
|
||||
if y == 0:
|
||||
coords.append(6)
|
||||
elif y == game.L[1]+1:
|
||||
coords.append(y0+cardh*(y-1)+6)
|
||||
coords.append(int(round(yf * (y0+cardh*(y-1)+6))))
|
||||
else:
|
||||
coords.append(y0+cardh/2+cardh*(y-1))
|
||||
coords.append(int(round(yf * (y0+cardh/2+cardh*(y-1)))))
|
||||
#print coords
|
||||
##s1 = min(cardw/2, cardh/2, 30)
|
||||
##w = min(s1/3, 7)
|
||||
|
|
|
@ -33,7 +33,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -64,7 +64,7 @@ class PushPin_Talon(DealRowTalonStack):
|
|||
if not r.cards:
|
||||
return self.dealRowAvail(rows=[r], sound=sound)
|
||||
return self.dealRowAvail(rows=[self.game.s.rows[0]], sound=sound)
|
||||
getBottomImage = Stack._getBlankBottomImage
|
||||
getBottomImage = Stack._getNoneBottomImage
|
||||
|
||||
class PushPin_RowStack(ReserveStack):
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
from unionsquare import UnionSquare_Foundation
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ Straight
|
|||
Three of a Kind
|
||||
Two Pair
|
||||
One Pair'''))
|
||||
self.texts.list.append(t)
|
||||
bb = t.bbox()
|
||||
x = bb[1][0] + 16
|
||||
h = bb[1][1] - bb[0][1]
|
||||
|
@ -91,6 +92,7 @@ One Pair'''))
|
|||
t = MfxCanvasText(self.canvas, x, y, anchor="nw",
|
||||
font=self.app.getFont("canvas_default"),
|
||||
text="100\n75\n50\n25\n20\n15\n10\n5\n2")
|
||||
self.texts.list.append(t)
|
||||
x = t.bbox()[1][0] + 16
|
||||
self.texts.misc = MfxCanvasText(self.canvas, x, y, anchor="nw",
|
||||
font=self.app.getFont("canvas_default"),
|
||||
|
@ -113,18 +115,17 @@ One Pair'''))
|
|||
|
||||
# create texts 2)
|
||||
if self.preview <= 1:
|
||||
self.texts.addattr(hands=[])
|
||||
for i in (4, 9, 14, 19, 24):
|
||||
tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="e")
|
||||
t = MfxCanvasText(self.canvas, tx+8, ty,
|
||||
anchor=ta,
|
||||
font=self.app.getFont("canvas_default"))
|
||||
self.texts.hands.append(t)
|
||||
self.texts.list.append(t)
|
||||
for i in range(20, 25):
|
||||
tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="ss")
|
||||
t = MfxCanvasText(self.canvas, tx, ty, anchor=ta,
|
||||
font=self.app.getFont("canvas_default"))
|
||||
self.texts.hands.append(t)
|
||||
self.texts.list.append(t)
|
||||
self.texts.score = MfxCanvasText(self.canvas, l.XM, 5*l.YS, anchor="sw",
|
||||
font=self.app.getFont("canvas_large"))
|
||||
|
||||
|
@ -171,7 +172,7 @@ One Pair'''))
|
|||
type, value = self.getHandScore(self.poker_hands[i])
|
||||
if 0 <= type <= 8:
|
||||
count[type] = count[type] + 1
|
||||
self.texts.hands[i].config(text=str(value))
|
||||
self.texts.list[i+2].config(text=str(value))
|
||||
score = score + value
|
||||
t = '\n'.join(map(str, count))
|
||||
self.texts.misc.config(text=t)
|
||||
|
|
|
@ -34,7 +34,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -34,7 +34,7 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * Sultan
|
||||
|
|
|
@ -34,7 +34,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -64,10 +64,12 @@ class FlowerClock(AbstractFlowerGame):
|
|||
for i in range(12):
|
||||
x0 = x + xoffset[i] * l.XS
|
||||
y0 = y + yoffset[i] * l.YS
|
||||
s.foundations.append(FlowerClock_Foundation(x0, y0, self, ANY_SUIT, base_rank=3))
|
||||
stack = FlowerClock_Foundation(x0, y0, self, ANY_SUIT, base_rank=3)
|
||||
s.foundations.append(stack)
|
||||
t = MfxCanvasText(self.canvas, x0 + l.CW / 2, y0 + l.YS,
|
||||
anchor="center", font=font,
|
||||
text=self.SUITS[i])
|
||||
stack.texts.misc = t
|
||||
|
||||
# Create row stacks
|
||||
for j in range(2):
|
||||
|
@ -311,15 +313,15 @@ class Pagoda(AbstractFlowerGame):
|
|||
self.setSize(l.XM + l.XS * 11, l.YS * 6)
|
||||
|
||||
# Create foundations
|
||||
self.foundation_texts = []
|
||||
id = 0
|
||||
for j in range(4):
|
||||
x, y = l.XM + l.XS * 8, l.YM * 3 + l.YS * j * 1.5
|
||||
for i in range(3):
|
||||
s.foundations.append(Pagoda_Foundation(x, y, self, id))
|
||||
stack = Pagoda_Foundation(x, y, self, id)
|
||||
s.foundations.append(stack)
|
||||
t = MfxCanvasText(self.canvas, x + l.CW / 2, y - 12,
|
||||
anchor="center", font=font)
|
||||
self.foundation_texts.append(t)
|
||||
stack.texts.misc = t
|
||||
x = x + l.XS
|
||||
id = id + 1
|
||||
|
||||
|
@ -370,7 +372,7 @@ class Pagoda(AbstractFlowerGame):
|
|||
text = _("Rising")
|
||||
else:
|
||||
text = _("Setting")
|
||||
self.foundation_texts[i].config(text=text)
|
||||
s.texts.misc.config(text=text)
|
||||
|
||||
#
|
||||
# Game over rides
|
||||
|
@ -468,13 +470,14 @@ class GreatWall(AbstractFlowerGame):
|
|||
self.setSize(w, h)
|
||||
|
||||
# Create foundations
|
||||
self.foundation_texts = []
|
||||
x, y = (l.XM, l.XM, w - l.XS, w - l.XS), (l.YM, h / 2, l.YM, h / 2)
|
||||
for i in range(4):
|
||||
s.foundations.append(GreatWall_FoundationStack(x[i], y[i] + l.YM, self, -1, base_rank=i))
|
||||
self.foundation_texts.append(MfxCanvasText(self.canvas,
|
||||
x[i] + l.CW / 2, y[i],
|
||||
anchor="center", font=font))
|
||||
stack = GreatWall_FoundationStack(x[i], y[i] + l.YM, self, -1,
|
||||
base_rank=i)
|
||||
s.foundations.append(stack)
|
||||
stack.texts.misc = MfxCanvasText(self.canvas,
|
||||
x[i] + l.CW / 2, y[i],
|
||||
anchor="center", font=font)
|
||||
|
||||
# Create row stacks
|
||||
x = l.XM + l.XS * 1.5
|
||||
|
@ -501,14 +504,15 @@ class GreatWall(AbstractFlowerGame):
|
|||
if self.preview > 1:
|
||||
return
|
||||
for i in range(4):
|
||||
l = len(self.s.foundations[i].cards) / 12
|
||||
stack = self.s.foundations[i]
|
||||
l = len(stack.cards) / 12
|
||||
if l == 0:
|
||||
t = ""
|
||||
text = ""
|
||||
elif l == 4:
|
||||
t = _("Filled")
|
||||
text = _("Filled")
|
||||
else:
|
||||
t = str(l) + (_("st"), _("nd"), _("rd"), _("th"))[l - 1] + _(" Deck")
|
||||
self.foundation_texts[i].config(text=str(t))
|
||||
text = str(l) + (_("st"), _("nd"), _("rd"), _("th"))[l - 1] + _(" Deck")
|
||||
stack.texts.misc.config(text=text)
|
||||
|
||||
#
|
||||
# Game over rides
|
||||
|
@ -568,11 +572,13 @@ class FourWinds(AbstractFlowerGame):
|
|||
for i in range(4):
|
||||
x0 = x + (xoffset[i] * l.XS)
|
||||
y0 = y + (yoffset[i] * l.YS)
|
||||
s.foundations.append(FourWinds_Foundation(x0, y0, self, -1,
|
||||
max_cards=12, max_accept=1, base_rank=i))
|
||||
stack = FourWinds_Foundation(x0, y0, self, -1,
|
||||
max_cards=12, max_accept=1, base_rank=i)
|
||||
s.foundations.append(stack)
|
||||
t = MfxCanvasText(self.canvas, x0 + l.CW / 2, y0 + l.YS + 5,
|
||||
anchor="center", font=font,
|
||||
text=TEXTS[i])
|
||||
stack.texts.misc = t
|
||||
|
||||
# Create rows
|
||||
xoffset = (1.25, 3.75, 3.75, 1.25)
|
||||
|
@ -580,11 +586,14 @@ class FourWinds(AbstractFlowerGame):
|
|||
for i in range(4):
|
||||
x0 = x + (xoffset[i] * l.XS)
|
||||
y0 = y + (yoffset[i] * l.YS)
|
||||
s.rows.append(FourWinds_RowStack(x0, y0, self, yoffset=10,
|
||||
max_cards=3, max_accept=1, base_rank=ANY_RANK))
|
||||
stack = FourWinds_RowStack(x0, y0, self, yoffset=10,
|
||||
max_cards=3, max_accept=1,
|
||||
base_rank=ANY_RANK)
|
||||
s.rows.append(stack)
|
||||
t = MfxCanvasText(self.canvas, x0 + l.CW / 2, y0 + l.YS + 5,
|
||||
anchor="center", font=font,
|
||||
text=TEXTS[i+4])
|
||||
stack.texts.misc = t
|
||||
self.setRegion(s.rows, (x + l.XS, y + l.YS * 0.65, x + l.XS * 4 + 5, y + l.YS * 3 + 5))
|
||||
|
||||
# Create talon
|
||||
|
|
|
@ -297,10 +297,12 @@ class BitsNBytes(Game):
|
|||
for j in range(4):
|
||||
x = l.XM * 4 + l.XS * 7
|
||||
for i in range(4):
|
||||
s.rows.append(Bits_RowStack(x, y, self, max_cards=1,
|
||||
max_accept=1, base_suit=j, max_move=0))
|
||||
self.bit_texts.append(MfxCanvasText(self.canvas, x + l.CW / 2 , y + l.CH / 2,
|
||||
anchor="center", font=font))
|
||||
stack = Bits_RowStack(x, y, self, max_cards=1, max_accept=1,
|
||||
base_suit=j, max_move=0)
|
||||
s.rows.append(stack)
|
||||
stack.texts.misc = MfxCanvasText(self.canvas,
|
||||
x + l.CW / 2 , y + l.CH / 2,
|
||||
anchor="center", font=font)
|
||||
x = x - l.XS
|
||||
y = y + l.YS
|
||||
|
||||
|
@ -347,7 +349,8 @@ class BitsNBytes(Game):
|
|||
break
|
||||
s = self.s.foundations[j].cards[-1].rank + 1
|
||||
for i in range(4):
|
||||
self.bit_texts[i + j * 4].config(text = str(s % 2))
|
||||
stack = self.s.rows[i + j * 4]
|
||||
stack.texts.misc.config(text = str(s % 2))
|
||||
s = int(s / 2)
|
||||
|
||||
def _shuffleHook(self, cards):
|
||||
|
|
|
@ -34,8 +34,6 @@ from pysollib.stack import *
|
|||
from pysollib.game import Game
|
||||
from pysollib.layout import Layout
|
||||
from pysollib.hint import AbstractHint, DefaultHint, CautiousDefaultHint
|
||||
from pysollib.pysoltk import MfxCanvasText
|
||||
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -29,10 +29,10 @@ import traceback
|
|||
# PySol imports
|
||||
from resource import CSI
|
||||
from settings import TOOLKIT
|
||||
from mfxutil import Image, ImageTk
|
||||
from mfxutil import Image, ImageTk, USE_PIL
|
||||
|
||||
# Toolkit imports
|
||||
from pysoltk import loadImage, copyImage, createImage, shadowImage, createBottom
|
||||
from pysoltk import loadImage, copyImage, createImage, shadowImage, createBottom, resizeBottom
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
@ -54,37 +54,26 @@ class Images:
|
|||
self.d = dataloader
|
||||
self.cs = cs
|
||||
self.reduced = r
|
||||
self._xfactor = 1.0
|
||||
self._yfactor = 1.0
|
||||
if cs is None:
|
||||
return
|
||||
self.use_pil = False
|
||||
if TOOLKIT == 'tk' and Image and Image.VERSION >= '1.1.7':
|
||||
self.use_pil = True
|
||||
# copy from cardset
|
||||
self.CARDW, self.CARDH, self.CARDD = cs.CARDW/r, cs.CARDH/r, cs.CARDD/r
|
||||
self.CARD_XOFFSET = cs.CARD_XOFFSET
|
||||
self.CARD_YOFFSET = cs.CARD_YOFFSET
|
||||
if r > 1:
|
||||
self.CARD_XOFFSET = max(10, cs.CARD_XOFFSET)/r
|
||||
self.CARD_YOFFSET = max(10, cs.CARD_YOFFSET)/r
|
||||
self.SHADOW_XOFFSET, self.SHADOW_YOFFSET = cs.SHADOW_XOFFSET/r, cs.SHADOW_YOFFSET/r
|
||||
self.CARD_DX, self.CARD_DY = cs.CARD_DX/r, cs.CARD_DY/r
|
||||
# other
|
||||
self._shade_index = 0
|
||||
self._setSize()
|
||||
self._card = []
|
||||
self._back = []
|
||||
self._bottom = []
|
||||
self._bottom_negative = []
|
||||
self._bottom_positive = []
|
||||
self._blank_bottom = None
|
||||
self._letter = []
|
||||
self._bottom = [] # bottom of stack (link to _bottom_negative/_bottom_positive)
|
||||
self._bottom_negative = [] # negative bottom of stack (white)
|
||||
self._bottom_positive = [] # positive bottom of stack (black)
|
||||
self._blank_bottom = None # blank (transparent) bottom of stack
|
||||
self._letter = [] # images of letter
|
||||
self._letter_negative = []
|
||||
self._letter_positive = []
|
||||
self._shadow = []
|
||||
self._xshadow = []
|
||||
self._shade = []
|
||||
self._shadow_cards = {} # key: (suit, rank)
|
||||
self._shadow = [] # vertical shadow of card (used when we drag a card)
|
||||
self._xshadow = [] # horizontal shadow of card
|
||||
self._pil_shadow = {} # key: (width, height)
|
||||
self._pil_shadow_image = None
|
||||
self._highlight = [] # highlight of card (tip)
|
||||
self._highlight_index = 0 #
|
||||
self._highlighted_images = {} # key: (suit, rank)
|
||||
|
||||
def destruct(self):
|
||||
pass
|
||||
|
@ -115,9 +104,13 @@ class Images:
|
|||
imagedir = self.d.findDir(cs_type, d)
|
||||
except:
|
||||
pass
|
||||
if not self.use_pil or imagedir is None:
|
||||
if not USE_PIL or imagedir is None:
|
||||
# load image
|
||||
return self.__loadCard(filename+self.cs.ext, check_w, check_h)
|
||||
img = self.__loadCard(filename+self.cs.ext, check_w, check_h)
|
||||
if USE_PIL:
|
||||
# we have no bottom images (data/images/cards/bottoms/<cs_type>)
|
||||
img = img.resize(self._xfactor, self._yfactor)
|
||||
return img
|
||||
# create image
|
||||
d = os.path.join('images', 'cards', 'bottoms', cs_type)
|
||||
try:
|
||||
|
@ -134,9 +127,10 @@ class Images:
|
|||
self._back.append(ImagesCardback(len(self._back), name, im1, im2))
|
||||
|
||||
def _createMissingImages(self):
|
||||
cw, ch = self.getSize()
|
||||
# back
|
||||
if not self._back:
|
||||
im = createImage(self.CARDW, self.CARDH, fill="#a0a0a0", outline="#000000")
|
||||
im = createImage(cw, ch, fill="#a0a0a0", outline="#000000")
|
||||
name = ""
|
||||
self.__addBack(im, name)
|
||||
self.cs.backnames = tuple(self.cs.backnames) + (name,)
|
||||
|
@ -145,21 +139,21 @@ class Images:
|
|||
neg_bottom = None
|
||||
while len(self._bottom_positive) < 7:
|
||||
if bottom is None:
|
||||
bottom = createImage(self.CARDW, self.CARDH, fill=None, outline="#000000")
|
||||
bottom = createImage(cw, ch, fill=None, outline="#000000")
|
||||
self._bottom_positive.append(bottom)
|
||||
while len(self._bottom_negative) < 7:
|
||||
if neg_bottom is None:
|
||||
neg_bottom = createImage(self.CARDW, self.CARDH, fill=None, outline="#ffffff")
|
||||
neg_bottom = createImage(cw, ch, fill=None, outline="#ffffff")
|
||||
self._bottom_negative.append(neg_bottom)
|
||||
while len(self._letter_positive) < 4:
|
||||
if bottom is None:
|
||||
bottom = createImage(self.CARDW, self.CARDH, fill=None, outline="#000000")
|
||||
bottom = createImage(cw, ch, fill=None, outline="#000000")
|
||||
self._letter_positive.append(bottom)
|
||||
while len(self._letter_negative) < 4:
|
||||
if neg_bottom is None:
|
||||
neg_bottom = createImage(self.CARDW, self.CARDH, fill=None, outline="#ffffff")
|
||||
neg_bottom = createImage(cw, ch, fill=None, outline="#ffffff")
|
||||
self._letter_negative.append(neg_bottom)
|
||||
self._blank_bottom = createImage(self.CARDW, self.CARDH, fill=None, outline=None)
|
||||
self._blank_bottom = createImage(cw, ch, fill=None, outline=None)
|
||||
|
||||
def load(self, app, progress=None):
|
||||
ext = self.cs.ext[1:]
|
||||
|
@ -199,7 +193,7 @@ class Images:
|
|||
self._letter_negative.append(self.__loadBottom(name, color='white'))
|
||||
if progress: progress.update(step=pstep)
|
||||
# shadow
|
||||
if not self.use_pil:
|
||||
if not USE_PIL:
|
||||
for i in range(self.cs.nshadows):
|
||||
name = "shadow%02d.%s" % (i, ext)
|
||||
im = self.__loadCard(name, check_w=0, check_h=0)
|
||||
|
@ -210,10 +204,10 @@ class Images:
|
|||
self._xshadow.append(im)
|
||||
if progress: progress.update(step=pstep)
|
||||
# shade
|
||||
if self.use_pil:
|
||||
self._shade.append(self._getShadow(self._card[0], None, '#3896f8'))
|
||||
if USE_PIL:
|
||||
self._highlight.append(self._getHighlight(self._card[0], None, '#3896f8'))
|
||||
else:
|
||||
self._shade.append(self.__loadCard("shade." + ext))
|
||||
self._highlight.append(self.__loadCard("shade." + ext))
|
||||
if progress: progress.update(step=pstep)
|
||||
# create missing
|
||||
self._createMissingImages()
|
||||
|
@ -278,8 +272,9 @@ class Images:
|
|||
x1, y1 = stack.getPositionFor(cards[-1])
|
||||
x0, x1 = min(x1, x0), max(x1, x0)
|
||||
y0, y1 = min(y1, y0), max(y1, y0)
|
||||
x1 += self.CARDW
|
||||
y1 += self.CARDH
|
||||
cw, ch = self.getSize()
|
||||
x1 += cw
|
||||
y1 += ch
|
||||
w, h = x1-x0, y1-y0
|
||||
if (w,h) in self._pil_shadow:
|
||||
return self._pil_shadow[(w,h)]
|
||||
|
@ -298,43 +293,43 @@ class Images:
|
|||
mask = mask.crop((sx,sy,w,h))
|
||||
tmp = Image.new('RGBA', (w-sx,h-sy))
|
||||
shadow.paste(tmp, (0,0), mask)
|
||||
#
|
||||
shadow = ImageTk.PhotoImage(shadow)
|
||||
self._pil_shadow[(w,h)] = shadow
|
||||
return shadow
|
||||
|
||||
def getShade(self):
|
||||
return self._shade[self._shade_index]
|
||||
# highlight
|
||||
return self._highlight[self._highlight_index]
|
||||
|
||||
def _getShadow(self, image, card, color='#3896f8', factor=0.3):
|
||||
if self.use_pil:
|
||||
# use alpha image; one for each color
|
||||
if color in self._shadow_cards:
|
||||
shade = self._shadow_cards[color]
|
||||
def _getHighlight(self, image, card, color='#3896f8', factor=0.3):
|
||||
if USE_PIL:
|
||||
# use semitransparent image; one for each color (PIL >= 1.1.7)
|
||||
if color in self._highlighted_images:
|
||||
shade = self._highlighted_images[color]
|
||||
else:
|
||||
shade = shadowImage(image, color, factor)
|
||||
self._shadow_cards[color] = shade
|
||||
self._highlighted_images[color] = shade
|
||||
else:
|
||||
if card in self._shadow_cards:
|
||||
shade = self._shadow_cards[card]
|
||||
# use alpha blending (PIL <= 1.1.6)
|
||||
if card in self._highlighted_images:
|
||||
shade = self._highlighted_images[card]
|
||||
else:
|
||||
shade = shadowImage(image, color, factor)
|
||||
self._shadow_cards[card] = shade
|
||||
self._highlighted_images[card] = shade
|
||||
if not shade:
|
||||
# we have not PIL
|
||||
return self.getShade()
|
||||
return shade
|
||||
|
||||
def getShadowCard(self, deck, suit, rank):
|
||||
def getHighlightedCard(self, deck, suit, rank, color=None):
|
||||
image = self.getFace(deck, suit, rank)
|
||||
return self._getShadow(image, (suit, rank))
|
||||
if color:
|
||||
return self._getHighlight(image, (suit, rank, color), color)
|
||||
return self._getHighlight(image, (suit, rank))
|
||||
|
||||
def getHighlightCard(self, deck, suit, rank):
|
||||
image = self.getFace(deck, suit, rank)
|
||||
return self._getShadow(image, (suit, rank, 'black'), 'black')
|
||||
|
||||
def getShadowBack(self):
|
||||
def getHighlightedBack(self):
|
||||
image = self.getBack()
|
||||
return self._getShadow(image, 'back')
|
||||
return self._getHighlight(image, 'back')
|
||||
|
||||
def getCardbacks(self):
|
||||
return self._back
|
||||
|
@ -347,6 +342,83 @@ class Images:
|
|||
self._bottom = self._bottom_positive
|
||||
self._letter = self._letter_positive
|
||||
|
||||
def _setSize(self, xf=1, yf=1):
|
||||
#print 'Images._setSize', xf, yf
|
||||
self._xfactor = xf
|
||||
self._yfactor = yf
|
||||
cs = self.cs
|
||||
if cs is None:
|
||||
return
|
||||
r = self.reduced
|
||||
xf = float(xf)/r
|
||||
yf = float(yf)/r
|
||||
# copy from cardset
|
||||
self.CARDW, self.CARDH = int(cs.CARDW*xf), int(cs.CARDH*yf)
|
||||
if r > 1:
|
||||
self.CARD_XOFFSET = max(10/r, int(cs.CARD_XOFFSET*xf))
|
||||
self.CARD_YOFFSET = max(10/r, int(cs.CARD_YOFFSET*yf))
|
||||
else:
|
||||
self.CARD_XOFFSET = int(cs.CARD_XOFFSET*xf)
|
||||
self.CARD_YOFFSET = int(cs.CARD_YOFFSET*yf)
|
||||
self.SHADOW_XOFFSET = int(cs.SHADOW_XOFFSET*xf)
|
||||
self.SHADOW_YOFFSET = int(cs.SHADOW_YOFFSET*yf)
|
||||
self.CARD_DX, self.CARD_DY = int(cs.CARD_DX*xf), int(cs.CARD_DY*yf)
|
||||
|
||||
def getSize(self):
|
||||
return (int(self.CARDW * self._xfactor),
|
||||
int(self.CARDH * self._yfactor))
|
||||
def getOffsets(self):
|
||||
return (int(self.CARD_XOFFSET * self._xfactor),
|
||||
int(self.CARD_YOFFSET * self._yfactor))
|
||||
def getDelta(self):
|
||||
return (int(self.CARD_DX * self._xfactor),
|
||||
int(self.CARD_DY * self._yfactor))
|
||||
|
||||
def resize(self, xf, yf):
|
||||
#print 'Images.resize:', xf, yf, self._card[0].width()
|
||||
if self._xfactor == xf and self._yfactor == yf:
|
||||
#print 'no resize'
|
||||
return
|
||||
self._xfactor = xf
|
||||
self._yfactor = yf
|
||||
# cards
|
||||
cards = []
|
||||
for c in self._card:
|
||||
c = c.resize(xf, yf)
|
||||
cards.append(c)
|
||||
self._card = cards
|
||||
# back
|
||||
for b in self._back:
|
||||
b.image = b.image.resize(xf, yf)
|
||||
# stack bottom image
|
||||
neg = self._bottom is self._bottom_negative
|
||||
self._bottom_negative = []
|
||||
self._bottom_positive = []
|
||||
for i in range(self.cs.nbottoms):
|
||||
name = "bottom%02d" % (i + 1)
|
||||
self._bottom_positive.append(self.__loadBottom(name, color='black'))
|
||||
name = "bottom%02d-n" % (i + 1)
|
||||
self._bottom_negative.append(self.__loadBottom(name, color='white'))
|
||||
# letters
|
||||
self._letter_positive = []
|
||||
self._letter_negative = []
|
||||
for rank in range(self.cs.nletters):
|
||||
name = "l%02d" % (rank + 1)
|
||||
self._letter_positive.append(self.__loadBottom(name, color='black'))
|
||||
name = "l%02d-n" % (rank + 1)
|
||||
self._letter_negative.append(self.__loadBottom(name, color='white'))
|
||||
self._createMissingImages()
|
||||
self.setNegative(neg)
|
||||
#
|
||||
self._highlighted_images = {}
|
||||
self._highlight = []
|
||||
self._highlight.append(self._getHighlight(self._card[0], None, '#3896f8'))
|
||||
self._pil_shadow = {}
|
||||
|
||||
def reset(self):
|
||||
print 'Image.reset'
|
||||
self.resize(1, 1)
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# *
|
||||
|
@ -371,9 +443,9 @@ class SubsampledImages(Images):
|
|||
self._back.append(ImagesCardback(len(self._back), _back.name, im, im))
|
||||
#
|
||||
CW, CH = self.CARDW, self.CARDH
|
||||
for im in images._shade:
|
||||
##self._shade.append(None)
|
||||
self._shade.append(copyImage(im, 0, 0, CW, CH))
|
||||
for im in images._highlight:
|
||||
##self._highlight.append(None)
|
||||
self._highlight.append(copyImage(im, 0, 0, CW, CH))
|
||||
|
||||
def getShadow(self, ncards):
|
||||
return None
|
||||
|
|
|
@ -89,10 +89,8 @@ class Layout:
|
|||
self.CH = images.CARDH
|
||||
self.XOFFSET = images.CARD_XOFFSET
|
||||
self.YOFFSET = images.CARD_YOFFSET
|
||||
|
||||
self.XM = layout_x_margin # XMARGIN
|
||||
self.YM = layout_y_margin # YMARGIN
|
||||
|
||||
self.XM = layout_x_margin # XMARGIN
|
||||
self.YM = layout_y_margin # YMARGIN
|
||||
|
||||
if card_x_space is None:
|
||||
self.XS = self.CW + layout_card_x_space # XSPACE
|
||||
|
@ -914,8 +912,9 @@ class Layout:
|
|||
w = XM * 2 + toprows * XS
|
||||
|
||||
# set size so that at least 2/3 of a card is visible with 12 cards
|
||||
h = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
|
||||
h = max(h, 2 * YS)
|
||||
h1 = CH * 2 / 3 + (playcards - 1) * self.YOFFSET
|
||||
h2 = (3 + reserves / decks) * YS
|
||||
h = max(h1, h2)
|
||||
|
||||
# create foundations
|
||||
x, y = w - XS * decks, YM
|
||||
|
|
|
@ -36,7 +36,7 @@ try:
|
|||
except:
|
||||
thread = None
|
||||
|
||||
from settings import PACKAGE, TOOLKIT
|
||||
from settings import PACKAGE, TOOLKIT, USE_TILE
|
||||
|
||||
Image = ImageTk = ImageOps = None
|
||||
if TOOLKIT == 'tk':
|
||||
|
@ -54,7 +54,13 @@ if TOOLKIT == 'tk':
|
|||
import BmpImagePlugin
|
||||
import PpmImagePlugin
|
||||
Image._initialized = 2
|
||||
USE_PIL = False
|
||||
if TOOLKIT == 'tk' and USE_TILE and Image and Image.VERSION >= '1.1.7':
|
||||
USE_PIL = True
|
||||
|
||||
# debug
|
||||
#Image = None
|
||||
#USE_PIL = False
|
||||
|
||||
# ************************************************************************
|
||||
# * exceptions
|
||||
|
|
|
@ -95,6 +95,7 @@ randomize_place = boolean
|
|||
save_cardsets = boolean
|
||||
dragcursor = boolean
|
||||
save_games_geometry = boolean
|
||||
game_geometry = int_list(min=2, max=2)
|
||||
sound = boolean
|
||||
sound_mode = integer(0, 1)
|
||||
sound_sample_volume = integer(0, 128)
|
||||
|
@ -166,7 +167,11 @@ highlight_piles = float(0.2, 9.9)
|
|||
7 = string_list(min=2, max=2)
|
||||
8 = string_list(min=2, max=2)
|
||||
9 = string_list(min=2, max=2)
|
||||
|
||||
scale_cards = boolean
|
||||
scale_x = float
|
||||
scale_y = float
|
||||
auto_scale = boolean
|
||||
preserve_aspect_ratio = boolean
|
||||
'''.splitlines()
|
||||
|
||||
|
||||
|
@ -237,7 +242,6 @@ class Options:
|
|||
#('favorite_gameid', 'list'),
|
||||
]
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self._config = None # configobj.ConfigObj instance
|
||||
self._config_encoding = 'utf-8'
|
||||
|
@ -367,10 +371,17 @@ class Options:
|
|||
self.wm_maximized = 0
|
||||
self.save_games_geometry = False
|
||||
self.games_geometry = {} # saved games geometry (gameid: (width, height))
|
||||
self.game_geometry = (0, 0) # game geometry before exit
|
||||
#
|
||||
self.randomize_place = False
|
||||
self.save_cardsets = True
|
||||
self.dragcursor = True
|
||||
#
|
||||
self.scale_cards = False
|
||||
self.scale_x = 1.0
|
||||
self.scale_y = 1.0
|
||||
self.auto_scale = False
|
||||
self.preserve_aspect_ratio = True
|
||||
|
||||
def setDefaults(self, top=None):
|
||||
WIN_SYSTEM = settings.WIN_SYSTEM
|
||||
|
@ -477,11 +488,15 @@ class Options:
|
|||
# cardsets
|
||||
for key, val in self.cardset.items():
|
||||
config['cardsets'][str(key)] = val
|
||||
for key in ('scale_cards', 'scale_x', 'scale_y',
|
||||
'auto_scale', 'preserve_aspect_ratio'):
|
||||
config['cardsets'][key] = getattr(self, key)
|
||||
|
||||
# games_geometry
|
||||
config['games_geometry'].clear()
|
||||
for key, val in self.games_geometry.items():
|
||||
config['games_geometry'][str(key)] = val
|
||||
config['general']['game_geometry'] = self.game_geometry
|
||||
|
||||
config.write()
|
||||
##config.write(sys.stdout); print
|
||||
|
@ -628,6 +643,14 @@ class Options:
|
|||
self.cardset[int(key)] = val
|
||||
except:
|
||||
traceback.print_exc()
|
||||
for key, t in (('scale_cards', 'bool'),
|
||||
('scale_x', 'float'),
|
||||
('scale_y', 'float'),
|
||||
('auto_scale', 'bool'),
|
||||
('preserve_aspect_ratio', 'bool')):
|
||||
val = self._getOption('cardsets', key, t)
|
||||
if val is not None:
|
||||
setattr(self, key, val)
|
||||
|
||||
# games_geometry
|
||||
for key, val in config['games_geometry'].items():
|
||||
|
@ -637,5 +660,11 @@ class Options:
|
|||
self.games_geometry[int(key)] = val
|
||||
except:
|
||||
traceback.print_exc()
|
||||
game_geometry = self._getOption('general', 'game_geometry', 'list')
|
||||
if game_geometry is not None:
|
||||
try:
|
||||
self.game_geometry = tuple(int(i) for i in game_geometry)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ PACKAGE = 'PySolFC'
|
|||
TITLE = 'PySol'
|
||||
PACKAGE_URL = 'http://pysolfc.sourceforge.net/'
|
||||
|
||||
VERSION = '2.0.1'
|
||||
VERSION_TUPLE = (2,0,1)
|
||||
VERSION = '3.0'
|
||||
VERSION_TUPLE = (3,0,0)
|
||||
|
||||
# Tk windowing system (auto set up in init.py)
|
||||
WIN_SYSTEM = 'x11' # win32, x11, aqua, classic
|
||||
|
|
|
@ -97,7 +97,7 @@ import types
|
|||
|
||||
# PySol imports
|
||||
from mfxutil import Struct, kwdefault, SubclassResponsibility
|
||||
from mfxutil import Image, ImageTk
|
||||
from mfxutil import Image, ImageTk, USE_PIL
|
||||
from util import ACE, KING
|
||||
from util import ANY_SUIT, ANY_COLOR, ANY_RANK, NO_RANK
|
||||
from pysoltk import EVENT_HANDLED, EVENT_PROPAGATE
|
||||
|
@ -238,7 +238,6 @@ class Stack:
|
|||
mapkey = (x, y)
|
||||
###assert not game.stackmap.has_key(mapkey) ## can happen in PyJonngg
|
||||
game.stackmap[mapkey] = id
|
||||
self.init_coord = (x, y)
|
||||
|
||||
#
|
||||
# setup our pseudo MVC scheme
|
||||
|
@ -282,15 +281,16 @@ class Stack:
|
|||
#
|
||||
# view
|
||||
#
|
||||
self.init_coord = (x, y)
|
||||
view.x = x
|
||||
view.y = y
|
||||
view.canvas = game.canvas
|
||||
view.CARD_XOFFSET = 0
|
||||
view.CARD_YOFFSET = 0
|
||||
view.INIT_CARD_OFFSETS = (0,0)
|
||||
view.INIT_CARD_YOFFSET = 0 # for reallocateCards
|
||||
view.group = MfxCanvasGroup(view.canvas)
|
||||
view.shrink_face_down = 1
|
||||
##view.group.move(view.x, view.y)
|
||||
# image items
|
||||
view.images = Struct(
|
||||
bottom = None, # canvas item
|
||||
|
@ -366,6 +366,11 @@ class Stack:
|
|||
self.CARD_YOFFSET = (oy,)
|
||||
else:
|
||||
self.CARD_YOFFSET = tuple([int(round(y)) for y in oy])
|
||||
|
||||
# preserve offsets
|
||||
self.INIT_CARD_OFFSETS = (self.CARD_XOFFSET, self.CARD_YOFFSET) # for resize()
|
||||
self.INIT_CARD_YOFFSET = self.CARD_YOFFSET # for reallocateCards
|
||||
|
||||
if self.can_hide_cards < 0:
|
||||
self.can_hide_cards = self.is_visible
|
||||
if self.cap.max_cards < 3:
|
||||
|
@ -398,7 +403,7 @@ class Stack:
|
|||
# bottom image
|
||||
if self.is_visible:
|
||||
self.prepareBottom()
|
||||
self.INIT_CARD_YOFFSET = self.CARD_YOFFSET # for reallocateCards
|
||||
|
||||
|
||||
# stack bottom image
|
||||
def prepareBottom(self):
|
||||
|
@ -520,26 +525,6 @@ class Stack:
|
|||
x, y = self.getPositionFor(card)
|
||||
card.moveTo(x, y)
|
||||
|
||||
# move stack to new coords
|
||||
def moveTo(self, x, y):
|
||||
dx, dy = x-self.x, y-self.y
|
||||
self.x, self.y = x, y
|
||||
for c in self.cards:
|
||||
x, y = self.getPositionFor(c)
|
||||
c.moveTo(x, y)
|
||||
if self.images.bottom:
|
||||
self.images.bottom.move(dx, dy)
|
||||
if self.images.redeal:
|
||||
self.images.redeal.move(dx, dy)
|
||||
if self.texts.ncards:
|
||||
self.texts.ncards.move(dx, dy)
|
||||
if self.texts.rounds:
|
||||
self.texts.rounds.move(dx, dy)
|
||||
if self.texts.redeal:
|
||||
self.texts.redeal.move(dx, dy)
|
||||
if self.texts.misc:
|
||||
self.texts.misc.move(dx, dy)
|
||||
|
||||
# find card
|
||||
def _findCard(self, event):
|
||||
model, view = self, self
|
||||
|
@ -553,11 +538,12 @@ class Stack:
|
|||
model, view = self, self
|
||||
if cards is None: cards = model.cards
|
||||
images = self.game.app.images
|
||||
cw, ch = images.getSize()
|
||||
index = -1
|
||||
for i in range(len(cards)):
|
||||
c = cards[i]
|
||||
r = (c.x, c.y, c.x + images.CARDW, c.y + images.CARDH)
|
||||
if x >= r[0] and x < r[2] and y >= r[1] and y < r[3]:
|
||||
r = (c.x, c.y, c.x + cw, c.y + ch)
|
||||
if r[0] <= x < r[2] and r[1] <= y < r[3]:
|
||||
index = i
|
||||
return index
|
||||
|
||||
|
@ -667,6 +653,10 @@ class Stack:
|
|||
def resetGame(self):
|
||||
# Called when starting a new game.
|
||||
self.CARD_YOFFSET = self.INIT_CARD_YOFFSET
|
||||
self.items.shade_item = None
|
||||
self.images.shade_img = None
|
||||
#self.items.bottom = None
|
||||
#self.images.bottom = None
|
||||
|
||||
def __repr__(self):
|
||||
# Return a string for debug print statements.
|
||||
|
@ -874,7 +864,7 @@ class Stack:
|
|||
if not self.canvas.winfo_ismapped():
|
||||
return False
|
||||
yoffset = self.CARD_YOFFSET[0]
|
||||
cardh = self.game.app.images.CARDH / 2 # 1/2 of a card is visible
|
||||
cardh = self.game.app.images.getSize()[0] / 2 # 1/2 of a card is visible
|
||||
num_face_up = len([c for c in self.cards if c.face_up])
|
||||
num_face_down = len(self.cards) - num_face_up
|
||||
stack_height = int(self.y +
|
||||
|
@ -882,13 +872,19 @@ class Stack:
|
|||
num_face_up * yoffset +
|
||||
cardh)
|
||||
visible_height = self.canvas.winfo_height()
|
||||
game_height = self.game.height + 2*self.canvas.ymargin
|
||||
if USE_PIL and self.game.app.opt.auto_scale:
|
||||
# use visible_height only
|
||||
game_height = 0
|
||||
else:
|
||||
game_height = self.game.height + 2*self.canvas.ymargin
|
||||
height = max(visible_height, game_height)
|
||||
#print 'reallocateCards:', stack_height, height, visible_height, game_height
|
||||
if stack_height > height:
|
||||
# compact stack
|
||||
n = num_face_down / self.shrink_face_down + num_face_up
|
||||
dy = float(height - self.y - cardh) / n
|
||||
if dy < yoffset:
|
||||
#print 'compact:', dy
|
||||
self.CARD_YOFFSET = (dy,)
|
||||
return True
|
||||
elif stack_height < height:
|
||||
|
@ -898,12 +894,62 @@ class Stack:
|
|||
n = num_face_down / self.shrink_face_down + num_face_up
|
||||
dy = float(height - self.y - cardh) / n
|
||||
dy = min(dy, self.INIT_CARD_YOFFSET[0])
|
||||
#print 'expande:', dy
|
||||
self.CARD_YOFFSET = (dy,)
|
||||
return True
|
||||
return False
|
||||
|
||||
def resize(self, xf, yf):
|
||||
print 'resize', self
|
||||
# resize and move stack
|
||||
# xf, yf - a multiplicative factor (from the original values)
|
||||
#print 'Stack.resize:', self, self.is_visible, xf, yf
|
||||
x0, y0 = self.init_coord
|
||||
x, y = int(round(x0*xf)), int(round(y0*yf))
|
||||
self.x, self.y = x, y
|
||||
# offsets
|
||||
xoffset = tuple(int(round(i*xf)) for i in self.INIT_CARD_OFFSETS[0])
|
||||
yoffset = tuple(int(round(i*yf)) for i in self.INIT_CARD_OFFSETS[1])
|
||||
self.CARD_XOFFSET = xoffset
|
||||
self.CARD_YOFFSET = yoffset
|
||||
self.INIT_CARD_YOFFSET = yoffset
|
||||
#print '* resize offset:', self.INIT_CARD_XOFFSET,
|
||||
# move cards
|
||||
for c in self.cards:
|
||||
cx, cy = self.getPositionFor(c)
|
||||
c.moveTo(cx, cy)
|
||||
# ---
|
||||
if not self.is_visible:
|
||||
return
|
||||
# bottom and shade
|
||||
if self.images.bottom:
|
||||
img = self.getBottomImage()
|
||||
self.images.bottom['image'] = img
|
||||
self.images.bottom.moveTo(x, y)
|
||||
if self.items.shade_item:
|
||||
c = self.cards[-1]
|
||||
img = self.game.app.images.getHighlightedCard(c.deck, c.suit, c.rank)
|
||||
if img:
|
||||
self.items.shade_item['image'] = img
|
||||
self.items.shade_item.moveTo(x, y)
|
||||
#
|
||||
def move(item):
|
||||
ix, iy = item.init_coord
|
||||
x = int(round(ix*xf))
|
||||
y = int(round(iy*yf))
|
||||
item.moveTo(x, y)
|
||||
# images
|
||||
if self.images.redeal:
|
||||
move(self.images.redeal)
|
||||
# texts
|
||||
if self.texts.ncards:
|
||||
move(self.texts.ncards)
|
||||
if self.texts.rounds:
|
||||
move(self.texts.rounds)
|
||||
if self.texts.redeal:
|
||||
move(self.texts.redeal)
|
||||
if self.texts.misc:
|
||||
move(self.texts.misc)
|
||||
|
||||
|
||||
def basicShallHighlightSameRank(self, card):
|
||||
# by default all open stacks are available for highlighting
|
||||
|
@ -1003,14 +1049,14 @@ class Stack:
|
|||
return 0
|
||||
##print self.cards[i]
|
||||
self.cards[i].item.tkraise()
|
||||
self.game.canvas.update_idletasks()
|
||||
self.canvas.update_idletasks()
|
||||
self.game.sleep(self.game.app.opt.timeouts['raise_card'])
|
||||
if TOOLKIT == 'tk':
|
||||
self.cards[i].item.lower(self.cards[i+1].item)
|
||||
elif TOOLKIT == 'gtk':
|
||||
for c in self.cards[i+1:]:
|
||||
c.tkraise()
|
||||
self.game.canvas.update_idletasks()
|
||||
self.canvas.update_idletasks()
|
||||
return 1
|
||||
|
||||
def controlmiddleclickHandler(self, event):
|
||||
|
@ -1026,7 +1072,7 @@ class Stack:
|
|||
if not face_up:
|
||||
self.cards[i].showFace()
|
||||
self.cards[i].item.tkraise()
|
||||
self.game.canvas.update_idletasks()
|
||||
self.canvas.update_idletasks()
|
||||
self.game.sleep(self.game.app.opt.timeouts['raise_card'])
|
||||
if not face_up:
|
||||
self.cards[i].showBack()
|
||||
|
@ -1036,7 +1082,7 @@ class Stack:
|
|||
elif TOOLKIT == 'gtk':
|
||||
for c in self.cards[i+1:]:
|
||||
c.tkraise()
|
||||
self.game.canvas.update_idletasks()
|
||||
self.canvas.update_idletasks()
|
||||
return 1
|
||||
|
||||
def rightclickHandler(self, event):
|
||||
|
@ -1074,8 +1120,7 @@ class Stack:
|
|||
x0, y0 = drag.stack.getPositionFor(c)
|
||||
x1, y1 = c.x, c.y
|
||||
dx, dy = abs(x0-x1), abs(y0-y1)
|
||||
w = self.game.app.images.CARDW
|
||||
h = self.game.app.images.CARDH
|
||||
w, h = self.game.app.images.getSize()
|
||||
if dx > 2*w or dy > 2*h:
|
||||
self.game.animatedMoveTo(drag.stack, drag.stack,
|
||||
drag.cards, x0, y0, frames=-1)
|
||||
|
@ -1185,7 +1230,7 @@ class Stack:
|
|||
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||
if self.acceptsCards(self.game.drag.stack,
|
||||
self.game.drag.cards):
|
||||
self.game.canvas.config(cursor=CURSOR_DOWN_ARROW)
|
||||
self.canvas.config(cursor=CURSOR_DOWN_ARROW)
|
||||
self.current_cursor = CURSOR_DOWN_ARROW
|
||||
self.cursor_changed = True
|
||||
else:
|
||||
|
@ -1203,13 +1248,13 @@ class Stack:
|
|||
if self.game.app.opt.mouse_type == 'drag-n-drop':
|
||||
return EVENT_HANDLED
|
||||
if self.cursor_changed:
|
||||
self.game.canvas.config(cursor='')
|
||||
self.canvas.config(cursor='')
|
||||
self.current_cursor = ''
|
||||
self.cursor_changed = False
|
||||
drag_stack = self.game.drag.stack
|
||||
if self is drag_stack:
|
||||
x, y = event.x, event.y
|
||||
w, h = self.game.canvas.winfo_width(), self.game.canvas.winfo_height()
|
||||
w, h = self.canvas.winfo_width(), self.canvas.winfo_height()
|
||||
if x < 0 or y < 0 or x >= w or y >= h:
|
||||
# cancel drag if mouse leave canvas
|
||||
drag_stack.cancelDrag(event)
|
||||
|
@ -1261,10 +1306,11 @@ class Stack:
|
|||
##sx, sy = 0, 0
|
||||
sx, sy = -images.SHADOW_XOFFSET, -images.SHADOW_YOFFSET
|
||||
dx, dy = 0, 0
|
||||
cw, ch = images.getSize()
|
||||
if game.app.opt.mouse_type == 'sticky-mouse':
|
||||
# return cards under mouse
|
||||
dx = event.x - (x_offset+images.CARDW+sx) - game.canvas.xmargin
|
||||
dy = event.y - (y_offset+images.CARDH+sy) - game.canvas.ymargin
|
||||
dx = event.x - (x_offset+cw+sx) - game.canvas.xmargin
|
||||
dy = event.y - (y_offset+ch+sy) - game.canvas.ymargin
|
||||
if dx < 0: dx = 0
|
||||
if dy < 0: dy = 0
|
||||
for s in drag.shadows:
|
||||
|
@ -1316,13 +1362,14 @@ class Stack:
|
|||
images = self.game.app.images
|
||||
cx, cy = cards[0].x, cards[0].y
|
||||
ddx, ddy = cx-cards[-1].x, cy-cards[-1].y
|
||||
if TOOLKIT == 'tk' and Image and Image.VERSION >= '1.1.7': # use PIL
|
||||
cw, ch = images.getSize()
|
||||
if USE_PIL:
|
||||
c0 = cards[-1]
|
||||
if self.CARD_XOFFSET[0] < 0: c0 = cards[0]
|
||||
if self.CARD_YOFFSET[0] < 0: c0 = cards[0]
|
||||
img = images.getShadowPIL(self, cards)
|
||||
cx, cy = c0.x + images.CARDW + dx, c0.y + images.CARDH + dy
|
||||
s = MfxCanvasImage(self.game.canvas, cx, cy,
|
||||
cx, cy = c0.x + cw + dx, c0.y + ch + dy
|
||||
s = MfxCanvasImage(self.canvas, cx, cy,
|
||||
image=img, anchor=ANCHOR_SE)
|
||||
s.lower(c0.item)
|
||||
return (s,)
|
||||
|
@ -1346,10 +1393,10 @@ class Stack:
|
|||
else:
|
||||
return ()
|
||||
if img0 and img1:
|
||||
cx, cy = c0.x + images.CARDW + dx, c0.y + images.CARDH + dy
|
||||
s1 = MfxCanvasImage(self.game.canvas, cx, cy - img0.height(),
|
||||
cx, cy = c0.x + cw + dx, c0.y + ch + dy
|
||||
s1 = MfxCanvasImage(self.canvas, cx, cy - img0.height(),
|
||||
image=img1, anchor=ANCHOR_SE)
|
||||
s2 = MfxCanvasImage(self.game.canvas, cx, cy,
|
||||
s2 = MfxCanvasImage(self.canvas, cx, cy,
|
||||
image=img0, anchor=ANCHOR_SE)
|
||||
if TOOLKIT == 'tk':
|
||||
s1.lower(c0.item)
|
||||
|
@ -1412,9 +1459,9 @@ class Stack:
|
|||
if sstack.cards:
|
||||
card = sstack.cards[-1]
|
||||
if card.face_up:
|
||||
img = images.getShadowCard(card.deck, card.suit, card.rank)
|
||||
img = images.getHighlightedCard(card.deck, card.suit, card.rank)
|
||||
else:
|
||||
img = images.getShadowBack()
|
||||
img = images.getHighlightedBack()
|
||||
else:
|
||||
img = images.getShade()
|
||||
if not img:
|
||||
|
@ -1440,11 +1487,11 @@ class Stack:
|
|||
## self.CARD_YOFFSET != (0,)):
|
||||
## return
|
||||
card = self.cards[-1]
|
||||
img = self.game.app.images.getShadowCard(card.deck, card.suit, card.rank)
|
||||
img = self.game.app.images.getHighlightedCard(card.deck, card.suit, card.rank)
|
||||
if img is None:
|
||||
return
|
||||
#self.game.canvas.update_idletasks()
|
||||
item = MfxCanvasImage(self.game.canvas, card.x, card.y,
|
||||
#self.canvas.update_idletasks()
|
||||
item = MfxCanvasImage(self.canvas, card.x, card.y,
|
||||
image=img, anchor=ANCHOR_NW, group=self.group)
|
||||
#item.tkraise()
|
||||
self.items.shade_item = item
|
||||
|
@ -1463,8 +1510,9 @@ class Stack:
|
|||
x1, y1 = self.getPositionFor(cards[-1])
|
||||
x0, x1 = min(x1, x0), max(x1, x0)
|
||||
y0, y1 = min(y1, y0), max(y1, y0)
|
||||
x1 = x1 + self.game.app.images.CARDW
|
||||
y1 = y1 + self.game.app.images.CARDH
|
||||
cw, ch = self.game.app.images.getSize()
|
||||
x1 += cw
|
||||
y1 += ch
|
||||
xx0, yy0 = x0, y0
|
||||
w, h = x1-x0, y1-y0
|
||||
#
|
||||
|
@ -1491,7 +1539,7 @@ class Stack:
|
|||
#
|
||||
shade = markImage(shade)
|
||||
tkshade = ImageTk.PhotoImage(shade)
|
||||
im = MfxCanvasImage(self.game.canvas, xx0, yy0,
|
||||
im = MfxCanvasImage(self.canvas, xx0, yy0,
|
||||
image=tkshade, anchor=ANCHOR_NW,
|
||||
group=self.group)
|
||||
drag.shadows.append(im)
|
||||
|
@ -1512,7 +1560,7 @@ class Stack:
|
|||
# finish a drag operation
|
||||
def finishDrag(self, event=None):
|
||||
if self.game.app.opt.dragcursor:
|
||||
self.game.canvas.config(cursor='')
|
||||
self.canvas.config(cursor='')
|
||||
drag = self.game.drag.copy()
|
||||
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||
drag.stack._stopDrag()
|
||||
|
@ -1528,7 +1576,7 @@ class Stack:
|
|||
# cancel a drag operation
|
||||
def cancelDrag(self, event=None):
|
||||
if self.game.app.opt.dragcursor:
|
||||
self.game.canvas.config(cursor='')
|
||||
self.canvas.config(cursor='')
|
||||
drag = self.game.drag.copy()
|
||||
if self.game.app.opt.mouse_type == 'point-n-click':
|
||||
drag.stack._stopDrag()
|
||||
|
@ -1726,6 +1774,11 @@ class TalonStack(Stack,
|
|||
Stack.__init__(self, x, y, game, cap=cap)
|
||||
self.max_rounds = max_rounds
|
||||
self.num_deal = num_deal
|
||||
self.init_redeal = Struct(
|
||||
top_bottom = None,
|
||||
img_coord = None,
|
||||
txt_coord = None,
|
||||
)
|
||||
self.resetGame()
|
||||
|
||||
def resetGame(self):
|
||||
|
@ -1787,22 +1840,34 @@ class TalonStack(Stack,
|
|||
self.texts.redeal.config(text=t)
|
||||
self.texts.redeal_str = t
|
||||
|
||||
def prepareView(self):
|
||||
Stack.prepareView(self)
|
||||
def _addRedealImage(self):
|
||||
# add or remove the redeal image/text
|
||||
if not self.is_visible or self.images.bottom is None:
|
||||
return
|
||||
if self.images.redeal is not None or self.texts.redeal is not None:
|
||||
return
|
||||
if self.game.preview > 1:
|
||||
return
|
||||
images = self.game.app.images
|
||||
cx, cy, ca = self.x + images.CARDW/2, self.y + images.CARDH/2, "center"
|
||||
if images.CARDW >= 54 and images.CARDH >= 54:
|
||||
cw, ch = images.getSize()
|
||||
cx, cy = self.init_redeal.img_coord
|
||||
ca = 'center'
|
||||
tx, ty = self.init_redeal.txt_coord
|
||||
|
||||
if self.images.redeal:
|
||||
self.canvas.delete(self.images.redeal)
|
||||
self.images.redeal = None
|
||||
self.images.redeal_img = None
|
||||
if self.texts.redeal:
|
||||
self.canvas.delete(self.texts.redeal)
|
||||
self.texts.redeal = None
|
||||
self.texts.redeal_str = ''
|
||||
self.top_bottom = self.init_redeal.top_bottom
|
||||
|
||||
if cw >= 60 and ch >= 60:
|
||||
# add a redeal image above the bottom image
|
||||
img = (self.getRedealImages())[self.max_rounds != 1]
|
||||
if img is not None:
|
||||
self.images.redeal_img = img
|
||||
self.images.redeal = MfxCanvasImage(self.game.canvas,
|
||||
self.images.redeal = MfxCanvasImage(self.canvas,
|
||||
cx, cy, image=img,
|
||||
anchor="center",
|
||||
group=self.group)
|
||||
|
@ -1812,19 +1877,21 @@ class TalonStack(Stack,
|
|||
### FIXME
|
||||
pass
|
||||
self.top_bottom = self.images.redeal
|
||||
if images.CARDH >= 90:
|
||||
cy, ca = self.y + images.CARDH - 4, "s"
|
||||
if ch >= 90:
|
||||
cy, ca = ty, "s"
|
||||
else:
|
||||
ca = None
|
||||
font = self.game.app.getFont("canvas_default")
|
||||
text_width = get_text_width(_('Redeal'), font=font,
|
||||
root=self.game.canvas)
|
||||
if images.CARDW >= text_width+4 and ca:
|
||||
# add a redeal text above the bottom image
|
||||
root=self.canvas)
|
||||
if cw >= text_width+4 and ca:
|
||||
# add a redeal text below the bottom image
|
||||
if self.max_rounds != 1:
|
||||
# FIXME: sometimes canvas do not show the text
|
||||
#print 'add txt', cx, cy
|
||||
self.texts.redeal_str = ""
|
||||
images = self.game.app.images
|
||||
self.texts.redeal = MfxCanvasText(self.game.canvas, cx, cy,
|
||||
self.texts.redeal = MfxCanvasText(self.canvas, cx, cy,
|
||||
anchor=ca, font=font,
|
||||
group=self.group)
|
||||
if TOOLKIT == 'tk':
|
||||
|
@ -1834,6 +1901,22 @@ class TalonStack(Stack,
|
|||
pass
|
||||
self.top_bottom = self.texts.redeal
|
||||
|
||||
def prepareView(self):
|
||||
Stack.prepareView(self)
|
||||
if 0:
|
||||
if not self.is_visible or self.images.bottom is None:
|
||||
return
|
||||
if self.images.redeal is not None or self.texts.redeal is not None:
|
||||
return
|
||||
if self.game.preview > 1:
|
||||
return
|
||||
images = self.game.app.images
|
||||
self.init_redeal.top_bottom = self.top_bottom
|
||||
cx, cy, ca = self.x + images.CARDW/2, self.y + images.CARDH/2, "center"
|
||||
ty = self.y + images.CARDH - 4
|
||||
self.init_redeal.img_coord = cx, cy
|
||||
self.init_redeal.txt_coord = cx, ty
|
||||
|
||||
getBottomImage = Stack._getTalonBottomImage
|
||||
|
||||
def getRedealImages(self):
|
||||
|
@ -1853,6 +1936,10 @@ class TalonStack(Stack,
|
|||
#def getBaseCard(self):
|
||||
# return self._getBaseCard()
|
||||
|
||||
def resize(self, xf, yf):
|
||||
self._addRedealImage()
|
||||
Stack.resize(self, xf, yf)
|
||||
|
||||
|
||||
# A single click deals one card to each of the RowStacks.
|
||||
class DealRowTalonStack(TalonStack):
|
||||
|
|
|
@ -107,6 +107,17 @@ class _OneImageCard(_HideableCard):
|
|||
item = self.item
|
||||
item.canvas.tk.call(item.canvas._w, "move", item.id, dx, dy)
|
||||
|
||||
# for resize
|
||||
def update(self, id, deck, suit, rank, game):
|
||||
self._face_image = game.getCardFaceImage(deck, suit, rank)
|
||||
self._back_image = game.getCardBackImage(deck, suit, rank)
|
||||
self._shade_image = game.getCardShadeImage()
|
||||
if self.face_up:
|
||||
img = self._face_image
|
||||
else:
|
||||
img = self._back_image
|
||||
self.item.config(image=img)
|
||||
self._active_image = img
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
|
|
@ -31,7 +31,7 @@ import tkFileDialog
|
|||
|
||||
# PySol imports
|
||||
from pysollib.mfxutil import Struct, kwdefault
|
||||
from pysollib.mfxutil import Image
|
||||
from pysollib.mfxutil import Image, USE_PIL
|
||||
from pysollib.util import CARDSET
|
||||
from pysollib.settings import TITLE, WIN_SYSTEM
|
||||
from pysollib.settings import SELECT_GAME_MENU
|
||||
|
@ -210,6 +210,7 @@ class PysolMenubarTk:
|
|||
mahjongg_show_removed = Tkinter.BooleanVar(),
|
||||
shisen_show_hint = Tkinter.BooleanVar(),
|
||||
sound = Tkinter.BooleanVar(),
|
||||
auto_scale = Tkinter.BooleanVar(),
|
||||
cardback = Tkinter.IntVar(),
|
||||
tabletile = Tkinter.IntVar(),
|
||||
animations = Tkinter.IntVar(),
|
||||
|
@ -260,6 +261,7 @@ class PysolMenubarTk:
|
|||
tkopt.mahjongg_show_removed.set(opt.mahjongg_show_removed)
|
||||
tkopt.shisen_show_hint.set(opt.shisen_show_hint)
|
||||
tkopt.sound.set(opt.sound)
|
||||
tkopt.auto_scale.set(opt.auto_scale)
|
||||
tkopt.cardback.set(self.app.cardset.backindex)
|
||||
tkopt.tabletile.set(self.app.tabletile_index)
|
||||
tkopt.animations.set(opt.animations)
|
||||
|
@ -448,6 +450,11 @@ class PysolMenubarTk:
|
|||
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")
|
||||
|
@ -489,7 +496,7 @@ class PysolMenubarTk:
|
|||
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)
|
||||
menu.add_checkbutton(label=n_("Save games &geometry"), variable=self.tkopt.save_games_geometry, command=self.mOptSaveGamesGeometry)
|
||||
#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()
|
||||
|
@ -538,6 +545,11 @@ class PysolMenubarTk:
|
|||
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
|
||||
|
@ -1134,6 +1146,56 @@ class PysolMenubarTk:
|
|||
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
|
||||
t = CARDSET
|
||||
|
@ -1141,14 +1203,30 @@ class PysolMenubarTk:
|
|||
d = SelectCardsetDialogWithPreview(self.top, title=_("Select ")+t,
|
||||
app=self.app, manager=self.app.cardset_manager, key=key)
|
||||
cs = self.app.cardset_manager.get(d.key)
|
||||
if cs is None or d.key == self.app.cardset.index:
|
||||
if d.status != 0 or d.button != 0 or cs is None:
|
||||
return
|
||||
if d.status == 0 and d.button == 0 and d.key >= 0:
|
||||
if USE_PIL:
|
||||
changed = (self.app.opt.scale_x,
|
||||
self.app.opt.scale_y,
|
||||
self.app.opt.auto_scale,
|
||||
self.app.opt.preserve_aspect_ratio) != d.scale_values
|
||||
else:
|
||||
changed = False
|
||||
if d.key == self.app.cardset.index and not changed:
|
||||
return
|
||||
if d.key >= 0:
|
||||
self.app.nextgame.cardset = cs
|
||||
if d.button == 0:
|
||||
self._cancelDrag()
|
||||
self.game.endGame(bookmark=1)
|
||||
self.game.quitGame(bookmark=1)
|
||||
if USE_PIL:
|
||||
(self.app.opt.scale_x,
|
||||
self.app.opt.scale_y,
|
||||
self.app.opt.auto_scale,
|
||||
self.app.opt.preserve_aspect_ratio) = d.scale_values
|
||||
if not self.app.opt.auto_scale:
|
||||
self.app.images.resize(self.app.opt.scale_x,
|
||||
self.app.opt.scale_y)
|
||||
self._cancelDrag()
|
||||
self.game.endGame(bookmark=1)
|
||||
self.game.quitGame(bookmark=1)
|
||||
|
||||
def _mOptCardback(self, index):
|
||||
if self._cancelDrag(break_pause=False): return
|
||||
|
@ -1323,7 +1401,7 @@ class PysolMenubarTk:
|
|||
self.game.showStackDesc()
|
||||
|
||||
#
|
||||
# Tlie
|
||||
# Tile (ttk)
|
||||
#
|
||||
|
||||
def mOptTheme(self, *event):
|
||||
|
|
|
@ -29,13 +29,13 @@ import Tkinter
|
|||
import ttk
|
||||
|
||||
# PySol imports
|
||||
from pysollib.mfxutil import KwStruct
|
||||
from pysollib.mfxutil import KwStruct, USE_PIL
|
||||
from pysollib.util import CARDSET
|
||||
from pysollib.resource import CSI
|
||||
|
||||
# Toolkit imports
|
||||
from tkutil import loadImage
|
||||
from tkwidget import MfxDialog, MfxScrolledCanvas
|
||||
from tkwidget import MfxDialog, MfxScrolledCanvas, PysolScale
|
||||
from tkcanvas import MfxCanvasImage
|
||||
from selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
|
||||
from selecttree import SelectDialogTreeData, SelectDialogTreeCanvas
|
||||
|
@ -179,6 +179,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
key = manager.getSelected()
|
||||
self.manager = manager
|
||||
self.key = key
|
||||
self.app = app
|
||||
#padx, pady = kw.padx, kw.pady
|
||||
padx, pady = 5, 5
|
||||
if self.TreeDataHolder_Class.data is None:
|
||||
|
@ -186,7 +187,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
#
|
||||
self.top.wm_minsize(400, 200)
|
||||
if self.top.winfo_screenwidth() >= 800:
|
||||
w1, w2 = 216, 400
|
||||
w1, w2 = 240, 400
|
||||
else:
|
||||
w1, w2 = 200, 300
|
||||
paned_window = ttk.PanedWindow(top_frame, orient='horizontal')
|
||||
|
@ -199,7 +200,56 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
self.tree = self.Tree_Class(self, left_frame, key=key,
|
||||
default=kw.default,
|
||||
font=font, width=w1)
|
||||
self.tree.frame.pack(fill='both', expand=True, padx=padx, pady=pady)
|
||||
self.tree.frame.grid(row=0, column=0, sticky='nsew',
|
||||
padx=padx, pady=pady)
|
||||
if USE_PIL:
|
||||
#
|
||||
var = Tkinter.DoubleVar()
|
||||
var.set(app.opt.scale_x)
|
||||
self.scale_x = PysolScale(
|
||||
left_frame, label=_('Scale X:'),
|
||||
from_=0.5, to=4.0, resolution=0.1,
|
||||
orient='horizontal', variable=var,
|
||||
value=app.opt.scale_x,
|
||||
command=self._updateScale)
|
||||
self.scale_x.grid(row=1, column=0, sticky='ew', padx=padx, pady=pady)
|
||||
#
|
||||
var = Tkinter.DoubleVar()
|
||||
var.set(app.opt.scale_y)
|
||||
self.scale_y = PysolScale(
|
||||
left_frame, label=_('Scale Y:'),
|
||||
from_=0.5, to=4.0, resolution=0.1,
|
||||
orient='horizontal', variable=var,
|
||||
value=app.opt.scale_y,
|
||||
command=self._updateScale)
|
||||
self.scale_y.grid(row=2, column=0, sticky='ew', padx=padx, pady=pady)
|
||||
#
|
||||
self.auto_scale = Tkinter.BooleanVar()
|
||||
self.auto_scale.set(app.opt.auto_scale)
|
||||
check = ttk.Checkbutton(
|
||||
left_frame, text=_('Auto scaling'),
|
||||
variable=self.auto_scale,
|
||||
takefocus=False,
|
||||
command=self._updateAutoScale
|
||||
)
|
||||
check.grid(row=3, column=0, columnspan=2, sticky='ew',
|
||||
padx=padx, pady=pady)
|
||||
#
|
||||
self.preserve_aspect = Tkinter.BooleanVar()
|
||||
self.preserve_aspect.set(app.opt.preserve_aspect_ratio)
|
||||
self.aspect_check = ttk.Checkbutton(
|
||||
left_frame, text=_('Preserve aspect ratio'),
|
||||
variable=self.preserve_aspect,
|
||||
takefocus=False,
|
||||
#command=self._updateScale
|
||||
)
|
||||
self.aspect_check.grid(row=4, column=0, sticky='ew',
|
||||
padx=padx, pady=pady)
|
||||
self._updateAutoScale()
|
||||
#
|
||||
left_frame.rowconfigure(0, weight=1)
|
||||
left_frame.columnconfigure(0, weight=1)
|
||||
#
|
||||
self.preview = MfxScrolledCanvas(right_frame, width=w2)
|
||||
self.preview.setTile(app, app.tabletile_index, force=True)
|
||||
self.preview.pack(fill='both', expand=True, padx=padx, pady=pady)
|
||||
|
@ -207,6 +257,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
# create a preview of the current state
|
||||
self.preview_key = -1
|
||||
self.preview_images = []
|
||||
self.scale_images = []
|
||||
self.updatePreview(key)
|
||||
#
|
||||
focus = self.createButtons(bottom_frame, kw)
|
||||
|
@ -233,6 +284,20 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
if button in (0, 1): # Load/Cancel
|
||||
self.key = self.tree.selection_key
|
||||
self.tree.n_expansions = 1 # save xyview in any case
|
||||
if USE_PIL:
|
||||
auto_scale = bool(self.auto_scale.get())
|
||||
if button == 1:
|
||||
self.app.menubar.tkopt.auto_scale.set(auto_scale)
|
||||
if auto_scale:
|
||||
self.scale_values = (self.app.opt.scale_x,
|
||||
self.app.opt.scale_y,
|
||||
auto_scale,
|
||||
bool(self.preserve_aspect.get()))
|
||||
else:
|
||||
self.scale_values = (self.scale_x.get(),
|
||||
self.scale_y.get(),
|
||||
auto_scale,
|
||||
self.app.opt.preserve_aspect_ratio)
|
||||
if button == 10: # Info
|
||||
cs = self.manager.get(self.tree.selection_key)
|
||||
if not cs:
|
||||
|
@ -243,9 +308,24 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
return
|
||||
MfxDialog.mDone(self, button)
|
||||
|
||||
def updatePreview(self, key):
|
||||
def _updateAutoScale(self, v=None):
|
||||
if self.auto_scale.get():
|
||||
self.aspect_check.config(state='normal')
|
||||
self.scale_x.state('disabled')
|
||||
self.scale_y.state('disabled')
|
||||
else:
|
||||
self.aspect_check.config(state='disabled')
|
||||
self.scale_x.state('!disabled')
|
||||
self.scale_y.state('!disabled')
|
||||
|
||||
def _updateScale(self, v):
|
||||
self.updatePreview()
|
||||
|
||||
def updatePreview(self, key=None):
|
||||
if key == self.preview_key:
|
||||
return
|
||||
if key is None:
|
||||
key = self.key
|
||||
canvas = self.preview.canvas
|
||||
canvas.deleteAllItems()
|
||||
self.preview_images = []
|
||||
|
@ -264,7 +344,16 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
self.preview_images = []
|
||||
return
|
||||
i, x, y, sx, sy, dx, dy = 0, 10, 10, 0, 0, cs.CARDW + 10, cs.CARDH + 10
|
||||
if USE_PIL:
|
||||
xf = self.scale_x.get()
|
||||
yf = self.scale_y.get()
|
||||
dx = int(dx*xf)
|
||||
dy = int(dy*yf)
|
||||
self.scale_images = []
|
||||
for image in self.preview_images:
|
||||
if USE_PIL:
|
||||
image = image.resize(xf, yf)
|
||||
self.scale_images.append(image)
|
||||
MfxCanvasImage(canvas, x, y, anchor="nw", image=image)
|
||||
sx, sy = max(x, sx), max(y, sy)
|
||||
i = i + 1
|
||||
|
@ -272,13 +361,12 @@ class SelectCardsetDialogWithPreview(MfxDialog):
|
|||
x, y = 10, y + dy
|
||||
else:
|
||||
x = x + dx
|
||||
## canvas.config(scrollregion=(0, 0, sx+dx, sy+dy))
|
||||
## canvas.config(width=sx+dx, height=sy+dy)
|
||||
canvas.config(scrollregion=(0, 0, sx+dx, sy+dy),
|
||||
width=sx+dx, height=sy+dy)
|
||||
#canvas.config(xscrollincrement=dx, yscrollincrement=dy)
|
||||
canvas.event_generate('<Configure>') # update bg image
|
||||
self.preview_key = key
|
||||
self.key = key
|
||||
|
||||
|
||||
class SelectCardsetByTypeDialogWithPreview(SelectCardsetDialogWithPreview):
|
||||
|
|
|
@ -58,14 +58,15 @@ class MfxCanvasGroup(Canvas.Group):
|
|||
return self.canvas.tk.splitlist(self._do("gettags"))
|
||||
|
||||
class MfxCanvasImage(Canvas.ImageItem):
|
||||
def __init__(self, canvas, *args, **kwargs):
|
||||
def __init__(self, canvas, x, y, **kwargs):
|
||||
self.init_coord = x, y
|
||||
group = None
|
||||
if 'group' in kwargs:
|
||||
group = kwargs['group']
|
||||
del kwargs['group']
|
||||
if 'image' in kwargs:
|
||||
self._image = kwargs['image']
|
||||
Canvas.ImageItem.__init__(self, canvas, *args, **kwargs)
|
||||
Canvas.ImageItem.__init__(self, canvas, x, y, **kwargs)
|
||||
if group:
|
||||
self.addtag(group)
|
||||
def moveTo(self, x, y):
|
||||
|
@ -90,6 +91,8 @@ class MfxCanvasRectangle(Canvas.Rectangle):
|
|||
|
||||
class MfxCanvasText(Canvas.CanvasText):
|
||||
def __init__(self, canvas, x, y, preview=-1, **kwargs):
|
||||
self.init_coord = x, y
|
||||
self.x, self.y = x, y
|
||||
if preview < 0:
|
||||
preview = canvas.preview
|
||||
if preview > 1:
|
||||
|
@ -105,6 +108,10 @@ class MfxCanvasText(Canvas.CanvasText):
|
|||
canvas._text_items.append(self)
|
||||
if group:
|
||||
self.addtag(group)
|
||||
def moveTo(self, x, y):
|
||||
dx, dy = x - self.x, y - self.y
|
||||
self.x, self.y = x, y
|
||||
self.move(dx, dy)
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
|
@ -229,17 +236,24 @@ class MfxCanvas(Tkinter.Canvas):
|
|||
#
|
||||
#
|
||||
|
||||
def setInitialSize(self, width, height):
|
||||
##print 'setInitialSize:', width, height
|
||||
def setInitialSize(self, width, height, margins=True, scrollregion=True):
|
||||
#print 'Canvas.setInitialSize:', width, height, scrollregion
|
||||
if self.preview:
|
||||
self.config(width=width, height=height,
|
||||
scrollregion=(0, 0, width, height))
|
||||
else:
|
||||
# add margins
|
||||
##dx, dy = 40, 40
|
||||
dx, dy = self.xmargin, self.ymargin
|
||||
self.config(width=dx+width+dx, height=dy+height+dy,
|
||||
scrollregion=(-dx, -dy, width+dx, height+dy))
|
||||
if margins:
|
||||
w, h = dx+width+dx, dy+height+dy
|
||||
else:
|
||||
w, h = width, height
|
||||
self.config(width=w, height=h)
|
||||
if scrollregion:
|
||||
self.config(scrollregion=(-dx, -dy, width+dx, height+dy))
|
||||
else:
|
||||
# no scrolls
|
||||
self.config(scrollregion=(-dx, -dy, dx, dy))
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -41,6 +41,7 @@ __all__ = ['wm_withdraw',
|
|||
'shadowImage',
|
||||
'markImage',
|
||||
'createBottom',
|
||||
'resizeBottom',
|
||||
'get_text_width',
|
||||
]
|
||||
|
||||
|
@ -248,11 +249,15 @@ def after_cancel(t):
|
|||
|
||||
if Image:
|
||||
class PIL_Image(ImageTk.PhotoImage):
|
||||
def __init__(self, file=None, image=None):
|
||||
def __init__(self, file=None, image=None, pil_image_orig=None):
|
||||
if file:
|
||||
image = Image.open(file).convert('RGBA')
|
||||
ImageTk.PhotoImage.__init__(self, image)
|
||||
self._pil_image = image
|
||||
if pil_image_orig:
|
||||
self._pil_image_orig = pil_image_orig
|
||||
else:
|
||||
self._pil_image_orig = image
|
||||
def subsample(self, r):
|
||||
im = self._pil_image
|
||||
w, h = im.size
|
||||
|
@ -260,6 +265,11 @@ if Image:
|
|||
im = im.resize((w, h))
|
||||
im = PIL_Image(image=im)
|
||||
return im
|
||||
def resize(self, xf, yf):
|
||||
w, h = self._pil_image_orig.size
|
||||
w0, h0 = int(w*xf), int(h*yf)
|
||||
im = self._pil_image_orig.resize((w0,h0), Image.ANTIALIAS)
|
||||
return PIL_Image(image=im, pil_image_orig=self._pil_image_orig)
|
||||
|
||||
|
||||
def makeImage(file=None, data=None, dither=None, alpha=None):
|
||||
|
@ -360,14 +370,11 @@ def markImage(image):
|
|||
out = Image.composite(tmp, image, image)
|
||||
return out
|
||||
|
||||
def createBottom(image, color='white', backfile=None):
|
||||
if not hasattr(image, '_pil_image'):
|
||||
return None
|
||||
im = image._pil_image
|
||||
def _createBottomImage(image, color='white', backfile=None):
|
||||
th = 1 # thickness
|
||||
sh = Image.new('RGBA', im.size, color)
|
||||
out = Image.composite(sh, im, im)
|
||||
w, h = im.size
|
||||
sh = Image.new('RGBA', image.size, color)
|
||||
out = Image.composite(sh, image, image)
|
||||
w, h = image.size
|
||||
size = (w-th*2, h-th*2)
|
||||
tmp = Image.new('RGBA', size, color)
|
||||
tmp.putalpha(60)
|
||||
|
@ -376,15 +383,27 @@ def createBottom(image, color='white', backfile=None):
|
|||
if backfile:
|
||||
back = Image.open(backfile).convert('RGBA')
|
||||
w0, h0 = back.size
|
||||
w1, h1 = im.size
|
||||
w1, h1 = w, h
|
||||
a = min(float(w1)/w0, float(h1)/h0)
|
||||
a = a*0.9
|
||||
w0, h0 = int(w0*a), int(h0*a)
|
||||
back = back.resize((w0,h0), Image.ANTIALIAS)
|
||||
x, y = (w1 - w0) / 2, (h1 - h0) / 2
|
||||
out.paste(back, (x,y), back)
|
||||
return out
|
||||
|
||||
def createBottom(maskimage, color='white', backfile=None):
|
||||
if not hasattr(maskimage, '_pil_image'):
|
||||
return None
|
||||
maskimage = maskimage._pil_image
|
||||
out = _createBottomImage(maskimage, color, backfile)
|
||||
return PIL_Image(image=out)
|
||||
|
||||
def resizeBottom(image, maskimage, color='white', backfile=None):
|
||||
maskimage = maskimage._pil_image
|
||||
out = _createBottomImage(maskimage, color, backfile)
|
||||
image['image'] = out
|
||||
|
||||
|
||||
# ************************************************************************
|
||||
# * font utils
|
||||
|
|
|
@ -667,7 +667,7 @@ class StackDesc:
|
|||
|
||||
font = game.app.getFont('canvas_small')
|
||||
##print self.app.cardset.CARDW, self.app.images.CARDW
|
||||
cardw = game.app.images.CARDW
|
||||
cardw = game.app.images.getSize()[0]
|
||||
x, y = stack.x+cardw/2, stack.y
|
||||
text = stack.getHelp()+'\n'+stack.getBaseCard()
|
||||
text = text.strip()
|
||||
|
@ -715,30 +715,26 @@ class MyPysolScale:
|
|||
kw['from_'] = kw['from_']/self.resolution
|
||||
if 'to' in kw:
|
||||
kw['to'] = kw['to']/self.resolution
|
||||
if 'command' in kw:
|
||||
self.command = kw['command']
|
||||
else:
|
||||
self.command = None
|
||||
if 'variable' in kw:
|
||||
self.variable = kw['variable']
|
||||
del kw['variable']
|
||||
else:
|
||||
self.variable = None
|
||||
value = None
|
||||
if 'value' in kw:
|
||||
value = kw['value']
|
||||
del kw['value']
|
||||
if self.variable:
|
||||
self.variable.set(value)
|
||||
else:
|
||||
value = None
|
||||
if self.variable:
|
||||
value = self.variable.get()
|
||||
if self.variable:
|
||||
self.variable.trace('w', self._trace_var)
|
||||
elif self.variable:
|
||||
value = self.variable.get()
|
||||
self.value = value
|
||||
self.command = command = None
|
||||
if 'command' in kw:
|
||||
command = kw['command']
|
||||
kw['command'] = self._scale_command
|
||||
if 'label' in kw:
|
||||
self.label_text = kw['label']
|
||||
width = len(self.label_text)+4
|
||||
#width = None
|
||||
del kw['label']
|
||||
else:
|
||||
self.label_text = None
|
||||
|
@ -753,13 +749,16 @@ class MyPysolScale:
|
|||
self.scale = ttk.Scale(self.frame, **kw)
|
||||
self.scale.pack(side=side, expand=True, fill='both', pady=4)
|
||||
|
||||
if self.variable:
|
||||
self.variable.trace('w', self._trace_var)
|
||||
if value is not None:
|
||||
if self.variable:
|
||||
self.variable.set(self._round(value))
|
||||
self._set_text(self._round(value))
|
||||
if self.variable:
|
||||
self.variable.set(value)
|
||||
self.command = command
|
||||
|
||||
def _round(self, value):
|
||||
return int(float(value)/self.resolution)*self.resolution
|
||||
return int(round(float(value)/self.resolution))*self.resolution
|
||||
|
||||
def _trace_var(self, *args):
|
||||
self.scale.set(float(self.variable.get())/self.resolution)
|
||||
|
@ -775,8 +774,9 @@ class MyPysolScale:
|
|||
v = self._round(float(value)*self.resolution)
|
||||
self._set_text(v)
|
||||
self.variable.set(v)
|
||||
if self.command:
|
||||
if value != self.value and self.command:
|
||||
self.command(value)
|
||||
self.value = value
|
||||
|
||||
def pack(self, **kw):
|
||||
self.frame.pack(**kw)
|
||||
|
@ -787,6 +787,15 @@ class MyPysolScale:
|
|||
self.scale.configure(**kw)
|
||||
config = configure
|
||||
|
||||
def state(self, v):
|
||||
self.scale.state(statespec=(v,))
|
||||
self.label.state(statespec=(v,))
|
||||
|
||||
def get(self):
|
||||
return self.variable.get()
|
||||
def set(self, v):
|
||||
self.variable.set(v)
|
||||
|
||||
|
||||
class TkinterScale(Tkinter.Scale):
|
||||
def __init__(self, parent, **kw):
|
||||
|
|
Loading…
Add table
Reference in a new issue