1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/tk/tkcanvas.py
skomoroh 5175caf86a + separated demo-mode and solver; solver dialog
+ added statistics progression; statistics progression dialog
+ new animation speed: `medium'; renamed `timer based' to `fast'
+ added flip animation (animatedFlip)
+ added move to waste animation (animatedFlipAndMove)
+ added cancel-drag animation (moveCardsBackHandler)
* improved demo game (snapshots based check for loop)
- removed setting text color from file name
- removed auto generation shadows (too slow)
* optimized menu creation
* changed some keybindings
* updated russian translation
* many bugfixes


git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@138 efabe8c0-fbe8-4139-b769-b5e6d273206e
2007-02-16 23:20:02 +00:00

383 lines
13 KiB
Python

## vim:ts=4:et:nowrap
##
##---------------------------------------------------------------------------##
##
## PySol -- a Python Solitaire game
##
## Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
## All Rights Reserved.
##
## 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.
##
## Markus F.X.J. Oberhumer
## <markus@oberhumer.com>
## http://www.oberhumer.com/pysol
##
##---------------------------------------------------------------------------##
__all__ = ['MfxCanvasGroup',
'MfxCanvasImage',
'MfxCanvasText',
'MfxCanvasLine',
'MfxCanvasRectangle',
'MfxCanvas']
# imports
import os, sys, types
import Tkinter, Canvas
# PySol imports
from pysollib.mfxutil import Image, ImageTk
# Toolkit imports
from tkutil import bind, unbind_destroy, loadImage
# /***********************************************************************
# // canvas items
# ************************************************************************/
class MfxCanvasGroup(Canvas.Group):
def __init__(self, canvas, tag=None):
Canvas.Group.__init__(self, canvas=canvas, tag=tag)
# register ourself so that we can unbind from the canvas
assert self.id not in self.canvas.items
self.canvas.items[self.id] = self
def addtag(self, tag, option="withtag"):
self.canvas.addtag(tag, option, self.id)
def delete(self):
del self.canvas.items[self.id]
Canvas.Group.delete(self)
def gettags(self):
return self.canvas.tk.splitlist(self._do("gettags"))
class MfxCanvasImage(Canvas.ImageItem):
def __init__(self, canvas, *args, **kwargs):
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)
if group:
self.addtag(group)
def moveTo(self, x, y):
c = self.coords()
self.move(x - int(c[0]), y - int(c[1]))
def show(self):
self.config(state='normal')
def hide(self):
self.config(state='hidden')
MfxCanvasLine = Canvas.Line
class MfxCanvasRectangle(Canvas.Rectangle):
def __init__(self, canvas, *args, **kwargs):
group = None
if 'group' in kwargs:
group = kwargs['group']
del kwargs['group']
Canvas.Rectangle.__init__(self, canvas, *args, **kwargs)
if group:
self.addtag(group)
class MfxCanvasText(Canvas.CanvasText):
def __init__(self, canvas, x, y, preview=-1, **kwargs):
if preview < 0:
preview = canvas.preview
if preview > 1:
return
if "fill" not in kwargs:
kwargs["fill"] = canvas._text_color
group = None
if 'group' in kwargs:
group = kwargs['group']
del kwargs['group']
Canvas.CanvasText.__init__(self, canvas, x, y, **kwargs)
self.text_format = None
canvas._text_items.append(self)
if group:
self.addtag(group)
# /***********************************************************************
# // canvas
# ************************************************************************/
class MfxCanvas(Tkinter.Canvas):
def __init__(self, *args, **kw):
Tkinter.Canvas.__init__(self, *args, **kw)
self.preview = 0
# this is also used by lib-tk/Canvas.py
self.items = {}
# private
self.__tileimage = None
self.__tiles = [] # id of canvas items
self.__topimage = None
self.__tops = [] # id of canvas items
# friend MfxCanvasText
self._text_color = "#000000"
self._stretch_bg_image = 0
self._text_items = []
#
self.xmargin, self.ymargin = 10, 10
# resize bg image
self.bind('<Configure>', lambda e: self.set_bg_image())
def set_bg_image(self):
##print 'set_bg_image', self._bg_img
if not hasattr(self, '_bg_img'):
return
if not self._bg_img: # solid color
return
stretch = self._stretch_bg_image
if Image:
if stretch:
w = max(self.winfo_width(), int(self.cget('width')))
h = max(self.winfo_height(), int(self.cget('height')))
im = self._bg_img.resize((w, h))
image = ImageTk.PhotoImage(im)
else:
image = ImageTk.PhotoImage(self._bg_img)
else: # not Image
stretch = 0
image = self._bg_img
for id in self.__tiles:
self.delete(id)
self.__tiles = []
# must keep a reference to the image, otherwise Python will
# garbage collect it...
self.__tileimage = image
if stretch:
#
if self.preview:
dx, dy = 0, 0
else:
dx, dy = -self.xmargin, -self.ymargin
id = self._x_create("image", dx, dy, image=image, anchor="nw")
self.tag_lower(id) # also see tag_lower above
self.__tiles.append(id)
else:
iw, ih = image.width(), image.height()
#sw = max(self.winfo_screenwidth(), 1024)
#sh = max(self.winfo_screenheight(), 768)
sw = max(self.winfo_width(), int(self.cget('width')))
sh = max(self.winfo_height(), int(self.cget('height')))
for x in range(-self.xmargin, sw, iw):
for y in range(-self.ymargin, sh, ih):
id = self._x_create("image", x, y, image=image, anchor="nw")
self.tag_lower(id) # also see tag_lower above
self.__tiles.append(id)
return 1
#
# top-image support
#
def _x_create(self, itemType, *args, **kw):
return Tkinter.Canvas._create(self, itemType, args, kw)
def _create(self, itemType, args, kw):
##print "_create:", itemType, args, kw
id = Tkinter.Canvas._create(self, itemType, args, kw)
if self.__tops:
self.tk.call(self._w, "lower", id, self.__tops[0])
return id
def tag_raise(self, id, aboveThis=None):
##print "tag_raise:", id, aboveThis
if aboveThis is None and self.__tops:
self.tk.call(self._w, "lower", id, self.__tops[0])
else:
self.tk.call(self._w, "raise", id, aboveThis)
def tag_lower(self, id, belowThis=None):
##print "tag_lower:", id, belowThis
if belowThis is None and self.__tiles:
self.tk.call(self._w, "raise", id, self.__tiles[-1])
else:
self.tk.call(self._w, "lower", id, belowThis)
#
#
#
def setInitialSize(self, width, height):
##print 'setInitialSize:', width, height
if self.preview:
self.config(width=width, height=height)
self.config(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)
self.config(scrollregion=(-dx, -dy, width+dx, height+dy))
#
#
#
# delete all CanvasItems, but keep the background and top tiles
def deleteAllItems(self):
self._text_items = []
for id in self.items.keys():
assert id not in self.__tiles # because the tile is created by id
unbind_destroy(self.items[id])
self.items[id].delete()
assert self.items == {}
def findCard(self, stack, event):
if isinstance(stack.cards[0].item, Canvas.Group):
current = self.gettags("current") # get tags
for i in range(len(stack.cards)):
if stack.cards[i].item.tag in current:
return i
else:
## current = self.find("withtag", "current") # get item ids
## for i in range(len(stack.cards)):
## if stack.cards[i].item.id in current:
## return i
if self.preview:
dx, dy = 0, 0
else:
dx, dy = -self.xmargin, -self.ymargin
x = event.x+dx+self.xview()[0]*int(self.cget('width'))
y = event.y+dy+self.yview()[0]*int(self.cget('height'))
##x, y = event.x, event.y
items = list(self.find_overlapping(x,y,x,y))
items.reverse()
for item in items:
for i in range(len(stack.cards)):
if stack.cards[i].item.id == item:
return i
return -1
def setTextColor(self, color):
if color is None:
c = self.cget("bg")
if not isinstance(c, str) or c[0] != "#" or len(c) != 7:
return
v = []
for i in (1, 3, 5):
v.append(int(c[i:i+2], 16))
luminance = (0.212671 * v[0] + 0.715160 * v[1] + 0.072169 * v[2]) / 255
##print c, ":", v, "luminance", luminance
color = ("#000000", "#ffffff") [luminance < 0.3]
if self._text_color != color:
self._text_color = color
for item in self._text_items:
item.config(fill=self._text_color)
def setTile(self, image, stretch=0):
##print 'setTile:', image, stretch
if image:
if Image:
try:
self._bg_img = Image.open(image)
except:
return 0
else:
try:
self._bg_img = loadImage(file=image, dither=1)
except:
return 0
self._stretch_bg_image = stretch
self.set_bg_image()
else:
for id in self.__tiles:
self.delete(id)
self.__tiles = []
self._bg_img = None
return 1
def setTopImage(self, image, cw=0, ch=0):
try:
if image and isinstance(image, str):
image = loadImage(file=image)
except Tkinter.TclError:
return 0
if len(self.__tops) == 1 and image is self.__tops[0]:
return 1
for id in self.__tops:
self.delete(id)
self.__tops = []
# must keep a reference to the image, otherwise Python will
# garbage collect it...
self.__topimage = image
if image is None:
return 1
iw, ih = image.width(), image.height()
if cw <= 0:
##cw = max(int(self.cget("width")), self.winfo_width())
cw = self.winfo_width()
if ch <= 0:
##ch = max(int(self.cget("height")), self.winfo_height())
ch = self.winfo_height()
###print iw, ih, cw, ch
x = (cw-iw)/2-self.xmargin+self.xview()[0]*int(self.cget('width'))
y = (ch-ih)/2-self.ymargin+self.yview()[0]*int(self.cget('height'))
id = self._x_create("image", x, y, image=image, anchor="nw")
self.tk.call(self._w, "raise", id)
self.__tops.append(id)
return 1
#
# Pause support
#
def hideAllItems(self):
for item in self.items.values():
item.config(state='hidden')
def showAllItems(self):
for item in self.items.values():
item.config(state='normal')
#
# restricted but fast _bind and _substitute
#
def _bind(self, what, sequence, func, add, needcleanup=1):
funcid = self._register(func, self._substitute, needcleanup)
cmd = ('%sif {"[%s %s]" == "break"} break\n' %
(add and '+' or '', funcid, "%x %y"))
self.tk.call(what + (sequence, cmd))
return funcid
def _substitute(self, *args):
e = Tkinter.Event()
try:
# Tk changed behavior in 8.4.2, returning "??" rather more often.
e.x = int(args[0])
except ValueError:
e.x = args[0]
try:
e.y = int(args[1])
except ValueError:
e.y = args[1]
return (e,)