1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-22 03:04:09 -04:00

toolbar updates (#333)

- quit button removed, makes no sense with kivy/android version
- shuffle/autodrop button managed dynamically
- delayed execution on new and restart buttons, to prevent
  accicental activation while playing
This commit is contained in:
lufebe16 2023-09-19 15:03:31 +02:00
parent 187bae25cb
commit 158c3137fd
5 changed files with 194 additions and 85 deletions

View file

@ -430,6 +430,16 @@ class Application:
self.toolbar.config( self.toolbar.config(
'shuffle', 'shuffle',
self.opt.toolbar_vars['shuffle'] and self.game.canShuffle()) self.opt.toolbar_vars['shuffle'] and self.game.canShuffle())
if TOOLKIT == 'kivy':
self.toolbar.config(
'undo',
self.opt.toolbar_vars['undo'] and self.game.canUndo())
self.toolbar.config(
'undo',
self.opt.toolbar_vars['redo'] and self.game.canRedo())
self.toolbar.config(
'autodrop',
self.opt.toolbar_vars['autodrop'] and not self.game.canShuffle()) # noqa
# delete intro progress bar # delete intro progress bar
if self.intro.progress: if self.intro.progress:
self.intro.progress.destroy() self.intro.progress.destroy()

View file

@ -44,6 +44,7 @@ from kivy.uix.actionbar import ActionPrevious
from kivy.uix.actionbar import ActionView from kivy.uix.actionbar import ActionView
from kivy.uix.behaviors import ButtonBehavior from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image as KivyImage from kivy.uix.image import Image as KivyImage
from kivy.uix.label import Label from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView from kivy.uix.scrollview import ScrollView
@ -1814,7 +1815,9 @@ class LApp(App):
# Config.set('input', 'multitouchscreen1', 'tuio,0.0.0.0:3333') # Config.set('input', 'multitouchscreen1', 'tuio,0.0.0.0:3333')
self.baseWindow = FloatLayout() # needed e.g. for toasts
self.mainWindow = LMainWindow() self.mainWindow = LMainWindow()
self.baseWindow.add_widget(self.mainWindow)
logging.info('top = %s' % str(self.mainWindow)) logging.info('top = %s' % str(self.mainWindow))
Cache.register('LAppCache', limit=10) Cache.register('LAppCache', limit=10)
Cache.append('LAppCache', 'mainWindow', self.mainWindow, timeout=0) Cache.append('LAppCache', 'mainWindow', self.mainWindow, timeout=0)

68
pysollib/kivy/toast.py Normal file
View file

@ -0,0 +1,68 @@
# ================================================================
# flake8: noqa
# Toast implementation
# LB230919
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.uix.label import Label
from kivy.graphics import Color
from kivy.graphics.vertex_instructions import RoundedRectangle
# ================================================================
class Toast(Label):
def __init__(self, **kw):
super().__init__(opacity=0, **kw)
self.duration = 4.0
self.tsize = self.size
self.rsize = 20
with self.canvas.before:
Color(0.2, 0.2, 0.2, 0.8)
self.rect = RoundedRectangle()
self.bind(size=self._update_rect)
self.bind(texture_size=self.eval_size)
def eval_size(self,instance,size):
width, height = size
if width > self.parent.width:
instance.text_size = (self.parent.width, None)
instance.texture_update()
width, height = instance.texture_size
ads = height * 1.7
self.tsize = (width + ads, height + ads)
self.rsize = [(ads+height)/2.0,]
#print(self.tsize,self.rsize)
def _update_rect(self, instance, value):
self.rect.size = self.tsize
self.rect.pos = (instance.center_x-self.tsize[0]/2.0,instance.center_y-self.tsize[1]/2.0)
self.rect.radius = self.rsize
def stop(self, *args):
self.parent.remove_widget(self)
def hide(self, *args):
anim = Animation(opacity=0, duration=0.4)
anim.bind(on_complete=self.stop)
anim.start(self)
# Timed display with fadein/-out
def show(self, parent=None, duration=2.0):
if parent is None:
return
self.duration = duration
parent.add_widget(self)
anim = Animation(opacity=1, duration=0.4)
anim.start(self)
Clock.schedule_once(self.hide,self.duration)
# Popup display - use 'stop' to terminate.
def start(self,parent=None):
if parent is None:
return
self.opacity = 1
parent.add_widget(self)
# ================================================================

View file

@ -20,10 +20,10 @@
# imports # imports
import os import os
from time import time
# PySol imports # PySol imports
from pysollib.mygettext import _, n_ from pysollib.mygettext import _, n_
from pysollib.settings import TITLE
from pysollib.util import IMAGE_EXTENSIONS from pysollib.util import IMAGE_EXTENSIONS
from pysollib.winsystems import TkSettings from pysollib.winsystems import TkSettings
@ -31,64 +31,36 @@ from pysollib.winsystems import TkSettings
# * # *
# ************************************************************************ # ************************************************************************
from pysollib.kivy.LApp import LImage
class AbstractToolbarButton: from pysollib.kivy.LApp import LBase
def __init__(self, parent, toolbar, toolbar_name, position): from pysollib.kivy.toast import Toast
self.toolbar = toolbar # from LApp import LMainWindow
self.toolbar_name = toolbar_name from kivy.uix.boxlayout import BoxLayout
self.position = position # from kivy.uix.button import Button
self.visible = False from kivy.uix.behaviors import ButtonBehavior
# from kivy.uix.behaviors import ToggleButtonBehavior
def show(self, orient, force=False): from kivy.uix.image import Image as KivyImage
if self.visible and not force:
return
self.visible = True
padx, pady = 2, 2
if orient == 'horizontal':
self.grid(row=0,
column=self.position,
ipadx=padx, ipady=pady,
sticky='nsew')
else:
self.grid(row=self.position,
column=0,
ipadx=padx, ipady=pady,
sticky='nsew')
def hide(self):
if not self.visible:
return
self.visible = False
self.grid_forget()
# ************************************************************************ # ************************************************************************
from kivy.cache import Cache
if True:
from pysollib.kivy.LApp import LImage
from pysollib.kivy.LApp import LBase
# from LApp import LMainWindow
from kivy.uix.boxlayout import BoxLayout
# from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
# from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.uix.image import Image as KivyImage
# ************************************************************************
class MyButton(ButtonBehavior, KivyImage, LBase): class MyButton(ButtonBehavior, KivyImage, LBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs) super(MyButton, self).__init__(**kwargs)
# super(MyButton, self).__init__()
self.src = None self.src = None
if ('image' in kwargs): if ('image' in kwargs):
self.src = kwargs['image'].source self.src = kwargs['image'].source
self.command = None self.command = None
if ('command' in kwargs): if ('command' in kwargs):
self.command = kwargs['command'] self.command = kwargs['command']
self.name = ""
if ('name' in kwargs):
self.name = kwargs['name']
self.source = self.src self.source = self.src
self.allow_stretch = True self.allow_stretch = True
self.shown = True
def on_press(self): def on_press(self):
self.allow_stretch = False self.allow_stretch = False
@ -102,13 +74,15 @@ class MyButton(ButtonBehavior, KivyImage, LBase):
class MyCheckButton(ButtonBehavior, KivyImage, LBase): class MyCheckButton(ButtonBehavior, KivyImage, LBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(MyCheckButton, self).__init__(**kwargs) super(MyCheckButton, self).__init__(**kwargs)
# super(MyCheckButton, self).__init__()
self.src = None self.src = None
if ('image' in kwargs): if ('image' in kwargs):
self.src = kwargs['image'].source self.src = kwargs['image'].source
self.command = None self.command = None
if ('command' in kwargs): if ('command' in kwargs):
self.command = kwargs['command'] self.command = kwargs['command']
self.name = ""
if ('name' in kwargs):
self.name = kwargs['name']
self.variable = None self.variable = None
if ('variable' in kwargs): if ('variable' in kwargs):
self.variable = kwargs['variable'] self.variable = kwargs['variable']
@ -118,6 +92,7 @@ class MyCheckButton(ButtonBehavior, KivyImage, LBase):
self.source = self.src self.source = self.src
self.allow_stretch = True self.allow_stretch = True
self.checked = False self.checked = False
self.shown = True
# self.variable = self.win.app.menubar.tkopt.pause # self.variable = self.win.app.menubar.tkopt.pause
if self.variable: if self.variable:
@ -163,6 +138,44 @@ class MyCheckButton(ButtonBehavior, KivyImage, LBase):
def on_release(self): def on_release(self):
pass pass
class MyToastButton(ButtonBehavior, KivyImage, LBase):
def __init__(self, **kwargs):
super(MyToastButton, self).__init__(**kwargs)
self.src = None
if ('image' in kwargs):
self.src = kwargs['image'].source
self.command = None
if ('command' in kwargs):
self.command = kwargs['command']
self.name = ""
if ('name' in kwargs):
self.name = kwargs['name']
self.timeout = 0.0
if ('timeout' in kwargs):
self.timeout = kwargs['timeout']
self.source = self.src
self.allow_stretch = True
self.shown = True
self.start_time = 0.0
def on_press(self):
self.allow_stretch = False
self.start_time = time()
def on_release(self):
self.allow_stretch = True
delta = time()-self.start_time
if (self.command is not None):
if delta > self.timeout:
self.command()
else:
mainApp = Cache.get('LAppCache', 'mainApp')
toast = Toast(text=_("button released too early"))
toast.show(parent=mainApp.baseWindow, duration=2.0)
# print('too early released')
# ************************************************************************ # ************************************************************************
# * Note: Applications should call show/hide after constructor. # * Note: Applications should call show/hide after constructor.
# ************************************************************************ # ************************************************************************
@ -179,15 +192,31 @@ class PysolToolbarTk(BoxLayout):
compound='none'): compound='none'):
super(PysolToolbarTk, self).__init__(orientation='vertical') super(PysolToolbarTk, self).__init__(orientation='vertical')
self.size_hint = (0.05, 1.0) self.size_hint = (0.06, 1.0)
# self.size_hint=(None, 1.0) # self.size_hint=(None, 1.0)
# self.width = 50 # self.width = 50
self.win = top self.win = top
self.menubar = menubar self.menubar = menubar
self.dir = dir self.dir = dir
self.win.setTool(self, 3) self.win.setTool(self, 3)
self.buttons = []
for label, f, t in ( # This is called only once after program start. Configurations
# have to take place elsewhere.
bl = []
bl.append((n_("New"), self.mNewGame, _("New game")))
bl.append((n_("Restart"), self.mRestart, _("Restart the\ncurrent game"))) # noqa
bl.append((n_("Undo"), self.mUndo, _("Undo last move"))) # noqa
bl.append((n_("Redo"), self.mRedo, _("Redo last move")))
bl.append((n_("Autodrop"), self.mDrop, _("Auto drop cards")))
bl.append((n_("Shuffle"), self.mShuffle, _("Shuffle tiles")))
bl.append((n_("Hint"), self.mHint, _("Hint")))
bl.append((n_("Pause"), self.mPause, _("Pause game")))
bl.append((n_("Rules"), self.mHelpRules, _("Rules for this game")))
'''
for label, f, t in [
(n_("New"), self.mNewGame, _("New game")), (n_("New"), self.mNewGame, _("New game")),
(n_("Restart"), self.mRestart, _("Restart the\ncurrent game")), (n_("Restart"), self.mRestart, _("Restart the\ncurrent game")),
(None, None, None), (None, None, None),
@ -205,40 +234,27 @@ class PysolToolbarTk(BoxLayout):
(n_("Rules"), self.mHelpRules, _("Rules for this game")), (n_("Rules"), self.mHelpRules, _("Rules for this game")),
(None, None, None), (None, None, None),
(n_("Quit"), self.mHoldAndQuit, _("Quit %s") % TITLE), (n_("Quit"), self.mHoldAndQuit, _("Quit %s") % TITLE),
): ]:
'''
for label, f, t in bl:
if label is None: if label is None:
# sep = self._createSeparator() # We dont have separators in kivy version.
# sep.bind("<1>", self.clickHandler)
# sep.bind("<3>", self.rightclickHandler)
pass pass
elif label == 'Pause': elif label == 'Pause':
self._createButton(label, f, check=True, tooltip=t) button = self._createButton(label, f, check=True, tooltip=t)
self.buttons.append(button)
elif label in ["New", "Restart"]:
button = self._createButton(label, f, check=False, tooltip=t, timeout=1.0) # noqa
self.buttons.append(button)
else: else:
self._createButton(label, f, tooltip=t) button = self._createButton(label, f, check=False, tooltip=t)
self.buttons.append(button)
# hier gibt es noch ein 'player label' mit contextmenu, wo
# der spielername gewählt und die spielstatistik etc.
# angezeigt werden könnte (TBD):
'''
sep = self._createFlatSeparator()
sep.bind("<1>", self.clickHandler)
sep.bind("<3>", self.rightclickHandler)
self._createLabel("player", label=n_('Player'),
tooltip=_("Player options"))
#
self.player_label.bind("<1>", self.mOptPlayerOptions)
# self.player_label.bind("<3>", self.mOptPlayerOptions)
self.popup = MfxMenu(master=None, label=n_('Toolbar'), tearoff=0)
createToolbarMenu(menubar, self.popup)
self.frame.bind("<1>", self.clickHandler)
self.frame.bind("<3>", self.rightclickHandler)
#
self.setCompound(compound, force=True)
'''
def show(self, on, **kw): def show(self, on, **kw):
side = self.menubar.tkopt.toolbar.get() side = self.menubar.tkopt.toolbar.get()
self.win.setTool(None, side) self.win.setTool(None, side)
print('******** toolbar show', on, side, kw)
return False return False
def mHoldAndQuit(self, *args): def mHoldAndQuit(self, *args):
@ -253,9 +269,23 @@ class PysolToolbarTk(BoxLayout):
pass pass
def config(self, w, v): def config(self, w, v):
print('PysolToolbarTk: config %s, %s' % (w, v)) print('********************* PysolToolbarTk: config %s, %s' % (w, v))
# y = self.yy
pass # This is the position, where the toolbar can be configured.
chgd = False
for b in self.buttons:
if b.name == w:
ov = b.shown
if v != ov:
b.shown = v
chgd = True
if chgd:
self.clear_widgets()
for b in self.buttons:
if b.shown:
self.add_widget(b)
# Lokale. # Lokale.
@ -267,11 +297,10 @@ class PysolToolbarTk(BoxLayout):
if os.path.isfile(file): if os.path.isfile(file):
image = LImage(source=file) image = LImage(source=file)
# print('_loadImage: file=%s' % file) # print('_loadImage: file=%s' % file)
# image = Tkinter.PhotoImage(file=file)
break break
return image return image
def _createButton(self, label, command, check=False, tooltip=None): def _createButton(self, label, command, check=False, tooltip=None, timeout=0.0): # noqa
name = label.lower() name = label.lower()
image = self._loadImage(name) image = self._loadImage(name)
# position = len(self._widgets) # position = len(self._widgets)
@ -289,27 +318,26 @@ class PysolToolbarTk(BoxLayout):
'padx': padx, 'padx': padx,
'pady': pady, 'pady': pady,
'overrelief': 'raised', 'overrelief': 'raised',
'timeout': timeout
} }
# print ('toolbar: print %s' % self.win) # print ('toolbar: print %s' % self.win)
# print ('toolbar: print %s' % self.win.app) # print ('toolbar: print %s' % self.win.app)
kw['win'] = self.win kw['win'] = self.win
if image: if image:
kw['image'] = image kw['image'] = image
if name:
kw['name'] = name
if check: if check:
kw['offrelief'] = button_relief kw['offrelief'] = button_relief
kw['indicatoron'] = False kw['indicatoron'] = False
kw['selectcolor'] = '' kw['selectcolor'] = ''
button = MyCheckButton(**kw) button = MyCheckButton(**kw)
elif timeout > 0.0:
button = MyToastButton(**kw)
else: else:
button = MyButton(**kw) button = MyButton(**kw)
# button.show(orient=self.orient)
setattr(self, name + "_image", image)
setattr(self, name + "_button", button)
# self._widgets.append(button)
self.add_widget(button)
# TBD: tooltip ev. auf basis einer statuszeile implementieren # TBD: tooltip ev. auf basis einer statuszeile implementieren
# if tooltip: # if tooltip:
# b = MfxTooltip(button) # b = MfxTooltip(button)

View file

@ -431,11 +431,11 @@ if TOOLKIT == 'kivy':
logging.info("KivyApp: build") logging.info("KivyApp: build")
self.app = app = Application() self.app = app = Application()
app.top = self.mainWindow app.top = self.baseWindow
self.startCode = pysol_init(app, self.args) self.startCode = pysol_init(app, self.args)
logging.info('Main: App Initialised - starting main loop') logging.info('Main: App Initialised - starting main loop')
return self.mainWindow return self.baseWindow
def main(args=None): def main(args=None):
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)