1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
PySolFC/pysollib/kivy/selectgame.py
2022-01-08 10:34:33 -05:00

491 lines
19 KiB
Python

#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
# ---------------------------------------------------------------------------#
#
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
# Copyright (C) 2003 Mt. Hood Playing Card Co.
# Copyright (C) 2005-2009 Skomoroh
#
# 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 3 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. If not, see <http://www.gnu.org/licenses/>.
#
# ---------------------------------------------------------------------------#
from kivy.clock import Clock
from pysollib.gamedb import GI
from pysollib.kivy.LApp import LScrollView
from pysollib.kivy.LApp import LTopLevel
from pysollib.kivy.LApp import LTreeNode
from pysollib.kivy.LApp import LTreeRoot
from pysollib.kivy.selecttree import SelectDialogTreeData
from pysollib.kivy.selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
from pysollib.mygettext import _
from six.moves import UserList
# ************************************************************************
# * Nodes
# ************************************************************************
class SelectGameLeaf(SelectDialogTreeLeaf):
def getContents(self):
return None
class SelectGameNode(SelectDialogTreeNode):
def _getContents(self):
contents = []
if isinstance(self.select_func, UserList):
# key/value pairs
for id, name in self.select_func:
if id and name:
node = SelectGameLeaf(self.tree, self, name, key=id)
contents.append(node)
else:
for gi in self.tree.all_games_gi:
if gi and self.select_func is None:
# All games
# name = '%s (%s)' % (gi.name, CSI.TYPE_NAME[gi.category])
name = gi.name
node = SelectGameLeaf(self.tree, self, name, key=gi.id)
contents.append(node)
elif gi and self.select_func(gi):
name = gi.name
node = SelectGameLeaf(self.tree, self, name, key=gi.id)
contents.append(node)
return contents or self.tree.no_games
# ************************************************************************
# * Tree database
# ************************************************************************
class SelectGameData(SelectDialogTreeData):
def __init__(self, app):
SelectDialogTreeData.__init__(self)
# originale.
self.all_games_gi = list(
map(app.gdb.get, app.gdb.getGamesIdSortedByName()))
self.no_games = [SelectGameLeaf(None, None, _("(no games)"), None), ]
#
s_by_type = s_oriental = s_special = None
s_original = s_contrib = s_mahjongg = None
g = []
for data in (GI.SELECT_GAME_BY_TYPE,
GI.SELECT_ORIENTAL_GAME_BY_TYPE,
GI.SELECT_SPECIAL_GAME_BY_TYPE,
GI.SELECT_ORIGINAL_GAME_BY_TYPE,
GI.SELECT_CONTRIB_GAME_BY_TYPE,
):
gg = []
for name, select_func in data:
if name is None or not filter(select_func, self.all_games_gi):
continue
gg.append(SelectGameNode(None, _(name), select_func))
g.append(gg)
def select_mahjongg_game(gi): return gi.si.game_type == GI.GT_MAHJONGG
gg = None
if filter(select_mahjongg_game, self.all_games_gi):
gg = SelectGameNode(None, _("Mahjongg Games"),
select_mahjongg_game)
g.append(gg)
if g[0]:
s_by_type = SelectGameNode(None, _("French Games"),
tuple(g[0]), expanded=1)
if g[1]:
s_oriental = SelectGameNode(None, _("Oriental Games"),
tuple(g[1]))
if g[2]:
s_special = SelectGameNode(None, _("Special Games"),
tuple(g[2]))
if g[3]:
s_original = SelectGameNode(None, _("Original Games"),
tuple(g[3]))
# if g[4]:
# s_contrib = SelectGameNode(None, "Contributed Games", tuple(g[4]))
if g[5]:
s_mahjongg = g[5]
#
# all games sorted (in pieces).
s_all_games, gg = None, []
agames = self.all_games_gi
n, d = 0, 17
i = 0
while True:
# columnbreak = i > 0 and (i % d) == 0
i += 1
if not agames[n:n + d]:
break
m = min(n + d - 1, len(agames) - 1)
label = agames[n].name[:4] + ' - ' + agames[m].name[:4]
# print('label = %s' % label)
ggg = []
for ag in agames[n:n + d]:
# print('game, id = %s, %s' % (ag.name, ag.id))
ggg.append((ag.id, ag.name + ' (' + str(ag.id) + ')'))
gg.append(SelectGameNode(None, label, UserList(ggg)))
n += d
if 1 and gg:
s_all_games = SelectGameNode(None, _("All Games"), tuple(gg))
#
s_by_compatibility, gg = None, []
for name, games in GI.GAMES_BY_COMPATIBILITY:
def select_func(gi, games=games):
return gi.id in games
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_compatibility = SelectGameNode(None, _("by Compatibility"),
tuple(gg))
pass
#
s_by_pysol_version, gg = None, []
for name, games in GI.GAMES_BY_PYSOL_VERSION:
def select_func(gi, games=games):
return gi.id in games
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
name = _("New games in v. %(version)s") % {'version': name}
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_pysol_version = SelectGameNode(None, _("by PySol version"),
tuple(gg))
#
s_by_inventors, gg = None, []
for name, games in GI.GAMES_BY_INVENTORS:
def select_func(gi, games=games):
return gi.id in games
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_inventors = SelectGameNode(None, _("by Inventors"),
tuple(gg))
#
ul_alternate_names = UserList(
list(app.gdb.getGamesTuplesSortedByAlternateName()))
#
self.rootnodes = [_f for _f in (
# SelectGameNode(None, _("All Games"), None),
SelectGameNode(None, _("Popular Games"),
lambda gi: gi.si.game_flags & GI.GT_POPULAR),
s_mahjongg,
s_oriental,
s_special,
# SelectGameNode(None, _("Custom Games"),
# lambda gi: gi.si.game_type == GI.GT_CUSTOM),
SelectGameNode(None, _("Alternate Names"), ul_alternate_names),
s_by_type,
s_all_games,
SelectGameNode(None, _('by Skill Level'), (
SelectGameNode(None, _('Luck only'),
lambda gi: gi.skill_level == GI.SL_LUCK),
SelectGameNode(None, _('Mostly luck'),
lambda gi: gi.skill_level == GI.SL_MOSTLY_LUCK),
SelectGameNode(None, _('Balanced'),
lambda gi: gi.skill_level == GI.SL_BALANCED),
SelectGameNode(None, _('Mostly skill'),
lambda gi: gi.skill_level == GI.SL_MOSTLY_SKILL),
SelectGameNode(None, _('Skill only'),
lambda gi: gi.skill_level == GI.SL_SKILL),
)),
SelectGameNode(None, _("by Game Feature"), (
SelectGameNode(None, _("by Number of Cards"), (
SelectGameNode(None, _("32 cards"),
lambda gi: gi.si.ncards == 32),
SelectGameNode(None, _("48 cards"),
lambda gi: gi.si.ncards == 48),
SelectGameNode(None, _("52 cards"),
lambda gi: gi.si.ncards == 52),
SelectGameNode(None, _("64 cards"),
lambda gi: gi.si.ncards == 64),
SelectGameNode(None, _("78 cards"),
lambda gi: gi.si.ncards == 78),
SelectGameNode(None, _("104 cards"),
lambda gi: gi.si.ncards == 104),
SelectGameNode(None, _("144 cards"),
lambda gi: gi.si.ncards == 144),
SelectGameNode(None, _("Other number"),
lambda gi: gi.si.ncards not in
(32, 48, 52, 64, 78, 104, 144)),
)),
SelectGameNode(None, _("by Number of Decks"), (
SelectGameNode(None, _("1 deck games"),
lambda gi: gi.si.decks == 1),
SelectGameNode(None, _("2 deck games"),
lambda gi: gi.si.decks == 2),
SelectGameNode(None, _("3 deck games"),
lambda gi: gi.si.decks == 3),
SelectGameNode(None, _("4 deck games"),
lambda gi: gi.si.decks == 4),
)),
SelectGameNode(None, _("by Number of Redeals"), (
SelectGameNode(None, _("No redeal"),
lambda gi: gi.si.redeals == 0),
SelectGameNode(None, _("1 redeal"),
lambda gi: gi.si.redeals == 1),
SelectGameNode(None, _("2 redeals"),
lambda gi: gi.si.redeals == 2),
SelectGameNode(None, _("3 redeals"),
lambda gi: gi.si.redeals == 3),
SelectGameNode(None, _("Unlimited redeals"),
lambda gi: gi.si.redeals == -1),
SelectGameNode(None, "Variable redeals",
lambda gi: gi.si.redeals == -2),
SelectGameNode(None, _("Other number of redeals"),
lambda gi: gi.si.redeals not in
(-1, 0, 1, 2, 3)),
)),
s_by_compatibility,
)),
s_by_pysol_version,
s_by_inventors,
SelectGameNode(None, _("Other Categories"), (
SelectGameNode(None, _("Games for Children (very easy)"),
lambda gi: gi.si.game_flags & GI.GT_CHILDREN),
SelectGameNode(None, _("Games with Scoring"),
lambda gi: gi.si.game_flags & GI.GT_SCORE),
SelectGameNode(None, _("Games with Stripped Decks"),
lambda gi: gi.si.game_flags & GI.GT_STRIPPED),
SelectGameNode(None, _("Games with Separate Decks"),
lambda gi: gi.si.game_flags & GI.GT_SEPARATE_DECKS),
SelectGameNode(None, _("Open Games (all cards visible)"),
lambda gi: gi.si.game_flags & GI.GT_OPEN),
SelectGameNode(None, _("Relaxed Variants"),
lambda gi: gi.si.game_flags & GI.GT_RELAXED),
)),
s_original,
s_contrib,
) if _f]
# ************************************************************************
# * Canvas that shows the tree
# ************************************************************************
'''
class SelectGameTreeWithPreview(SelectDialogTreeCanvas):
data = None
class SelectGameTree(SelectGameTreeWithPreview):
def singleClick(self, event=None):
self.doubleClick(event)
'''
# ************************************************************************
# * Kivy support
# ************************************************************************
class LGameRoot(LTreeRoot):
def __init__(self, gametree, gameview, **kw):
super(LGameRoot, self).__init__(**kw)
self.gametree = gametree
self.gameview = gameview
self.kw = kw
class LGameNode(LTreeNode):
def __init__(self, gamenode, gameview, **kw):
self.lastpos = None
self.gamenode = gamenode
self.gameview = gameview
super(LGameNode, self).__init__(**kw)
self.coreFont = self.font_size
# self.scaleFont(self.gameview.size[1])
# self.gameview.bind(size=self.scaleFontCB)
self.command = None
if 'command' in kw:
self.command = kw['command']
self.bind(on_release=self.on_released)
# font skalierung.
def scaleFont(self, value):
self.font_size = int(self.coreFont * value / 550.0)
def scaleFontCB(self, instance, value):
self.scaleFont(value[1])
# benutzer interaktion.
def on_released(self, v):
if self.gamenode.key:
if self.command:
# print('game number = %s' % self.gamenode.key)
Clock.schedule_once(self.commandCB, 0.1)
else:
# verzögert aufrufen, wegen user feedback.
Clock.schedule_once(self.toggleCB, 0.1)
'''
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
if self.lastpos==None:
self.lastpos = touch.pos
print('touch.pos %s' % str(touch.pos))
return
print ('touch move on %s - %s' % (self.text, touch.profile))
print('touch.pos(2) %s' % str(touch.pos))
# tbd: nur wenn horizontal move !
if (touch.pos[0]+2) < self.lastpos[0]:
Clock.schedule_once(self.collapseParentCB, 0.1)
pass
'''
def commandCB(self, d):
self.command(self.gamenode.key)
def toggleCB(self, d):
self.parent.toggle_node(self)
'''
def collapseParentCB(self, d):
if self.parent:
if self.parent_node.is_open:
self.parent.toggle_node(self.parent_node)
self.lastpos = None
'''
# ************************************************************************
# * Dialog
# ************************************************************************
class SelectGameDialog(object):
# Dialog, einmal erzeugt, wird rezykliert.
SingleInstance = None
def onClick(self, event):
print('LTopLevel: onClick')
SelectGameDialog.SingleInstance.parent.popWork('SelectGame')
SelectGameDialog.SingleInstance.running = False
def selectCmd(self, gameid):
self.app.menubar._mSelectGame(gameid)
def __init__(self, parent, title, app, gameid, **kw):
super(SelectGameDialog, self).__init__()
self.parent = parent
self.app = app
self.gameid = gameid
self.random = None
self.running = False
self.window = None
# bestehenden Dialog rezyklieren.
si = SelectGameDialog.SingleInstance
# if (si and si.running): return
if (si and si.running):
si.parent.popWork('SelectGame')
si.running = False
return
if (si):
si.parent.pushWork('SelectGame', si.window)
si.running = True
return
# neuen Dialog aufbauen.
window = LTopLevel(parent, title)
window.titleline.bind(on_press=self.onClick)
self.parent.pushWork('SelectGame', window)
self.window = window
self.running = True
SelectGameDialog.SingleInstance = self
# Asynchron laden.
def loaderCB(treeview, node):
# Beispielcode aus doku:
#
# for name in ('Item 1', 'Item 2'):
# yield TreeViewLabel(text=name, parent=node)
#
# LGameNode ist ein Button. Es stellt sich heraus, dass
# wir (ev. darum) parent=node NICHT setzen dürfen, da das
# sonst zum versuchten doppelten einfügen des gleichen
# widget im tree führt.
if node:
if not hasattr(node, "gamenode"):
# (das löst ein problem mit dem root knoten),
return
v = treeview.gameview
if node:
n = node.gamenode
n.tree = treeview.gametree
nodes = n.getContents()
if type(nodes) is list:
# Blaetter
for node in nodes:
# print ('**game=%s' % node.text)
yield LGameNode(
node, v, text=node.text,
is_leaf=True,
command=self.selectCmd)
if type(nodes) is tuple:
# Knoten
for nn in nodes:
# print ('**node=%s' % nn.text)
newnode = LGameNode(
nn, v, text=nn.text, is_leaf=False)
yield newnode
print('all nodes done')
else:
# Knoten
nodes = treeview.gametree.rootnodes[:]
for n in nodes:
newnode = LGameNode(n, v, text=n.text, is_leaf=False)
# print ('**node=%s' % newnode)
yield newnode
# treeview aufsetzen.
tree = SelectGameData(app)
tv = self.tvroot = LGameRoot(
tree,
self.app.canvas,
root_options=dict(text='Tree One'))
tv.size_hint = 1, None
tv.hide_root = True
tv.load_func = loaderCB
tv.bind(minimum_height=tv.setter('height'))
# tree in einem Scrollwindow präsentieren.
root = LScrollView(pos=(0, 0))
root.add_widget(tv)
window.content.add_widget(root)
# ************************************************************************