home · contact · privacy
Some more class abstraction.
authorChristian Heller <c.heller@plomlompom.de>
Tue, 3 Jun 2025 15:52:41 +0000 (17:52 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 3 Jun 2025 15:52:41 +0000 (17:52 +0200)
ircplom.py

index 241eab1c84d399b9895de2f6ebe617878726ddf0..0751ca2f92b72782bc94286e61cb3719ff9c731a 100755 (executable)
@@ -371,7 +371,19 @@ class Loop:
             self._q_to_main.eput('EXCEPTION', e)
 
 
-class ScrollableWidget(ABC):
+class Widget(ABC):
+    'Defines most basic TUI object API.'
+
+    @abstractmethod
+    def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
+        'Update widget\'s measurements, re-generate content where necessary.'
+
+    @abstractmethod
+    def draw(self) -> None:
+        'Print widget\'s content in shape appropriate to set geometry.'
+
+
+class ScrollableWidget(Widget):
     'Defines some API shared between PromptWidget and LogWidget.'
     _history_idx: int
 
@@ -379,18 +391,10 @@ class ScrollableWidget(ABC):
         self._write_yx = write_yx
         self._history: list[str] = []
 
-    @abstractmethod
-    def set_geometry(self, measurements: Any) -> None:
-        'Update widget\'s measurements, re-generate content where necessary.'
-
     @abstractmethod
     def append(self, to_append: str) -> None:
         'Append to widget content.'
 
-    @abstractmethod
-    def draw(self) -> None:
-        'Print widget\'s content in shape appropriate to applied geometry.'
-
     @abstractmethod
     def _scroll(self, up=True) -> None:
         pass
@@ -410,8 +414,9 @@ class PromptWidget(ScrollableWidget):
         self._input_buffer = ''
         self._history_idx = 0
 
-    def set_geometry(self, measurements: int) -> None:
-        self._start_y = measurements
+    def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
+        assert isinstance(measurements[0], int)
+        self._start_y = measurements[0]
 
     def append(self, to_append: str) -> None:
         self._input_buffer += to_append
@@ -477,8 +482,9 @@ class LogWidget(ScrollableWidget):
         self._wrapped += [(idx_original, line) for line in wrapped_lines]
         return len(wrapped_lines)
 
-    def set_geometry(self, measurements: YX) -> None:
-        self._view_size = measurements
+    def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
+        assert isinstance(measurements[0], YX)
+        self._view_size = measurements[0]
         self._y_pgscroll = self._view_size.y // 2
         self._wrapped.clear()
         self._wrapped += [(None, '')] * self._view_size.y
@@ -524,7 +530,7 @@ class LogWidget(ScrollableWidget):
         self._history_idx = history_idx_to_wrapped_idx - len(self._history)
 
 
-class Window:
+class Window(Widget):
     'Collects a log and a prompt meant for the same content stream.'
 
     def __init__(self, term: Terminal) -> None:
@@ -532,13 +538,16 @@ class Window:
         self.log = LogWidget(self._term.wrap, self._term.write_yx)
         self.prompt = PromptWidget(self._term.write_yx)
 
-    def set_geometry(self, log_height: int, start_y_prompt: int) -> None:
-        'Reconfigure included widgets\' geometry.'
-        self.log.set_geometry(YX(log_height, self._term.size.x))
-        self.prompt.set_geometry(start_y_prompt)
+    def set_geometry(self, measurements: tuple[int | YX, ...]) -> None:
+        assert len(measurements) == 2
+        assert isinstance(measurements[0], int)
+        assert isinstance(measurements[1], int)
+        log_height = measurements[0]
+        start_y_prompt = measurements[1]
+        self.log.set_geometry((YX(log_height, self._term.size.x),))
+        self.prompt.set_geometry((start_y_prompt,))
 
     def draw(self) -> None:
-        'Draw both log and prompt.'
         self.log.draw()
         self.prompt.draw()
 
@@ -593,7 +602,7 @@ class TuiLoop(Loop):
         self._term.write_yx(YX(y_separator, 0), '=' * self._term.size.x)
         self._term.write_yx(YX(y_prompt, 0), INPUT_PROMPT)
         for window in self._windows:
-            window.set_geometry(y_separator, y_prompt)
+            window.set_geometry((y_separator, y_prompt))
         self._window.draw()
 
     def _cmd__prompt_backspace(self) -> None: