mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-05 00:02:29 -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:
parent
187bae25cb
commit
158c3137fd
5 changed files with 194 additions and 85 deletions
pysollib
|
@ -430,6 +430,16 @@ class Application:
|
|||
self.toolbar.config(
|
||||
'shuffle',
|
||||
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
|
||||
if self.intro.progress:
|
||||
self.intro.progress.destroy()
|
||||
|
|
|
@ -44,6 +44,7 @@ from kivy.uix.actionbar import ActionPrevious
|
|||
from kivy.uix.actionbar import ActionView
|
||||
from kivy.uix.behaviors import ButtonBehavior
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.floatlayout import FloatLayout
|
||||
from kivy.uix.image import Image as KivyImage
|
||||
from kivy.uix.label import Label
|
||||
from kivy.uix.scrollview import ScrollView
|
||||
|
@ -1814,7 +1815,9 @@ class LApp(App):
|
|||
|
||||
# Config.set('input', 'multitouchscreen1', 'tuio,0.0.0.0:3333')
|
||||
|
||||
self.baseWindow = FloatLayout() # needed e.g. for toasts
|
||||
self.mainWindow = LMainWindow()
|
||||
self.baseWindow.add_widget(self.mainWindow)
|
||||
logging.info('top = %s' % str(self.mainWindow))
|
||||
Cache.register('LAppCache', limit=10)
|
||||
Cache.append('LAppCache', 'mainWindow', self.mainWindow, timeout=0)
|
||||
|
|
68
pysollib/kivy/toast.py
Normal file
68
pysollib/kivy/toast.py
Normal 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)
|
||||
|
||||
# ================================================================
|
|
@ -20,10 +20,10 @@
|
|||
|
||||
# imports
|
||||
import os
|
||||
from time import time
|
||||
|
||||
# PySol imports
|
||||
from pysollib.mygettext import _, n_
|
||||
from pysollib.settings import TITLE
|
||||
from pysollib.util import IMAGE_EXTENSIONS
|
||||
from pysollib.winsystems import TkSettings
|
||||
|
||||
|
@ -31,64 +31,36 @@ from pysollib.winsystems import TkSettings
|
|||
# *
|
||||
# ************************************************************************
|
||||
|
||||
|
||||
class AbstractToolbarButton:
|
||||
def __init__(self, parent, toolbar, toolbar_name, position):
|
||||
self.toolbar = toolbar
|
||||
self.toolbar_name = toolbar_name
|
||||
self.position = position
|
||||
self.visible = False
|
||||
|
||||
def show(self, orient, force=False):
|
||||
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 pysollib.kivy.LApp import LImage
|
||||
from pysollib.kivy.LApp import LBase
|
||||
from pysollib.kivy.toast import Toast
|
||||
# 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
|
||||
|
||||
# ************************************************************************
|
||||
|
||||
|
||||
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
|
||||
|
||||
# ************************************************************************
|
||||
from kivy.cache import Cache
|
||||
|
||||
|
||||
class MyButton(ButtonBehavior, KivyImage, LBase):
|
||||
def __init__(self, **kwargs):
|
||||
super(MyButton, self).__init__(**kwargs)
|
||||
# super(MyButton, self).__init__()
|
||||
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.source = self.src
|
||||
self.allow_stretch = True
|
||||
self.shown = True
|
||||
|
||||
def on_press(self):
|
||||
self.allow_stretch = False
|
||||
|
@ -102,13 +74,15 @@ class MyButton(ButtonBehavior, KivyImage, LBase):
|
|||
class MyCheckButton(ButtonBehavior, KivyImage, LBase):
|
||||
def __init__(self, **kwargs):
|
||||
super(MyCheckButton, self).__init__(**kwargs)
|
||||
# super(MyCheckButton, self).__init__()
|
||||
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.variable = None
|
||||
if ('variable' in kwargs):
|
||||
self.variable = kwargs['variable']
|
||||
|
@ -118,6 +92,7 @@ class MyCheckButton(ButtonBehavior, KivyImage, LBase):
|
|||
self.source = self.src
|
||||
self.allow_stretch = True
|
||||
self.checked = False
|
||||
self.shown = True
|
||||
|
||||
# self.variable = self.win.app.menubar.tkopt.pause
|
||||
if self.variable:
|
||||
|
@ -163,6 +138,44 @@ class MyCheckButton(ButtonBehavior, KivyImage, LBase):
|
|||
def on_release(self):
|
||||
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.
|
||||
# ************************************************************************
|
||||
|
@ -179,15 +192,31 @@ class PysolToolbarTk(BoxLayout):
|
|||
compound='none'):
|
||||
|
||||
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.width = 50
|
||||
self.win = top
|
||||
self.menubar = menubar
|
||||
self.dir = dir
|
||||
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_("Restart"), self.mRestart, _("Restart the\ncurrent game")),
|
||||
(None, None, None),
|
||||
|
@ -205,40 +234,27 @@ class PysolToolbarTk(BoxLayout):
|
|||
(n_("Rules"), self.mHelpRules, _("Rules for this game")),
|
||||
(None, None, None),
|
||||
(n_("Quit"), self.mHoldAndQuit, _("Quit %s") % TITLE),
|
||||
):
|
||||
]:
|
||||
'''
|
||||
|
||||
for label, f, t in bl:
|
||||
if label is None:
|
||||
# sep = self._createSeparator()
|
||||
# sep.bind("<1>", self.clickHandler)
|
||||
# sep.bind("<3>", self.rightclickHandler)
|
||||
# We dont have separators in kivy version.
|
||||
pass
|
||||
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:
|
||||
self._createButton(label, f, tooltip=t)
|
||||
|
||||
# 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)
|
||||
'''
|
||||
button = self._createButton(label, f, check=False, tooltip=t)
|
||||
self.buttons.append(button)
|
||||
|
||||
def show(self, on, **kw):
|
||||
side = self.menubar.tkopt.toolbar.get()
|
||||
self.win.setTool(None, side)
|
||||
print('******** toolbar show', on, side, kw)
|
||||
return False
|
||||
|
||||
def mHoldAndQuit(self, *args):
|
||||
|
@ -253,9 +269,23 @@ class PysolToolbarTk(BoxLayout):
|
|||
pass
|
||||
|
||||
def config(self, w, v):
|
||||
print('PysolToolbarTk: config %s, %s' % (w, v))
|
||||
# y = self.yy
|
||||
pass
|
||||
print('********************* PysolToolbarTk: config %s, %s' % (w, v))
|
||||
|
||||
# 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.
|
||||
|
||||
|
@ -267,11 +297,10 @@ class PysolToolbarTk(BoxLayout):
|
|||
if os.path.isfile(file):
|
||||
image = LImage(source=file)
|
||||
# print('_loadImage: file=%s' % file)
|
||||
# image = Tkinter.PhotoImage(file=file)
|
||||
break
|
||||
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()
|
||||
image = self._loadImage(name)
|
||||
# position = len(self._widgets)
|
||||
|
@ -289,27 +318,26 @@ class PysolToolbarTk(BoxLayout):
|
|||
'padx': padx,
|
||||
'pady': pady,
|
||||
'overrelief': 'raised',
|
||||
'timeout': timeout
|
||||
}
|
||||
# print ('toolbar: print %s' % self.win)
|
||||
# print ('toolbar: print %s' % self.win.app)
|
||||
kw['win'] = self.win
|
||||
if image:
|
||||
kw['image'] = image
|
||||
if name:
|
||||
kw['name'] = name
|
||||
if check:
|
||||
kw['offrelief'] = button_relief
|
||||
kw['indicatoron'] = False
|
||||
kw['selectcolor'] = ''
|
||||
|
||||
button = MyCheckButton(**kw)
|
||||
elif timeout > 0.0:
|
||||
button = MyToastButton(**kw)
|
||||
else:
|
||||
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
|
||||
# if tooltip:
|
||||
# b = MfxTooltip(button)
|
||||
|
|
|
@ -431,11 +431,11 @@ if TOOLKIT == 'kivy':
|
|||
logging.info("KivyApp: build")
|
||||
|
||||
self.app = app = Application()
|
||||
app.top = self.mainWindow
|
||||
app.top = self.baseWindow
|
||||
self.startCode = pysol_init(app, self.args)
|
||||
|
||||
logging.info('Main: App Initialised - starting main loop')
|
||||
return self.mainWindow
|
||||
return self.baseWindow
|
||||
|
||||
def main(args=None):
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
|
Loading…
Add table
Reference in a new issue