[elbe-devel] [PATCH 06/14] Debianize - Grid widget

dion at linutronix.de dion at linutronix.de
Thu Aug 1 14:14:05 CEST 2019


From: Olivier Dion <dion at linutronix.de>

Urwid is a poor library that offer next to nothing in term of good
widgets.  The grid widget is a recursive abstraction around column and
pile widgets.

One can nest grid inside of grid .. and so on.  Grids also accept the
emac's keybinding format to move around.

Signed-off-by: Olivier Dion <dion at linutronix.de>
---
 elbepack/debianize/widgets/grid.py | 130 +++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)
 create mode 100644 elbepack/debianize/widgets/grid.py

diff --git a/elbepack/debianize/widgets/grid.py b/elbepack/debianize/widgets/grid.py
new file mode 100644
index 00000000..1112fcbd
--- /dev/null
+++ b/elbepack/debianize/widgets/grid.py
@@ -0,0 +1,130 @@
+# ELBE - Debian Based Embedded Rootfilesystem Builder
+# Copyright (c) 2019 Olivier Dion <dion at linutronix.de>
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+from urwid import (
+    Columns,
+    Pile as Rows,
+    WidgetWrap
+)
+
+
+class Grid(WidgetWrap):
+
+    def __init__(self, rows):
+
+        m = 1
+        cols = []
+
+        for row in rows:
+            if len(row) > m:
+                m = len(row)
+
+            for c in row:
+                if isinstance(c, Grid):
+                    c.parent = self
+
+            cols.append(Columns(row))
+
+        super().__init__(Rows(cols))
+
+        self.n = len(rows)
+        self.m = m
+
+        self.i = 0
+        self.j = 0
+
+        self.focus(self.i, self.j)
+
+        self.keybind = {
+            "down"     : lambda: self.focus_recursive(forward=True, horizontal=False),
+            "up"       : lambda: self.focus_recursive(forward=False, horizontal=False),
+            "tab"      : lambda: self.focus_recursive(forward=True, horizontal=True),
+            "shift tab": lambda: self.focus_recursive(forward=False, horizontal=True)
+        }
+
+        self.aliases = {
+            "ctrl f": "right",
+            "ctrl b": "left",
+            "ctrl p": "up",
+            "ctrl n": "down"
+        }
+
+        self.parent = None
+
+    def focus_direction(self, forward: bool, horizontal: bool):
+
+        j = self.j
+        i = self.i
+        direction = 1 if forward else -1
+
+        while True:
+            if horizontal:
+                j += direction
+                i += j // self.m
+            else:
+                i += direction
+                j += i // self.n
+
+            i %= self.n
+            j %= self.m
+
+            try:
+                self.focus(i, j)
+                break
+            except IndexError:
+                pass
+
+    def focus_recursive(self, forward: bool, horizontal: bool):
+        while True:
+            child = self.current_focus()
+
+            if isinstance(child, Grid):
+                child.focus_recursive(forward, horizontal)
+            elif not forward and self._is_first():
+                if self.parent is not None and not self.parent._is_first():
+                    return self.parent.focus_direction(forward, horizontal)
+                else:
+                    self.focus_direction(forward, horizontal)
+            elif forward and self._is_last():
+                if self.parent is not None and not self.parent._is_last():
+                    return self.parent.focus_direction(forward, horizontal)
+                else:
+                    self.focus_direction(forward, horizontal)
+            else:
+                self.focus_direction(forward, horizontal)
+
+            if self.current_focus().selectable():
+                break
+
+    def focus_first(self):
+        self.focus(0, 0)
+        self.i = 0
+        self.j = 0
+
+    def focus(self, i, j):
+        self._w.base_widget.set_focus_path([i, j])
+        self.i = i
+        self.j = j
+
+    def current_focus(self):
+        return self._w.base_widget.contents[self.i][0].contents[self.j][0].base_widget
+
+    def _is_last(self):
+        return self.i == self.n - 1 and self.j == self.m - 1
+
+    def _is_first(self):
+        return self.i == 0 and self.j == 0
+
+    def keypress(self, size, key):
+
+        if key in self.aliases:
+            key = self.aliases[key]
+
+        if key in self.keybind:
+            self.keybind[key]()
+            return None
+
+        return super().keypress(size, key)
-- 
2.11.0




More information about the elbe-devel mailing list