1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00

Kivy/Android

- switching of redeal images (redeal/stopped) corrected.
 - new wrapper class for options management. Refactorings.
 - redeal, pause and demo logo style selections updated.
This commit is contained in:
lufebe16 2023-12-12 10:46:55 +01:00
parent 611bd37024
commit c5b22563a8
6 changed files with 162 additions and 56 deletions

View file

@ -1779,6 +1779,8 @@ class Game(object):
return return
if TOOLKIT == 'gtk': if TOOLKIT == 'gtk':
return return
if TOOLKIT == 'kivy':
return
if not Image: if not Image:
return return
self.canvas.hideAllItems() self.canvas.hideAllItems()
@ -1801,6 +1803,8 @@ class Game(object):
return return
def redealAnimation(self): def redealAnimation(self):
if TOOLKIT == 'kivy':
return
if self.preview: if self.preview:
return return
if not self.app.opt.animations or not self.app.opt.redeal_animation: if not self.app.opt.animations or not self.app.opt.redeal_animation:
@ -3428,6 +3432,11 @@ class Game(object):
d = time.time() - self.stats.update_time + self.stats.elapsed_time d = time.time() - self.stats.update_time + self.stats.elapsed_time
self.updateStatus(time=format_time(d)) self.updateStatus(time=format_time(d))
def displayPauseImage(self):
n = self.random.initial_seed % len(self.app.gimages.pause)
self.pause_logo = self.app.gimages.pause[int(n)]
self.canvas.setTopImage(self.pause_logo)
def doPause(self): def doPause(self):
if self.finished: if self.finished:
return return
@ -3439,9 +3448,7 @@ class Game(object):
if self.pause: if self.pause:
# self.updateTime() # self.updateTime()
self.canvas.hideAllItems() self.canvas.hideAllItems()
n = self.random.initial_seed % len(self.app.gimages.pause) self.displayPauseImage()
self.pause_logo = self.app.gimages.pause[int(n)]
self.canvas.setTopImage(self.pause_logo)
else: else:
self.stats.update_time = time.time() self.stats.update_time = time.time()
self.updatePlayTime() self.updatePlayTime()

View file

@ -698,12 +698,17 @@ class LImageItem(BoxLayout, LBase):
self.game = None self.game = None
self.card = None self.card = None
self.group = None self.group = None
self.image_type = "undefined"
if 'game' in kw: if 'game' in kw:
self.game = kw['game'] self.game = kw['game']
if 'card' in kw: if 'card' in kw:
self.card = kw['card'] self.card = kw['card']
self.image_type = "card"
if 'group' in kw: if 'group' in kw:
self.group = kw['group'] self.group = kw['group']
if 'image_type' in kw:
self.image_type = kw['image_type']
self.dragstart = None self.dragstart = None
# ev. noch globales cache für stacks->game und cards->stack # ev. noch globales cache für stacks->game und cards->stack
# einrichten. Aber: stacks hängt vom jeweiligen spiel ab. # einrichten. Aber: stacks hängt vom jeweiligen spiel ab.
@ -711,6 +716,9 @@ class LImageItem(BoxLayout, LBase):
def __str__(self): def __str__(self):
return f'<LImageItem @ {hex(id(self))}>' return f'<LImageItem @ {hex(id(self))}>'
def get_image_type(self):
return self.image_type
def send_event_pressed_n(self, event, n): def send_event_pressed_n(self, event, n):
if self.group and n in self.group.bindings: if self.group and n in self.group.bindings:
self.group.bindings[n](event) self.group.bindings[n](event)

69
pysollib/kivy/LObjWrap.py Normal file
View file

@ -0,0 +1,69 @@
#!/usr/bin/python
# -*- mode: python; coding: utf-8; -*-
# =============================================================================
# Copyright (C) 2017-2023 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.
# Flake8: noqa
#
# =============================================================================
import logging
from kivy.event import EventDispatcher
from kivy.properties import BooleanProperty
from kivy.properties import NumericProperty
from kivy.properties import ListProperty
from kivy.properties import StringProperty
# =============================================================================
# Joins kivy properties to object members of referenced class.
# Usage:
# - use derived classes LBoolWrap etc. according to type.
# - write: obj.value = <new value>
# - read: <actual value> = obj.value
# - If you need additional functionality on change add a callback function
# as 'command'. It will be called whenever the value changes.
class LObjWrap(EventDispatcher):
def __init__(self,obj,ref,command=None):
self.obj = obj
self.ref = ref
self.value = getattr(self.obj,self.ref)
# logging.info("LObjWrap: setup for %s" % (self.ref))
self.bind(value=self.on_value)
if command is not None:
self.bind(value=command)
def on_value(self,inst,val):
logging.info("LObjWrap: %s = %s" % (self.ref,val))
setattr(self.obj,self.ref,val)
class LBoolWrap(LObjWrap):
value = BooleanProperty(False)
def __init__(self,obj,ref,command=None):
super(LBoolWrap,self).__init__(obj,ref,command)
class LNumWrap(LObjWrap):
value = NumericProperty(0)
def __init__(self,obj,ref,command=None):
super(LNumWrap,self).__init__(obj,ref,command)
class LStringWrap(LObjWrap):
value = StringProperty('')
def __init__(self,obj,ref,command=None):
super(LStringWrap,self).__init__(obj,ref,command)
class LListWrap(LObjWrap):
value = ListProperty([])
def __init__(self,obj,ref,command=None):
super(LListWrap,self).__init__(obj,ref,command)
# =============================================================================

View file

@ -40,6 +40,9 @@ from pysollib.kivy.LApp import LScrollView
from pysollib.kivy.LApp import LTopLevel from pysollib.kivy.LApp import LTopLevel
from pysollib.kivy.LApp import LTreeNode from pysollib.kivy.LApp import LTreeNode
from pysollib.kivy.LApp import LTreeRoot from pysollib.kivy.LApp import LTreeRoot
from pysollib.kivy.LObjWrap import LBoolWrap
from pysollib.kivy.LObjWrap import LNumWrap
from pysollib.kivy.LObjWrap import LStringWrap
from pysollib.kivy.androidrot import AndroidScreenRotation from pysollib.kivy.androidrot import AndroidScreenRotation
from pysollib.kivy.findcarddialog import destroy_find_card_dialog from pysollib.kivy.findcarddialog import destroy_find_card_dialog
from pysollib.kivy.fullpicturedialog import destroy_full_picture_dialog from pysollib.kivy.fullpicturedialog import destroy_full_picture_dialog
@ -119,15 +122,17 @@ class LMenuBase(object):
self.closeWindow(0) self.closeWindow(0)
return auto_close_command return auto_close_command
def make_auto_command(self, variable, command): def make_toggle_command(self, variable, command):
def auto_command(): def auto_command():
variable.set(not variable.get()) variable.value = not variable.value
if command is not None:
command() command()
return auto_command return auto_command
def make_val_command(self, variable, value, command): def make_val_command(self, variable, value, command):
def val_command(): def val_command():
variable.value = value variable.value = value
if command is not None:
command() command()
return val_command return val_command
@ -149,7 +154,7 @@ class LMenuBase(object):
return _command return _command
def addCheckNode(self, tv, rg, title, auto_var, auto_com): def addCheckNode(self, tv, rg, title, auto_var, auto_com):
command = self.make_auto_command(auto_var, auto_com) command = self.make_toggle_command(auto_var, auto_com)
rg1 = tv.add_node( rg1 = tv.add_node(
LTreeNode(text=title, command=command, variable=auto_var), rg) LTreeNode(text=title, command=command, variable=auto_var), rg)
return rg1 return rg1
@ -278,7 +283,7 @@ class MainMenuDialog(LMenuDialog):
menubar, parent, title, app, **kw) menubar, parent, title, app, **kw)
print('MainMenuDialog starting') print('MainMenuDialog starting')
AndroidScreenRotation.unlock() AndroidScreenRotation.unlock(toaster=False)
def buildTree(self, tv, node): def buildTree(self, tv, node):
rg = tv.add_node( rg = tv.add_node(
@ -1134,17 +1139,23 @@ class LOptionsMenuGenerator(LTreeGenerator):
self.menubar.tkopt.animations, 5, self.menubar.tkopt.animations, 5,
self.menubar.mOptAnimations) self.menubar.mOptAnimations)
# submenu.add_separator() # NOTE: All the following animation features only work on the
# desktop and only if pillow is installed. So its useless to
# present them here.
'''
self.addCheckNode(tv, rg, self.addCheckNode(tv, rg,
_('Redeal animation'), _('Redeal animation'),
self.menubar.tkopt.redeal_animation, self.menubar.tkopt.redeal_animation,
self.menubar.mRedealAnimation) self.menubar.mRedealAnimation)
self.addCheckNode(tv, rg, self.addCheckNode(tv, rg,
_('Winning animation'), _('Winning animation'),
self.menubar.tkopt.win_animation, self.menubar.tkopt.win_animation,
self.menubar.mWinAnimation) self.menubar.mWinAnimation)
self.addCheckNode(tv, rg,
_('Flip animation'),
self.menubar.tkopt.flip_animation,
None)
'''
yield yield
# ------------------------------------------- # -------------------------------------------
@ -1472,6 +1483,7 @@ class PysolMenubarTk:
self.progress.update(step=1) self.progress.update(step=1)
def _createTkOpt(self): def _createTkOpt(self):
opt = self.app.opt
# structure to convert menu-options to Toolkit variables # structure to convert menu-options to Toolkit variables
self.tkopt = Struct( self.tkopt = Struct(
gameid=IntVar(), gameid=IntVar(),
@ -1501,9 +1513,10 @@ class PysolMenubarTk:
sound_music_volume=IntVar(), sound_music_volume=IntVar(),
cardback=IntVar(), cardback=IntVar(),
tabletile=IntVar(), tabletile=IntVar(),
animations=IntVar(), animations=LNumWrap(opt, "animations"),
redeal_animation=BooleanVar(), redeal_animation=LBoolWrap(opt, "redeal_animation"),
win_animation=BooleanVar(), win_animation=LBoolWrap(opt, "win_animation"),
flip_animation=LBoolWrap(opt, "flip_animation"),
shadow=BooleanVar(), shadow=BooleanVar(),
shade=BooleanVar(), shade=BooleanVar(),
shade_filled_stacks=BooleanVar(), shade_filled_stacks=BooleanVar(),
@ -1518,10 +1531,10 @@ class PysolMenubarTk:
helpbar=BooleanVar(), helpbar=BooleanVar(),
save_games_geometry=BooleanVar(), save_games_geometry=BooleanVar(),
splashscreen=BooleanVar(), splashscreen=BooleanVar(),
demo_logo=BooleanVar(), demo_logo=LBoolWrap(opt, "demo_logo"),
demo_logo_style=StringVar(), demo_logo_style=LStringWrap(opt, "demo_logo_style"),
pause_text_style=StringVar(), pause_text_style=LStringWrap(opt, "pause_text_style"),
redeal_icon_style=StringVar(), redeal_icon_style=LStringWrap(opt, "redeal_icon_style"),
mouse_type=StringVar(), mouse_type=StringVar(),
mouse_undo=BooleanVar(), mouse_undo=BooleanVar(),
negative_bottom=BooleanVar(), negative_bottom=BooleanVar(),
@ -1570,9 +1583,6 @@ class PysolMenubarTk:
tkopt.sound_music_volume.set(opt.sound_music_volume) tkopt.sound_music_volume.set(opt.sound_music_volume)
tkopt.cardback.set(self.app.cardset.backindex) tkopt.cardback.set(self.app.cardset.backindex)
tkopt.tabletile.set(self.app.tabletile_index) tkopt.tabletile.set(self.app.tabletile_index)
tkopt.animations.set(opt.animations)
tkopt.redeal_animation.set(opt.redeal_animation)
tkopt.win_animation.set(opt.win_animation)
tkopt.shadow.set(opt.shadow) tkopt.shadow.set(opt.shadow)
tkopt.shade.set(opt.shade) tkopt.shade.set(opt.shade)
tkopt.toolbar.set(opt.toolbar) tkopt.toolbar.set(opt.toolbar)
@ -1583,10 +1593,6 @@ class PysolMenubarTk:
tkopt.toolbar_relief.set(opt.toolbar_relief) tkopt.toolbar_relief.set(opt.toolbar_relief)
tkopt.statusbar.set(opt.statusbar) tkopt.statusbar.set(opt.statusbar)
tkopt.save_games_geometry.set(opt.save_games_geometry) tkopt.save_games_geometry.set(opt.save_games_geometry)
tkopt.demo_logo.set(opt.demo_logo)
tkopt.demo_logo_style.set(opt.demo_logo_style)
tkopt.pause_text_style.set(opt.pause_text_style)
tkopt.redeal_icon_style.set(opt.redeal_icon_style)
tkopt.splashscreen.set(opt.splashscreen) tkopt.splashscreen.set(opt.splashscreen)
tkopt.mouse_type.set(opt.mouse_type) tkopt.mouse_type.set(opt.mouse_type)
tkopt.mouse_undo.set(opt.mouse_undo) tkopt.mouse_undo.set(opt.mouse_undo)
@ -2334,17 +2340,14 @@ the next time you restart the %(app)s""") % {'app': TITLE})
def mOptAnimations(self, *args): def mOptAnimations(self, *args):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.animations = self.tkopt.animations.value
def mRedealAnimation(self, *args): def mRedealAnimation(self, *args):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.redeal_animation = self.tkopt.redeal_animation.value
def mWinAnimation(self, *args): def mWinAnimation(self, *args):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.win_animation = self.tkopt.win_animation.value
def mWinDialog(self, *args): def mWinDialog(self, *args):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
@ -2499,13 +2502,13 @@ the next time you restart the %(app)s""") % {'app': TITLE})
self.toolbarConfig(w, self.tkopt.toolbar_vars[w].get()) self.toolbarConfig(w, self.tkopt.toolbar_vars[w].get())
def mOptDemoLogoStyle(self, *event): def mOptDemoLogoStyle(self, *event):
self.setDemoLogoStyle(self.tkopt.demo_logo_style.get()) self.setDemoLogoStyle()
def mOptPauseTextStyle(self, *event): def mOptPauseTextStyle(self, *event):
self.setPauseTextStyle(self.tkopt.pause_text_style.get()) self.setPauseTextStyle()
def mOptRedealIconStyle(self, *event): def mOptRedealIconStyle(self, *event):
self.setRedealIconStyle(self.tkopt.redeal_icon_style.get()) self.setRedealIconStyle()
def mOptStatusbar(self, *event): def mOptStatusbar(self, *event):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
@ -2542,7 +2545,6 @@ the next time you restart the %(app)s""") % {'app': TITLE})
def mOptDemoLogo(self, *event): def mOptDemoLogo(self, *event):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.demo_logo = self.tkopt.demo_logo.get()
def mOptSplashscreen(self, *event): def mOptSplashscreen(self, *event):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
@ -2630,20 +2632,15 @@ the next time you restart the %(app)s""") % {'app': TITLE})
# other graphics # other graphics
# #
def setDemoLogoStyle(self, style): def setDemoLogoStyle(self, style=None):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
if style == "none": if self.tkopt.demo_logo_style.value == "none":
self.app.opt.demo_logo = False self.tkopt.demo_logo.value = False
else: else:
self.app.opt.demo_logo = True self.tkopt.demo_logo.value = True
self.app.opt.demo_logo_style = style
self.tkopt.demo_logo_style.set(style) # update radiobutton
self.app.loadImages2() self.app.loadImages2()
self.app.loadImages4() self.app.loadImages4()
self.app.updateCardset()
self.game.endGame(bookmark=1)
self.game.quitGame(bookmark=1)
def setDialogIconStyle(self, style): def setDialogIconStyle(self, style):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
@ -2653,27 +2650,25 @@ the next time you restart the %(app)s""") % {'app': TITLE})
self.app.loadImages1() self.app.loadImages1()
self.app.loadImages4() self.app.loadImages4()
def setPauseTextStyle(self, style): def setPauseTextStyle(self, style=None):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.pause_text_style = style
self.tkopt.pause_text_style.set(style) # update radiobutton
self.app.loadImages2() self.app.loadImages2()
self.app.loadImages4() self.app.loadImages4()
self.app.updateCardset() if self.tkopt.pause.value:
self.game.endGame(bookmark=1) self.app.game.displayPauseImage()
self.game.quitGame(bookmark=1)
def setRedealIconStyle(self, style): def setRedealIconStyle(self, style=None):
if self._cancelDrag(break_pause=False): if self._cancelDrag(break_pause=False):
return return
self.app.opt.redeal_icon_style = style
self.tkopt.redeal_icon_style.set(style) # update radiobutton
self.app.loadImages2() self.app.loadImages2()
self.app.loadImages4() self.app.loadImages4()
self.app.updateCardset() try:
self.game.endGame(bookmark=1) images = self.app.game.canvas.findImagesByType("redeal_image")
self.game.quitGame(bookmark=1) for i in images:
i.group.stack.updateRedealImage()
except: # noqa
pass
# #
# stacks descriptions # stacks descriptions

View file

@ -277,6 +277,7 @@ class MfxCanvasImage(object):
super(MfxCanvasImage, self).__init__() super(MfxCanvasImage, self).__init__()
self.canvas = canvas self.canvas = canvas
self.redeal = False
# animation mode support: # animation mode support:
self.animation = 0 self.animation = 0
@ -291,12 +292,15 @@ class MfxCanvasImage(object):
else: else:
image = LImage(texture=ed.texture) image = LImage(texture=ed.texture)
if self.hint == "redeal_image": if self.hint == "redeal_image":
cm = cardmagnif(canvas, size)/3.0 cm = cardmagnif(canvas, size)/1.9
image.size = [cm*ed.getWidth(), cm*ed.getHeight()] image.size = [cm*ed.getWidth(), cm*ed.getHeight()]
self.redeal = True
aimage = LImageItem(
size=ed.size, group=group, image_type=self.hint)
else: else:
image.size = [ed.getWidth(), ed.getHeight()] image.size = [ed.getWidth(), ed.getHeight()]
aimage = LImageItem(size=ed.size, group=group) aimage = LImageItem(size=ed.size, group=group)
aimage.add_widget(image) aimage.add_widget(image)
aimage.size = image.size aimage.size = image.size
size = image.size size = image.size
@ -322,6 +326,13 @@ class MfxCanvasImage(object):
return f'<MfxCanvasImage @ {hex(id(self))}>' return f'<MfxCanvasImage @ {hex(id(self))}>'
def config(self, **kw): 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 pass
def makeDeferredRaise(self, pos): def makeDeferredRaise(self, pos):
@ -819,6 +830,14 @@ class MfxCanvas(LImage):
print('MfxCanvas: findCard no cardid') print('MfxCanvas: findCard no cardid')
return -1 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): def setTextColor(self, color):
# print('MfxCanvas: setTextColor') # print('MfxCanvas: setTextColor')
# color is ignored: it sets a predefined (option settable) # color is ignored: it sets a predefined (option settable)

View file

@ -1857,6 +1857,14 @@ class TalonStack(Stack,
for stack in self.game.allstacks: for stack in self.game.allstacks:
stack.updateText() stack.updateText()
def updateRedealImage(self):
deal = self.canDealCards() != 0
if self.images.redeal is not None:
img = (self.getRedealImages())[deal]
if img is not None and img is not self.images.redeal_img:
self.images.redeal.config(image=img)
self.images.redeal_img = img
def updateText(self, update_rounds=1, update_redeal=1): def updateText(self, update_rounds=1, update_redeal=1):
# assertView(self) # assertView(self)
Stack.updateText(self) Stack.updateText(self)