From 8a97ed47be3093c7404fcdd25f19cf4b53f833a8 Mon Sep 17 00:00:00 2001 From: skomoroh Date: Fri, 20 Oct 2006 21:18:06 +0000 Subject: [PATCH] * improved statistics * improved tile support * misc. bugs fixes and improvements git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@81 efabe8c0-fbe8-4139-b769-b5e6d273206e --- po/ru_games.po | 4 +- pysollib/actions.py | 27 ++-- pysollib/app.py | 8 +- pysollib/game.py | 8 +- pysollib/games/capricieuse.py | 4 +- pysollib/games/fortythieves.py | 10 +- pysollib/games/numerica.py | 5 + pysollib/games/royalcotillion.py | 19 ++- pysollib/pysolgtk/tkstats.py | 105 +++++++------- pysollib/stats.py | 197 ++++++++++++++++----------- pysollib/tile/progressbar.py | 3 +- pysollib/tile/tkconst.py | 4 +- pysollib/tile/tkstats.py | 227 ++++++++++--------------------- pysollib/tile/tktree.py | 4 +- pysollib/tk/tkstats.py | 205 +++++++++------------------- 15 files changed, 371 insertions(+), 459 deletions(-) diff --git a/po/ru_games.po b/po/ru_games.po index a8361fb1..419db16f 100644 --- a/po/ru_games.po +++ b/po/ru_games.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PySol 0.0.1\n" "POT-Creation-Date: Sat Oct 7 20:02:33 2006\n" -"PO-Revision-Date: 2006-10-07 20:10+0400\n" +"PO-Revision-Date: 2006-10-08 18:43+0400\n" "Last-Translator: Скоморох \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" @@ -1430,7 +1430,7 @@ msgid "Intelligence +" msgstr "Смекалка +" msgid "Interchange" -msgstr "Чередование" +msgstr "Перестановка" msgid "Interment" msgstr "Погребение" diff --git a/pysollib/actions.py b/pysollib/actions.py index 0358bbc8..54f85814 100644 --- a/pysollib/actions.py +++ b/pysollib/actions.py @@ -46,18 +46,16 @@ from settings import TOP_TITLE from gamedb import GI # stats imports -from stats import PysolStatsFormatter +from stats import FileStatsFormatter from pysoltk import SingleGame_StatsDialog, AllGames_StatsDialog from pysoltk import FullLog_StatsDialog, SessionLog_StatsDialog from pysoltk import Status_StatsDialog, Top_StatsDialog from pysoltk import GameInfoDialog # toolkit imports -from pysoltk import EVENT_HANDLED, EVENT_PROPAGATE from pysoltk import MfxMessageDialog, MfxSimpleEntry from pysoltk import MfxExceptionDialog from pysoltk import PlayerOptionsDialog -#from pysoltk import HintOptionsDialog from pysoltk import TimeoutsDialog from pysoltk import ColorsDialog from pysoltk import FontsDialog @@ -533,7 +531,7 @@ class PysolMenubarActions: # Game menu - statistics # - def _mStatsSave(self, player, header, filename, write_method): + def _mStatsSave(self, player, filename, write_method): file = None if player is None: text = _("Demo statistics") @@ -544,10 +542,8 @@ class PysolMenubarActions: filename = os.path.normpath(filename) try: file = open(filename, "a") - a = PysolStatsFormatter(self.app) - writer = a.FileWriter(file) - apply(write_method, (a, writer, player, header)) - destruct(a) + a = FileStatsFormatter(self.app, file) + write_method(a, player) except EnvError, ex: if file: file.close() d = MfxExceptionDialog(self.top, ex, @@ -597,19 +593,16 @@ class PysolMenubarActions: d = GameInfoDialog(self.top, header, self.app) elif mode == 202: # print stats to file - header = _("Statistics for ") + p0 - write_method = PysolStatsFormatter.writeStats - self._mStatsSave(player, header, "stats", write_method) + write_method = FileStatsFormatter.writeStats + self._mStatsSave(player, "stats", write_method) elif mode == 203: # print full log to file - header = _("Full log for ") + p0 - write_method = PysolStatsFormatter.writeFullLog - self._mStatsSave(player, header, "log", write_method) + write_method = FileStatsFormatter.writeFullLog + self._mStatsSave(player, "log", write_method) elif mode == 204: # print session log to file - header = _("Session log for ") + p0 - write_method = PysolStatsFormatter.writeSessionLog - self._mStatsSave(player, header, "log", write_method) + write_method = FileStatsFormatter.writeSessionLog + self._mStatsSave(player, "log", write_method) elif mode == 301: # reset all player stats if self.game.areYouSure(_("Reset all statistics"), diff --git a/pysollib/app.py b/pysollib/app.py index c1c8329f..6d73bbbb 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -143,10 +143,10 @@ class Options: 'startdrag' : True, 'turnwaste' : True, 'undo' : True, - 'gamefinished' : True, - 'gamelost' : True, - 'gameperfect' : True, - 'gamewon' : True, + 'gamefinished' : False, + 'gamelost' : False, + 'gameperfect' : False, + 'gamewon' : False, } # fonts self.fonts = {"default" : None, diff --git a/pysollib/game.py b/pysollib/game.py index b52018da..f5f77889 100644 --- a/pysollib/game.py +++ b/pysollib/game.py @@ -778,8 +778,6 @@ class Game: def _defaultHandler(self): self.interruptSleep() self.deleteStackDesc() - if self.demo: - self.stopDemo() def clickHandler(self, event): self._defaultHandler() @@ -789,6 +787,9 @@ class Game: def undoHandler(self, event): if not self.app: return EVENT_PROPAGATE # FIXME (GTK) self._defaultHandler() + if self.demo: + self.stopDemo() + return if self.app.opt.mouse_undo and not self.event_handled: self.app.menubar.mUndo() self.event_handled = False @@ -797,6 +798,9 @@ class Game: def redoHandler(self, event): if not self.app: return EVENT_PROPAGATE # FIXME (GTK) self._defaultHandler() + if self.demo: + self.stopDemo() + return if self.app.opt.mouse_undo and not self.event_handled: self.app.menubar.mRedo() self.event_handled = False diff --git a/pysollib/games/capricieuse.py b/pysollib/games/capricieuse.py index f3351ded..032391b1 100644 --- a/pysollib/games/capricieuse.py +++ b/pysollib/games/capricieuse.py @@ -132,7 +132,7 @@ class Strata(Game): for i in range(8): s.rows.append(AC_RowStack(x, y, self, max_move=1, max_accept=1)) x = x + l.XS - s.talon = RedealTalonStack(l.XM, l.YM, self, max_rounds=2) + s.talon = RedealTalonStack(l.XM, l.YM, self, max_rounds=3) # define stack-groups l.defaultStackGroups() @@ -157,6 +157,6 @@ registerGame(GameInfo(293, Nationale, "Nationale", GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 0, GI.SL_MOSTLY_SKILL, altnames=('Zigzag Course',) )) registerGame(GameInfo(606, Strata, "Strata", - GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 1, GI.SL_MOSTLY_SKILL, + GI.GT_BAKERS_DOZEN | GI.GT_OPEN, 2, 2, GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12) )) diff --git a/pysollib/games/fortythieves.py b/pysollib/games/fortythieves.py index 9115b21d..526f217e 100644 --- a/pysollib/games/fortythieves.py +++ b/pysollib/games/fortythieves.py @@ -693,18 +693,20 @@ class Octagon(Game): i = 0 for x, y in ((l.XM+w1, l.YM), (l.XM+w1+l.XS, l.YM), - (l.XM+w1-2*l.XS-l.XM, l.YM+l.YS), - (l.XM+w1-l.XS-l.XM, l.YM+l.YS), - (l.XM+w1+2*l.XS+l.XM, l.YM+l.YS), - (l.XM+w1+3*l.XS+l.XM, l.YM+l.YS), + (l.XM+w1-2*l.XS-l.XS/2-l.XM, l.YM+l.YS), + (l.XM+w1-l.XS-l.XS/2-l.XM, l.YM+l.YS), + (l.XM+w1+2*l.XS+l.XS/2+l.XM, l.YM+l.YS), + (l.XM+w1+3*l.XS+l.XS/2+l.XM, l.YM+l.YS), (l.XM+w1, l.YM+2*l.YS), (l.XM+w1+l.XS, l.YM+2*l.YS),): s.foundations.append(SS_FoundationStack(x, y, self, suit=i%4)) i += 1 x, y = l.XM+w1, l.YM+l.YS s.talon = WasteTalonStack(x, y, self, max_rounds=4) + l.createText(s.talon, 'nw') x += l.XS s.waste = WasteStack(x, y, self) + l.createText(s.waste, 'ne') l.defaultStackGroups() diff --git a/pysollib/games/numerica.py b/pysollib/games/numerica.py index 7497c5a6..e06a1edf 100644 --- a/pysollib/games/numerica.py +++ b/pysollib/games/numerica.py @@ -596,6 +596,10 @@ class Toad(Game): # // Shifting # ************************************************************************/ +class Shifting_Hint(Numerica_Hint): + shallMovePile = DefaultHint._cautiousShallMovePile + + class Shifting_RowStack(Numerica_RowStack): def acceptsCards(self, from_stack, cards): if not BasicRowStack.acceptsCards(self, from_stack, cards): @@ -611,6 +615,7 @@ class Shifting_RowStack(Numerica_RowStack): class Shifting(Numerica): + Hint_Class = Shifting_Hint RowStack_Class = StackWrapper(Shifting_RowStack, max_accept=1) diff --git a/pysollib/games/royalcotillion.py b/pysollib/games/royalcotillion.py index 0c1e134b..d11f2cff 100644 --- a/pysollib/games/royalcotillion.py +++ b/pysollib/games/royalcotillion.py @@ -415,10 +415,8 @@ class Carpet(Game): # // British Constitution # ************************************************************************/ -class BritishConstitution_RowStack(AC_RowStack): +class BritishConstitution_RowStackMethods: def acceptsCards(self, from_stack, cards): - if not AC_RowStack.acceptsCards(self, from_stack, cards): - return False if self in self.game.s.rows[:8] and from_stack in self.game.s.rows[8:16]: return True if self in self.game.s.rows[8:16] and from_stack in self.game.s.rows[16:24]: @@ -429,6 +427,18 @@ class BritishConstitution_RowStack(AC_RowStack): return True return False +class BritishConstitution_RowStack(BritishConstitution_RowStackMethods, AC_RowStack): + def acceptsCards(self, from_stack, cards): + if not AC_RowStack.acceptsCards(self, from_stack, cards): + return False + return BritishConstitution_RowStackMethods.acceptsCards(self, from_stack, cards) + +class NewBritishConstitution_RowStack(BritishConstitution_RowStackMethods, RK_RowStack): + def acceptsCards(self, from_stack, cards): + if not RK_RowStack.acceptsCards(self, from_stack, cards): + return False + return BritishConstitution_RowStackMethods.acceptsCards(self, from_stack, cards) + class BritishConstitution_Foundation(SS_FoundationStack): def acceptsCards(self, from_stack, cards): @@ -500,8 +510,7 @@ class BritishConstitution(Game): class NewBritishConstitution(BritishConstitution): - RowStack_Class = StackWrapper(BritishConstitution_RowStack, base_rank=JACK) - + RowStack_Class = StackWrapper(NewBritishConstitution_RowStack, base_rank=JACK) # /*********************************************************************** diff --git a/pysollib/pysolgtk/tkstats.py b/pysollib/pysolgtk/tkstats.py index 28e2281d..e2ff02fe 100644 --- a/pysollib/pysolgtk/tkstats.py +++ b/pysollib/pysolgtk/tkstats.py @@ -40,61 +40,71 @@ gettext = _ # // # ************************************************************************/ -class StatsWriter(PysolStatsFormatter.StringWriter): +class StatsFormatter(PysolStatsFormatter): - def __init__(self, store): + def __init__(self, app, store): + self.app = app 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 + def writeStats(self, player, sort_by='name'): + for result in self.getStatResults(player, sort_by): + iter = self.store.append(None) + self.store.set(iter, + 0, gettext(result[0]), + 1, result[1], + 2, result[2], + 3, result[3], + 4, result[4], + 5, result[5], + 6, result[6], + 7, result[7]) + total, played, won, lost, time, moves, perc = self.getStatSummary() + text = _("Total (%d out of %d games)") % (played, total) iter = self.store.append(None) self.store.set(iter, - 0, gettext(args[0]), - 1, args[1], - 2, args[2], - 3, args[3], - 4, args[4], - 5, args[5], - 6, args[6], - 7, gameid) + 0, text, + 1, won+lost, + 2, won, + 3, lost, + 4, time, + 5, moves, + 6, perc, + 7, -1) + return 1 -class LogWriter(PysolStatsFormatter.StringWriter): +class LogFormatter(PysolStatsFormatter): MAX_ROWS = 10000 - def __init__(self, store): + def __init__(self, app, store): + self.app = app self.store = store self._num_rows = 0 - def p(self, s): - pass + def writeLog(self, player, prev_games): + if not player or not prev_games: + return 0 + num_rows = 0 + for result in self.getLogResults(player, prev_games): + iter = self.store.append(None) + self.store.set(iter, + 0, gettext(result[0]), + 1, result[1], + 2, result[2], + 3, result[3], + 4, result[4]) + num_rows += 1 + if num_rows > self.MAX_ROWS: + break + return 1 - def pheader(self, s): - pass + def writeFullLog(self, player): + prev_games = self.app.stats.prev_games.get(player) + return self.writeLog(player, prev_games) - def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): - if gameid < 0: - # header - return - if self._num_rows > self.MAX_ROWS: - return - iter = self.store.append(None) - self.store.set(iter, - 0, gettext(gamename), - 1, gamenumber, - 2, date, - 3, status, - 4, gameid) - self._num_rows += 1 + def writeSessionLog(self, player): + prev_games = self.app.stats.session_games.get(player) + return self.writeLog(player, prev_games) class Game_StatsDialog: @@ -107,7 +117,6 @@ class Game_StatsDialog: self.games = {} self.games_id = [] # sorted by name # - formatter = PysolStatsFormatter(self.app) glade_file = app.dataloader.findFile('pysolfc.glade') # games = app.gdb.getGamesIdSortedByName() @@ -142,16 +151,16 @@ class Game_StatsDialog: self._updateTop(gameid) # all games stat store = self._createStatsList() - writer = StatsWriter(store) - formatter.writeStats(writer, player, header, sort_by='name') + formatter = StatsFormatter(app, store) + formatter.writeStats(player) # full log store = self._createLogList('full_log_treeview') - writer = LogWriter(store) - formatter.writeFullLog(writer, player, header) + formatter = LogFormatter(app, store) + formatter.writeFullLog(player) # session log store = self._createLogList('session_log_treeview') - writer = LogWriter(store) - formatter.writeSessionLog(writer, player, header) + formatter = LogFormatter(app, store) + formatter.writeSessionLog(player) # self._translateLabels() dialog = self.widgets_tree.get_widget('stats_dialog') diff --git a/pysollib/stats.py b/pysollib/stats.py index 65b311db..0fd6a6d2 100644 --- a/pysollib/stats.py +++ b/pysollib/stats.py @@ -38,69 +38,28 @@ import os, sys, time, types # PySol imports -from mfxutil import SubclassResponsibility, Struct, destruct from mfxutil import format_time from settings import PACKAGE, VERSION from gamedb import GI - -# // FIXME - this a quick hack and needs a rewrite - - # /*********************************************************************** # // # ************************************************************************/ class PysolStatsFormatter: - def __init__(self, app): - self.app = app - - # - # - # - - class StringWriter: - def __init__(self): - self.text = "" - - def p(self, s): - self.text = self.text + s - - def nl(self, count=1): - self.p("\n" * count) - - def pheader(self, s): - self.p(s) - - def pstats(self, *args, **kwargs): - s = "%-30s %7s %7s %7s %7s %7s %7s\n" % args - self.p(s) - - def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): - self.p("%-25s %-20s %17s %s\n" % (gamename, gamenumber, date, status)) - class FileWriter(StringWriter): - def __init__(self, file): - self.file = file + def getStatHeader(self): + return (_("Game"), + _("Played"), + _("Won"), + _("Lost"), + _('Playing time'), + _('Moves'), + _("% won")) - def p(self, s): - self.file.write(s.encode('utf-8')) - - # - # - # - - def writeHeader(self, writer, header, pagewidth=72): - date = time.ctime(time.time()) - date = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())) - blanks = max(pagewidth - len(header) - len(date), 1) - writer.pheader(header + " "*blanks + date + "\n") - writer.pheader("-" * pagewidth + "\n") - writer.pheader("\n") - - def writeStats(self, writer, player, header, sort_by='name'): + def getStatResults(self, player, sort_by='name'): app = self.app # sort_functions = { @@ -113,18 +72,8 @@ class PysolStatsFormatter: 'percent': app.getGamesIdSortedByPercent, } sort_func = sort_functions[sort_by] - - self.writeHeader(writer, header, 62) - writer.pstats(player or _("Demo games"), - _("Played"), - _("Won"), - _("Lost"), - _('Playing time'), - _('Moves'), - _("% won")) - writer.nl() - twon, tlost, tgames, ttime, tmoves = 0, 0, 0, 0, 0 g = sort_func() + twon, tlost, tgames, ttime, tmoves = 0, 0, 0, 0, 0 for id in g: name = app.getGameTitleName(id) #won, lost = app.stats.getStats(player, id) @@ -134,33 +83,43 @@ class PysolStatsFormatter: if won + lost > 0: perc = "%.1f" % (100.0 * won / (won + lost)) else: perc = "0.0" if won > 0 or lost > 0 or id == app.game.id: - #writer.pstats(name, won+lost, won, lost, perc, gameid=id) t = format_time(time) m = str(round(moves, 1)) - writer.pstats(name, won+lost, won, lost, t, m, perc, gameid=id) + yield [name, won+lost, won, lost, t, m, perc, id] tgames = tgames + 1 - writer.nl() won, lost = twon, tlost if won + lost > 0: if won > 0: - time = format_time(ttime/won) - moves = round(tmoves/won, 1) + time = format_time(ttime/tgames) + moves = round(tmoves/tgames, 1) else: time = format_time(0) moves = 0 perc = "%.1f" % (100.0*won/(won+lost)) else: perc = "0.0" - writer.pstats(_("Total (%d out of %d games)") % (tgames, len(g)), - won+lost, won, lost, time, moves, perc) - writer.nl(2) - return tgames + self.total_games = len(g) + self.played_games = tgames + self.won_games = won + self.lost_games = lost + self.avrg_time = time + self.avrg_moves = moves + self.percent = perc + #yield (_("Total (%d out of %d games)") % (tgames, len(g)), + # won+lost, won, lost, time, moves, perc, '') - def _writeLog(self, writer, player, header, prev_games): - if not player or not prev_games: - return 0 - self.writeHeader(writer, header, 71) - writer.plog(_("Game"), _("Game number"), _("Started at"), _("Status")) - writer.nl() + def getStatSummary(self): + return self.total_games, \ + self.played_games, \ + self.won_games, \ + self.lost_games, \ + self.avrg_time, \ + self.avrg_moves, \ + self.percent + + def getLogHeader(self): + return _("Game"), _("Game number"), _("Started at"), _("Status") + + def getLogResults(self, player, prev_games): twon, tlost = 0, 0 for pg in prev_games: if type(pg) is not types.TupleType: @@ -198,14 +157,88 @@ class PysolStatsFormatter: status = "*error*" if -2 <= pg[2] <= 2: status = (_("Loaded"), _("Not won"), _("Lost"), _("Won"), _("Perfect")) [pg[2]+2] - writer.plog(name, gamenumber, date, status, gameid=gameid, won=pg[2]) - writer.nl(2) + #writer.plog(name, gamenumber, date, status, gameid=gameid, won=pg[2]) + yield [name, gamenumber, date, status, pg[2], gameid] + + # + # + # + + def writeStats(self, player, sort_by='name'): + pass + def writeFullLog(self, player): + pass + def writeSessionLog(self, player): + pass + + +class FileStatsFormatter(PysolStatsFormatter): + + def __init__(self, app, file): + self.app = app + self.file = file + + def p(self, s): + self.file.write(s.encode('utf-8')) + + def nl(self, count=1): + self.p("\n" * count) + + def pheader(self, s): + self.p(s) + + def pstats(self, *args, **kwargs): + s = "%-30s %7s %7s %7s %7s %7s %7s\n" % args + self.p(s) + + def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): + self.p("%-25s %-20s %17s %s\n" % (gamename, gamenumber, date, status)) + + def writeHeader(self, header, pagewidth=72): + date = time.ctime(time.time()) + date = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())) + blanks = max(pagewidth - len(header) - len(date), 1) + self.pheader(header + " "*blanks + date + "\n") + self.pheader("-" * pagewidth + "\n") + self.pheader("\n") + + def writeStats(self, player, sort_by='name'): + header = _("Statistics for ") + player + self.writeHeader(header, 62) + header = self.getStatHeader() + self.pstats(*header) + self.nl() + for result in self.getStatResults(player, sort_by): + gameid = result.pop() + self.pstats(gameid=gameid, *result) + self.nl() + total, played, won, lost, time, moves, perc = self.getStatSummary() + self.pstats(_("Total (%d out of %d games)") % (played, total), + won+lost, won, lost, time, moves, perc) + self.nl(2) + return played + + def writeLog(self, player, header, prev_games): + if not player or not prev_games: + return 0 + self.writeHeader(header, 71) + header = self.getLogHeader() + self.plog(*header) + self.nl() + for result in self.getLogResults(player, prev_games): + gameid = result.pop() + won = result.pop() + self.plog(gameid=gameid, won=won, *result) + self.nl(2) return 1 - def writeFullLog(self, writer, player, header): + def writeFullLog(self, player): + header = _("Full log for ") + player prev_games = self.app.stats.prev_games.get(player) - return self._writeLog(writer, player, header, prev_games) + return self.writeLog(player, header, prev_games) - def writeSessionLog(self, writer, player, header): + def writeSessionLog(self, player): + header = _("Session log for ") + player prev_games = self.app.stats.session_games.get(player) - return self._writeLog(writer, player, header, prev_games) + return self.writeLog(player, header, prev_games) + diff --git a/pysollib/tile/progressbar.py b/pysollib/tile/progressbar.py index cb01eaaf..e8af51bb 100644 --- a/pysollib/tile/progressbar.py +++ b/pysollib/tile/progressbar.py @@ -112,7 +112,8 @@ class PysolProgressBar: return self.percent = min(100, max(0, self.percent)) self.progress.config(value=self.percent) - self.top.update_idletasks() + ##self.top.update_idletasks() + self.top.update() # /*********************************************************************** diff --git a/pysollib/tile/tkconst.py b/pysollib/tile/tkconst.py index ec3e405d..308ffd4a 100644 --- a/pysollib/tile/tkconst.py +++ b/pysollib/tile/tkconst.py @@ -54,7 +54,8 @@ __all__ = ['tkversion', # imports import sys, os -import Tile as Tkinter +import traceback +import Tkinter # Toolkit imports @@ -73,6 +74,7 @@ try: tkversion = tuple(m[:4]) del m except: + traceback.print_exc() pass # experimental diff --git a/pysollib/tile/tkstats.py b/pysollib/tile/tkstats.py index d0114c6f..f623f3d8 100644 --- a/pysollib/tile/tkstats.py +++ b/pysollib/tile/tkstats.py @@ -80,12 +80,7 @@ class SingleGame_StatsDialog(MfxDialog): self.top.wm_minsize(200, 200) self.button = kw.default # - ##createChart = self.create3DBarChart createChart = self.createPieChart - ##createChart = self.createSimpleChart -## if parent.winfo_screenwidth() < 800 or parent.winfo_screenheight() < 600: -## createChart = self.createPieChart -## createChart = self.createSimpleChart # self.font = self.app.getFont("default") self.tk_font = tkFont.Font(self.top, self.font) @@ -177,79 +172,6 @@ class SingleGame_StatsDialog(MfxDialog): c.create_text(x, ty[1]-dy, text="%d%%" % (100-pw), anchor="ne", font=tfont, fill=fg) -## def _createChart3DBar(self, canvas, perc, x, y, p, col): -## if perc < 0.005: -## return -## # translate and scale -## p = list(p[:]) -## for i in (0, 1, 2, 3): -## p[i] = (x + p[i][0], y + p[i][1]) -## j = i + 4 -## dx = int(round(p[j][0] * perc)) -## dy = int(round(p[j][1] * perc)) -## p[j] = (p[i][0] + dx, p[i][1] + dy) -## # draw rects -## def draw_rect(a, b, c, d, col, canvas=canvas, p=p): -## points = (p[a][0], p[a][1], p[b][0], p[b][1], -## p[c][0], p[c][1], p[d][0], p[d][1]) -## canvas.create_polygon(points, fill=col) -## draw_rect(0, 1, 5, 4, col[0]) -## draw_rect(1, 2, 6, 5, col[1]) -## draw_rect(4, 5, 6, 7, col[2]) -## # draw lines -## def draw_line(a, b, canvas=canvas, p=p): -## ##print a, b, p[a], p[b] -## canvas.create_line(p[a][0], p[a][1], p[b][0], p[b][1]) -## draw_line(0, 1) -## draw_line(1, 2) -## draw_line(0, 4) -## draw_line(1, 5) -## draw_line(2, 6) -## ###draw_line(3, 7) ## test -## draw_line(4, 5) -## draw_line(5, 6) -## draw_line(6, 7) -## draw_line(7, 4) - - - # - # charts - # - -## def createSimpleChart(self, app, won, lost, text): -## #c, tfont, fg = self._createChartInit(frame, 300, 100, text) -## self._createChartInit(300, 100, text) -## c, tfont, fg = self.canvas, self.font, self.fg -## # -## tx = (90, 180, 210) -## ty = (21, 41, 75) -## self._createChartTexts(tx, ty, won, lost) - -## def create3DBarChart(self, app, won, lost, text): -## image = app.gimages.stats[0] -## iw, ih = image.width(), image.height() -## #c, tfont, fg = self._createChartInit(frame, iw+160, ih, text) -## self._createChartInit(iw+160, ih, text) -## c, tfont, fg = self.canvas, self.font, self.fg -## pwon, plost = self._getPwon(won, lost) -## # -## tx = (iw+20, iw+110, iw+140) -## yy = ih/2 ## + 7 -## ty = (yy+21-46, yy+41-46, yy+75-46) -## # -## c.create_image(0, 7, image=image, anchor="nw") -## # -## p = ((0, 0), (44, 6), (62, -9), (20, -14), -## (-3, -118), (-1, -120), (-1, -114), (-4, -112)) -## col = ("#00ff00", "#008200", "#00c300") -## self._createChart3DBar(c, pwon, 102, 145+7, p, col) -## p = ((0, 0), (49, 6), (61, -10), (15, -15), -## (1, -123), (3, -126), (4, -120), (1, -118)) -## col = ("#ff0000", "#860400", "#c70400") -## self._createChart3DBar(c, plost, 216, 159+7, p, col) -## # -## self._createChartTexts(tx, ty, won, lost) -## c.create_text(tx[0], ty[0]-48, text=self.player, anchor="nw", font=tfont, fill=fg) def createPieChart(self, app, won, lost, text): #c, tfont, fg = self._createChartInit(frame, 300, 100, text) @@ -300,8 +222,11 @@ class SingleGame_StatsDialog(MfxDialog): # // # ************************************************************************/ -class TreeWriter(PysolStatsFormatter.StringWriter): - def __init__(self, tree, parent_window, font, w, h): +class TreeFormatter(PysolStatsFormatter): + MAX_ROWS = 10000 + + def __init__(self, app, tree, parent_window, font, w, h): + self.app = app self.tree = tree self.parent_window = parent_window self.font = font @@ -311,12 +236,6 @@ class TreeWriter(PysolStatsFormatter.StringWriter): self.w = w self.h = h - def p(self, s): - pass - - def pheader(self, s): - pass - def _calc_tabs(self, arg): if self.parent_window.tree_tabs: self._tabs = self.parent_window.tree_tabs @@ -331,57 +250,73 @@ class TreeWriter(PysolStatsFormatter.StringWriter): self._tabs.append(10) self.parent_window.tree_tabs = self._tabs - def pstats(self, *args, **kwargs): - header = False + def writeStats(self, player, sort_by='name'): + header = self.getStatHeader() if self._tabs is None: - # header - self._calc_tabs(args) - header = True + self._calc_tabs(header) + t1, t2, t3, t4, t5, t6, t7 = header + for column, text, anchor, tab in ( + ('#0', t1, 'nw', self._tabs[0]), + ('played', t2, 'ne', self._tabs[1]), + ('won', t3, 'ne', self._tabs[2]), + ('lost', t4, 'ne', self._tabs[3]), + ('time', t5, 'ne', self._tabs[4]), + ('moves', t6, 'ne', self._tabs[5]), + ('percent', t7, 'ne', self._tabs[6]), ): + self.tree.heading(column, text=text, + command=lambda par=self.parent_window, col=column: par.headerClick(col)) + self.tree.column(column, width=tab) - t1, t2, t3, t4, t5, t6, t7 = args - if not header: t1=gettext(t1) # game name - - if header: - for column, text, anchor, tab in ( - ('#0', t1, 'nw', self._tabs[0]), - ('played', t2, 'ne', self._tabs[1]), - ('won', t3, 'ne', self._tabs[2]), - ('lost', t4, 'ne', self._tabs[3]), - ('time', t5, 'ne', self._tabs[4]), - ('moves', t6, 'ne', self._tabs[5]), - ('percent', t7, 'ne', self._tabs[6]), ): - self.tree.heading(column, text=text, - command=lambda par=self.parent_window, col=column: par.headerClick(col)) - self.tree.column(column, width=tab) - else: + for result in self.getStatResults(player, sort_by): + t1, t2, t3, t4, t5, t6, t7, t8 = result + t1=gettext(t1) # game name id = self.tree.insert(None, "end", text=t1, values=(t2, t3, t4, t5, t6, t7)) self.parent_window.tree_items.append(id) - def plog(self, *args, **kwargs): - header = False + total, played, won, lost, time, moves, perc = self.getStatSummary() + text = _("Total (%d out of %d games)") % (played, total) + id = self.tree.insert(None, "end", text=text, + values=(won+lost, won, lost, time, moves, perc)) + self.parent_window.tree_items.append(id) + + return 1 + + def writeLog(self, player, prev_games): if self._tabs is None: - # header self._calc_tabs(('', '99999999999999999999', '9999-99-99 99:99', 'XXXXXXXXXXXX')) - header = True - - t1, t2, t3, t4 = args[:4] - if not header: t1=gettext(t1) # game name - - if header: - for column, text, anchor, tab in ( - ('#0', t1, 'nw', self._tabs[0]), - ('gamenumber', t2, 'ne', self._tabs[1]), - ('date', t3, 'ne', self._tabs[2]), - ('status', t4, 'ne', self._tabs[3]), ): - self.tree.heading(column, text=text, - command=lambda par=self.parent_window, col=column: par.headerClick(col)) - self.tree.column(column, width=tab) - ##if column in ('gamenumber', 'date', 'status'): - ## self.tree.column(column, anchor='center') - else: + header = self.getLogHeader() + t1, t2, t3, t4 = header + for column, text, anchor, tab in ( + ('#0', t1, 'nw', self._tabs[0]), + ('gamenumber', t2, 'ne', self._tabs[1]), + ('date', t3, 'ne', self._tabs[2]), + ('status', t4, 'ne', self._tabs[3]), ): + self.tree.heading(column, text=text, + command=lambda par=self.parent_window, col=column: par.headerClick(col)) + self.tree.column(column, width=tab) + ##if column in ('gamenumber', 'date', 'status'): + ## self.tree.column(column, anchor='center') + if not player or not prev_games: + return 0 + num_rows = 0 + for result in self.getLogResults(player, prev_games): + t1, t2, t3, t4, t5, t6 = result + t1=gettext(t1) # game name id = self.tree.insert(None, "end", text=t1, values=(t2, t3, t4)) self.parent_window.tree_items.append(id) + num_rows += 1 + if num_rows > self.MAX_ROWS: + break + return 1 + + def writeFullLog(self, player): + prev_games = self.app.stats.prev_games.get(player) + return self.writeLog(player, prev_games) + + def writeSessionLog(self, player): + prev_games = self.app.stats.session_games.get(player) + return self.writeLog(player, prev_games) # /*********************************************************************** @@ -467,14 +402,9 @@ class AllGames_StatsDialog(MfxDialog): if self.tree_items: self.tree.delete(tuple(self.tree_items)) self.tree_items = [] - a = PysolStatsFormatter(self.app) - writer = TreeWriter(self.tree, self, + formatter = TreeFormatter(self.app, self.tree, self, self.font, self.CHAR_W, self.CHAR_H) - if not a.writeStats(writer, player, header, sort_by=self.sort_by): - # FIXME - pass - destruct(writer) - destruct(a) + formatter.writeStats(player, sort_by=self.sort_by) # /*********************************************************************** @@ -487,13 +417,9 @@ class FullLog_StatsDialog(AllGames_StatsDialog): COLUMNS = ('gamenumber', 'date', 'status') def fillCanvas(self, player, header): - a = PysolStatsFormatter(self.app) - writer = TreeWriter(self.tree, self, self.font, - self.CHAR_W, self.CHAR_H) - if not a.writeFullLog(writer, player, header): - # FIXME - pass - destruct(a) + formatter = TreeFormatter(self.app, self.tree, self, self.font, + self.CHAR_W, self.CHAR_H) + formatter.writeFullLog(player) def initKw(self, kw): kw = KwStruct(kw, @@ -509,13 +435,9 @@ class FullLog_StatsDialog(AllGames_StatsDialog): class SessionLog_StatsDialog(FullLog_StatsDialog): def fillCanvas(self, player, header): - a = PysolStatsFormatter(self.app) - writer = TreeWriter(self.tree, self, self.font, - self.CHAR_W, self.CHAR_H) - if not a.writeSessionLog(writer, player, header): - # FIXME - pass - destruct(a) + formatter = TreeFormatter(self.app, self.tree, self, self.font, + self.CHAR_W, self.CHAR_H) + formatter.writeSessionLog(player) def initKw(self, kw): kw = KwStruct(kw, @@ -582,8 +504,7 @@ class _TopDialog(MfxDialog): self.createBitmaps(top_frame, kw) cnf = {'master': top_frame, - 'highlightthickness': 1, - 'highlightbackground': 'black', + 'padding': (4, 1), } frame = apply(Tkinter.Frame, (), cnf) frame.pack(expand=Tkinter.YES, fill=Tkinter.BOTH, padx=10, pady=10) @@ -654,9 +575,9 @@ class Top_StatsDialog(MfxDialog): app.stats.games_stats[player].has_key(gameid) and app.stats.games_stats[player][gameid].time_result.top): - Tkinter.Label(frame, text=_('Minimum')).grid(row=0, column=1) - Tkinter.Label(frame, text=_('Maximum')).grid(row=0, column=2) - Tkinter.Label(frame, text=_('Average')).grid(row=0, column=3) + Tkinter.Label(frame, text=_('Minimum')).grid(row=0, column=1, padx=4) + Tkinter.Label(frame, text=_('Maximum')).grid(row=0, column=2, padx=4) + Tkinter.Label(frame, text=_('Average')).grid(row=0, column=3, padx=4) ##Tkinter.Label(frame, text=_('Total')).grid(row=0, column=4) s = app.stats.games_stats[player][gameid] diff --git a/pysollib/tile/tktree.py b/pysollib/tile/tktree.py index 35599f68..fb092f5f 100644 --- a/pysollib/tile/tktree.py +++ b/pysollib/tile/tktree.py @@ -297,7 +297,9 @@ class MfxTreeInCanvas(MfxScrolledCanvas): # set scroll region bbox = self.canvas.bbox("all") ##self.canvas.config(scrollregion=bbox) - self.canvas.config(scrollregion=(0,0,bbox[2],bbox[3])) + ##self.canvas.config(scrollregion=(0,0,bbox[2],bbox[3])) + dx, dy = 8, 0 # margins + self.canvas.config(scrollregion=(-dx,-dy,bbox[2]+dx,bbox[3]+dy)) self.canvas.config(yscrollincrement=self.style.disty) def clear(self): diff --git a/pysollib/tk/tkstats.py b/pysollib/tk/tkstats.py index 0c699e56..58a842d4 100644 --- a/pysollib/tk/tkstats.py +++ b/pysollib/tk/tkstats.py @@ -299,8 +299,9 @@ class SingleGame_StatsDialog(MfxDialog): # // # ************************************************************************/ -class CanvasWriter(PysolStatsFormatter.StringWriter): - def __init__(self, canvas, parent_window, font, w, h): +class CanvasFormatter(PysolStatsFormatter): + def __init__(self, app, canvas, parent_window, font, w, h): + self.app = app self.canvas = canvas self.parent_window = parent_window ##self.fg = canvas.cget("insertbackground") @@ -308,7 +309,7 @@ class CanvasWriter(PysolStatsFormatter.StringWriter): self.font = font self.w = w self.h = h - self.x = self.y = 0 + #self.x = self.y = 0 self.gameid = None self.gamenumber = None self.canvas.config(yscrollincrement=h) @@ -317,26 +318,6 @@ class CanvasWriter(PysolStatsFormatter.StringWriter): def _addItem(self, id): self.canvas.dialog.nodes[id] = (self.gameid, self.gamenumber) - def p(self, s): - if self.y > 16000: - return - h1, h2 = 0, 0 - while s and s[0] == "\n": - s = s[1:] - h1 = h1 + self.h - while s and s[-1] == "\n": - s = s[:-1] - h2 = h2 + self.h - self.y = self.y + h1 - if s: - id = self.canvas.create_text(self.x, self.y, text=s, anchor="nw", - font=self.font, fill=self.fg) - self._addItem(id) - self.y = self.y + h2 - - def pheader(self, s): - pass - def _calc_tabs(self, arg): tw = 15*self.w ##tw = 160 @@ -347,59 +328,12 @@ class CanvasWriter(PysolStatsFormatter.StringWriter): self._tabs.append(tw) self._tabs.append(10) - def pstats(self, *args, **kwargs): - gameid=kwargs.get('gameid', None) - header = False - if self._tabs is None: - # header - header = True - self._calc_tabs(args) - self.gameid = 'header' - self.gamenumber = None -## if False: -## sort_by = ( 'name', 'played', 'won', 'lost', -## 'time', 'moves', 'percent', ) -## frame = Tkinter.Frame(self.canvas) -## i = 0 -## for t in args: -## w = self._tabs[i] -## if i == 0: -## w += 10 -## b = Tkinter.Button(frame, text=t) -## b.grid(row=0, column=i, sticky='ew') -## b.bind('<1>', lambda e, f=self.parent_window.rearrange, s=sort_by[i]: f(s)) -## frame.columnconfigure(i, minsize=w) -## i += 1 -## self.canvas.create_window(0, 0, window=frame, anchor='nw') -## self.y += 20 -## return -## if False: -## i = 0 -## x = 0 -## for t in args: -## w = self._tabs[i] -## h = 18 -## anchor = 'ne' -## y = 0 -## self.canvas.create_rectangle(x+2, y, x+w, y+h, width=1, -## fill="#00ff00", outline="#000000") -## x += w -## self.canvas.create_text(x-3, y+3, text=t, anchor=anchor) -## i += 1 -## self.y += 20 -## return - - else: - self.gameid = gameid - self.gamenumber = None - if self.y > 16000: - return - x, y = 1, self.y - p = self._pstats_text + def pstats(self, y, args, gameid=None): + x = 1 t1, t2, t3, t4, t5, t6, t7 = args - h = 0 - if not header: t1=gettext(t1) # game name - + self.gamenumber = None + if gameid is None: # header + self.gameid = 'header' for var, text, anchor, tab in ( ('name', t1, 'nw', self._tabs[0]+self._tabs[1]), ('played', t2, 'ne', self._tabs[2]), @@ -408,46 +342,13 @@ class CanvasWriter(PysolStatsFormatter.StringWriter): ('time', t5, 'ne', self._tabs[5]), ('moves', t6, 'ne', self._tabs[6]), ('percent', t7, 'ne', self._tabs[7]), ): - if header: self.gamenumber=var - h = max(h, p(x, y, anchor=anchor, text=text)) + if gameid is None: # header + self.gamenumber=var + id = self.canvas.create_text(x, y, text=text, anchor=anchor, + font=self.font, fill=self.fg) + self._addItem(id) x += tab - self.pstats_perc(x, y, t7) - self.y += h - self.gameid = None - return - -## h = max(h, p(x, y, anchor="nw", text=t1)) -## if header: self.gamenumber='played' -## x += self._tabs[0]+self._tabs[1] -## h = max(h, p(x, y, anchor="ne", text=t2)) -## if header: self.gamenumber='won' -## x += self._tabs[2] -## h = max(h, p(x, y, anchor="ne", text=t3)) -## if header: self.gamenumber='lost' -## x += self._tabs[3] -## h = max(h, p(x, y, anchor="ne", text=t4)) -## if header: self.gamenumber='time' -## x += self._tabs[4] -## h = max(h, p(x, y, anchor="ne", text=t5)) -## if header: self.gamenumber='moves' -## x += self._tabs[5] -## h = max(h, p(x, y, anchor="ne", text=t6)) -## if header: self.gamenumber='percent' -## x += self._tabs[6] -## h = max(h, p(x, y, anchor="ne", text=t7)) -## x += self._tabs[7] -## self.pstats_perc(x, y, t7) -## self.y += h -## self.gameid = None - - def _pstats_text(self, x, y, **kw): - kwdefault(kw, font=self.font, fill=self.fg) - id = apply(self.canvas.create_text, (x, y), kw) - self._addItem(id) - return self.h - ##bbox = self.canvas.bbox(id) - ##return bbox[3] - bbox[1] def pstats_perc(self, x, y, t): if not (t and "0" <= t[0] <= "9"): @@ -498,13 +399,51 @@ class CanvasWriter(PysolStatsFormatter.StringWriter): ix = ix + 8 p = max(0.0, p - 0.1) - def plog(self, gamename, gamenumber, date, status, gameid=-1, won=-1): - if gameid > 0 and "0" <= gamenumber[0:1] <= "9": - self.gameid = gameid - self.gamenumber = gamenumber - self.p("%-25s %-20s %17s %s\n" % (gamename, gamenumber, date, status)) - self.gameid = None - self.gamenumber = None + def writeStats(self, player, sort_by='name'): + header = self.getStatHeader() + y = 0 + if self._tabs is None: + self._calc_tabs(header) + self.pstats(y, header) + # + y += 2*self.h + for result in self.getStatResults(player, sort_by): + gameid = result.pop() + result[0]=gettext(result[0]) # game name + self.pstats(y, result, gameid) + y += self.h + # + y += self.h + total, played, won, lost, time, moves, perc = self.getStatSummary() + s = _("Total (%d out of %d games)") % (played, total) + self.pstats(y, (s, won+lost, won, lost, time, moves, perc)) + + def writeLog(self, player, prev_games): + y = 0 + header = self.getLogHeader() + t1, t2, t3, t4 = header + s = "%-25s %-20s %-17s %s" % header + id = self.canvas.create_text(1, y, text=s, anchor="nw", + font=self.font, fill=self.fg) + self._addItem(id) + y += 2*self.h + if not player or not prev_games: + return 0 + for result in self.getLogResults(player, prev_games): + result[0]=gettext(result[0]) # game name + s = "%-25s %-20s %-17s %s" % tuple(result[:4]) + id = self.canvas.create_text(1, y, text=s, anchor="nw", + font=self.font, fill=self.fg) + y += self.h + return 1 + + def writeFullLog(self, player): + prev_games = self.app.stats.prev_games.get(player) + return self.writeLog(player, prev_games) + + def writeSessionLog(self, player): + prev_games = self.app.stats.session_games.get(player) + return self.writeLog(player, prev_games) # /*********************************************************************** @@ -617,14 +556,9 @@ class AllGames_StatsDialog(MfxDialog): def fillCanvas(self, player, header): self.canvas.delete('all') self.nodes = {} - a = PysolStatsFormatter(self.app) - #print 'CHAR_W:', self.CHAR_W - writer = CanvasWriter(self.canvas, self, + writer = CanvasFormatter(self.app, self.canvas, self, self.font, self.CHAR_W, self.CHAR_H) - if not a.writeStats(writer, player, header, sort_by=self.sort_by): - writer.p(_("No entries for player ") + player + "\n") - destruct(writer) - destruct(a) + writer.writeStats(player, self.sort_by) # /*********************************************************************** @@ -636,11 +570,9 @@ class FullLog_StatsDialog(AllGames_StatsDialog): FONT_TYPE = "fixed" def fillCanvas(self, player, header): - a = PysolStatsFormatter(self.app) - writer = CanvasWriter(self.canvas, self, self.font, self.CHAR_W, self.CHAR_H) - if not a.writeFullLog(writer, player, header): - writer.p(_("No log entries for %s\n") % player) - destruct(a) + writer = CanvasFormatter(self.app, self.canvas, self, + self.font, self.CHAR_W, self.CHAR_H) + writer.writeFullLog(player) def initKw(self, kw): kw = KwStruct(kw, @@ -652,11 +584,10 @@ class FullLog_StatsDialog(AllGames_StatsDialog): class SessionLog_StatsDialog(FullLog_StatsDialog): def fillCanvas(self, player, header): - a = PysolStatsFormatter(self.app) - writer = CanvasWriter(self.canvas, self, self.font, self.CHAR_W, self.CHAR_H) - if not a.writeSessionLog(writer, player, header): - writer.p(_("No current session log entries for %s\n") % player) - destruct(a) + a = PysolStatsFormatter() + writer = CanvasFormatter(self.app, self.canvas, self, + self.font, self.CHAR_W, self.CHAR_H) + writer.writeSessionLog(player) def initKw(self, kw): kw = KwStruct(kw,