diff --git a/data/pysolfc.glade b/data/pysolfc.glade new file mode 120000 index 00000000..2d4f6279 --- /dev/null +++ b/data/pysolfc.glade @@ -0,0 +1 @@ +../../../pysolfc/pysolfc.glade \ No newline at end of file diff --git a/pysol b/pysol index 77070ee1..b53c9be6 100755 --- a/pysol +++ b/pysol @@ -59,6 +59,12 @@ if os.name == 'nt': ##if locale_dir: locale_dir = os.path.normpath(locale_dir) gettext.install('pysol', locale_dir, unicode=True) +## init toolkit +if '--gtk' in sys.argv: + import pysollib.settings + pysollib.settings.TOOLKIT = 'gtk' + sys.argv.remove('--gtk') + from pysollib.main import main #import pychecker.checker diff --git a/pysollib/app.py b/pysollib/app.py index 8032d75e..cb8d6771 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -58,7 +58,7 @@ from gamedb import GI, GAME_DB, loadGame from settings import TOP_SIZE, TOP_TITLE, TOOLKIT # Toolkit imports -from pysoltk import tkname, tkversion, wm_withdraw, loadImage +from pysoltk import wm_withdraw, loadImage from pysoltk import MfxMessageDialog, MfxExceptionDialog from pysoltk import TclError, MfxRoot, MfxCanvas, MfxScrolledCanvas from pysoltk import PysolMenubar @@ -107,7 +107,7 @@ class Options: self.shrink_face_down = True self.shade_filled_stacks = True self.demo_logo = True - self.toolbar = True + self.toolbar = 1 # 0 == hide, 1,2,3,4 == top, bottom, lef, right ##self.toolbar_style = 'default' self.toolbar_style = 'crystal' if os.name == 'posix': diff --git a/pysollib/game.py b/pysollib/game.py index 85a2ef2a..7555d1d9 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -52,7 +52,7 @@ from resource import CSI from pysolrandom import PysolRandom, LCRandom31 from pysoltk import EVENT_HANDLED, EVENT_PROPAGATE from pysoltk import CURSOR_WATCH, ANCHOR_SW, ANCHOR_SE -from pysoltk import tkname, bind, wm_map +from pysoltk import bind, wm_map from pysoltk import after, after_idle, after_cancel from pysoltk import MfxMessageDialog, MfxExceptionDialog from pysoltk import MfxCanvasText, MfxCanvasImage @@ -393,8 +393,8 @@ class Game: if self.canvas: self.canvas.config(cursor=cursor) ##self.canvas.update_idletasks() - if self.app and self.app.toolbar: - self.app.toolbar.setCursor(cursor=cursor) + #if self.app and self.app.toolbar: + # self.app.toolbar.setCursor(cursor=cursor) # @@ -529,7 +529,6 @@ class Game: self.busy = old_busy def resetGame(self): - ##print '--- resetGame ---' self.hints.list = None self.s.talon.removeAllCards() for stack in self.allstacks: @@ -560,7 +559,6 @@ class Game: # with another game from there def quitGame(self, id=0, random=None, loadedgame=None, startdemo=0, bookmark=0, holdgame=0): - print 'quitGame' self.updateTime() if bookmark: id, random = self.id, self.random diff --git a/pysollib/help.py b/pysollib/help.py index 40ef2287..28dfeca4 100644 --- a/pysollib/help.py +++ b/pysollib/help.py @@ -41,9 +41,9 @@ import Tkinter # PySol imports from mfxutil import EnvError -from settings import PACKAGE, PACKAGE_URL +from settings import PACKAGE, PACKAGE_URL, TOOLKIT from version import VERSION, FC_VERSION -from pysoltk import tkname, makeHelpToplevel, wm_map, wm_set_icon +from pysoltk import makeHelpToplevel, wm_map, wm_set_icon from pysoltk import MfxMessageDialog from pysoltk import tkHTMLViewer from gamedb import GAME_DB @@ -95,10 +95,10 @@ def helpCredits(app, timeout=0, sound=1): if sound: app.audio.playSample("credits") t = "" - if tkname == "tk": t = "Tcl/Tk, " - elif tkname == "gnome": t = "PyGTK, " - elif tkname == "kde": t = "pyKDE, " - elif tkname == "wx": t = "wxPython, " + if TOOLKIT == "tk": t = "Tcl/Tk, " + elif TOOLKIT == "gtk": t = "PyGTK, " + elif TOOLKIT == "kde": t = "pyKDE, " + elif TOOLKIT == "wx": t = "wxPython, " d = MfxMessageDialog(app.top, title=_("Credits"), timeout=timeout, text=PACKAGE+_(''' credits go to: diff --git a/pysollib/main.py b/pysollib/main.py index 705d89fc..afdc65ae 100644 --- a/pysollib/main.py +++ b/pysollib/main.py @@ -44,7 +44,7 @@ import gettext from mfxutil import destruct, EnvError from util import CARDSET, DataLoader from version import VERSION -from settings import PACKAGE +from settings import PACKAGE, TOOLKIT from resource import Tile from gamedb import GI from app import Application @@ -52,12 +52,11 @@ from pysolaudio import thread, pysolsoundserver from pysolaudio import AbstractAudioClient, PysolSoundServerModuleClient, Win32AudioClient # Toolkit imports -from pysoltk import tkname, tkversion, wm_withdraw, wm_set_icon, loadImage +from pysoltk import tkversion, wm_withdraw, wm_set_icon, loadImage from pysoltk import MfxMessageDialog, MfxExceptionDialog from pysoltk import TclError, MfxRoot from pysoltk import PysolProgressBar -from tkFont import Font # /*********************************************************************** # // @@ -327,20 +326,22 @@ def pysol_init(app, args): font = top.option_get('font', '') else: font = None - try: - f = Font(top, font) - except: - print >> sys.stderr, "invalid font name:", font - pass - else: - if font: - fa = f.actual() - app.opt.fonts["default"] = (fa["family"], - fa["size"], - fa["slant"], - fa["weight"]) + if TOOLKIT == 'tk': + from tkFont import Font + try: + f = Font(top, font) + except: + print >> sys.stderr, "invalid font name:", font + pass else: - app.opt.fonts["default"] = None + if font: + fa = f.actual() + app.opt.fonts["default"] = (fa["family"], + fa["size"], + fa["slant"], + fa["weight"]) + else: + app.opt.fonts["default"] = None # check games if len(app.gdb.getGamesIdSortedByName()) == 0: @@ -559,7 +560,7 @@ def main(args=None): print "%s needs Python 1.5.2 or better (you have %s)" % (PACKAGE, sys.version) return 1 assert len(tkversion) == 4 - if tkname == "tk": + if TOOLKIT == "tk": import Tkinter if tkversion < (8, 0, 0, 0): print "%s needs Tcl/Tk 8.0 or better (you have %s)" % (PACKAGE, str(tkversion)) diff --git a/pysollib/pysolgtk/menubar.py b/pysollib/pysolgtk/menubar.py index 0223101b..068bc18b 100644 --- a/pysollib/pysolgtk/menubar.py +++ b/pysollib/pysolgtk/menubar.py @@ -53,6 +53,7 @@ gettext = _ def ltk2gtk(s): + # label tk to gtk return gettext(s).replace('&', '_') @@ -69,7 +70,7 @@ class PysolMenubar(PysolMenubarActions): # create menus menubar = self.createMenubar() self.top.table.attach(menubar, - 0, 1, 0, 1, + 0, 3, 0, 1, gtk.EXPAND | gtk.FILL, 0, 0, 0); menubar.show() @@ -119,7 +120,7 @@ class PysolMenubar(PysolMenubarActions): ('stats', gtk.STOCK_INDEX, ltk2gtk('Stats'), None, ltk2gtk('Statistics'), - self.mStatus), + lambda w, self=self: self.mPlayerStats(mode=101)), ('rules', gtk.STOCK_HELP, ltk2gtk('Rules'), 'F1', ltk2gtk('Rules'), @@ -136,9 +137,12 @@ class PysolMenubar(PysolMenubarActions): ('game', None, ltk2gtk('&Game')), ('assist', None, ltk2gtk('&Assist')), ('options', None, ltk2gtk('&Options')), - ('assistlevel', None, ltk2gtk("Assist &level")), - ("automaticplay", None, ltk2gtk("&Automatic play")), + ('assistlevel', None, ltk2gtk('Assist &level')), + ('automaticplay', None, ltk2gtk('&Automatic play')), ('animations', None, ltk2gtk('A&nimations')), + ('cardview', None, ltk2gtk('Card &view')), + ('toolbar', None, ltk2gtk('&Toolbar')), + ('statusbar', None, ltk2gtk('Stat&usbar')), ('help', None, ltk2gtk('&Help')), ### menuitems @@ -150,7 +154,10 @@ class PysolMenubar(PysolMenubarActions): None, self.mSelectGameById), ('saveas', None, ltk2gtk('Save &as...'), None, - None, self.m), + None, self.mSaveAs), + ('holdandquit', None, + ltk2gtk('&Hold and quit'), None, + None, self.mHoldAndQuit), ('redoall', None, ltk2gtk('Redo &all'), None, None, self.mRedoAll), @@ -195,34 +202,53 @@ class PysolMenubar(PysolMenubarActions): # toggle_entries = [ - ('pause', # name - gtk.STOCK_STOP, ltk2gtk('&Pause'), # stock, label - 'P', ltk2gtk('Pause game'), # accelerator, tooltip - self.mPause, # callback - False, # initial value - ), ] - for label, name, opt_name in ( - ('A&uto drop', 'optautodrop', 'autodrop'), - ('Auto &face up', '', 'autofaceup'), - ('Auto &deal', '', 'autodeal'), - ('&Quick play', '', 'quickplay'), - ('Enable &undo', '', 'undo'), - ('Enable &bookmarks' , '', 'bookmarks'), - ('Enable &hint', '', 'hint'), - ('Enable highlight p&iles', '', 'highlight_piles'), - ('Enable highlight &cards', '', 'highlight_cards'), - ('Enable highlight same &rank', '', 'highlight_samerank'), - ('Highlight &no matching', '', 'highlight_not_matching'), - ('Card shado&w', '', 'shadow'), - ('Shade &legal moves', '', 'shade'), + ('pause', gtk.STOCK_STOP, # action, stock + ltk2gtk('&Pause'), 'P', # label, accelerator + ltk2gtk('Pause game'), # tooltip + self.mPause, # callback + False, # initial value + ), + ('negativecardsbottom', None, + ltk2gtk('&Negative cards bottom'), None, None, + self.mOptNegativeBottom, + self.app.opt.negative_bottom, + ), + ('showstatusbar', None, + ltk2gtk('Show &statusbar'), None, None, + self.mOptStatusbar, + self.app.opt.statusbar, + ), + ] + for label, action, opt_name, update_game in ( + ('A&uto drop', 'optautodrop', 'autodrop', False), + ('Auto &face up', '', 'autofaceup', False), + ('Auto &deal', '', 'autodeal', False), + ('&Quick play', '', 'quickplay', False), + ('Enable &undo', '', 'undo', False), + ('Enable &bookmarks', '', 'bookmarks', False), + ('Enable &hint', '', 'hint', False), + ('Enable highlight p&iles', '', 'highlight_piles', False), + ('Enable highlight &cards', '', 'highlight_cards', False), + ('Enable highlight same &rank', '', 'highlight_samerank', False), + ('Highlight &no matching', '', 'highlight_not_matching', False), + ('Card shado&w', '', 'shadow', False), + ('Shade &legal moves', '', 'shade', False), + ('Shrink face-down cards', '', 'shrink_face_down', True), + ('Shade &filled stacks', '', 'shade_filled_stacks', True), + ('Stick&y mouse', '', 'sticky_mouse', False), + ('Show &number of cards', '', 'num_cards', False), + ('&Demo logo', '', 'demo_logo', False), + ('Startup splash sc&reen', '', 'splashscreen', False), + ('&Show removed tiles (in Mahjongg games)', '', 'mahjongg_show_removed', True), + ('Show hint &arrow (in Shisen-Sho games)', '', 'shisen_show_hint', False), ): - if not name: - name = re.sub(r"[^0-9a-zA-Z]", "", label).lower() + if not action: + action = re.sub(r'[^0-9a-zA-Z]', '', label).lower() toggle_entries.append( - (name, + (action, None, ltk2gtk(label), None, None, - lambda w, opt_name=opt_name: self.mOptToggle(w, opt_name), + lambda w, o=opt_name, u=update_game: self.mOptToggle(w, o, u), getattr(self.app.opt, opt_name))) # @@ -233,6 +259,14 @@ class PysolMenubar(PysolMenubarActions): ('animationslow', None, ltk2gtk('&Slow'), None, None, 3), ('animationveryslow', None, ltk2gtk('&Very slow'), None, None, 4), ) + toolbar_side_entries = ( + ('toolbarhide', None, ltk2gtk('Hide'), None, None, 0), + ('toolbartop', None, ltk2gtk('Top'), None, None, 1), + ('toolbarbottom', None, ltk2gtk('Bottom'), None, None, 2), + ('toolbarleft', None, ltk2gtk('Left'), None, None, 3), + ('toolbarright', None, ltk2gtk('Right'), None, None, 4), + ) + # ui_info = ''' @@ -247,6 +281,7 @@ class PysolMenubar(PysolMenubarActions): + @@ -256,8 +291,10 @@ class PysolMenubar(PysolMenubarActions): + @@ -266,6 +303,7 @@ class PysolMenubar(PysolMenubarActions): + @@ -292,6 +330,9 @@ class PysolMenubar(PysolMenubarActions): + + + @@ -303,8 +344,28 @@ class PysolMenubar(PysolMenubarActions): - - + + + + + + + + + + + + + + + + + + + + + + @@ -326,6 +387,9 @@ class PysolMenubar(PysolMenubarActions): action_group.add_radio_actions(animations_entries, self.app.opt.animations, self.mOptAnimations) + action_group.add_radio_actions(toolbar_side_entries, + self.app.opt.toolbar, + self.mOptToolbar) ui_manager.insert_action_group(action_group, 0) self.top.add_accel_group(ui_manager.get_accel_group()) @@ -421,7 +485,6 @@ class PysolMenubar(PysolMenubarActions): d = gtk.FileChooserDialog(title, self.top, action, (gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) - d.set_current_folder(idir) if ifile: d.set_current_name(ifile) @@ -451,7 +514,7 @@ class PysolMenubar(PysolMenubarActions): if filename: idir, ifile = os.path.split(os.path.normpath(filename)) else: - idir, ifile = "", "" + idir, ifile = '', '' if not idir: idir = self.app.dn.savegames filename = self._createFileChooser(_('Open Game'), @@ -471,12 +534,12 @@ class PysolMenubar(PysolMenubarActions): filename = self.game.filename if not filename: filename = self.app.getGameSaveName(self.game.id) - if os.name == "posix": - filename = filename + "-" + self.game.getGameNumber(format=0) + if os.name == 'posix': + filename = filename + '-' + self.game.getGameNumber(format=0) elif os.path.supports_unicode_filenames: # new in python 2.3 - filename = filename + "-" + self.game.getGameNumber(format=0) + filename = filename + '-' + self.game.getGameNumber(format=0) else: - filename = filename + "-01" + filename = filename + '-01' filename = filename + '.pso' idir, ifile = os.path.split(os.path.normpath(filename)) if not idir: @@ -493,49 +556,14 @@ class PysolMenubar(PysolMenubarActions): - def mOptTableTile(self, *args): - if self._cancelDrag(break_pause=False): return - key = self.app.tabletile_index - if key <= 0: - key = self.app.opt.table_color.lower() - d = SelectTileDialogWithPreview(self.top, app=self.app, - title=_('Select table background'), - manager=self.app.tabletile_manager, - key=key) - if d.status == 0 and d.button in (0, 1): - if type(d.key) is str: - self._mOptTableColor(d.key) - elif d.key > 0 and d.key != self.app.tabletile_index: - self._mOptTableTile(d.key) - - - def mOptHintOptions(self, *args): - pass - - def mOptDemoOptions(self, *args): - pass - def updateFavoriteGamesMenu(self, *args): pass + def mSelectGame(self, menu_item, game_id): if menu_item.get_active(): self._mSelectGame(game_id) - def mOptAnimations(self, a1, a2): - ##print a1.get_current_value(), a2.get_current_value() - self.app.opt.animations = a1.get_current_value() - - - def _mOptTableTile(self, i): - self.app.setTile(i) - - def _mOptTableColor(self, color): - tile = self.app.tabletile_manager.get(0) - tile.color = color - self.app.setTile(0) - - def mSelectGameDialogWithPreview(self, *event): if self._cancelDrag(break_pause=False): return ## self.game.setCursor(cursor=CURSOR_WATCH) @@ -546,12 +574,9 @@ class PysolMenubar(PysolMenubarActions): ## bookmark = self.game.gsaveinfo.bookmarks[-2][0] ## del self.game.gsaveinfo.bookmarks[-2] ##~ after_idle(self.top, self.__restoreCursor) - d = SelectGameDialogWithPreview(self.top, title=_("Select game"), + d = SelectGameDialogWithPreview(self.top, title=_('Select game'), app=self.app, gameid=self.game.id, bookmark=bookmark) - return self._mSelectGameDialog(d) - - def _mSelectGameDialog(self, d): if d.status == 0 and d.button == 0 and d.gameid != self.game.id: ##~ self.tkopt.gameid.set(d.gameid) ##~ self.tkopt.gameid_popular.set(d.gameid) @@ -564,10 +589,28 @@ class PysolMenubar(PysolMenubarActions): self.game.quitGame(d.gameid, random=d.random) + def mOptTableTile(self, *args): + if self._cancelDrag(break_pause=False): return + key = self.app.tabletile_index + if key <= 0: + key = self.app.opt.table_color.lower() + d = SelectTileDialogWithPreview(self.top, app=self.app, + title=_('Select table background'), + manager=self.app.tabletile_manager, + key=key) + if d.status == 0 and d.button in (0, 1): + if type(d.key) is str: + tile = self.app.tabletile_manager.get(0) + tile.color = color + self.app.setTile(0) + elif d.key > 0 and d.key != self.app.tabletile_index: + self.app.setTile(i) + + def mSelectCardsetDialog(self, *event): if self._cancelDrag(break_pause=False): return key = self.app.nextgame.cardset.index - d = SelectCardsetDialogWithPreview(self.top, title=_("Select cardset"), + d = SelectCardsetDialogWithPreview(self.top, title=_('Select cardset'), 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: @@ -581,10 +624,42 @@ class PysolMenubar(PysolMenubarActions): self.app.opt.games_geometry = {} # clear saved games geometry - def mOptToggle(self, w, opt): + def mOptToggle(self, w, opt_name, update_game): ##print 'mOptToggle:', opt, w.get_active() if self._cancelDrag(break_pause=False): return - self.app.opt.__dict__[opt] = w.get_active() + self.app.opt.__dict__[opt_name] = w.get_active() + if update_game: + self.game.endGame(bookmark=1) + self.game.quitGame(bookmark=1) + + def mOptNegativeBottom(self, w): + if self._cancelDrag(): return + self.app.opt.negative_bottom = w.get_active() + self.app.updateCardset() + self.game.endGame(bookmark=1) + self.game.quitGame(bookmark=1) + + + def mOptAnimations(self, w1, w2): + self.app.opt.animations = w1.get_current_value() + + + def mOptToolbar(self, w1, w2): + if self._cancelDrag(break_pause=False): return + side = w1.get_current_value() + self.app.opt.toolbar = side + if self.app.toolbar.show(side, resize=1): + self.top.update_idletasks() + + + def mOptStatusbar(self, w): + if self._cancelDrag(break_pause=False): return + if not self.app.statusbar: return + side = w.get_active() + self.app.opt.statusbar = side + resize = not self.app.opt.save_games_geometry + if self.app.statusbar.show(side, resize=resize): + self.top.update_idletasks() def updateAll(self, *event): diff --git a/pysollib/pysolgtk/progressbar.py b/pysollib/pysolgtk/progressbar.py index 6238455b..82e8e6c3 100644 --- a/pysollib/pysolgtk/progressbar.py +++ b/pysollib/pysolgtk/progressbar.py @@ -86,12 +86,6 @@ class PysolProgressBar: self.pbar.set_text(str(show_text)+'%') w, h = self.pbar.size_request() self.pbar.set_size_request(max(w, 300), max(h, height)) - # set color - ##~ c = self.pbar.get_colormap().alloc_color(color) - ##~ self.pbar.style.bg[gtk.STATE_PRELIGHT] = c - ##~ style = self.pbar.get_style().copy() - ##~ style.bg[gtk.STATE_PRELIGHT] = c - ##~ self.pbar.set_style(style) # hbox-3:image if images and images[1]: im = gtk.Image() diff --git a/pysollib/pysolgtk/tkcanvas.py b/pysollib/pysolgtk/tkcanvas.py index 90b6572d..1570974d 100644 --- a/pysollib/pysolgtk/tkcanvas.py +++ b/pysollib/pysolgtk/tkcanvas.py @@ -76,6 +76,7 @@ class _CanvasItem: def __init__(self, canvas): self.canvas = canvas canvas._all_items.append(self) + self._is_hidden = False def addtag(self, group): ##print self, 'addtag' @@ -126,9 +127,11 @@ class _CanvasItem: def show(self): if self._item: self._item.show() + self._is_hidden = False def hide(self): if self._item: self._item.hide() + self._is_hidden = True def connect(self, signal, func, args): ##print signal @@ -251,6 +254,7 @@ class MfxCanvas(gnome.canvas.Canvas): self.items = {} self._all_items = [] self._text_items = [] + self._hidden_items = [] self._width, self._height = -1, -1 self._tile = None # private @@ -327,13 +331,10 @@ class MfxCanvas(gnome.canvas.Canvas): ##print 'configure: bg:', v c = self.get_colormap().alloc_color(v) self.style.bg[gtk.STATE_NORMAL] = c - ##~ self.set_style(self.style) - ##~ self.queue_draw() elif k == "cursor": - ##~ w = self.window - ##~ if w: - ##~ w.set_cursor(cursor_new(v)) - pass + if not self.window: + self.realize() + self.window.set_cursor(gdk.Cursor(v)) elif k == "height": height = v elif k == "width": @@ -359,12 +360,16 @@ class MfxCanvas(gnome.canvas.Canvas): self.__tileimage = None def hideAllItems(self): + self._hidden_items = [] for i in self._all_items: - i.hide() + if not i._is_hidden: + i.hide() + self._hidden_items.append(i) def showAllItems(self): - for i in self._all_items: + for i in self._hidden_items: i.show() + self._hidden_items = [] # PySol extension def findCard(self, stack, event): @@ -440,8 +445,9 @@ class MfxCanvas(gnome.canvas.Canvas): gtk.idle_add(self.setBackgroundImage, filename, stretch) + def setBackgroundImage(self, filename, stretch=False): - print 'setBackgroundImage', filename + ##print 'setBackgroundImage', filename if filename is None: if self.__tileimage: self.__tileimage.destroy() @@ -504,6 +510,9 @@ class MfxCanvas(gnome.canvas.Canvas): ##print 'MfxCanvas.update_idletasks' #gdk.window_process_all_updates() #self.show_now() + # FIXME + ##if self.__topimage: + ## self.__topimage.raise_to_top() self.update_now() pass @@ -523,7 +532,7 @@ class MfxCanvas(gnome.canvas.Canvas): def grid(self, *args, **kw): self.top.table.attach(self, - 0, 1, 2, 3, + 1, 2, 2, 3, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL | gtk.SHRINK, 0, 0) self.show() diff --git a/pysollib/pysolgtk/tkconst.py b/pysollib/pysolgtk/tkconst.py index df733e72..d7a36b1e 100644 --- a/pysollib/pysolgtk/tkconst.py +++ b/pysollib/pysolgtk/tkconst.py @@ -42,7 +42,6 @@ from gtk import ANCHOR_NW, ANCHOR_SW, ANCHOR_NE, ANCHOR_SE # // constants # ************************************************************************/ -tkname = "gnome" # (major version, minor version, micro version, patchlevel) tkversion = (0, 0, 0, 0) diff --git a/pysollib/pysolgtk/tkstats.py b/pysollib/pysolgtk/tkstats.py index 7d9c893c..70ccdafe 100644 --- a/pysollib/pysolgtk/tkstats.py +++ b/pysollib/pysolgtk/tkstats.py @@ -31,21 +31,275 @@ # imports -import os, sys -import gtk +import os, sys, time +import gtk, gobject, pango +import gtk.glade # PySol imports +from pysollib.mfxutil import format_time +from pysollib.settings import TOP_TITLE +from pysollib.stats import PysolStatsFormatter # Toolkit imports -from tkwidget import MfxDialog +from tkwidget import MfxDialog, MfxMessageDialog + + +glade_file = os.path.join(sys.path[0], 'data', 'pysolfc.glade') + +open(glade_file) # /*********************************************************************** # // # ************************************************************************/ -class SingleGame_StatsDialog(MfxDialog): - pass +class StatsWriter(PysolStatsFormatter.StringWriter): + def __init__(self, store): + self.store = store + + def p(self, s): + pass + + def pheader(self, s): + pass + + def pstats(self, *args, **kwargs): + gameid=kwargs.get('gameid', None) + if gameid is None: + # header + return + iter = self.store.append(None) + self.store.set(iter, + 0, args[0], + 1, args[1], + 2, args[2], + 3, args[3], + 4, args[4], + 5, args[5], + 6, args[6], + 7, gameid) + + +class FullLogWriter(PysolStatsFormatter.StringWriter): + def __init__(self, store): + self.store = store + + def p(self, s): + pass + + def pheader(self, s): + pass + + def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): + if gameid < 0: + # header + return + iter = self.store.append(None) + self.store.set(iter, + 0, gamename, + 1, gamenumber, + 2, date, + 3, status, + 4, gameid) + + +class Game_StatsDialog: + + def __init__(self, parent, header, app, player, gameid): + # + self.app = app + + formatter = PysolStatsFormatter(self.app) + # + self.widgets_tree = gtk.glade.XML(glade_file) + #game_name_combo = self.widgets_tree.get_widget('game_name_combo') + #model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT) + #game_name_combo.set_model(model) + #game_name_combo.set_text_column(0) + stats_dialog = self.widgets_tree.get_widget('stats_dialog') + stats_dialog.set_title('Game Statistics') + stats_dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) + # total + won, lost = app.stats.getStats(player, gameid) + self._createText('total', won, lost) + drawing = self.widgets_tree.get_widget('total_drawingarea') + drawing.connect('expose_event', self._createChart, won, lost) + # current session + won, lost = app.stats.getSessionStats(player, gameid) + self._createText('current', won, lost) + drawing = self.widgets_tree.get_widget('session_drawingarea') + drawing.connect('expose_event', self._createChart, won, lost) + # + store = self._createStatsList() + writer = StatsWriter(store) + formatter.writeStats(writer, player, header, sort_by='name') + # + store = self._createLogList('full_log_treeview') + writer = FullLogWriter(store) + formatter.writeFullLog(writer, player, header) + # + store = self._createLogList('session_log_treeview') + writer = FullLogWriter(store) + formatter.writeSessionLog(writer, player, header) + # + stats_dialog.set_transient_for(parent) + stats_dialog.resize(400, 300) + + stats_dialog.run() + self.status = -1 + stats_dialog.destroy() + + + def _createText(self, name, won, lost): + pwon, plost = self._getPwon(won, lost) + label = self.widgets_tree.get_widget(name+'_num_won_label') + label.set_text(str(won)) + label = self.widgets_tree.get_widget(name+'_num_lost_label') + label.set_text(str(lost)) + label = self.widgets_tree.get_widget(name+'_percent_won_label') + label.set_text(str(int(round(pwon*100)))+'%') + label = self.widgets_tree.get_widget(name+'_percent_lost_label') + label.set_text(str(int(round(plost*100)))+'%') + label = self.widgets_tree.get_widget(name+'_num_total_label') + label.set_text(str(won+lost)) + + + def _createChart(self, drawing, e, won, lost): + pwon, plost = self._getPwon(won, lost) + s, ewon, elost = 0, int(360.0*pwon), int(360.0*plost) + + win = drawing.window + colormap = drawing.get_colormap() + gc = win.new_gc() + gc.set_colormap(colormap) + + alloc = drawing.allocation + width, height = alloc.width, alloc.height + w, h = 90, 50 + ##x, y = 10, 10 + x, y = (width-w)/2, (height-h)/2 + dy = 9 + y = y-dy/2 + + if won+lost > 0: + gc.set_rgb_fg_color(colormap.alloc_color('#007f00')) + win.draw_arc(gc, True, x, y+dy, w, h, s*64, ewon*64) + gc.set_rgb_fg_color(colormap.alloc_color('#7f0000')) + win.draw_arc(gc, True, x, y+dy, w, h, (s+ewon)*64, elost*64) + gc.set_rgb_fg_color(colormap.alloc_color('#00ff00')) + win.draw_arc(gc, True, x, y, w, h, s*64, ewon*64) + gc.set_rgb_fg_color(colormap.alloc_color('#ff0000')) + win.draw_arc(gc, True, x, y, w, h, (s+ewon)*64, elost*64) + else: + gc.set_rgb_fg_color(colormap.alloc_color('#7f7f7f')) + win.draw_arc(gc, True, x, y+dy, w, h, 0, 360*64) + gc.set_rgb_fg_color(colormap.alloc_color('#f0f0f0')) + win.draw_arc(gc, True, x, y, w, h, 0, 360*64) + gc.set_rgb_fg_color(colormap.alloc_color('#bfbfbf')) + pangolayout = drawing.create_pango_layout('No games') + ext = pangolayout.get_extents() + tw, th = ext[1][2]/pango.SCALE, ext[1][3]/pango.SCALE + win.draw_layout( + gc, + x+w/2-tw/2, y+h/2-th/2, + pangolayout) + + + def _createStatsList(self): + treeview = self.widgets_tree.get_widget('all_games_treeview') + n = 0 + for label in ( + '', + _('Played'), + _('Won'), + _('Lost'), + _('Playing time'), + _('Moves'), + _('% won'), + ): + column = gtk.TreeViewColumn(label, gtk.CellRendererText(), + text=n) + column.set_resizable(True) + column.set_sort_column_id(n) + treeview.append_column(column) + n += 1 + # + store = gtk.ListStore(gobject.TYPE_STRING, # name + gobject.TYPE_INT, # played + gobject.TYPE_INT, # won + gobject.TYPE_INT, # lost + gobject.TYPE_STRING, # playing time + gobject.TYPE_STRING, # moves + gobject.TYPE_STRING, # % won + gobject.TYPE_INT, # gameid + ) + sortable = gtk.TreeModelSort(store) + treeview.set_model(sortable) + sortable.set_sort_func(4, self._cmpPlayingTime) + sortable.set_sort_func(5, self._cmpMoves) + sortable.set_sort_func(6, self._cmpPercent) + return store + + + def _createLogList(self, name): + # + treeview = self.widgets_tree.get_widget(name) + n = 0 + for label in ( + _('Game'), + _('Game number'), + _('Started at'), + _('Status'), + ): + column = gtk.TreeViewColumn(label, gtk.CellRendererText(), + text=n) + column.set_resizable(True) + column.set_sort_column_id(n) + treeview.append_column(column) + n += 1 + # + store = gtk.ListStore(gobject.TYPE_STRING, # game name + gobject.TYPE_STRING, # game number + gobject.TYPE_STRING, # started at + gobject.TYPE_STRING, # status + gobject.TYPE_INT, # gameid + ) + treeview.set_model(store) + return store + + + def _getPwon(self, won, lost): + pwon, plost = 0.0, 0.0 + if won + lost > 0: + pwon = float(won) / (won + lost) + pwon = min(max(pwon, 0.00001), 0.99999) + plost = 1.0 - pwon + return pwon, plost + + + def _cmpPlayingTime(self, store, iter1, iter2): + val1 = store.get_value(iter1, 4) + val2 = store.get_value(iter2, 4) + t1 = map(int, val1.split(':')) + t2 = map(int, val2.split(':')) + return cmp(len(t1), len(t2)) or cmp(t1, t2) + + def _cmpMoves(self, store, iter1, iter2): + val1 = store.get_value(iter1, 5) + val2 = store.get_value(iter2, 5) + return cmp(float(val1), float(val2)) + + def _cmpPercent(self, store, iter1, iter2): + val1 = store.get_value(iter1, 6) + val2 = store.get_value(iter2, 6) + return cmp(float(val1), float(val2)) + + +# /*********************************************************************** +# // +# ************************************************************************/ + +SingleGame_StatsDialog = Game_StatsDialog class AllGames_StatsDialog(MfxDialog): pass @@ -56,8 +310,54 @@ class FullLog_StatsDialog(AllGames_StatsDialog): class SessionLog_StatsDialog(FullLog_StatsDialog): pass -class Status_StatsDialog(MfxDialog): - pass + +# /*********************************************************************** +# // +# ************************************************************************/ + +class Status_StatsDialog(MfxMessageDialog): #MfxDialog + def __init__(self, parent, game): + stats, gstats = game.stats, game.gstats + w1 = w2 = '' + n = 0 + for s in game.s.foundations: + n = n + len(s.cards) + w1 = (_('Highlight piles: ') + str(stats.highlight_piles) + '\n' + + _('Highlight cards: ') + str(stats.highlight_cards) + '\n' + + _('Highlight same rank: ') + str(stats.highlight_samerank) + '\n') + if game.s.talon: + if game.gameinfo.redeals != 0: + w2 = w2 + _('\nRedeals: ') + str(game.s.talon.round - 1) + w2 = w2 + _('\nCards in Talon: ') + str(len(game.s.talon.cards)) + if game.s.waste and game.s.waste not in game.s.foundations: + w2 = w2 + _('\nCards in Waste: ') + str(len(game.s.waste.cards)) + if game.s.foundations: + w2 = w2 + _('\nCards in Foundations: ') + str(n) + # + date = time.strftime('%Y-%m-%d %H:%M', time.localtime(game.gstats.start_time)) + MfxMessageDialog.__init__(self, parent, title=_('Game status'), + text=game.getTitleName() + '\n' + + game.getGameNumber(format=1) + '\n' + + _('Playing time: ') + game.getTime() + '\n' + + _('Started at: ') + date + '\n\n'+ + _('Moves: ') + str(game.moves.index) + '\n' + + _('Undo moves: ') + str(stats.undo_moves) + '\n' + + _('Bookmark moves: ') + str(gstats.goto_bookmark_moves) + '\n' + + _('Demo moves: ') + str(stats.demo_moves) + '\n' + + _('Total player moves: ') + str(stats.player_moves) + '\n' + + _('Total moves in this game: ') + str(stats.total_moves) + '\n' + + _('Hints: ') + str(stats.hints) + '\n' + + '\n' + + w1 + w2, + strings=(_('&OK'), + (_('&Statistics...'), 101), + (TOP_TITLE+'...', 105), ), + image=game.app.gimages.logos[3], + image_side='left', image_padx=20, + padx=20, + ) + + class Top_StatsDialog(MfxDialog): pass diff --git a/pysollib/pysolgtk/tkutil.py b/pysollib/pysolgtk/tkutil.py index 69b07582..f19d28dd 100644 --- a/pysollib/pysolgtk/tkutil.py +++ b/pysollib/pysolgtk/tkutil.py @@ -58,8 +58,6 @@ def wm_set_icon(window, icon): def makeToplevel(parent, title=None, class_=None, gtkclass=gtk.Window): window = gtkclass() - ##~ window.style = window.get_style().copy() - ##~ window.set_style(window.style) if not hasattr(window, 'table'): window.table = gtk.Table(1, 4, False) window.table.show() diff --git a/pysollib/pysolgtk/tkwidget.py b/pysollib/pysolgtk/tkwidget.py index 974853b9..71d8f24d 100644 --- a/pysollib/pysolgtk/tkwidget.py +++ b/pysollib/pysolgtk/tkwidget.py @@ -51,8 +51,6 @@ from pysollib.mfxutil import kwdefault, KwStruct class _MyDialog(gtk.Dialog): def __init__(self): gtk.Dialog.__init__(self) - ##~ style = self.get_style().copy() - ##~ self.set_style(style) self.connect("destroy", self.quit) self.connect("delete_event", self.quit) @@ -110,6 +108,7 @@ class MfxDialog(_MyDialog): return self.createBox(widget_class=gtk.VBox) def createTable(self): + # FIXME return self.createBox(widget_class=gtk.Table) def createBitmaps(self, box, kw): @@ -140,13 +139,17 @@ class MfxDialog(_MyDialog): text = strings[i] if not text: continue + if isinstance(text, (list, tuple)): + text, index = text + else: # str + index = i text = text.replace('&', '_') b = gtk.Button(text) b.set_property('can-default', True) - if i == default: + if index == default: b.grab_focus() #b.grab_default() - b.set_data("user_data", i) + b.set_data("user_data", index) b.connect("clicked", self.done) box.pack_start(b) b.show() diff --git a/pysollib/pysolgtk/tkwrap.py b/pysollib/pysolgtk/tkwrap.py index 2b8065b7..7813fcc1 100644 --- a/pysollib/pysolgtk/tkwrap.py +++ b/pysollib/pysolgtk/tkwrap.py @@ -109,12 +109,10 @@ class StringVar: class _MfxToplevel(gtk.Window): def __init__(self, *args, **kw): gtk.Window.__init__(self, type=gtk.WINDOW_TOPLEVEL) - ##~ self.style = self.get_style().copy() - ##~ self.set_style(self.style) #self.vbox = gtk.VBox() #self.vbox.show() #self.add(self.vbox) - self.table = gtk.Table(3, 5, False) + self.table = gtk.Table(3, 6, False) self.add(self.table) self.table.show() self.realize() @@ -137,10 +135,6 @@ class _MfxToplevel(gtk.Window): for k, v in kw.items(): if k in ("background", "bg"): ##print "Toplevel configure: bg" - ##~ c = self.get_colormap().alloc_color(v) - ##~ self.style.bg[gtk.STATE_NORMAL] = c - ##~ self.set_style(self.style) - ##~ self.queue_draw() pass elif k == "cursor": self.setCursor(v) @@ -256,7 +250,9 @@ class _MfxToplevel(gtk.Window): pass def option_get(self, *args): - ##print self, 'option_get' + if args and args[0] == 'font': + return self.get_style().font_desc.to_string() + print '_MfxToplevel: option_get', args return None def grid_columnconfigure(self, *args, **kw): diff --git a/pysollib/pysolgtk/toolbar.py b/pysollib/pysolgtk/toolbar.py index f2e7845d..93f32386 100644 --- a/pysollib/pysolgtk/toolbar.py +++ b/pysollib/pysolgtk/toolbar.py @@ -32,12 +32,10 @@ # imports import os, re, sys - import gtk -TRUE, FALSE = True, False +from gtk import gdk # PySol imports - from pysollib.actions import PysolToolbarActions @@ -54,9 +52,6 @@ class PysolToolbar(PysolToolbarActions): self.dir = dir self.side = -1 - self.toolbar = gtk.Toolbar(gtk.ORIENTATION_HORIZONTAL, - gtk.TOOLBAR_ICONS) - ui_info = ''' @@ -82,15 +77,11 @@ class PysolToolbar(PysolToolbarActions): ui_manager_id = ui_manager.add_ui_from_string(ui_info) toolbar = ui_manager.get_widget("/toolbar") + self.toolbar = toolbar toolbar.set_tooltips(True) toolbar.set_style(gtk.TOOLBAR_ICONS) - toolbar.show() - top.table.attach(toolbar, - 0, 1, 1, 2, - gtk.EXPAND | gtk.FILL, 0, - 0, 0) - toolbar.show() + self._attached = False # @@ -103,6 +94,11 @@ class PysolToolbar(PysolToolbarActions): def destroy(self): self.toolbar.destroy() + + # + # public methods + # + def getSide(self): return self.side @@ -110,24 +106,51 @@ class PysolToolbar(PysolToolbarActions): return 0 def hide(self, resize=1): - self.show(None, resize) + self.show(0, resize) def show(self, side=1, resize=1): + if self.side == side: + return 0 self.side = side - if side: - self.toolbar.show() - else: + if not side: + # hide self.toolbar.hide() + return 1 + # show + if side == 1: + # top + x, y = 1, 1 + elif side == 2: + # bottom + x, y = 1, 3 + elif side == 3: + # left + x, y = 0, 2 + else: + # right + x, y = 2, 2 + # set orient + if side in (1, 2): + orient = gtk.ORIENTATION_HORIZONTAL + else: + orient = gtk.ORIENTATION_VERTICAL + self.toolbar.set_orientation(orient) + if self._attached: + self.top.table.remove(self.toolbar) + row_span, column_span = 1, 1 + self.top.table.attach(self.toolbar, + x, x+1, y, y+1, + gtk.FILL, gtk.FILL, + 0, 0) + self.toolbar.show() + self._attached = True + return 1 - # - # public methods - # - def setCursor(self, cursor): if self.side: - # FIXME - pass + if self.toolbar.window: + self.toolbar.window.set_cursor(gdk.Cursor(v)) def setRelief(self, relief): # FIXME diff --git a/pysollib/settings.py b/pysollib/settings.py index 491b40d7..70cb08f8 100644 --- a/pysollib/settings.py +++ b/pysollib/settings.py @@ -29,7 +29,7 @@ PACKAGE = "PySol" PACKAGE_URL = "http://sourceforge.net/projects/pysolfc/" TOOLKIT = 'gtk' -#TOOLKIT = 'tk' +TOOLKIT = 'tk' # data dirs DATA_DIRS = [] diff --git a/pysollib/stack.py b/pysollib/stack.py index e33e9a23..72d06e79 100644 --- a/pysollib/stack.py +++ b/pysollib/stack.py @@ -99,7 +99,7 @@ from util import Timer from util import ACE, KING, SUITS from util import ANY_SUIT, ANY_COLOR, ANY_RANK, NO_RANK from util import NO_REDEAL, UNLIMITED_REDEALS, VARIABLE_REDEALS -from pysoltk import tkname, EVENT_HANDLED, EVENT_PROPAGATE +from pysoltk import EVENT_HANDLED, EVENT_PROPAGATE from pysoltk import CURSOR_DRAG, ANCHOR_NW, ANCHOR_SE from pysoltk import bind, unbind_destroy from pysoltk import after, after_idle, after_cancel @@ -887,7 +887,11 @@ class Stack: self.cards[i].item.tkraise() self.game.canvas.update_idletasks() self.game.sleep(self.game.app.opt.raise_card_sleep) - self.cards[i].item.lower(self.cards[i+1].item) + 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() return 1 @@ -1160,10 +1164,10 @@ class Stack: if TOOLKIT == 'tk': s1.lower(c.item) s2.lower(c.item) - elif TOOLKIT == 'gtk': - positions = 2 ## FIXME - s1.lower(positions) - s2.lower(positions) +## elif TOOLKIT == 'gtk': +## positions = 2 ## FIXME +## s1.lower(positions) +## s2.lower(positions) return (s1, s2) return () diff --git a/pysollib/tk/menubar.py b/pysollib/tk/menubar.py index f43b3b33..8357442e 100644 --- a/pysollib/tk/menubar.py +++ b/pysollib/tk/menubar.py @@ -1042,8 +1042,7 @@ class PysolMenubar(PysolMenubarActions): def mOptNegativeBottom(self, *event): if self._cancelDrag(): return - n = self.tkopt.negative_bottom.get() - self.app.opt.negative_bottom = n + self.app.opt.negative_bottom = self.tkopt.negative_bottom.get() self.app.updateCardset() self.game.endGame(bookmark=1) self.game.quitGame(bookmark=1) diff --git a/pysollib/tk/tkconst.py b/pysollib/tk/tkconst.py index 94c52dbc..f5fefcb1 100644 --- a/pysollib/tk/tkconst.py +++ b/pysollib/tk/tkconst.py @@ -33,8 +33,7 @@ ## ##---------------------------------------------------------------------------## -__all__ = ['tkname', - 'tkversion', +__all__ = ['tkversion', 'TK_DASH_PATCH', 'EVENT_HANDLED', 'EVENT_PROPAGATE', @@ -64,8 +63,6 @@ n_ = lambda x: x # // constants # ************************************************************************/ -tkname = "tk" - # (major version, minor version, micro version, patchlevel) tkversion = (8, 0, 0, 0) try: