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

more rework on toolbar and menu options

- toolbar button configurations added to option menu
 - refactoring
 - metadata (fastlane) updated
This commit is contained in:
lufebe16 2023-09-21 12:18:55 +02:00
parent 158c3137fd
commit ae9aa78cde
11 changed files with 194 additions and 93 deletions

View file

@ -63,9 +63,6 @@ Cardsets:
LB230301.
(After new changes as of 27.3.23 - not contained in the last f-droid
version):
Allow external storage access for Android 10 and later.
- on Android 10 it ist still possible to write to the extenal storage. A
@ -83,3 +80,10 @@ LB230301.
never query you for that. You may do it on your own.
LB230327.
Scheduled for the next Android release:
- Screen rotation lock.
- Toolbar actualised
- Protection from accidental reset or redeal.
LB230919.

View file

@ -173,7 +173,7 @@ mkdir -p "$PKGTREE"
### Alternate toolkit.
- Kivy (10.0 or later)
- Kivy
- Features:
- Sound support integrated.
- Android apk build support.
@ -189,7 +189,11 @@ On the basis of Kivy an Android App is also available. You may build
your own using appropriate build instructions in README.android and
in Directory buildozer.
Some versions will also be published on F-droid (https://f-droid.org)
Some versions will also be published on F-droid.
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.lufebe16.pysolfc/)
### Configuring Freecell Solver

View file

@ -5,3 +5,7 @@ Please use the new setup presented in directory
buildozer.
LB221118.
This Directory will soon be deleted from the Repo.
LB230919.

View file

@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 102122001,
"versionName": "2.20.1",
"versionCode": 102122100,
"versionName": "2.21.0",
"outputFile": "pysolfc-release.apk"
}
],

View file

@ -0,0 +1,10 @@
Android specific:
- Temporary screen orientation lock added. Long tap (5 seconds) to the
playground locks/unlocks (toggle) automatic screen rotation.
- Toolbar: configuration of displayed toolbar buttons added to options menu.
- Toolbar: dynamic updates on Toolbar and Options settings.
- Toolbar buttons for 'new deal' and 'restart' have now a delayed
functionality. This prevents from accidental execution.
Main version:
- consult NEWS.asscidoc or html-src/news.html on
github for more change informations.

View file

@ -430,16 +430,6 @@ 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()

View file

@ -38,6 +38,7 @@ from kivy.graphics import Color
from kivy.graphics import Line
from kivy.graphics import Rectangle
from kivy.graphics import Triangle
from kivy.properties import NumericProperty
from kivy.properties import StringProperty
from kivy.uix.actionbar import ActionButton
from kivy.uix.actionbar import ActionPrevious
@ -52,7 +53,6 @@ from kivy.uix.treeview import TreeView
from kivy.uix.treeview import TreeViewLabel
from kivy.uix.widget import Widget
from kivy.utils import platform
from kivy.properties import NumericProperty
from pysollib.kivy.androidperms import requestStoragePerm
from pysollib.kivy.androidrot import AndroidScreenRotation

View file

@ -1112,10 +1112,11 @@ class OptionsMenuDialog(LMenuDialog):
# 'Top',
# self.menubar.tkopt.toolbar, 1,
# self.menubar.mOptToolbar)
# self.addRadioNode(tv, rg,
# 'Bottom',
# self.menubar.tkopt.toolbar, 2,
# self.menubar.mOptToolbar)
# _('Bottom'),
# self.menubar.tkopt.toolbar, 2,
# self.menubar.mOptToolbar)
self.addRadioNode(tv, rg,
_('Left'),
@ -1126,6 +1127,17 @@ class OptionsMenuDialog(LMenuDialog):
self.menubar.tkopt.toolbar, 4,
self.menubar.mOptToolbar)
rg1 = tv.add_node(
LTreeNode(text=_('Buttons:')), rg)
if rg1:
for w in TOOLBAR_BUTTONS:
ww = w
ww[0].upper()
self.addCheckNode(tv, rg,
_(ww), # noqa
self.menubar.tkopt.toolbar_vars[w],
self.make_vars_command(self.menubar.mOptToolbarConfig, w)) # noqa
# -------------------------------------------
# Statusbar - not implemented
@ -2441,7 +2453,6 @@ the next time you restart the %(app)s""") % {'app': TITLE})
if self._cancelDrag(break_pause=False):
return
self.app.opt.toolbar_vars[w] = v
self.app.toolbar.config(w, v)
self.top.update_idletasks()
#

View file

@ -53,18 +53,19 @@ COMPOUNDS = (
TOOLBAR_BUTTONS = (
"new",
"restart",
"open",
"save",
# "open",
# "save",
"undo",
"redo",
"autodrop",
"shuffle",
"hint",
"pause",
"statistics",
# "statistics",
"rules",
"quit",
"player",
)
# "quit",
# "player",
)
STATUSBAR_ITEMS = (
('stuck', "'You Are Stuck' indicator"),

View file

@ -17,12 +17,11 @@ class Toast(Label):
self.duration = 4.0
self.tsize = self.size
self.rsize = 20
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
@ -33,14 +32,17 @@ class Toast(Label):
ads = height * 1.7
self.tsize = (width + ads, height + ads)
self.rsize = [(ads+height)/2.0,]
#print(self.tsize,self.rsize)
# 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)
# print(self.top)
# print(self.pos_hint)
self.rect.pos = (self.center_x-self.tsize[0]/2.0,self.center_y-self.tsize[1]/2.0)
self.rect.radius = self.rsize
def stop(self, *args):
self.unbind(texture_size=self.eval_size)
self.parent.remove_widget(self)
def hide(self, *args):
@ -54,6 +56,7 @@ class Toast(Label):
return
self.duration = duration
parent.add_widget(self)
self.bind(texture_size=self.eval_size)
anim = Animation(opacity=1, duration=0.4)
anim.start(self)
Clock.schedule_once(self.hide,self.duration)
@ -64,5 +67,6 @@ class Toast(Label):
return
self.opacity = 1
parent.add_widget(self)
self.bind(texture_size=self.eval_size)
# ================================================================

View file

@ -22,33 +22,33 @@
import os
from time import time
from kivy.cache import Cache
from kivy.clock import Clock
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image as KivyImage
# PySol kivy imports
from pysollib.kivy.LApp import LBase
from pysollib.kivy.LApp import LImage
from pysollib.kivy.toast import Toast
# PySol imports
from pysollib.mygettext import _, n_
from pysollib.mygettext import _, n_ # noqa
from pysollib.util import IMAGE_EXTENSIONS
from pysollib.winsystems import TkSettings
# ************************************************************************
# *
# ************************************************************************
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
# ************************************************************************
from kivy.cache import Cache
class MyButtonBase(ButtonBehavior, KivyImage, LBase):
shown = BooleanProperty(True)
enabled = BooleanProperty(True)
config = BooleanProperty(True)
class MyButton(ButtonBehavior, KivyImage, LBase):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
super(MyButtonBase, self).__init__(**kwargs)
self.src = None
if ('image' in kwargs):
self.src = kwargs['image'].source
@ -60,7 +60,23 @@ class MyButton(ButtonBehavior, KivyImage, LBase):
self.name = kwargs['name']
self.source = self.src
self.allow_stretch = True
self.shown = True
def set_shown(self, instance, value):
# print ('** set shown (',self.name ,') called', value)
self.shown = value
def set_enabled(self, instance, value):
# print ('** set enabled (',self.name ,') called', value)
self.enabled = value
def set_config(self, instance, value):
# print ('** set config (',self.name ,') called', value)
self.config = value
class MyButton(MyButtonBase):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
def on_press(self):
self.allow_stretch = False
@ -71,28 +87,16 @@ class MyButton(ButtonBehavior, KivyImage, LBase):
self.command()
class MyCheckButton(ButtonBehavior, KivyImage, LBase):
class MyCheckButton(MyButtonBase):
def __init__(self, **kwargs):
super(MyCheckButton, 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.variable = None
if ('variable' in kwargs):
self.variable = kwargs['variable']
self.win = None
if ('win' in kwargs):
self.win = kwargs['win']
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:
@ -139,24 +143,12 @@ class MyCheckButton(ButtonBehavior, KivyImage, LBase):
pass
class MyToastButton(ButtonBehavior, KivyImage, LBase):
class MyToastButton(MyButtonBase):
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):
@ -172,10 +164,46 @@ class MyToastButton(ButtonBehavior, KivyImage, LBase):
else:
mainApp = Cache.get('LAppCache', 'mainApp')
toast = Toast(text=_("button released too early"))
# toast = Toast(text=_("button released too early"),pos_hint={'top': 0.8}) # noqa
# pos hint wirkt nur auf den text, nicht auf die box !!!
toast.show(parent=mainApp.baseWindow, duration=2.0)
# print('too early released')
class MyWaitButton(MyButtonBase):
def __init__(self, **kwargs):
super(MyWaitButton, self).__init__(**kwargs)
self.timeout = 0.0
if ('timeout' in kwargs):
self.timeout = kwargs['timeout']
self.start_time = 0.0
self.eventId = None
self.wait_toast = None
def time_out(self, *args):
self.wait_toast.stop()
self.wait_toast = None
self.eventId = None
if (self.command is not None):
self.command()
# print ('timeout')
def on_press(self):
self.allow_stretch = False
self.eventId = Clock.schedule_once(self.time_out, 1.0)
mainApp = Cache.get('LAppCache', 'mainApp')
self.wait_toast = Toast(text=_("hold on ..."))
self.wait_toast.start(mainApp.baseWindow)
def on_release(self):
self.allow_stretch = True
if self.eventId is not None:
Clock.unschedule(self.eventId)
# print ('unscheduled')
if self.wait_toast is not None:
self.wait_toast.stop()
self.wait_toast = None
# ************************************************************************
# * Note: Applications should call show/hide after constructor.
# ************************************************************************
@ -200,6 +228,7 @@ class PysolToolbarTk(BoxLayout):
self.dir = dir
self.win.setTool(self, 3)
self.buttons = []
self.buttond = {}
# This is called only once after program start. Configurations
# have to take place elsewhere.
@ -237,8 +266,11 @@ class PysolToolbarTk(BoxLayout):
]:
'''
# Build all the buttions.
for label, f, t in bl:
if label is None:
button = None
# We dont have separators in kivy version.
pass
elif label == 'Pause':
@ -251,6 +283,23 @@ class PysolToolbarTk(BoxLayout):
button = self._createButton(label, f, check=False, tooltip=t)
self.buttons.append(button)
if button is not None:
# print('button name: ', button.name)
self.buttond[button.name] = button
# check buttons if configurated or opted out.
# (could ev. be integrated into _createButton)
toolbar_opt = getattr(self.menubar.tkopt, 'toolbar_vars')
for k in toolbar_opt.keys():
opt = toolbar_opt[k]
if k in self.buttond.keys():
b = self.buttond[k]
b.config = opt.get()
opt.bind(value=b.set_config)
self.redraw()
def show(self, on, **kw):
side = self.menubar.tkopt.toolbar.get()
self.win.setTool(None, side)
@ -268,24 +317,22 @@ class PysolToolbarTk(BoxLayout):
def updateText(self, **kw):
pass
def redraw(self):
self.clear_widgets()
for b in self.buttons:
# print(b.name,b.config,b.shown,b.enabled)
if b.shown and b.enabled and b.config:
self.add_widget(b)
def changed_state(self, instance, value):
self.redraw()
def config(self, w, v):
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)
if w == 'shuffle':
self.buttond['shuffle'].shown = v
self.buttond['autodrop'].shown = not v
# Lokale.
@ -334,10 +381,36 @@ class PysolToolbarTk(BoxLayout):
button = MyCheckButton(**kw)
elif timeout > 0.0:
button = MyToastButton(**kw)
# button = MyToastButton(**kw)
button = MyWaitButton(**kw)
else:
button = MyButton(**kw)
try:
oname = name
# redo is handled same way as undo, there is no separate option.
if name == 'redo':
oname = 'undo'
opt = getattr(self.menubar.tkopt, oname)
# specialisation (differently used options):
# - autodrop button has no own option. option 'autodrop' is used
# for the different effect of fully automatic dropping!
# - pause button sets and clears the pause option, not vice versa!
# it is an option that only exists internaly (not saved). (same
# applies also to the tk and tile implementations)
if oname not in ['autodrop', 'pause']:
button.enabled = opt.get()
# print('** ', oname, '(enabled) = ', opt.get())
opt.bind(value=button.set_enabled)
button.bind(enabled=self.changed_state)
button.bind(shown=self.changed_state)
except: # noqa
pass
button.bind(config=self.changed_state)
# TBD: tooltip ev. auf basis einer statuszeile implementieren
# if tooltip:
# b = MfxTooltip(button)