From 70909f6469620de785b34890dc7303639c70acbc Mon Sep 17 00:00:00 2001 From: lufebe16 Date: Mon, 11 Nov 2024 11:30:53 +0100 Subject: [PATCH] Android/Kivy: - zoom settings persistence - event mapping --- pysollib/game/__init__.py | 2 ++ pysollib/kivy/LApp.py | 73 +++++++++++++++++++++++++++------------ pysollib/kivy/menubar.py | 2 ++ pysollib/kivy/tkwidget.py | 29 ++++++++++++++-- pysollib/options.py | 11 ++++++ 5 files changed, 93 insertions(+), 24 deletions(-) diff --git a/pysollib/game/__init__.py b/pysollib/game/__init__.py index 6e7831a6..fec8cb51 100644 --- a/pysollib/game/__init__.py +++ b/pysollib/game/__init__.py @@ -1347,6 +1347,7 @@ class Game(object): # pause game if root window has been iconified if self.app and not self.pause: self.app.menubar.mPause() + # should return EVENT_HANDLED or EVENT_PROPAGATE _resizeHandlerID = None @@ -1370,6 +1371,7 @@ class Game(object): if self._resizeHandlerID: self.canvas.after_cancel(self._resizeHandlerID) self._resizeHandlerID = self.canvas.after(250, self._resizeHandler) + # should return EVENT_HANDLED or EVENT_PROPAGATE explicitly. def playSample(self, name, priority=0, loop=0): diff --git a/pysollib/kivy/LApp.py b/pysollib/kivy/LApp.py index 4c94dd35..dcd350d7 100644 --- a/pysollib/kivy/LApp.py +++ b/pysollib/kivy/LApp.py @@ -57,6 +57,7 @@ from pysollib.kivy.LBase import LBase from pysollib.kivy.LTask import LTask, LTaskQ from pysollib.kivy.androidperms import requestStoragePerm from pysollib.kivy.androidrot import AndroidScreenRotation +from pysollib.kivy.tkconst import EVENT_HANDLED, EVENT_PROPAGATE from pysollib.resource import CSI if platform != 'android': @@ -792,27 +793,44 @@ class LImageItem(BoxLayout, LBase): def get_image_type(self): return self.image_type + ''' + NOTE: + The following code binds kivy events to tk-like (?) events used + in common code. There are several problems + - EVENT_HANDLED and EVENT_PROPAGATE constants are defined separately in + different ui implementations, but are used in common code (stack.py, + game/__init__.py, many game implementations: (241 functions!)) + - EVENT_PROPAGATE is defined to 'None', which is highly unspecific. + (conditions would evaluate to False, empty returns of event function + implicitly return EVENT_PROPAGATE). + - Most events return EVENT_HANDLED even if they did not change anything + in current situations. I would expect specifically for stack base cards + that they return HANDLE_PROPAGATE if nothing happened. + LB241111. + ''' + def send_event_pressed_n(self, event, n): + r = EVENT_PROPAGATE if self.group and n in self.group.bindings: - self.group.bindings[n](event) + r = self.group.bindings[n](event) + return r def send_event_pressed(self, touch, event): + r = EVENT_PROPAGATE if touch.is_double_tap: - self.send_event_pressed_n(event, '') + r = self.send_event_pressed_n(event, '') else: button = 'left' if 'button' in touch.profile: button = touch.button if button == 'left': - self.send_event_pressed_n(event, '<1>') - return + r = self.send_event_pressed_n(event, '<1>') if button == 'middle': - self.send_event_pressed_n(event, '<2>') - return + r = self.send_event_pressed_n(event, '<2>') if button == 'right': - self.send_event_pressed_n(event, '<3>') - return + r = self.send_event_pressed_n(event, '<3>') + return r def on_touch_down(self, touch): @@ -825,9 +843,6 @@ class LImageItem(BoxLayout, LBase): if stack.cards[i] == self.card: print('LCardImage: stack = %s' % stack) print('LCardImage: touch = %s' % str(touch)) - print('grab') - # grab the touch! - touch.grab(self) ppos, psize = self.game.canvas.KivyToCore( touch.pos, self.size) event = LEvent() @@ -835,9 +850,14 @@ class LImageItem(BoxLayout, LBase): event.y = ppos[1] self.dragstart = touch.pos event.cardid = i - self.send_event_pressed(touch, event) - AndroidScreenRotation.lock(toaster=False) - return True + r = self.send_event_pressed(touch, event) + # print("********* event return = ",r) + if r == EVENT_HANDLED: + AndroidScreenRotation.lock(toaster=False) + print('grab') + touch.grab(self) + return True + return False if self.group is not None: print('LCardImage: self=%s group=%s' % (self, self.group)) @@ -847,8 +867,10 @@ class LImageItem(BoxLayout, LBase): event = LEvent() event.x = ppos[0] event.y = ppos[1] - self.group.bindings['<1>'](event) - return True + r = self.group.bindings['<1>'](event) + if r == EVENT_HANDLED: + return True + return False if self.card is None: return False @@ -859,12 +881,14 @@ class LImageItem(BoxLayout, LBase): return False def send_event_released_1(self, event): + r = EVENT_PROPAGATE if self.group and '' in self.group.bindings: - self.group.bindings[''](event) + r = self.group.bindings[''](event) + return r def on_touch_up(self, touch): if touch.grab_current is self: - # release my grabbed touch! + # ungrab. this stops move events after a drag. print('ungrab') touch.ungrab(self) return True @@ -882,8 +906,11 @@ class LImageItem(BoxLayout, LBase): event.x = ppos[0] event.y = ppos[1] event.cardid = i - self.send_event_released_1(event) - return True + r = self.send_event_released_1(event) + # print("********* event return = ",r) + if r == EVENT_HANDLED: + return True + return False if self.group is not None: print('LCardImage: self=%s group=%s' % (self, self.group)) @@ -893,8 +920,10 @@ class LImageItem(BoxLayout, LBase): event = LEvent() event.x = ppos[0] event.y = ppos[1] - self.group.bindings[''](event) - return True + r = self.group.bindings[''](event) + if r == EVENT_HANDLED: + return True + return False if self.card is None: return False diff --git a/pysollib/kivy/menubar.py b/pysollib/kivy/menubar.py index e9139845..c6521173 100644 --- a/pysollib/kivy/menubar.py +++ b/pysollib/kivy/menubar.py @@ -38,6 +38,7 @@ from pysollib.kivy.LApp import LTopLevel from pysollib.kivy.LApp import LTreeNode from pysollib.kivy.LApp import LTreeRoot from pysollib.kivy.LObjWrap import LBoolWrap +from pysollib.kivy.LObjWrap import LListWrap from pysollib.kivy.LObjWrap import LNumWrap from pysollib.kivy.LObjWrap import LStringWrap from pysollib.kivy.androidrot import AndroidScreenRotation @@ -1531,6 +1532,7 @@ class PysolMenubarTk: language=LStringWrap(opt, "language"), save_games_geometry=LBoolWrap(opt, "save_games_geometry"), pause=LBoolWrap(self, "pause"), + table_zoom=LListWrap(opt, "table_zoom"), # cards cardset=LNumWrap(self, "cardset"), cardback=LNumWrap(self, "cardback"), diff --git a/pysollib/kivy/tkwidget.py b/pysollib/kivy/tkwidget.py index 8a1a1e87..bc053f83 100644 --- a/pysollib/kivy/tkwidget.py +++ b/pysollib/kivy/tkwidget.py @@ -371,7 +371,6 @@ class MfxTooltip: # ************************************************************************ # Kivy implementation of MfxScrolledCanvas. - from kivy.uix.scatterlayout import Scatter # noqa from kivy.uix.stencilview import StencilView # noqa from kivy.graphics.transformation import Matrix # noqa @@ -389,8 +388,27 @@ class LScatterFrame(Scatter): self.scale_max = 2.2 self.lock_pos = None self.offset = None + self.tkopt = None + + def set_scale(self,zoom): + scale = zoom[0] + self.transform = Matrix().scale(scale,scale,1) + xoff = zoom[1] + yoff = zoom[2] + self.offset = (xoff,yoff) def _update(self): + # initialisation + if self.tkopt is None: + app = self.inner.wmain.app + tkopt = None + if app is not None: tkopt = app.menubar.tkopt + if tkopt is not None: + self.tkopt = tkopt + self.set_scale(tkopt.table_zoom.value) + print("table_zoom",tkopt.table_zoom.value) + + # update if self.lock_pos is None: self.lock_pos = "locked" if self.offset is not None: @@ -470,7 +488,14 @@ class LScatterFrame(Scatter): offmy = float(self.bbox[1][1] - self.size[1]) if (offmx>0 and offmy>0): self.offset = (offx/offmx,offy/offmy) - # print ("offset = ",self.offset) + + # update persistent zoom parameters + zoom = self.bbox[1][0]/float(self.size[0]) + if self.offset is not None: + zoominfo = [zoom, self.offset[0], self.offset[1]] + else: + zoominfo = [zoom, 0.0, 0.0] + self.tkopt.table_zoom.value = zoominfo class LScrollFrame(BoxLayout,StencilView): diff --git a/pysollib/options.py b/pysollib/options.py index f5cfc7e7..e1b2865a 100644 --- a/pysollib/options.py +++ b/pysollib/options.py @@ -143,6 +143,7 @@ solver_iterations_output_step = integer solver_preset = string display_win_message = boolean language = string +table_zoom = list [sound_samples] move = boolean @@ -322,6 +323,7 @@ class Options: # ('favorite_gameid', 'list'), ('display_win_message', 'bool'), ('language', 'str'), + # ('table_zoom', 'list'), ] def __init__(self): @@ -417,6 +419,7 @@ class Options: self.translate_game_names = True self.display_win_message = True self.language = '' + self.table_zoom = [1.0, 0.0, 0.0] # sound self.sound = True self.sound_mode = 1 @@ -668,6 +671,7 @@ class Options: config['general']['recent_gameid'] = self.recent_gameid config['general']['favorite_gameid'] = self.favorite_gameid + config['general']['table_zoom'] = self.table_zoom visible_buttons = [b for b in self.toolbar_vars if self.toolbar_vars[b]] config['general']['visible_buttons'] = visible_buttons @@ -813,6 +817,13 @@ class Options: except Exception: traceback.print_exc() + table_zoom = self._getOption('general', 'table_zoom', 'list') + if table_zoom is not None: + try: + self.table_zoom = [float(i) for i in table_zoom] + except Exception: + traceback.print_exc() + visible_buttons = self._getOption('general', 'visible_buttons', 'list') if visible_buttons is not None: for key in TOOLBAR_BUTTONS: