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:
parent
158c3137fd
commit
ae9aa78cde
11 changed files with 194 additions and 93 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,3 +5,7 @@ Please use the new setup presented in directory
|
|||
buildozer.
|
||||
|
||||
LB221118.
|
||||
|
||||
This Directory will soon be deleted from the Repo.
|
||||
|
||||
LB230919.
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 102122001,
|
||||
"versionName": "2.20.1",
|
||||
"versionCode": 102122100,
|
||||
"versionName": "2.21.0",
|
||||
"outputFile": "pysolfc-release.apk"
|
||||
}
|
||||
],
|
||||
|
|
10
fastlane/metadata/android/en-US/changelogs/102122100.txt
Normal file
10
fastlane/metadata/android/en-US/changelogs/102122100.txt
Normal 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.
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
#
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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)
|
||||
|
||||
# ================================================================
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue