1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/tile/tkstats.py
skomoroh 890fa91e54 * migration to new ttk (tile) module: http://gpolo.ath.cx:81/projects/ttk_to_tkinter/
* minore improvements of pysolaudio.py

git-svn-id: file:///home/shlomif/Backup/svn-dumps/PySolFC/svnsync-repos/pysolfc/PySolFC/trunk@227 efabe8c0-fbe8-4139-b769-b5e6d273206e
2008-06-10 07:23:08 +00:00

1105 lines
41 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__ = ['SingleGame_StatsDialog',
'AllGames_StatsDialog',
'FullLog_StatsDialog',
'SessionLog_StatsDialog',
'Status_StatsDialog',
'Top_StatsDialog',
'ProgressionDialog',
]
# imports
import os
import time
import Tkinter
import ttk
import tkFont
# PySol imports
from pysollib.mfxutil import KwStruct
from pysollib.mfxutil import format_time
##from pysollib.util import *
from pysollib.stats import PysolStatsFormatter, ProgressionFormatter
from pysollib.settings import TOP_TITLE
# Toolkit imports
from tkutil import bind, unbind_destroy, loadImage
from tkwidget import MfxDialog, MfxMessageDialog
# /***********************************************************************
# //
# ************************************************************************/
class StatsDialog(MfxDialog):
SELECTED_TAB = 0
def __init__(self, parent, title, app, player, gameid, **kw):
kw = self.initKw(kw)
title = _('Statistics')
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
self.font = app.getFont('default')
self.tkfont = tkFont.Font(parent, self.font)
self.font_metrics = self.tkfont.metrics()
style = ttk.Style(parent)
heading_font = style.lookup('Heading', 'font') # treeview heading
self.heading_tkfont = tkFont.Font(parent, heading_font)
self.selected_game = None
top_frame, bottom_frame = self.createFrames(kw)
notebook = ttk.Notebook(top_frame)
notebook.pack(expand=True, fill='both', padx=10, pady=10)
self.notebook_tabs = []
single_frame = SingleGameFrame(self, notebook, app, player, gameid)
notebook.add(single_frame, text=_('Current game'))
self.notebook_tabs.append(single_frame._w)
all_frame = AllGamesFrame(self, notebook, app, player)
notebook.add(all_frame, text=_('All games'))
self.all_games_frame = all_frame
self.notebook_tabs.append(all_frame._w)
top_frame = TopFrame(self, notebook, app, player, gameid)
notebook.add(top_frame, text=TOP_TITLE)
self.notebook_tabs.append(top_frame._w)
if player is not None:
progr_frame = ProgressionFrame(self, notebook, app, player, gameid)
notebook.add(progr_frame, text=_('Progression'))
self.notebook_tabs.append(progr_frame._w)
if StatsDialog.SELECTED_TAB < len(self.notebook_tabs):
notebook.select(StatsDialog.SELECTED_TAB)
bind(notebook, '<<NotebookTabChanged>>', self.tabChanged)
##notebook.enableTraversal()
self.notebook = notebook
focus = self.createButtons(bottom_frame, kw)
self.tabChanged() # configure buttons state
self.mainloop(focus, kw.timeout)
def initKw(self, kw):
kw = KwStruct(kw,
strings=((_("&Play this game"), 401),
"sep", _("&OK"),
(_("&Reset..."), 500)),
default=0,
separator=False,
)
return MfxDialog.initKw(self, kw)
def tabChanged(self, *args):
w = self.notebook.select()
run_button = self.buttons[0]
indx = self.notebook_tabs.index(w)
if indx == 1: # "All games"
g = self.all_games_frame.getSelectedGame()
if g is None:
run_button.config(state='disabled')
else:
run_button.config(state='normal')
else:
run_button.config(state='disabled')
reset_button = self.buttons[2]
if indx in (0, 1): # "Current game" or "All games"
reset_button.config(state='normal')
else:
reset_button.config(state='disabled')
def mDone(self, button):
self.selected_game = self.all_games_frame.getSelectedGame()
w = self.notebook.select()
indx = self.notebook_tabs.index(w)
StatsDialog.SELECTED_TAB = indx
if button == 500: # "Reset..."
assert indx in (0, 1)
if indx == 0: # "Current game"
button = 302
else: # "All games"
button = 301
MfxDialog.mDone(self, button)
SingleGame_StatsDialog = AllGames_StatsDialog = Top_StatsDialog = ProgressionDialog = StatsDialog
# /***********************************************************************
# //
# ************************************************************************/
class SingleGameFrame(ttk.Frame):
def __init__(self, dialog, parent, app, player, gameid, **kw):
ttk.Frame.__init__(self, parent)
self.oval_width = 120
self.oval_height = 60
left_label = ttk.Label(self, image=app.gimages.logos[5])
left_label.pack(side='left', expand=True, fill='both')
self.right_frame = ttk.Frame(self)
self.right_frame.pack(side='right', expand=True)
self.dialog = dialog
self.app = app
self.parent = parent
self.player = player or _("Demo games")
#
self._calc_tabs()
#
won, lost = app.stats.getStats(player, gameid)
self.createPieChart(app, won, lost, _("Total"))
won, lost = app.stats.getSessionStats(player, gameid)
self.createPieChart(app, won, lost, _("Current session"))
#
#
# helpers
#
def _calc_tabs(self):
#
font = self.dialog.tkfont
t0 = self.oval_width+70
t = ''
for i in (_("Won:"),
_("Lost:"),
_("Total:")):
if len(i) > len(t):
t = i
t1 = font.measure(t)
## t1 = max(font.measure(_("Won:")),
## font.measure(_("Lost:")),
## font.measure(_("Total:")))
t1 += 10
##t2 = font.measure('99999')+10
t2 = 45
##t3 = font.measure('100%')+10
t3 = 45
tx = (t0, t0+t1+t2, t0+t1+t2+t3, t0+t1+t2+t3+20)
#
ls = self.dialog.font_metrics['linespace']
ls += 5
#ls = max(ls, 20)
ty = (5, 5+ls, 5+2*ls+15, max(85, 5+3*ls+15))
#
self.tab_x, self.tab_y = tx, ty
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 _createChartInit(self, text):
frame = ttk.LabelFrame(self.right_frame, text=text)
frame.pack(side='top', fill='both', expand=False, padx=20, pady=10)
style = ttk.Style(self.parent)
fg = style.lookup('.', 'foreground') or None # use default if fg == ''
bg = style.lookup('.', 'background') or None
self.fg = fg
#
w, h = self.tab_x[-1], max(self.tab_y[-1], self.oval_height+40)
c = Tkinter.Canvas(frame, width=w, height=h,
bg=bg, highlightthickness=0)
c.pack(fill='both', expand=True)
self.canvas = c
def _createChartTexts(self, tx, ty, won, lost):
c, tfont, fg = self.canvas, self.dialog.font, self.fg
pwon, plost = self._getPwon(won, lost)
#
x = tx[0]
dy = int(self.dialog.font_metrics['ascent']) - 10
dy = dy/2
c.create_text(x, ty[0]-dy, text=_("Won:"),
anchor="nw", font=tfont, fill=fg)
c.create_text(x, ty[1]-dy, text=_("Lost:"),
anchor="nw", font=tfont, fill=fg)
c.create_text(x, ty[2]-dy, text=_("Total:"),
anchor="nw", font=tfont, fill=fg)
x = tx[1] - 16
c.create_text(x, ty[0]-dy, text="%d" % won,
anchor="ne", font=tfont, fill=fg)
c.create_text(x, ty[1]-dy, text="%d" % lost,
anchor="ne", font=tfont, fill=fg)
c.create_text(x, ty[2]-dy, text="%d" % (won + lost),
anchor="ne", font=tfont, fill=fg)
y = ty[2] - 11
c.create_line(tx[0], y, x, y, fill=fg)
if won + lost > 0:
x = tx[2]
pw = int(round(100.0 * pwon))
c.create_text(x, ty[0]-dy, text="%d%%" % pw,
anchor="ne", font=tfont, fill=fg)
c.create_text(x, ty[1]-dy, text="%d%%" % (100-pw),
anchor="ne", font=tfont, fill=fg)
def createPieChart(self, app, won, lost, text):
#c, tfont, fg = self._createChartInit(frame, 300, 100, text)
#
self._createChartInit(text)
c, tfont, fg = self.canvas, self.dialog.font, self.fg
pwon, plost = self._getPwon(won, lost)
#
#tx = (160, 250, 280)
#ty = (21, 41, 75)
#
tx, ty = self.tab_x, self.tab_y
x0, y0 = 20, 10 # base coords
w = self.oval_width
h = self.oval_height
d = 9 # delta
if won + lost > 0:
##s, ewon, elost = 90.0, -360.0 * pwon, -360.0 * plost
s, ewon, elost = 0.0, 360.0 * pwon, 360.0 * plost
c.create_arc(x0, y0+d, x0+w, y0+h+d, fill="#007f00",
start=s, extent=ewon)
c.create_arc(x0, y0+d, x0+w, y0+h+d, fill="#7f0000",
start=s+ewon, extent=elost)
c.create_arc(x0, y0, x0+w, y0+h, fill="#00ff00",
start=s, extent=ewon)
c.create_arc(x0, y0, x0+w, y0+h, fill="#ff0000",
start=s+ewon, extent=elost)
x, y = tx[0] - 25, ty[0]
c.create_rectangle(x, y, x+10, y+10, fill="#00ff00")
y = ty[1]
c.create_rectangle(x, y, x+10, y+10, fill="#ff0000")
else:
c.create_oval(x0, y0+d, x0+w, y0+h+d, fill="#7f7f7f")
c.create_oval(x0, y0, x0+w, y0+h, fill="#f0f0f0")
c.create_text(x0+w/2, y0+h/2, text=_("No games"),
anchor="center", font=tfont, fill="#bfbfbf")
#
self._createChartTexts(tx, ty, won, lost)
# /***********************************************************************
# //
# ************************************************************************/
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.tkfont = font
self.gameid = None
self.gamenumber = None
self._tabs = None
self.w = w
self.h = h
def _calc_tabs(self, arg):
if self.parent_window.tree_tabs:
self._tabs = self.parent_window.tree_tabs
return
tw = 20*self.w
##tw = 160
self._tabs = [tw]
measure = self.tkfont.measure
for t in arg[1:]:
tw = measure(t)+8
self._tabs.append(tw)
self._tabs.append(10)
self.parent_window.tree_tabs = self._tabs
def createHeader(self, player, header):
i = 0
for column in ('#0',) + self.parent_window.COLUMNS:
text = header[i]
anchor = i == 0 and 'nw' or 'ne'
self.tree.heading(column, text=text,
command=lambda par=self.parent_window, col=column: par.headerClick(col))
self.tree.column(column, width=16)
i += 1
def resizeHeader(self, player, header, tree_width=0):
if self._tabs is not None:
return
self._calc_tabs(header)
# set first column width
if tree_width != 0:
tab = tree_width - sum(self._tabs[1:])
tab = min(tree_width, self._tabs[0])
else:
tab = self._tabs[0]
self.tree.column('#0', width=tab)
# other column
i = 1
for column in self.parent_window.COLUMNS:
tab = self._tabs[i]
self.tree.column(column, width=tab)
i += 1
def writeStats(self, player, sort_by='name'):
header = self.getStatHeader()
tree_width = self.tree.winfo_width()
self.resizeHeader(player, header, tree_width)
for result in self.getStatResults(player, sort_by):
# result == [name, won+lost, won, lost, time, moves, perc, id]
t1, t2, t3, t4, t5, t6, t7, t8 = result
id = self.tree.insert("", "end", text=t1,
values=(t2, t3, t4, t5, t6, t7))
self.parent_window.tree_items.append(id)
self.parent_window.games[id] = t8
total, played, won, lost, time_, moves, perc = self.getStatSummary()
text = _("Total (%d out of %d games)") % (played, total)
id = self.tree.insert("", "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 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
id = self.tree.insert("", "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)
# /***********************************************************************
# //
# ************************************************************************/
class AllGamesFrame(ttk.Frame):
COLUMNS = ('played', 'won', 'lost', 'time', 'moves', 'percent')
def __init__(self, dialog, parent, app, player, **kw):
ttk.Frame.__init__(self, parent)
#
self.dialog = dialog
self.app = app
self.CHAR_H = self.dialog.font_metrics['linespace']
self.CHAR_W = self.dialog.tkfont.measure('M')
#
self.player = player
self.sort_by = 'name'
self.tree_items = []
self.tree_tabs = None
self.games = {} # tree_itemid: gameid
#
frame = ttk.Frame(self)
frame.pack(fill='both', expand=True, padx=10, pady=10)
vsb = ttk.Scrollbar(frame)
vsb.grid(row=0, column=1, sticky='ns')
self.tree = ttk.Treeview(frame, columns=self.COLUMNS,
selectmode='browse')
self.tree.grid(row=0, column=0, sticky='nsew')
self.tree.config(yscrollcommand=vsb.set)
vsb.config(command=self.tree.yview)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
hsb = ttk.Scrollbar(frame, orient='horizontal')
hsb.grid(row=1, column=0, sticky='ew')
self.tree.config(xscrollcommand=hsb.set)
hsb.config(command=self.tree.xview)
bind(self.tree, '<<TreeviewSelect>>', self.treeviewSelected)
#
self.formatter = TreeFormatter(self.app, self.tree, self,
self.dialog.heading_tkfont,
self.CHAR_W, self.CHAR_H)
self.createHeader(player)
bind(self.tree, '<Map>', self.mapEvent)
def getSelectedGame(self):
sel = self.tree.selection()
if sel and len(sel) == 1:
if sel[0] in self.games:
return self.games[sel[0]]
return None
def treeviewSelected(self, *args):
sel = self.tree.selection()
run_button = self.dialog.buttons[0]
if sel and len(sel) == 1:
if sel[0] not in self.games: # "Total"
run_button.config(state='disabled')
else:
run_button.config(state='normal')
else:
run_button.config(state='disabled')
def mapEvent(self, *args):
if not self.tree_items:
self.fillTreeview(self.player)
def headerClick(self, column):
if column == '#0':
sort_by = 'name'
else:
sort_by = column
if self.sort_by == sort_by: return
self.sort_by = sort_by
self.fillTreeview(self.player)
def createHeader(self, player):
header = self.formatter.getStatHeader()
self.formatter.createHeader(player, header)
def fillTreeview(self, player):
if self.tree_items:
self.tree.delete(tuple(self.tree_items))
self.tree_items = []
self.formatter.writeStats(player, sort_by=self.sort_by)
if self.dialog.buttons:
run_button = self.dialog.buttons[0]
run_button.config(state='disabled')
# /***********************************************************************
# //
# ************************************************************************/
class LogDialog(MfxDialog):
SELECTED_TAB = 0
def __init__(self, parent, title, app, player, **kw):
self.font = app.getFont('default')
self.tkfont = tkFont.Font(parent, self.font)
style = ttk.Style(parent)
heading_font = style.lookup('Heading', 'font') # treeview heading
self.heading_tkfont = tkFont.Font(parent, heading_font)
self.font_metrics = self.tkfont.metrics()
self.CHAR_H = self.font_metrics['linespace']
self.CHAR_W = self.tkfont.measure('M')
kw = self.initKw(kw)
title = _('Log')
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
##self.selected_game = None
top_frame, bottom_frame = self.createFrames(kw)
notebook = ttk.Notebook(top_frame)
notebook.pack(expand=True, fill='both', padx=10, pady=10)
self.notebook_tabs = []
full_frame = FullLogFrame(self, notebook, app, player)
notebook.add(full_frame, text=_('Full log'))
self.notebook_tabs.append(full_frame._w)
session_frame = SessionLogFrame(self, notebook, app, player)
notebook.add(session_frame, text=_('Session log'))
self.notebook_tabs.append(session_frame._w)
notebook.select(LogDialog.SELECTED_TAB)
## bind(notebook, '<<NotebookTabChanged>>', self.tabChanged)
self.notebook = notebook
focus = self.createButtons(bottom_frame, kw)
##self.tabChanged() # configure buttons state
self.mainloop(focus, kw.timeout)
def initKw(self, kw):
kw = KwStruct(kw,
strings=(_("&OK"),
(_("&Save to file"), 500)),
default=0,
width=76*self.CHAR_W,
separator=False,
)
return MfxDialog.initKw(self, kw)
def mDone(self, button):
##self.selected_game = self.all_games_frame.getSelectedGame()
w = self.notebook.select()
indx = self.notebook_tabs.index(w)
LogDialog.SELECTED_TAB = indx
if button == 500: # "Save to file"
assert indx in (0, 1)
if indx == 0: # "Full log"
button = 203
else: # "Session log"
button = 204
MfxDialog.mDone(self, button)
FullLog_StatsDialog = SessionLog_StatsDialog = LogDialog
# /***********************************************************************
# //
# ************************************************************************/
class FullLogFrame(AllGamesFrame):
COLUMNS = ('gamenumber', 'date', 'status')
def __init__(self, dialog, parent, app, player, **kw):
AllGamesFrame.__init__(self, dialog, parent, app, player, **kw)
header = ('', '99999999999999999999', '9999-99-99 99:99',
'XXXXXXXXXXXX')
self.formatter.resizeHeader(player, header)
def createHeader(self, player):
header = self.formatter.getLogHeader()
self.formatter.createHeader(player, header)
def fillTreeview(self, player):
if self.tree_items:
return
self.formatter.writeFullLog(player)
def treeviewSelected(self, *args):
pass
def headerClick(self, column):
pass
class SessionLogFrame(FullLogFrame):
def fillTreeview(self, player):
if self.tree_items:
return
self.formatter.writeSessionLog(player)
# /***********************************************************************
# //
# ************************************************************************/
class Status_StatsDialog(MfxMessageDialog):
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=((_("&Statistics..."), 101),
'sep',
_("&OK")),
image=game.app.gimages.logos[3],
image_side="left", image_padx=20,
padx=20,
)
# /***********************************************************************
# //
# ************************************************************************/
class _TopDialog(MfxDialog):
def __init__(self, parent, title, app, gameid, top, **kw):
kw = self.initKw(kw)
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
top_frame, bottom_frame = self.createFrames(kw)
self.createBitmaps(top_frame, kw)
cnf = {'master': top_frame,
'padding': (4, 1),
}
frame = ttk.Frame(**cnf)
frame.pack(expand=True, fill='both', padx=10, pady=10)
frame.columnconfigure(0, weight=1)
cnf['master'] = frame
cnf['text'] = _('N')
l = ttk.Label(**cnf)
l.grid(row=0, column=0, sticky='ew')
if gameid == 'all':
cnf['text'] = _('Game')
l = ttk.Label(**cnf)
l.grid(row=0, column=1, sticky='ew')
cnf['text'] = _('Game number')
l = ttk.Label(**cnf)
l.grid(row=0, column=2, sticky='ew')
cnf['text'] = _('Started at')
l = ttk.Label(**cnf)
l.grid(row=0, column=3, sticky='ew')
cnf['text'] = _('Result')
l = ttk.Label(**cnf)
l.grid(row=0, column=4, sticky='ew')
row = 1
for i in top:
# N
cnf['text'] = str(row)
l = ttk.Label(**cnf)
l.grid(row=row, column=0, sticky='ew')
if gameid == 'all':
name = app.getGameTitleName(i.gameid)
if name is None:
name = _("** UNKNOWN %d **") % i.gameid
cnf['text'] = name
l = ttk.Label(**cnf)
l.grid(row=row, column=1, sticky='ew')
# Game number
cnf['text'] = '#'+str(i.game_number)
l = ttk.Label(**cnf)
l.grid(row=row, column=2, sticky='ew')
# Start time
t = time.strftime('%Y-%m-%d %H:%M', time.localtime(i.game_start_time))
cnf['text'] = t
l = ttk.Label(**cnf)
l.grid(row=row, column=3, sticky='ew')
# Result
if isinstance(i.value, float):
# time
s = format_time(i.value)
else:
# moves
s = str(i.value)
cnf['text'] = s
l = ttk.Label(**cnf)
l.grid(row=row, column=4, sticky='ew')
row += 1
focus = self.createButtons(bottom_frame, kw)
self.mainloop(focus, kw.timeout)
def initKw(self, kw):
kw = KwStruct(kw, strings=(_('&OK'),), default=0, separator=True)
return MfxDialog.initKw(self, kw)
class TopFrame(ttk.Frame):
def __init__(self, dialog, parent, app, player, gameid):
ttk.Frame.__init__(self, parent)
self.app = app
self.dialog = dialog
left_label = ttk.Label(self, image=app.gimages.logos[5])
left_label.pack(side='left', expand=True, fill='both')
frame = ttk.LabelFrame(self, text=_('Current game'),
padding=(10,5,10,10))
frame.pack(side='top', expand=True, fill='x', padx=10, pady=10)
##frame.columnconfigure(0, weight=1)
if not self.createTopFrame(frame, player, gameid):
ttk.Label(frame, text=_('No TOP for this game')
).pack(padx=10, pady=10)
frame = ttk.LabelFrame(self, text=_('All games'),
padding=(10,5,10,10))
frame.pack(side='top', expand=True, fill='x', padx=10, pady=10)
##frame.columnconfigure(0, weight=1)
if not self.createTopFrame(frame, player, 'all'):
ttk.Label(frame, text=_('No TOP for all games')
).pack(padx=10, pady=10)
def createTopFrame(self, frame, player, gameid):
app = self.app
if (player not in app.stats.games_stats or
gameid not in app.stats.games_stats[player] or
not app.stats.games_stats[player][gameid].time_result.top):
return False
ttk.Label(frame, text=_('Minimum')
).grid(row=0, column=1, padx=5, pady=5)
ttk.Label(frame, text=_('Maximum')
).grid(row=0, column=2, padx=5, pady=5)
ttk.Label(frame, text=_('Average')
).grid(row=0, column=3, padx=5, pady=5)
##ttk.Label(frame, text=_('Total')).grid(row=0, column=4)
s = app.stats.games_stats[player][gameid]
row = 1
ll = [
(_('Playing time:'),
format_time(s.time_result.min),
format_time(s.time_result.max),
format_time(s.time_result.average),
format_time(s.time_result.total),
s.time_result.top,
),
(_('Moves:'),
s.moves_result.min,
s.moves_result.max,
round(s.moves_result.average, 2),
s.moves_result.total,
s.moves_result.top,
),
(_('Total moves:'),
s.total_moves_result.min,
s.total_moves_result.max,
round(s.total_moves_result.average, 2),
s.total_moves_result.total,
s.total_moves_result.top,
),
]
## if s.score_result.min:
## ll.append(('Score:',
## s.score_result.min,
## s.score_result.max,
## round(s.score_result.average, 2),
## s.score_result.top,
## ))
## if s.score_casino_result.min:
## ll.append(('Casino Score:',
## s.score_casino_result.min,
## s.score_casino_result.max,
## round(s.score_casino_result.average, 2), ))
for l, min, max, avr, tot, top in ll:
ttk.Label(frame, text=l
).grid(row=row, column=0, padx=5, pady=5)
ttk.Label(frame, text=str(min)
).grid(row=row, column=1, padx=5, pady=5)
ttk.Label(frame, text=str(max)
).grid(row=row, column=2, padx=5, pady=5)
ttk.Label(frame, text=str(avr)
).grid(row=row, column=3, padx=5, pady=5)
##ttk.Label(frame, text=str(tot)).grid(row=row, column=4)
def command(gameid=gameid, top=top):
self.showTop(gameid, top)
b = ttk.Button(frame, text=TOP_TITLE+' ...',
width=10, command=command)
b.grid(row=row, column=5)
row += 1
return True
def showTop(self, gameid, top):
d = _TopDialog(self.dialog.top, TOP_TITLE, self.app, gameid, top)
# /***********************************************************************
# //
# ************************************************************************/
class ProgressionFrame(ttk.Frame):
def __init__(self, dialog, parent, app, player, gameid, **kw):
ttk.Frame.__init__(self, parent)
self.mapped = False
self.dialog = dialog
self.app = app
self.player = player
self.gameid = gameid
self.items = []
self.formatter = ProgressionFormatter(app, player, gameid)
frame = ttk.Frame(self)
frame.pack(expand=True, fill='both', padx=5, pady=10)
frame.columnconfigure(0, weight=1)
# constants
w = dialog.tkfont.measure('M') * 42
w = max(w, 500)
w = min(w, 600)
self.canvas_width, self.canvas_height = w, 250
if parent.winfo_screenwidth() < 800 or \
parent.winfo_screenheight() < 600:
self.canvas_width, self.canvas_height = 400, 200
self.xmargin, self.ymargin = 10, 10
self.graph_dx, self.graph_dy = 10, 10
self.played_color = '#ff7ee9'
self.won_color = '#00dc28'
self.percent_color = 'blue'
# create canvas
self.canvas = canvas = Tkinter.Canvas(frame, bg='#dfe8ff', bd=0,
highlightthickness=1,
highlightbackground='black',
width=self.canvas_width,
height=self.canvas_height)
canvas.pack(side='left', padx=5)
# right frame
right_frame = ttk.Frame(frame)
right_frame.pack(side='left', fill='x', padx=5)
self.all_games_variable = var = Tkinter.StringVar()
var.set('all')
b = ttk.Radiobutton(right_frame, text=_('All games'),
variable=var, value='all',
command=self.updateGraph)
b.pack(fill='x', expand=True, padx=3, pady=1)
b = ttk.Radiobutton(right_frame, text=_('Current game'),
variable=var, value='current',
command=self.updateGraph)
b.pack(fill='x', expand=True, padx=3, pady=1)
label_frame = ttk.LabelFrame(right_frame, text=_('Statistics for'))
label_frame.pack(side='top', fill='x', pady=10)
self.variable = var = Tkinter.StringVar()
var.set('week')
for v, t in (
('week', _('Last 7 days')),
('month', _('Last month')),
('year', _('Last year')),
('all', _('All time')),
):
b = ttk.Radiobutton(label_frame, text=t, variable=var,
value=v, command=self.updateGraph)
b.pack(fill='x', expand=True, padx=3, pady=1)
label_frame = ttk.LabelFrame(right_frame, text=_('Show graphs'))
label_frame.pack(side='top', fill='x')
self.played_graph_var = Tkinter.BooleanVar()
self.played_graph_var.set(True)
b = ttk.Checkbutton(label_frame, text=_('Played'),
command=self.updateGraph,
variable=self.played_graph_var)
b.pack(fill='x', expand=True, padx=3, pady=1)
self.won_graph_var = Tkinter.BooleanVar()
self.won_graph_var.set(True)
b = ttk.Checkbutton(label_frame, text=_('Won'),
command=self.updateGraph,
variable=self.won_graph_var)
b.pack(fill='x', expand=True, padx=3, pady=1)
self.percent_graph_var = Tkinter.BooleanVar()
self.percent_graph_var.set(True)
b = ttk.Checkbutton(label_frame, text=_('% won'),
command=self.updateGraph,
variable=self.percent_graph_var)
b.pack(fill='x', expand=True, padx=3, pady=1)
#self.createGraph()
bind(canvas, '<Map>', self.createGraph)
def createGraph(self, event):
if self.mapped:
return
self.mapped = True
canvas = self.canvas
self.text_height = self.dialog.font_metrics['linespace']
measure = self.dialog.tkfont.measure
self.text_width_1 = measure('XX.XX')
self.text_width_2 = measure('XX.XX.XX')
dir = os.path.join('images', 'stats')
try:
fn = self.app.dataloader.findImage('progression', dir)
self.bg_image = loadImage(fn)
canvas.create_image(0, 0, image=self.bg_image, anchor='nw')
except:
pass
#
tw = max(measure(_('Games/day')),
measure(_('Games/week')),
measure(_('% won')))
self.left_margin = self.xmargin+tw/2
self.right_margin = self.xmargin+tw/2
self.top_margin = 15+self.text_height
self.bottom_margin = 15+self.text_height+10+self.text_height
#
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
canvas.create_rectangle(x0, y0, x1, y1, fill='white')
# horizontal axis
canvas.create_line(x0, y0, x1, y0, width=3)
# left vertical axis
canvas.create_line(x0, y0, x0, y1, width=3)
t = _('Games/day')
self.games_text_id = canvas.create_text(x0-4, y1-4, anchor='s', text=t)
# right vertical axis
canvas.create_line(x1, y0, x1, y1, width=3)
canvas.create_text(x1+4, y1-4, anchor='s', text=_('% won'))
# caption
d = self.text_height
x, y = self.xmargin, self.canvas_height-self.ymargin
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
fill=self.played_color)
x += d+5
canvas.create_text(x, y, anchor='sw', text=_('Played'))
x += measure(_('Played'))+20
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
fill=self.won_color)
x += d+5
canvas.create_text(x, y, anchor='sw', text=_('Won'))
x += measure(_('Won'))+20
id = canvas.create_rectangle(x, y, x+d, y-d, outline='black',
fill=self.percent_color)
x += d+5
canvas.create_text(x, y, anchor='sw', text=_('% won'))
self.updateGraph()
def updateGraph(self, *args):
interval = self.variable.get()
canvas = self.canvas
if self.items:
canvas.delete(*self.items)
self.items = []
all_games = (self.all_games_variable.get() == 'all')
result = self.formatter.getResults(interval, all_games)
if interval in ('week', 'month'):
t = _('Games/day')
else:
t = _('Games/week')
canvas.itemconfig(self.games_text_id, text=t)
graph_width = self.canvas_width-self.left_margin-self.right_margin
graph_height = self.canvas_height-self.top_margin-self.bottom_margin
dx = (graph_width-2*self.graph_dx)/(len(result)-1)
graph_dx = (graph_width-(len(result)-1)*dx)/2
dy = (graph_height-self.graph_dy)/5
x0, y0 = self.left_margin, self.canvas_height-self.bottom_margin
x1, y1 = self.canvas_width-self.right_margin, self.top_margin
td = self.text_height/2
# vertical scale
x = x0+graph_dx
xx = -100 # coord. of prev. text
for res in result:
text = res[0]
text_width = 0
if text is not None:
if len(text) == 5: # day.month
text_width = self.text_width_1
else: # day.month.year
text_width = self.text_width_2
if text is not None and x > xx+text_width+4:
##id = canvas.create_line(x, y0, x, y0-5, width=3)
##self.items.append(id)
id = canvas.create_line(x, y0, x, y1, stipple='gray50')
self.items.append(id)
id = canvas.create_text(x, y0+td, anchor='n', text=text)
self.items.append(id)
xx = x
else:
id = canvas.create_line(x, y0, x, y0-3, width=1)
self.items.append(id)
x += dx
# horizontal scale
max_games = max([i[1] for i in result])
games_delta = max_games/5+1
percent = 0
games = 0
for y in range(y0, y1, -dy):
if y != y0:
id = canvas.create_line(x0, y, x1, y, stipple='gray50')
self.items.append(id)
id = canvas.create_text(x0-td, y, anchor='e', text=str(games))
self.items.append(id)
id = canvas.create_text(x1+td, y, anchor='w', text=str(percent))
self.items.append(id)
games += games_delta
percent += 20
# draw result
games_resolution = float(dy)/games_delta
percent_resolution = float(dy)/20
played_coords = []
won_coords = []
percent_coords = []
x = x0+graph_dx
for res in result:
played, won = res[1], res[2]
y = y0 - int(games_resolution*played)
played_coords += [x,y]
y = y0 - int(games_resolution*won)
won_coords += [x,y]
if played > 0:
percent = int(100.*won/played)
else:
percent = 0
y = y0 - int(percent_resolution*percent)
percent_coords += [x,y]
x += dx
if self.played_graph_var.get():
id = canvas.create_line(fill=self.played_color, width=3,
*played_coords)
self.items.append(id)
if self.won_graph_var.get():
id = canvas.create_line(fill=self.won_color, width=3,
*won_coords)
self.items.append(id)
if self.percent_graph_var.get():
id = canvas.create_line(fill=self.percent_color, width=3,
*percent_coords)
self.items.append(id)