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


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

547 lines
20 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
##
##---------------------------------------------------------------------------##
# imports
import os, re, sys, types
import gtk, gobject
#from UserList import UserList
# PySol imports
from pysollib.mfxutil import destruct, Struct, KwStruct
from pysollib.mfxutil import kwdefault
from pysollib.mfxutil import format_time
from pysollib.gamedb import GI
from pysollib.help import help_html
from pysollib.resource import CSI
# Toolkit imports
from tkutil import unbind_destroy
from tkwidget import MfxDialog
from tkcanvas import MfxCanvas, MfxCanvasText
from pysoltree import PysolTreeView
gettext = _
# /***********************************************************************
# // Dialog
# ************************************************************************/
class SelectGameDialogWithPreview(MfxDialog):
#Tree_Class = SelectGameTreeWithPreview
game_store = None
#
_paned_position = 300
_expanded_rows = []
_geometry = None
_selected_row = None
_vadjustment_position = None
def __init__(self, parent, title, app, gameid, bookmark=None, **kw):
kw = self.initKw(kw)
MfxDialog.__init__(self, parent, title, **kw)
#
self.app = app
self.gameid = gameid
self.bookmark = bookmark
self.random = None
#
if self.game_store is None:
self.createGameStore()
#
top_box, bottom_box = self.createHBox()
# paned
hpaned = gtk.HPaned()
self.hpaned = hpaned
hpaned.show()
top_box.pack_start(hpaned, expand=True, fill=True)
# left
self.treeview = PysolTreeView(self, self.game_store)
hpaned.pack1(self.treeview.scrolledwindow, True, True)
# right
table = gtk.Table(2, 2, False)
table.show()
hpaned.pack2(table, True, True)
# frames
frame = gtk.Frame(label=_('About game'))
frame.show()
table.attach(frame,
0, 1, 0, 1,
gtk.FILL, gtk.FILL,
0, 0)
frame.set_border_width(4)
info_frame = gtk.Table(2, 7, False)
info_frame.show()
frame.add(info_frame)
info_frame.set_border_width(4)
#
frame = gtk.Frame(label=_('Statistics'))
frame.show()
table.attach(frame,
1, 2, 0, 1,
gtk.FILL, gtk.FILL,
0, 0)
frame.set_border_width(4)
stats_frame = gtk.Table(2, 6, False)
stats_frame.show()
frame.add(stats_frame)
stats_frame.set_border_width(4)
# info
self.info_labels = {}
i = 0
for n, t, f, row in (
('name', _('Name:'), info_frame, 0),
('altnames', _('Alternate names:'), info_frame, 1),
('category', _('Category:'), info_frame, 2),
('type', _('Type:'), info_frame, 3),
('skill_level', _('Skill level:'), info_frame, 4),
('decks', _('Decks:'), info_frame, 5),
('redeals', _('Redeals:'), info_frame, 6),
#
('played', _('Played:'), stats_frame, 0),
('won', _('Won:'), stats_frame, 1),
('lost', _('Lost:'), stats_frame, 2),
('time', _('Playing time:'), stats_frame, 3),
('moves', _('Moves:'), stats_frame, 4),
('percent', _('% won:'), stats_frame, 5),
):
title_label = gtk.Label()
title_label.show()
title_label.set_text(t)
title_label.set_alignment(0., 0.)
title_label.set_property('xpad', 2)
title_label.set_property('ypad', 2)
f.attach(title_label,
0, 1, row, row+1,
gtk.FILL, 0,
0, 0)
text_label = gtk.Label()
text_label.show()
text_label.set_alignment(0., 0.)
text_label.set_property('xpad', 2)
text_label.set_property('ypad', 2)
f.attach(text_label,
1, 2, row, row+1,
gtk.FILL, 0,
0, 0)
self.info_labels[n] = (title_label, text_label)
# canvas
self.preview = MfxCanvas(self)
self.preview.show()
table.attach(self.preview,
0, 2, 1, 2,
gtk.EXPAND|gtk.FILL|gtk.SHRINK, gtk.EXPAND|gtk.FILL|gtk.SHRINK,
0, 0)
self.preview.set_border_width(4)
self.preview.setTile(app, app.tabletile_index, force=True)
# set the scale factor
self.preview.preview = 2
# create a preview of the current game
self.preview_key = -1
self.preview_game = None
self.preview_app = None
##~ self.updatePreview(gameid, animations=0)
##~ SelectGameTreeWithPreview.html_viewer = None
self.connect('unrealize', self._unrealizeEvent)
self.createButtons(bottom_box, kw)
self._restoreSettings()
self.show_all()
gtk.main()
def _addGamesFromData(self, data, store, root_iter, root_label, all_games):
gl = []
for label, selecter in data:
games = self._selectGames(all_games, selecter)
if games:
gl.append((label, games))
if not gl:
return
iter = store.append(root_iter)
store.set(iter, 0, root_label, 1, -1)
for label, games in gl:
label = gettext(label)
label = label.replace("&", "")
self._addGames(store, iter, label, games)
def _addGames(self, store, root_iter, root_label, games):
if not games:
return
iter = store.append(root_iter)
store.set(iter, 0, root_label, 1, -1)
for id, name in games:
child_iter = store.append(iter)
name = gettext(name)
store.set(child_iter, 0, name, 1, id)
def _selectGames(self, all_games, selecter):
# return list of tuples (gameid, gamename)
if selecter is None:
return [(gi.id, gi.name) for gi in all_games]
elif selecter == 'alt':
return all_games
return [(gi.id, gi.name) for gi in all_games if selecter(gi)]
def createGameStore(self):
store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_INT)
app = self.app
gdb = app.gdb
all_games = map(gdb.get, gdb.getGamesIdSortedByName())
#
alter_games = gdb.getGamesTuplesSortedByAlternateName()
for label, games, selecter in (
(_('All Games'), all_games, None),
(_('Alternate Names'), alter_games, 'alt'),
(_('Popular Games'), all_games, lambda gi: gi.si.game_flags & GI.GT_POPULAR),
):
games = self._selectGames(games, selecter)
self._addGames(store, None, label, games)
# by type
games = self._selectGames(all_games,
lambda gi: gi.si.game_type == GI.GT_MAHJONGG)
self._addGames(store, None, _("Mahjongg Games"), games)
self._addGamesFromData(GI.SELECT_ORIENTAL_GAME_BY_TYPE, store,
None, _("Oriental Games"), all_games)
self._addGamesFromData(GI.SELECT_SPECIAL_GAME_BY_TYPE, store,
None, _("Special Games"), all_games)
self._addGamesFromData(GI.SELECT_GAME_BY_TYPE, store,
None, _("French games"), all_games)
# by skill level
data = (
(_('Luck only'), lambda gi: gi.skill_level == GI.SL_LUCK),
(_('Mostly luck'), lambda gi: gi.skill_level == GI.SL_MOSTLY_LUCK),
(_('Balanced'), lambda gi: gi.skill_level == GI.SL_BALANCED),
(_('Mostly skill'), lambda gi: gi.skill_level == GI.SL_MOSTLY_SKILL),
(_('Skill only'), lambda gi: gi.skill_level == GI.SL_SKILL),
)
self._addGamesFromData(data, store, None,
_("by Skill Level"), all_games)
# by game feature
root_iter = store.append(None)
store.set(root_iter, 0, _('by Game Feature'), 1, -1)
data = (
(_("32 cards"), lambda gi: gi.si.ncards == 32),
(_("48 cards"), lambda gi: gi.si.ncards == 48),
(_("52 cards"), lambda gi: gi.si.ncards == 52),
(_("64 cards"), lambda gi: gi.si.ncards == 64),
(_("78 cards"), lambda gi: gi.si.ncards == 78),
(_("104 cards"), lambda gi: gi.si.ncards == 104),
(_("144 cards"), lambda gi: gi.si.ncards == 144),
(_("Other number"), lambda gi: gi.si.ncards not in (32, 48, 52, 64, 78, 104, 144)),)
self._addGamesFromData(data, store, root_iter,
_("by Number of Cards"), all_games)
data = (
(_("1 deck games"), lambda gi: gi.si.decks == 1),
(_("2 deck games"), lambda gi: gi.si.decks == 2),
(_("3 deck games"), lambda gi: gi.si.decks == 3),
(_("4 deck games"), lambda gi: gi.si.decks == 4),)
self._addGamesFromData(data, store, root_iter,
_("by Number of Decks"), all_games)
data = (
(_("No redeal"), lambda gi: gi.si.redeals == 0),
(_("1 redeal"), lambda gi: gi.si.redeals == 1),
(_("2 redeals"), lambda gi: gi.si.redeals == 2),
(_("3 redeals"), lambda gi: gi.si.redeals == 3),
(_("Unlimited redeals"), lambda gi: gi.si.redeals == -1),
##(_("Variable redeals"), lambda gi: gi.si.redeals == -2),
(_("Other number of redeals"), lambda gi: gi.si.redeals not in (-1, 0, 1, 2, 3)),)
self._addGamesFromData(data, store, root_iter,
_("by Number of Redeals"), all_games)
data = []
for label, vg in GI.GAMES_BY_COMPATIBILITY:
selecter = lambda gi, vg=vg: gi.id in vg
label = gettext(label)
data.append((label, selecter))
self._addGamesFromData(data, store, root_iter,
_("by Compatibility"), all_games)
# by PySol version
data = []
for version, vg in GI.GAMES_BY_PYSOL_VERSION:
selecter = lambda gi, vg=vg: gi.id in vg
label = _("New games in v. ") + version
data.append((label, selecter))
self._addGamesFromData(data, store, None,
_("by PySol version"), all_games)
#
data = (
(_("Games for Children (very easy)"), lambda gi: gi.si.game_flags & GI.GT_CHILDREN),
(_("Games with Scoring"), lambda gi: gi.si.game_flags & GI.GT_SCORE),
(_("Games with Separate Decks"), lambda gi: gi.si.game_flags & GI.GT_SEPARATE_DECKS),
(_("Open Games (all cards visible)"), lambda gi: gi.si.game_flags & GI.GT_OPEN),
(_("Relaxed Variants"), lambda gi: gi.si.game_flags & GI.GT_RELAXED),)
self._addGamesFromData(data, store, None,
_("Other Categories"), all_games)
#
self._addGamesFromData(GI.SELECT_ORIGINAL_GAME_BY_TYPE, store,
None, _("Original Games"), all_games)
##self._addGamesFromData(GI.SELECT_CONTRIB_GAME_BY_TYPE, store,
## None, _("Contrib Game"), all_games)
SelectGameDialogWithPreview.game_store = store
return
def initKw(self, kw):
kwdefault(kw,
strings=(_("&Select"), _("&Rules"), _("&Cancel"),),
default=0,
width=600, height=400,
)
return MfxDialog.initKw(self, kw)
def _unrealizeEvent(self, w):
self.deletePreview(destroy=1)
#self.preview.unbind_all()
self._saveSettings()
def _saveSettings(self):
SelectGameDialogWithPreview._geometry = self.get_size()
SelectGameDialogWithPreview._paned_position = self.hpaned.get_position()
def _restoreSettings(self):
if self._geometry:
self.resize(self._geometry[0], self._geometry[1])
self.hpaned.set_position(self._paned_position)
def getSelected(self):
index = self.treeview.getSelected()
if index < 0:
return None
return index
def showSelected(self, w):
id = self.getSelected()
if id:
self.updatePreview(id)
def deletePreview(self, destroy=0):
self.preview_key = -1
# clean up the canvas
if self.preview:
unbind_destroy(self.preview)
self.preview.deleteAllItems()
##~ if destroy:
##~ self.preview.delete("all")
#
#for l in self.info_labels.values():
# l.config(text='')
# destruct the game
if self.preview_game:
self.preview_game.endGame()
self.preview_game.destruct()
destruct(self.preview_game)
self.preview_game = None
# destruct the app
if destroy:
if self.preview_app:
destruct(self.preview_app)
self.preview_app = None
def updatePreview(self, gameid, animations=10):
if gameid == self.preview_key:
return
self.deletePreview()
canvas = self.preview
#
gi = self.app.gdb.get(gameid)
if not gi:
self.preview_key = -1
return
#
if self.preview_app is None:
self.preview_app = Struct(
# variables
audio = self.app.audio,
canvas = canvas,
cardset = self.app.cardset.copy(),
comments = self.app.comments.new(),
gamerandom = self.app.gamerandom,
gdb = self.app.gdb,
gimages = self.app.gimages,
images = self.app.subsampled_images,
menubar = None,
miscrandom = self.app.miscrandom,
opt = self.app.opt.copy(),
startup_opt = self.app.startup_opt,
stats = self.app.stats.new(),
top = None,
top_cursor = self.app.top_cursor,
toolbar = None,
# methods
constructGame = self.app.constructGame,
getFont = self.app.getFont,
)
self.preview_app.opt.shadow = 0
self.preview_app.opt.shade = 0
#
self.preview_app.audio = None # turn off audio for intial dealing
if animations >= 0:
self.preview_app.opt.animations = animations
#
if self.preview_game:
self.preview_game.endGame()
self.preview_game.destruct()
##self.top.wm_title("Select Game - " + self.app.getGameTitleName(gameid))
title = self.app.getGameTitleName(gameid)
self.set_title(_("Playable Preview - ") + title)
#
self.preview_game = gi.gameclass(gi)
self.preview_game.createPreview(self.preview_app)
tx, ty = 0, 0
gw, gh = self.preview_game.width, self.preview_game.height
##~ canvas.config(scrollregion=(-tx, -ty, -tx, -ty))
##~ canvas.xview_moveto(0)
##~ canvas.yview_moveto(0)
#
random = None
if gameid == self.gameid:
random = self.app.game.random.copy()
if gameid == self.gameid and self.bookmark:
self.preview_game.restoreGameFromBookmark(self.bookmark)
else:
self.preview_game.newGame(random=random, autoplay=1)
##~ canvas.config(scrollregion=(-tx, -ty, gw, gh))
#
self.preview_app.audio = self.app.audio
if self.app.opt.animations:
self.preview_app.opt.animations = 10
else:
self.preview_app.opt.animations = 0
# save seed
self.random = self.preview_game.random.copy()
self.random.origin = self.random.ORIGIN_PREVIEW
self.preview_key = gameid
#
self.updateInfo(gameid)
#
rules_button = self.buttons[1]
if self.app.getGameRulesFilename(gameid):
rules_button.set_sensitive(True)
else:
rules_button.set_sensitive(False)
def updateInfo(self, gameid):
gi = self.app.gdb.get(gameid)
# info
name = gettext(gi.name)
altnames = '\n'.join([gettext(n) for n in gi.altnames])
category = gettext(CSI.TYPE[gi.category])
type = ''
if gi.si.game_type in GI.TYPE_NAMES:
type = gettext(GI.TYPE_NAMES[gi.si.game_type])
sl = {
GI.SL_LUCK: _('Luck only'),
GI.SL_MOSTLY_LUCK: _('Mostly luck'),
GI.SL_BALANCED: _('Balanced'),
GI.SL_MOSTLY_SKILL: _('Mostly skill'),
GI.SL_SKILL: _('Skill only'),
}
skill_level = sl.get(gi.skill_level)
if gi.redeals == -2: redeals = _('variable')
elif gi.redeals == -1: redeals = _('unlimited')
else: redeals = str(gi.redeals)
# stats
won, lost, time, moves = self.app.stats.getFullStats(self.app.opt.player, gameid)
if won+lost > 0: percent = "%.1f" % (100.0*won/(won+lost))
else: percent = "0.0"
time = format_time(time)
moves = str(round(moves, 1))
for n, t in (
('name', name),
('altnames', altnames),
('category', category),
('type', type),
('skill_level', skill_level),
('decks', gi.decks),
('redeals', redeals),
('played', won+lost),
('won', won),
('lost', lost),
('time', time),
('moves', moves),
('percent', percent),
):
title_label, text_label = self.info_labels[n]
if t in ('', None):
title_label.hide()
text_label.hide()
else:
title_label.show()
text_label.show()
text_label.set_text(str(t))
def done(self, button):
button = button.get_data("user_data")
print 'done', button
if button == 0: # Ok or double click
id = self.getSelected()
if id:
self.gameid = id
##~ self.tree.n_expansions = 1 # save xyview in any case
if button == 1: # Rules
id = self.getSelected()
if id:
doc = self.app.getGameRulesFilename(id)
if not doc:
return
dir = os.path.join("html", "rules")
help_html(self.app, doc, dir, self)
return
self.status = 0
self.button = button
self.quit()