## 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 ## ## http://www.oberhumer.com/pysol ## ##---------------------------------------------------------------------------## # imports import os, sys, string, types, Tkinter # PySol imports if __name__ == "__main__": #bundle# import pysoltk #bundle# from mfxtools import ustr from mfxutil import destruct from util import IMAGE_EXTENSIONS from actions import PysolToolbarActions # Toolkit imports from tkconst import tkversion, TK_DASH_PATCH from tkconst import EVENT_HANDLED, EVENT_PROPAGATE from tkwidget import MfxTooltip # /*********************************************************************** # // A canvas that supports hiding. # // # // Note: Applications should call show/hide after constructor. # ************************************************************************/ class _MfxToolbar: def __init__(self, top, relief=1): relief = 1 self.top = top self.button_bg = None self.__setRelief(relief) self.side = -1 self._tooltips = [] self._widgets = [] self._icon_height = 0 # We must create a Canvas and a Frame with these parameters # in order to be able to hide the toolbar. self.canvas = Tkinter.Canvas(self.top, bd=0, highlightthickness=0) self.frame = Tkinter.Frame(self.canvas, bd=0, highlightthickness=1) self._initFrame() self.canvas.pack(side=Tkinter.TOP, fill=Tkinter.X) def __setRelief(self, relief): if type(relief) is types.IntType: relief = (Tkinter.RAISED, Tkinter.FLAT)[relief] elif relief in (Tkinter.RAISED, Tkinter.FLAT): pass else: relief = Tkinter.FLAT self.button_relief = relief if relief == Tkinter.RAISED: self.separator_relief = Tkinter.FLAT else: self.separator_relief = Tkinter.RAISED return relief # subclass overrideable def _initFrame(self): self.frame.pack(side=Tkinter.TOP, fill=Tkinter.X) # util def _createSeparator(self, width=12, side=Tkinter.LEFT, relief=None): if relief is None: relief = self.separator_relief if relief == Tkinter.FLAT or width <= 6: sep = Tkinter.Frame(self.frame, highlightthickness=0, width=width, height=0, takefocus=0, relief=relief) padx = 0 else: height = max((self._icon_height or 38) - 4, 20) sep = Tkinter.Frame(self.frame, bd=1, highlightthickness=1, width=4, height=height, takefocus=0, relief=relief) padx = (width - 4) / 2 sep.pack(side=side, padx=padx) self._widgets.append(sep) # # public methods # def show(self, side=1, resize=1): if self.side == side: return 0 if resize: self.top.wm_geometry("") # cancel user-specified geometry if not side: # hide if 0 and TK_DASH_PATCH: ### hmm, this doesn't work self.canvas.config(state="hidden") else: self.canvas.pack_propagate(0) self.canvas.config(height=0) else: # show if 0 and TK_DASH_PATCH: self.canvas.config(state="normal") else: self.canvas.pack_propagate(1) s = (None, Tkinter.TOP, Tkinter.BOTTOM)[side] self.canvas.pack(side=s, fill=Tkinter.X) self.side = side return 1 def hide(self, resize=1): self.show(0, resize) def getSide(self): return self.side def destroy(self): for w in self._tooltips: if w: w.destroy() self._tooltips = [] for w in self._widgets: if w: w.destroy() self._widgets = [] def setCursor(self, cursor): if self.side: self.frame.config(cursor=cursor) self.frame.update_idletasks() # /*********************************************************************** # // # ************************************************************************/ class PysolToolbar(_MfxToolbar, PysolToolbarActions): def __init__(self, top, dir, size, relief=1): _MfxToolbar.__init__(self, top, relief) PysolToolbarActions.__init__(self) self.dir = dir self.size = size self._createButton("new", self.mNewGame, tooltip="New game") self._createButton("restart", self.mRestart, tooltip="Restart the \ncurrent game") self._createSeparator() self._createButton("open", self.mOpen , tooltip="Open a \nsaved game") self._createButton("save", self.mSave, tooltip="Save game") self._createSeparator() self._createButton("undo", self.mUndo, tooltip="Undo last move") self._createButton("redo", self.mRedo, tooltip="Redo last move") self._createButton("autodrop", self.mDrop, tooltip="Auto drop cards") self._createSeparator() self._createButton("stats", self.mPlayerStats, tooltip="View statistics") self._createButton("rules", self.mHelpRules, tooltip="Rules for this game") self._createSeparator() self._createButton("quit", self.mQuit, tooltip="Quit PySol") self._createSeparator(width=20, relief=Tkinter.FLAT) ##self._createLabel("moves", padx=8, tooltip="Number of moves\nin this game") self._createLabel("player", padx=8, tooltip="Player options") self.player_label.bind("<1>",self.mOptPlayerOptions) ##self.player_label.bind("<3>",self.mOptPlayerOptions) self.popup = None self.frame.bind("<1>", self.clickHandler) self.frame.bind("<3>", self.rightclickHandler) # Change the look of the frame to match the platform look def _initFrame(self): if 0 or os.name == "nt": self.frame.config(bd=1, relief=Tkinter.SOLID) self.frame.pack(side=Tkinter.TOP, fill=Tkinter.X, ipady=4) self._createSeparator(width=4, side=Tkinter.LEFT, relief=Tkinter.FLAT) self._createSeparator(width=4, side=Tkinter.RIGHT, relief=Tkinter.FLAT) else: self.frame.pack(side=Tkinter.TOP, fill=Tkinter.X, ipady=1) def _loadImage(self, name): file = os.path.join(self.dir, name) image = None for ext in IMAGE_EXTENSIONS: file = os.path.join(self.dir, name+ext) if os.path.isfile(file): image = Tkinter.PhotoImage(file=file) break return image def _createButton(self, name, command, padx=0, tooltip=None): image = self._loadImage(name) button = Tkinter.Button(self.frame, command=command, takefocus=0, relief=self.button_relief) button.toolbar_name = name if image: button.config(image=image) if self._icon_height == 0: self._icon_height = image.height() if self.button_relief == Tkinter.FLAT: if self.button_bg is None: self.button_bg = self._getButtonBg(button["activebackground"]) ##print self.button_bg button["activebackground"] = self.button_bg button.pack(side=Tkinter.LEFT, padx=padx) setattr(self, name + "_image", image) setattr(self, name + "_button", button) self._widgets.append(button) if tooltip: b = MfxTooltip(button) self._tooltips.append(b) b.setText(tooltip) def _getButtonBg(self, col): if type(col) is not types.StringType or col[0] != "#" or len(col) != 7: return "#f0f0f0" c = "#" for i in (1, 3, 5): v = string.atoi(col[i:i+2], 16) v = int(v + 24) if (v > 255): v = 255 c = c + ("%02x" % v) return c def _createLabel(self, name, padx=0, side=Tkinter.RIGHT, tooltip=None): aspect = (400, 300) [self.size != 0] label = Tkinter.Message(self.frame, relief="ridge", justify="center", aspect=aspect) label.pack(side=side, padx=padx) setattr(self, name + "_label", label) self._widgets.append(label) if tooltip: b = MfxTooltip(label) self._tooltips.append(b) b.setText(tooltip) def _busy(self): if not self.side or not self.game or not self.menubar: return 1 if self.game.demo: self.game.stopDemo() return self.game.busy # # public methods # def connectGame(self, game, menubar): PysolToolbarActions.connectGame(self, game, menubar) if self.popup: self.popup.destroy() destruct(self.popup) self.popup = None if menubar: tkopt = menubar.tkopt self.popup = Tkinter.Menu(self.canvas, tearoff=0) self.popup.add_command(label="Toolbar", state=Tkinter.DISABLED) self.popup.add_radiobutton(label="Hide", variable=tkopt.toolbar, value=0, command=menubar.mOptToolbar, underline=0) self.popup.add_radiobutton(label="Top", variable=tkopt.toolbar, value=1, command=menubar.mOptToolbar, underline=0) self.popup.add_radiobutton(label="Bottom", variable=tkopt.toolbar, value=2, command=menubar.mOptToolbar, underline=0) if 1: self.popup.add_separator() self.popup.add_radiobutton(label="Small icons", variable=tkopt.toolbar_size, value=0, command=menubar.mOptToolbarSize, underline=0) self.popup.add_radiobutton(label="Large icons", variable=tkopt.toolbar_size, value=1, command=menubar.mOptToolbarSize, underline=0) if 0: self.popup.add_separator() self.popup.add_radiobutton(label="Raised", variable=tkopt.toolbar_relief, value=0, command=menubar.mOptToolbarRelief, underline=0) self.popup.add_radiobutton(label="Flat", variable=tkopt.toolbar_relief, value=1, command=menubar.mOptToolbarRelief, underline=0) def setRelief(self, relief): pass # FIXME def updateText(self, **kw): for name in kw.keys(): label = getattr(self, name + "_label") label["text"] = ustr(kw[name]) def updateImages(self, dir, size): if dir == self.dir and size == self.size: return 0 if not os.path.isdir(dir): return 0 old_dir, old_size = self.dir, self.size self.dir, self.size = dir, size data = [] try: l = self.player_label for w in self._widgets: if not isinstance(w, Tkinter.Button): continue name = w.toolbar_name image = self._loadImage(name) data.append((name, w, image)) except: self.dir, self.size = old_dir, old_size return 0 aspect = (400, 300) [size != 0] l.config(aspect=aspect) for name, w, image in data: w.config(image=image) setattr(self, name + "_image", image) return 1 # # Mouse event handlers # def clickHandler(self, event): if self._busy(): return EVENT_HANDLED return EVENT_HANDLED def rightclickHandler(self, event): if self._busy(): return EVENT_HANDLED if self.popup: ##print event.x, event.y, event.x_root, event.y_root, event.__dict__ self.popup.tk_popup(event.x_root, event.y_root) return EVENT_HANDLED def middleclickHandler(self, event): if self._busy(): return EVENT_HANDLED if 1 <= self.side <= 2: self.menubar.setToolbarSide(3 - self.side) return EVENT_HANDLED # /*********************************************************************** # // # ************************************************************************/ class TestToolbar(PysolToolbar): def __init__(self, top, args): dir = "large" if len(args) > 1: dir = args[1] dir = os.path.join(os.pardir, os.pardir, "data", "toolbar", dir) relief = 1 relief = 0 PysolToolbar.__init__(self, top, dir=dir, size=1, relief=relief) # test some settings self.updateText(player="Player\nPySol") self.undo_button["state"] = Tkinter.DISABLED def mQuit(self, *args): self.top.after_idle(self.top.quit) def toolbar_main(args): tk = Tkinter.Tk() toolbar = TestToolbar(tk, args) toolbar.show() tk.mainloop() return 0 if __name__ == "__main__": sys.exit(toolbar_main(sys.argv))