mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -04:00
- Added new menu option to adjust font size in general. - Fixed a bug with doubleclick moves addressed in #117.
1000 lines
30 KiB
Python
1000 lines
30 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
|
|
# Copyright (C) 2017 LB
|
|
#
|
|
# 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 __future__ import division
|
|
|
|
import logging
|
|
import math
|
|
|
|
from kivy.clock import Clock
|
|
from kivy.properties import StringProperty
|
|
from kivy.uix.anchorlayout import AnchorLayout
|
|
|
|
from pysollib.kivy.LApp import LAnimationManager
|
|
from pysollib.kivy.LApp import LColorToKivy
|
|
from pysollib.kivy.LApp import LImageItem
|
|
from pysollib.kivy.LApp import LLine
|
|
from pysollib.kivy.LApp import LRectangle
|
|
from pysollib.kivy.LApp import LText
|
|
from pysollib.kivy.LImage import LImage
|
|
|
|
# ************************************************************************
|
|
# * canvas items helpers
|
|
# ************************************************************************
|
|
|
|
|
|
def addAnchorOffset(pos, anchor, size):
|
|
# print ('MfxCanvas: anchor=%s' % (anchor))
|
|
x = pos[0]
|
|
y = pos[1]
|
|
xa = 0
|
|
ya = 0
|
|
if anchor == "n":
|
|
ya = -1
|
|
elif anchor == "w":
|
|
xa = -1
|
|
elif anchor == "s":
|
|
ya = 1
|
|
elif anchor == "e":
|
|
xa = 1
|
|
elif anchor == "ne":
|
|
ya = -1
|
|
xa = 1
|
|
elif anchor == "nw":
|
|
ya = -1
|
|
xa = -1
|
|
elif anchor == "se":
|
|
ya = 1
|
|
xa = 1
|
|
elif anchor == "sw":
|
|
ya = 1
|
|
xa = -1
|
|
|
|
if xa == 0:
|
|
x = x - size[0] / 2.0
|
|
elif xa == 1:
|
|
x = x - size[0]
|
|
if ya == 0:
|
|
y = y - size[1] / 2.0
|
|
elif ya == 1:
|
|
y = y - size[1]
|
|
return (x, y)
|
|
|
|
|
|
def subAnchorOffset(pos, anchor, size):
|
|
# print ('MfxCanvas: anchor=%s' % (anchor))
|
|
x = pos[0]
|
|
y = pos[1]
|
|
xa = 0
|
|
ya = 0
|
|
if anchor == "n":
|
|
ya = -1
|
|
elif anchor == "w":
|
|
xa = -1
|
|
elif anchor == "s":
|
|
ya = 1
|
|
elif anchor == "e":
|
|
xa = 1
|
|
elif anchor == "ne":
|
|
ya = -1
|
|
xa = 1
|
|
elif anchor == "nw":
|
|
ya = -1
|
|
xa = -1
|
|
elif anchor == "se":
|
|
ya = 1
|
|
xa = 1
|
|
elif anchor == "sw":
|
|
ya = 1
|
|
xa = -1
|
|
|
|
if xa == 0:
|
|
x = x + size[0] / 2.0
|
|
elif xa == 1:
|
|
x = x + size[0]
|
|
if ya == 0:
|
|
y = y + size[1] / 2.0
|
|
elif ya == 1:
|
|
y = y + size[1]
|
|
return (x, y)
|
|
|
|
# ************************************************************************
|
|
# * canvas items
|
|
# ************************************************************************
|
|
|
|
|
|
class MfxCanvasGroup():
|
|
def __init__(self, canvas, tag=None):
|
|
# print(self, '__init__(', canvas, tag, ')')
|
|
|
|
self.canvas = canvas
|
|
self.bindings = {}
|
|
self.stack = None
|
|
|
|
def __str__(self):
|
|
return f'<MfxCanvasGroup @ {hex(id(self))}>'
|
|
|
|
def _imglist(self, group):
|
|
ilst = []
|
|
for w in group.canvas.children:
|
|
if isinstance(w, LImageItem):
|
|
if w.group == group:
|
|
ilst.append(w)
|
|
return ilst
|
|
|
|
def makeDeferredRaise(self, pos):
|
|
def animCallback():
|
|
self.tkraise(position=pos)
|
|
return animCallback
|
|
|
|
def tkraise(self, position=None):
|
|
# print(self, ' tkraise(', position, ')')
|
|
# Mainly used by Mahjongg game after a move.
|
|
# import inspect
|
|
# print('stack[1] = ',inspect.stack()[1].frame)
|
|
# print('stack[2] = ',inspect.stack()[2].frame)
|
|
|
|
if LAnimationManager.checkRunning():
|
|
LAnimationManager.addEndCallback(
|
|
self.makeDeferredRaise(position))
|
|
return
|
|
|
|
imgs = self._imglist(self)
|
|
if len(imgs) == 0:
|
|
return
|
|
|
|
if position is not None:
|
|
# add all images above specified position
|
|
pimgs = self._imglist(position)
|
|
if len(pimgs) == 0:
|
|
return
|
|
|
|
self.canvas.clear_widgets(imgs)
|
|
k = self.canvas.children.index(pimgs[-1])
|
|
for i in imgs:
|
|
self.canvas.add_widget(i, index=k)
|
|
k += 1
|
|
else:
|
|
# add all images to top
|
|
self.canvas.clear_widgets(imgs)
|
|
k = 0
|
|
for i in imgs:
|
|
self.canvas.add_widget(i, index=k)
|
|
k += 1
|
|
|
|
def makeDeferredLower(self, pos):
|
|
def animCallback():
|
|
self.lower(position=pos)
|
|
return animCallback
|
|
|
|
def lower(self, position=None):
|
|
# print(self, ' lower(', position, ')')
|
|
# import inspect
|
|
# print('stack[1] = ',inspect.stack()[1].frame)
|
|
# print('stack[2] = ',inspect.stack()[2].frame)
|
|
|
|
if LAnimationManager.checkRunning():
|
|
LAnimationManager.addEndCallback(
|
|
self.makeDeferredLower(position))
|
|
return
|
|
|
|
imgs = self._imglist(self)
|
|
if len(imgs) == 0:
|
|
return
|
|
|
|
if position is not None:
|
|
# add below specified position
|
|
pimgs = self._imglist(position)
|
|
if len(pimgs) == 0:
|
|
return
|
|
|
|
self.canvas.clear_widgets(imgs)
|
|
k = self.canvas.children.index(pimgs[0]) # the spec. item
|
|
k += 1 # insert before
|
|
for i in imgs:
|
|
self.canvas.add_widget(i, index=k)
|
|
k += 1
|
|
else:
|
|
# add all to bottom
|
|
self.canvas.clear_widgets(imgs)
|
|
k = len(self.canvas.children)-1 # the last item
|
|
k += 1 # insert before
|
|
for i in imgs:
|
|
self.canvas.add_widget(i, index=k)
|
|
k += 1
|
|
|
|
def addtag(self, tag, option="withtag"):
|
|
# logging.info('MfxCanvasGroup: addtag(%s, %s)' % (tag, option))
|
|
# self.canvas.addtag(tag, option, self.id)
|
|
pass
|
|
|
|
def delete(self):
|
|
# logging.info('MfxCanvasGroup: delete()')
|
|
# del self.canvas.items[self.id]
|
|
pass
|
|
|
|
def gettags(self):
|
|
# logging.info('MfxCanvasGroup: gettags()')
|
|
# return self.canvas.tk.splitlist(self._do("gettags"))
|
|
return None
|
|
|
|
|
|
def cardmagnif(canvas, size):
|
|
def pyth(s):
|
|
return math.sqrt(s[0]*s[0]+s[1]*s[1])
|
|
cs = canvas.wmain.app.images.getSize()
|
|
csl = pyth(cs)
|
|
sl = pyth(size)
|
|
return csl/sl
|
|
|
|
|
|
class MfxCanvasImage(object):
|
|
def __init__(self, canvas, *args, **kwargs):
|
|
|
|
# print ('MfxCanvasImage: %s | %s | %s' % (canvas, args, kwargs))
|
|
|
|
self.group = None
|
|
group = None
|
|
if 'group' in kwargs:
|
|
group = kwargs['group']
|
|
del kwargs['group']
|
|
self._image = None
|
|
if 'image' in kwargs:
|
|
self._image = kwargs['image']
|
|
self._anchor = None
|
|
if 'anchor' in kwargs:
|
|
self._anchor = kwargs['anchor']
|
|
self.hint = None
|
|
if 'hint' in kwargs:
|
|
self.hint = kwargs['hint']
|
|
|
|
# print ('MfxCanvasImage: group = %s ' % (group))
|
|
# wir kommen üblicherweise aus Card.__init__(). und da ist keine
|
|
# group (group wird über addtag gesetzt, sobald das image
|
|
# in einem stack ist.)
|
|
|
|
super(MfxCanvasImage, self).__init__()
|
|
self.canvas = canvas
|
|
self.redeal = False
|
|
|
|
# animation mode support:
|
|
self.animation = 0
|
|
self.duration = 0.2
|
|
self.deferred_raises = []
|
|
self.animations = []
|
|
|
|
ed = kwargs['image']
|
|
size = ed.size
|
|
|
|
if type(ed) is LImageItem:
|
|
aimage = ed
|
|
else:
|
|
image = LImage(texture=ed.texture)
|
|
if self.hint == "redeal_image":
|
|
cm = cardmagnif(canvas, size)/1.9
|
|
image.size = [cm*ed.getWidth(), cm*ed.getHeight()]
|
|
self.redeal = True
|
|
aimage = LImageItem(
|
|
size=ed.size, group=group, image_type=self.hint)
|
|
else:
|
|
image.size = [ed.getWidth(), ed.getHeight()]
|
|
aimage = LImageItem(size=ed.size, group=group)
|
|
|
|
aimage.add_widget(image)
|
|
aimage.size = image.size
|
|
size = image.size
|
|
|
|
xy = addAnchorOffset(args, self._anchor, size)
|
|
|
|
aimage.coreSize = (aimage.size[0], aimage.size[1])
|
|
aimage.corePos = (xy[0], xy[1])
|
|
|
|
aimage.pos, aimage.size = canvas.CoreToKivy(xy, aimage.size)
|
|
self.canvas.add_widget(aimage)
|
|
self.image = aimage
|
|
self.widget = aimage
|
|
|
|
if group:
|
|
self.addtag(group)
|
|
|
|
def __del__(self):
|
|
# print('MfxCanvasImage: __del__(%s)' % self.image)
|
|
self.canvas.clear_widgets([self.image])
|
|
|
|
def __str__(self):
|
|
return f'<MfxCanvasImage @ {hex(id(self))}>'
|
|
|
|
def config(self, **kw):
|
|
# print('MfxCanvasImage conifg:',kw)
|
|
if "image" in kw:
|
|
# print('is redeal image:',self.redeal)
|
|
if self.redeal:
|
|
image = self.image.children[0]
|
|
image.texture = kw["image"].texture
|
|
# print('redeal texture:',image.texture)
|
|
pass
|
|
|
|
def makeDeferredRaise(self, pos):
|
|
def animCallback():
|
|
self.canvas.tag_raise(self.image, pos)
|
|
return animCallback
|
|
|
|
def tkraise(self, aboveThis=None):
|
|
|
|
abitm = None
|
|
if aboveThis:
|
|
abitm = aboveThis.widget
|
|
|
|
# import inspect
|
|
# print('stack[1] = ', inspect.stack()[1].frame)
|
|
# print('stack[2] = ', inspect.stack()[2].frame)
|
|
# print('stack[3] = ', inspect.stack()[3].frame)
|
|
|
|
if self.animation > 0:
|
|
# print('defer tkraise to animation', abitm)
|
|
if len(self.deferred_raises) < self.animation:
|
|
self.deferred_raises.append(self.makeDeferredRaise(abitm))
|
|
return
|
|
|
|
# print('direct tkraise', abitm)
|
|
self.canvas.tag_raise(self.image, abitm)
|
|
|
|
def addtag(self, tag):
|
|
# print('MfxCanvasImage: addtag %s' % tag.stack)
|
|
self.group = tag
|
|
if (self.image):
|
|
self.image.group = tag
|
|
|
|
def dtag(self, tag):
|
|
# print('MfxCanvasImage: remtag %s' % tag.stack)
|
|
self.group = None
|
|
if (self.image):
|
|
self.image.group = None
|
|
pass
|
|
|
|
def delete(self):
|
|
# print('MfxCanvasImage: delete()')
|
|
self.canvas.clear_widgets([self.image])
|
|
|
|
def move(self, dx, dy):
|
|
# print('MfxCanvasImage: move %s, %s' % (dx, dy))
|
|
image = self.image
|
|
dsize = image.coreSize
|
|
dpos = (image.corePos[0] + dx, image.corePos[1] + dy)
|
|
image.corePos = dpos
|
|
if self.animation == 0:
|
|
image.pos, image.size = self.canvas.CoreToKivy(dpos, dsize)
|
|
else:
|
|
pos, size = self.canvas.CoreToKivy(dpos, dsize)
|
|
self.animations[self.animation-1].updateDestPos(pos)
|
|
|
|
def makeAnimStart(self):
|
|
def animStart(anim, widget):
|
|
# print('MfxCanvasImage: animStart %s' % self)
|
|
|
|
# raise to top if reqested for this move
|
|
if self.deferred_raises:
|
|
self.deferred_raises[0]()
|
|
self.deferred_raises = self.deferred_raises[1:]
|
|
|
|
# update z-order (for some specials)
|
|
while 1:
|
|
from pysollib.games.grandfathersclock import Clock_RowStack
|
|
specials = [Clock_RowStack, ]
|
|
|
|
if self.group is None: break # noqa
|
|
stack = self.group.stack
|
|
if stack is None: break # noqa
|
|
if type(stack) not in specials: break; # noqa
|
|
|
|
cards = self.group.stack.cards
|
|
card = self.image.card
|
|
if card is None: break # noqa
|
|
if card == cards[-1]: break # noqa
|
|
i = cards.index(card) + 1
|
|
|
|
# print('stack =', self.group.stack)
|
|
# print('cards:', [c.__str__() for c in cards])
|
|
# print('card =', card)
|
|
# print('***** adjust z-reordering:',card,'before',cards[i])
|
|
|
|
def lower_z(dt):
|
|
self.canvas.tag_lower(card.item.image, cards[i].item.image)
|
|
|
|
Clock.schedule_once(lower_z, self.duration/2.0)
|
|
break
|
|
|
|
return animStart
|
|
|
|
def makeAnimEnd(self, dpos, dsize):
|
|
def animEnd(anim, widget):
|
|
# print('MfxCanvasImage: animEnd %s' % self)
|
|
|
|
if self.animation > 0:
|
|
self.animation -= 1
|
|
self.animations = self.animations[1:]
|
|
|
|
if self.animation == 0:
|
|
# just for the case, keep in sync:
|
|
self.deferred_raises = []
|
|
self.animations = []
|
|
|
|
# print('MfxCanvasImage: animEnd moved to %s, %s' % (dpos[0], dpos[1])) # noqa
|
|
return animEnd
|
|
|
|
def animatedMove(self, dx, dy, duration=0.2):
|
|
# print('MfxCanvasImage: animatedMove %s, %s' % (dx, dy))
|
|
# import inspect
|
|
# for insi in range(1,9):
|
|
# print('stack[insi] = ', inspect.stack()[insi].frame)
|
|
|
|
image = self.image
|
|
dsize = image.coreSize
|
|
dpos = (image.corePos[0] + dx, image.corePos[1] + dy)
|
|
pos, size = self.canvas.CoreToKivy(dpos, dsize)
|
|
transition1 = 'out_expo'
|
|
# transition2 = 'out_cubic'
|
|
# transition3 = 'out_quad'
|
|
# transition4 = 'out_quint'
|
|
# transition5 = 'out_sine'
|
|
transition6 = 'in_out_quad'
|
|
# transition7 = 'in_bounce'
|
|
# transition8 = 'in_elastic'
|
|
transition = transition6
|
|
if self.canvas.wmain.app.game.demo:
|
|
transition = transition1
|
|
|
|
self.duration = duration
|
|
ssize = image.coreSize
|
|
spos = (image.corePos[0], image.corePos[1])
|
|
spos, ssize = self.canvas.CoreToKivy(spos, ssize)
|
|
|
|
from pysollib.kivy.LApp import LAnimationTask
|
|
task = LAnimationTask(
|
|
spos,
|
|
image,
|
|
x=pos[0], y=pos[1],
|
|
duration=duration, transition=transition,
|
|
bindS=self.makeAnimStart(),
|
|
bindE=self.makeAnimEnd(dpos, dsize))
|
|
self.animations.append(task)
|
|
self.animation += 1
|
|
LAnimationManager.taskInsert(task)
|
|
|
|
def show(self):
|
|
self.config(state='normal')
|
|
|
|
def hide(self):
|
|
self.config(state='hidden')
|
|
|
|
|
|
class MfxCanvasLine(object):
|
|
def __init__(self, canvas, *args, **kwargs):
|
|
# print('MfxCanvasLine: %s %s' % (args, kwargs))
|
|
|
|
self.canvas = canvas
|
|
line = LLine(canvas, args, **kwargs)
|
|
line.pos, line.size = canvas.CoreToKivy(line.corePos, line.coreSize)
|
|
canvas.add_widget(line)
|
|
self.canvas = canvas
|
|
self.line = line
|
|
self.widget = line
|
|
|
|
def delete_deferred(self, seconds):
|
|
# print('MfxCanvasLine: delete_deferred(%s)' % seconds)
|
|
from kivy.animation import Animation
|
|
z = 0
|
|
t = 'in_expo'
|
|
anim = Animation(opacity=z, t=t, d=seconds/1.5)
|
|
anim.start(self.line)
|
|
Clock.schedule_once(lambda dt: self.delete(), seconds)
|
|
|
|
def delete(self):
|
|
# print('MfxCanvasLine: delete()')
|
|
self.canvas.clear_widgets([self.line])
|
|
|
|
|
|
class MfxCanvasRectangle(object):
|
|
def __init__(self, canvas, *args, **kwargs):
|
|
|
|
# logging.info('MfxCanvasRectangle: %s %s' % (args, kwargs))
|
|
|
|
rect = LRectangle(canvas, args, **kwargs)
|
|
rect.pos, rect.size = canvas.CoreToKivy(rect.corePos, rect.coreSize)
|
|
canvas.add_widget(rect)
|
|
self.canvas = canvas
|
|
self.rect = rect
|
|
self.widget = rect
|
|
|
|
def delete(self):
|
|
# print('MfxCanvasRectangle: delete()')
|
|
self.canvas.clear_widgets([self.rect])
|
|
|
|
def __del__(self):
|
|
# print('MfxCanvasRectangle: __del__()')
|
|
self.delete()
|
|
|
|
def delete_deferred_step(self, seconds):
|
|
# print ('MfxCanvasRectangle: delete_deferred_step(%s)' % seconds)
|
|
Clock.schedule_once(lambda dt: self.delete(), seconds)
|
|
|
|
def delete_deferred(self, seconds):
|
|
# self.canvas.canvas.ask_update()
|
|
# print ('MfxCanvasRectangle: delete_deferred(%s)' % seconds)
|
|
Clock.schedule_once(
|
|
lambda dt: self.delete_deferred_step(seconds), 0.05)
|
|
|
|
def addtag(self, tag):
|
|
logging.info('MfxCanvasRectangle: addtag(%s) - fake' % tag)
|
|
pass
|
|
|
|
def tkraise(self, aboveThis=None):
|
|
# logging.info('MfxCanvasRectangle: tkraise(%s) - fake' % item)
|
|
abitm = None
|
|
if aboveThis:
|
|
abitm = aboveThis.widget
|
|
self.canvas.tag_raise(self.rect, abitm)
|
|
pass
|
|
|
|
|
|
class MfxCanvasText(object):
|
|
def __init__(self, canvas, x, y, preview=-1, **kwargs):
|
|
|
|
if preview < 0:
|
|
preview = canvas.preview
|
|
if preview > 1:
|
|
return
|
|
if "fill" not in kwargs:
|
|
kwargs["fill"] = canvas._text_color
|
|
if 'group' in kwargs:
|
|
del kwargs['group']
|
|
|
|
super(MfxCanvasText, self).__init__()
|
|
|
|
label = LText(canvas, x, y, **kwargs)
|
|
label.pos, label.size = canvas.CoreToKivy(
|
|
label.corePos, label.coreSize)
|
|
canvas.add_widget(label)
|
|
self.canvas = canvas
|
|
self.label = label
|
|
self.widget = label
|
|
self.canvas.bind(_text_color=self.setColor)
|
|
|
|
def setColor(self, w, c):
|
|
self.label.label.color = LColorToKivy(c)
|
|
|
|
def config(self, **kw):
|
|
# print('MfxCanvasText: config %s' % kw)
|
|
if ('text' in kw):
|
|
self.label.text = kw['text']
|
|
|
|
def tkraise(self, aboveThis=None):
|
|
abitm = None
|
|
if aboveThis:
|
|
abitm = aboveThis.widget
|
|
self.canvas.tag_raise(self.label, abitm)
|
|
pass
|
|
|
|
def bbox(self):
|
|
# Dimensionen als 2x2 array zurückgeben.
|
|
# (aufruf z.B. bei games/special/poker.py und bei Memory!)
|
|
label = self.label
|
|
canvas = self.canvas
|
|
pos = label.pos
|
|
size = label.size
|
|
pos, size = canvas.KivyToCore(pos, size)
|
|
ret = [[pos[0], pos[1]], [pos[0] + size[0], pos[1] + size[1]]]
|
|
return ret
|
|
|
|
def addtag(self, tag):
|
|
pass
|
|
|
|
# ************************************************************************
|
|
# * canvas
|
|
# ************************************************************************
|
|
|
|
|
|
class MfxCanvas(LImage):
|
|
_text_color = StringProperty("#000000")
|
|
|
|
def __str__(self):
|
|
return f'<MfxCanvas @ {hex(id(self))}>'
|
|
|
|
def __init__(self, wmain, *args, **kw):
|
|
super(MfxCanvas, self).__init__(background=True)
|
|
|
|
# print('MfxCanvas: __init__()')
|
|
# self.tags = {} # bei basisklasse widget (ev. nur vorläufig)
|
|
|
|
self.wmain = wmain
|
|
# print('MfxCanvas: wmain = %s' % self.wmain)
|
|
|
|
# Tkinter.Canvas.__init__(self, *args, **kw)
|
|
self.preview = 0
|
|
self.busy = False
|
|
self._text_color = '#000000'
|
|
self._bg_color = '#00ffff'
|
|
self._stretch_bg_image = 0
|
|
self._save_aspect_bg_image = 0
|
|
#
|
|
self.xmargin, self.ymargin = 0.0, 0.0
|
|
self.topImage = None
|
|
|
|
# Skalierung
|
|
# self.lastsize = (self.size[0], self.size[1])
|
|
# self.lastpos = (self.pos[0], self.pos[1])
|
|
|
|
self.scale = 1.2
|
|
self.r_width = None
|
|
self.r_height = None
|
|
|
|
self.bindings = {}
|
|
self.bind(pos=self.pos_update_widget)
|
|
self.bind(size=self.size_update_widget)
|
|
|
|
def KivyToCoreP(self, pos, size, scale):
|
|
cpos = pos
|
|
cpos = (cpos[0] - self.pos[0], self.pos[1] +
|
|
self.size[1] - cpos[1] - size[1])
|
|
cpos = (1.0 * cpos[0] / scale, 1.0 * cpos[1] / scale)
|
|
csize = (1.0 * size[0] / scale, 1.0 * size[1] / scale)
|
|
return cpos, csize
|
|
|
|
def CoreToKivyP(self, cpos, csize, scale):
|
|
size = (1.0 * csize[0] * scale, 1.0 * csize[1] * scale)
|
|
pos = (1.0 * cpos[0] * scale, 1.0 * cpos[1] * scale)
|
|
pos = (self.pos[0] + pos[0], self.pos[1] +
|
|
self.size[1] - pos[1] - size[1])
|
|
return pos, size
|
|
|
|
def KivyToCore(self, pos, size=(0.0, 0.0)):
|
|
return self.KivyToCoreP(pos, size, self.scale)
|
|
|
|
def CoreToKivy(self, cpos, csize=(0.0, 0.0)):
|
|
return self.CoreToKivyP(cpos, csize, self.scale)
|
|
|
|
def move(self, itm, dx, dy):
|
|
# print ('MfxCanvas: move %s %s %s' % (itm, dx, dy))
|
|
scale = self.scale
|
|
dx = scale * dx
|
|
dy = scale * dy
|
|
itm.pos = (itm.pos[0] + dx, itm.pos[1] - dy)
|
|
|
|
def scalefactor(self):
|
|
if self.r_width is None:
|
|
return self.scale
|
|
if self.r_height is None:
|
|
return self.scale
|
|
|
|
# TBD (idee).
|
|
# Hier ev. einen 2ten Modus zulassen, welche das Spielfeld
|
|
# knapp auf die vorhandenen Karten/Anzeigeelemente bemisst.
|
|
# Zur Optimierung der Sichtbarkeit auf kleinen Geräten.
|
|
# Könnte z.B. über Doppelklick umgeschaltet werden. (Die
|
|
# Skalierung müsste dann allerding nach jedem Zug dem ev.
|
|
# veränderten Feld angepasst werden.)
|
|
|
|
wid = self.size[0]
|
|
hei = self.size[1]
|
|
scfx = wid / self.r_width
|
|
scfy = hei / self.r_height
|
|
|
|
scf = scfx
|
|
if (scfx < scfy):
|
|
# print('scale factor by x = %s' % (scfx))
|
|
scf = scfx
|
|
else:
|
|
# print('scale factor by y = %s' % (scfy))
|
|
scf = scfy
|
|
|
|
return scf
|
|
|
|
def pos_update_widget(self, posorobj, size):
|
|
# print('MfxCanvas: pos_update_widget size=(%s, %s)' %
|
|
# (self.size[0], self.size[1]))
|
|
self.update_widget(posorobj, size)
|
|
|
|
def size_update_widget(self, posorobj, size):
|
|
# print('MfxCanvas: size_update_widget size=(%s, %s)' %
|
|
# (self.size[0], self.size[1]))
|
|
self.update_widget(posorobj, size)
|
|
|
|
def update_widget(self, posorobj, size):
|
|
def psize(s):
|
|
return "({:1.2f}, {:1.2f})".format(s[0], s[1])
|
|
|
|
# logging.info('MfxCanvas: update_widget to: '+psize(size))
|
|
|
|
# print('MfxCanvas: update_widget size=(%s, %s)' %
|
|
# (self.size[0], self.size[1]))
|
|
|
|
# Update Skalierungsparameter
|
|
|
|
# oldscale = self.scale
|
|
newscale = self.scalefactor()
|
|
# logging.info('MfxCanvas: scale factor: {:1.2f})'.format(newscale))
|
|
self.scale = newscale
|
|
|
|
# Anpassung Skalierung.
|
|
|
|
for c in self.children:
|
|
if not hasattr(c, 'corePos'):
|
|
continue
|
|
if not hasattr(c, 'coreSize'):
|
|
continue
|
|
|
|
bpos = c.corePos
|
|
bsiz = c.coreSize
|
|
if bpos and bsiz:
|
|
npos, nsiz = self.CoreToKivy(bpos, bsiz)
|
|
c.pos = npos
|
|
c.size = nsiz
|
|
|
|
# Hintergrund update.
|
|
|
|
kc = LColorToKivy(self._bg_color)
|
|
texture = None
|
|
if self._bg_img:
|
|
texture = self._bg_img.texture
|
|
|
|
self.texture = texture
|
|
if texture is None:
|
|
self.setColor(kc)
|
|
else:
|
|
self.setColor([1,1,1,1]) # noqa
|
|
if self._stretch_bg_image:
|
|
if self._save_aspect_bg_image == 0:
|
|
self.fit_mode = "fill"
|
|
else:
|
|
self.fit_mode = "cover"
|
|
else:
|
|
self.fit_mode = "tiling"
|
|
|
|
# Funktionen, welche vom Core aufgerufen werden.
|
|
|
|
def winfo_width(self):
|
|
# return self.r_width
|
|
cpos, csize = self.KivyToCoreP(self.pos, self.size, self.scale)
|
|
# print('MfxCanvas: winfo_width %s' % (csize[0]))
|
|
return csize[0]
|
|
|
|
def winfo_height(self):
|
|
# return self.r_height
|
|
cpos, csize = self.KivyToCoreP(self.pos, self.size, self.scale)
|
|
# print('MfxCanvas: winfo_height %s' % (csize[1]))
|
|
return csize[1]
|
|
|
|
def cget(self, f):
|
|
print('MfxCanvas: cget %s -> %s, %s' % (f, self.pos, self.size))
|
|
cpos, csize = self.KivyToCoreP(self.pos, self.size, self.scale)
|
|
if f == 'width':
|
|
print('MfxCanvas: cget %s -> x=%s' % (f, cpos[0]))
|
|
return cpos[0]
|
|
if f == 'height':
|
|
print('MfxCanvas: cget %s -> y=%s' % (f, cpos[1]))
|
|
return cpos[1]
|
|
# if f=='bg':
|
|
# return background-color
|
|
print('MfxCanvas: cget unsupported token')
|
|
return 1
|
|
|
|
def xview(self):
|
|
print('MfxCanvas: xview')
|
|
return [1, 1]
|
|
pass
|
|
|
|
def yview(self):
|
|
print('MfxCanvas: yview')
|
|
return [1, 1]
|
|
pass
|
|
|
|
#
|
|
# top-image support
|
|
#
|
|
def tag_raise(self, itm, abitm=None):
|
|
# print('MfxCanvas: tag_raise(%s, %s)' % (itm, abitm))
|
|
|
|
def findTop(itm):
|
|
t = type(itm)
|
|
for c in self.children:
|
|
if type(c) is t:
|
|
return self.children.index(c)
|
|
return 0
|
|
|
|
if (itm is not None):
|
|
if (abitm is None):
|
|
self.remove_widget(itm)
|
|
self.add_widget(itm, index=findTop(itm))
|
|
else:
|
|
self.remove_widget(itm)
|
|
k = self.children.index(abitm)
|
|
self.add_widget(itm, index=k)
|
|
|
|
def tag_lower(self, itm, belowThis=None):
|
|
# print('MfxCanvas: tag_lower(%s, %s)' % (itm, belowThis))
|
|
|
|
if (itm is not None):
|
|
if (belowThis is None):
|
|
self.remove_widget(itm)
|
|
k = len(self.children)
|
|
self.add_widget(itm, index=k)
|
|
else:
|
|
self.remove_widget(itm)
|
|
k = self.children.index(belowThis)
|
|
k += 1
|
|
self.add_widget(itm, index=k)
|
|
|
|
def setInitialSize(self, width, height):
|
|
self.r_width = width
|
|
self.r_height = height
|
|
self.update_widget(self.pos, self.size)
|
|
return
|
|
|
|
# delete all CanvasItems, but keep the background and top tiles
|
|
def deleteAllItems(self):
|
|
print('MfxCanvas: deleteAllItems')
|
|
self.clear_widgets()
|
|
pass
|
|
|
|
def findCard(self, stack, event):
|
|
print('MfxCanvas: findCard(%s, %s)' % (stack, event))
|
|
if (event.cardid > -1):
|
|
return event.cardid
|
|
|
|
print('MfxCanvas: findCard no cardid')
|
|
return -1
|
|
|
|
def findImagesByType(self, image_type):
|
|
images = []
|
|
for c in self.children:
|
|
if type(c) is LImageItem:
|
|
if c.get_image_type() == image_type:
|
|
images.append(c)
|
|
return images
|
|
|
|
def setTextColor(self, color):
|
|
# print('MfxCanvas: setTextColor')
|
|
# color is ignored: it sets a predefined (option settable)
|
|
# color. We do not support that. Instead of this wie examine
|
|
# the background and set the color accordingly.
|
|
if self._bg_img is not None:
|
|
from pysollib.kivy.LApp import LTextureToLuminance
|
|
lumi = LTextureToLuminance(self._bg_img.texture)
|
|
else:
|
|
from pysollib.kivy.LApp import LColorToLuminance
|
|
lumi = LColorToLuminance(self._bg_color)
|
|
|
|
self._text_color = ("#000000", "#ffffff")[lumi < 0.4]
|
|
# print('average luminance =', lumi)
|
|
|
|
def setTile(self, image, stretch=0, save_aspect=0):
|
|
|
|
# print('setTile: %s, %s, %s' % (image, stretch, save_aspect))
|
|
if image:
|
|
try:
|
|
from pysollib.kivy.tkutil import LImageInfo
|
|
self._bg_img = LImageInfo(image)
|
|
self._stretch_bg_image = stretch
|
|
self._save_aspect_bg_image = save_aspect
|
|
self.update_widget(self.pos, self.size)
|
|
except Exception:
|
|
return 0
|
|
else:
|
|
# print ('setTile: no image!')
|
|
self._bg_img = None
|
|
self.update_widget(self.pos, self.size)
|
|
return 1
|
|
|
|
def setTopImage(self, image, cw=0, ch=0):
|
|
print('MfxCanvas: setTopImage %s' % image)
|
|
|
|
if self.topImage:
|
|
self.clear_widgets([self.topImage])
|
|
self.topImage = None
|
|
|
|
if image:
|
|
tex = LImage(texture=image.texture)
|
|
tex.size_hint = (0.4, 0.4)
|
|
lay = AnchorLayout(anchor_y='bottom')
|
|
lay.size = self.size
|
|
lay.add_widget(tex)
|
|
|
|
self.topImage = lay
|
|
self.add_widget(self.topImage)
|
|
|
|
return 1
|
|
#
|
|
# Pause support
|
|
#
|
|
|
|
def hideAllItems(self):
|
|
print('MfxCanvas: hideAllItems')
|
|
# TBD
|
|
# Wir lassen das. Das TopImage deckt alles ab. Spielen ist
|
|
# nicht möglich.
|
|
pass
|
|
|
|
def showAllItems(self):
|
|
print('MfxCanvas: showAllItems')
|
|
# TBD
|
|
# Brauchts darum auch nicht.
|
|
pass
|
|
|
|
# Erweiterungen fuer Tk Canvas (prüfen was noch nötig!!).
|
|
|
|
def itemconfig(self, tagOrId, cnf=None, **kw):
|
|
"""Configure resources of an item TAGORID.
|
|
|
|
The values for resources are specified as keyword
|
|
arguments. To get an overview about
|
|
the allowed keyword arguments call the method without arguments.
|
|
"""
|
|
print(
|
|
'MfxCanvas: itemconfigure tagOrId=%s, cnf=%s, kw=%s'
|
|
% (tagOrId, cnf, kw))
|
|
|
|
if 'image' in cnf:
|
|
# tagOrId ist ein Image oder ein CardImage
|
|
# self.clear_widgets([cnf['image']])
|
|
# self.add_widget(cnf['image'])
|
|
# y = self.yy
|
|
pass
|
|
if 'text' in cnf:
|
|
# tagOrId ist das Label.
|
|
tagOrId.text = cnf['text']
|
|
pass
|
|
|
|
def config(self, cnf={}, **kw):
|
|
# print('MfxCanvas: config %s %s' % (cnf, kw))
|
|
if ('cursor' in kw):
|
|
pass
|
|
if ('width' in kw):
|
|
self.size[0] = kw['width']
|
|
if ('height' in kw):
|
|
self.size[1] = kw['height']
|
|
if ('bg' in kw):
|
|
self._bg_color = kw['bg']
|
|
self.update_widget(self.pos, self.size)
|
|
|
|
def dtag(self, tag, b=None):
|
|
# print ('Canvas: dtag %s %s' % (tag, b))
|
|
# if (tag in self.tags):
|
|
# if (self.tags[tag]==b):
|
|
# del self.tags[tag]
|
|
pass
|
|
|
|
def addtag(self, tag, b, c):
|
|
# print ('Canvas: addtag %s %s %s' % (tag, b, c))
|
|
# self.tags[c] = tag
|
|
# self.tags.append(tag)
|
|
pass
|
|
|
|
def delete(self, tag):
|
|
# print ('MfxCanvas: delete tag=%s' % tag)
|
|
# y = self.yy
|
|
pass
|
|
|
|
def update_idletasks(self):
|
|
print('MfxCanvas: update_idletasks')
|
|
self.wmain.update_idletasks()
|