Selaa lähdekoodia

refactor advance_focus_paths to fix focus issues

Daniel Sheffield 3 vuotta sitten
vanhempi
sitoutus
60cc811d16
3 muutettua tiedostoa jossa 77 lisäystä ja 54 poistoa
  1. 8 3
      app/activities/PriceCheck.py
  2. 5 1
      app/activities/TransactionEditor.py
  3. 64 50
      app/widgets.py

+ 8 - 3
app/activities/PriceCheck.py

@@ -267,10 +267,15 @@ class PriceCheck(FocusWidget):
         widget = urwid.Filler(widget, 'top') 
         widget = urwid.AttrMap(widget, 'bg')
         widget.original_widget.original_widget.set_focus_path([3,0,0])
-        super().__init__(widget, [2,0,1], [
+        super().__init__(widget, 4, [3,0,0,0], [
+                [0, 0,], [0,1,],
+                [1,],
+                [2,],
+                [2,0,],
                 [2,0,0,], [2,0,2], [2,2,0], [2,2,2],
-                [3,0,2,], [3,0,3,], [3,0,4,],
+                [3,0,], [3,0,0,],
+                [3,0,1,0,], [3,0,1,1,], [3,0,1,2,],
                 [3,1,3,],
-                [4,0,0,],
+                [4,],
             ]
         )

+ 5 - 1
app/activities/TransactionEditor.py

@@ -183,10 +183,14 @@ class TransactionEditor(FocusWidget):
         ])
         widget = urwid.Filler(widget, 'top') 
         widget = urwid.AttrMap(widget, 'bg')
-        super().__init__(widget, [2,0,0,0,0], [
+        super().__init__(widget, 5, [2,0,0,0], [
+            [0, 0], [0,1],
+            [1,],
+            [2,], [2,0], [2,0,0],
             [2, 0, 1, 0],
             [4,],
             [5,],
+            [6,],
             [6, 1],
             [7,],
         ])

+ 64 - 50
app/widgets.py

@@ -5,7 +5,7 @@
 #
 # THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
 from decimal import Decimal
-from typing import Callable, Iterable, Union
+from typing import Callable, Iterable, List, Union
 
 import urwid
 from additional_urwid_widgets import IndicativeListBox
@@ -128,10 +128,11 @@ class NoTabCheckBox(urwid.CheckBox):
 
 class FocusWidget(urwid.WidgetPlaceholder):
 
-    def __init__(self, widget, initial_focus, skip_focus):
+    def __init__(self, widget, max_focus_path_len, initial_focus, skip_focus):
         super().__init__(widget)
         self._initial_focus = tuple([ i for i in initial_focus ])
         self._skip_focus = tuple([ i for i in skip_focus ])
+        self.max_focus_path_len = max_focus_path_len
     
     @property
     def skip_focus(self):
@@ -144,69 +145,82 @@ class FocusWidget(urwid.WidgetPlaceholder):
     @property
     def container(self):
         return self.original_widget.original_widget.original_widget
-    
-    def _set_focus_path(self, path):
+
+    def _can_set_focus_path(self, path):
+        old = self.container.get_focus_path()
         try:
             self.container.set_focus_path(path)
-            return
+            return True
         except IndexError:
-            pass
+            return False
+        finally:
+            self.container.set_focus_path(old)
+
+    def _set_focus_path(self, path):
+        self.container.set_focus_path(path)
+
+    def _next_path(self, path: Iterable, ext=True) -> List:
+        if len(path) < self.max_focus_path_len:
+            next_path = [*path, 0]
+            if self._can_set_focus_path(next_path):
+                return next_path
         
-        if path[-1] == 0 and len(path) > 1:
-            self._set_focus_path(path[:-1])
-            return
-    
-        raise IndexError
+        next_path = [*path[:-1], path[-1]+1]
+        if self._can_set_focus_path(next_path):
+            return next_path
+
+        next_path = path
+        while len(next_path) > 1 and next_path[-1] == 0:
+            next_path = [*next_path[:-1]]
+            if self._can_set_focus_path(next_path):
+                return next_path
+        if len(next_path) >= 2:
+            next_path = [*next_path[:-2], next_path[-2]+1, 0]
+            if self._can_set_focus_path(next_path):
+                return next_path
+            return self._next_path(next_path)
+        if self._can_set_focus_path([*path[:-1], path[-1]+1]):
+            return self._next_path(next_path)
+        return
 
     def iter_focus_paths(self):
+        path = None
         self._set_focus_path(self.initial_focus)
-        while True:
-            path = self.container.get_focus_path()
-            yield path
-            self.advance_focus()
-            path = self.container.get_focus_path()
-            while len(path) < len(self.initial_focus):
-                path.extend([0])
-            if path == self.initial_focus:
-                return
-
+        while path != self.initial_focus:
+            if path is None:
+                path = self.container.get_focus_path()
+            if path not in self.skip_focus:
+                yield path
+            path = self._next_path(path)
+            if path is None:
+                path = self._next_path([0])
+            self._set_focus_path(path)
+    
     def advance_focus(self, reverse=False):
 
         path = self.container.get_focus_path()
-                
+
+        paths = [ i for i in self.iter_focus_paths() ]
+
         if reverse:
-            paths = [ i for i in self.iter_focus_paths() ]
             zipped_paths = zip(paths, [
                 *paths[1:], paths[0]
             ])
-            prev_path = map(lambda x: x[0], filter(
-                lambda x: x[1] == path,
-                zipped_paths
-            ))
-            p = next(prev_path)
-            self._set_focus_path(p)
-            return
+        else:
+            zipped_paths = zip([
+                *paths[1:], paths[0]
+            ], paths)
         
-        _iter = [ i for i in enumerate(path) ][::-1]
-
-        for idx, part in _iter:
-            p = [ i for i in path ]
-            if reverse:
-                p[idx] -= 1
-            else:
-                p[idx] += 1
-            
-            try:
-                self._set_focus_path(p)
-                if p in self.skip_focus:
-                    self.advance_focus(reverse=reverse)
-                return
-            except IndexError:
-                path[idx] = 0
-                while len(path) < len(self.initial_focus):
-                    path.extend([0])
-
-        self._set_focus_path(self.initial_focus)
+        next_path = map(lambda x: x[0], filter(
+            lambda x: x[1] == path,
+            zipped_paths
+        ))
+        p = next(next_path)
+        if p in self.skip_focus:
+            self.advance_focus(reverse=reverse)
+            return
+        self._set_focus_path(p)
+        return
 
 class AutoCompletePopUp(PopUpLauncher):
     _default_pop_up_parameters = {