home · contact · privacy
More TUI client refactoring.
[plomrogue2] / plomrogue_client / tui.py
index ec04304b0b0358b1083b62b90038ab5096dab8a3..9f28a04c542ba586ad3650679c43c70b3fd24734 100644 (file)
@@ -3,12 +3,20 @@ import curses
 
 
 
-class CursesScreen:
+class AbortOnGetkey(Exception):
+    pass
 
-    def wrap_loop(self, loop):
-        curses.wrapper(self.start_loop, loop)
 
-    def safe_addstr(self, y, x, line, attr=0):
+
+class TUI:
+
+    def __init__(self):
+        self._log = []
+        self.do_refresh = True
+        self.store_widechar = False
+        curses.wrapper(self.run_loop)
+
+    def addstr(self, y, x, line, attr=0):
         if y < self.size.y - 1 or x + len(line) < self.size.x:
             self.stdscr.addstr(y, x, line, attr)
         else:  # workaround to <https://stackoverflow.com/q/7063128>
@@ -25,12 +33,41 @@ class CursesScreen:
         self.size = self.size - YX(self.size.y % 4, 0)
         self.size = self.size - YX(0, self.size.x % 4)
 
-    def start_loop(self, stdscr, loop):
-        self.stdscr = stdscr
+    def init_loop(self):
         curses.curs_set(0)  # hide cursor
-        stdscr.timeout(10)
-        loop()
+        self.stdscr.timeout(10)
+        self.reset_size()
+
+    def run_loop(self, stdscr):
+        self.stdscr = stdscr
+        self.init_loop()
+        while True:
+            try:
+                self.loop()
+            except AbortOnGetkey:
+                continue
+            self.do_refresh = True
+
+    def log(self, msg):
+        self._log += [msg]
+        self.do_refresh = True
 
+    def get_key_and_keycode(self):
+        try:
+            key = self.stdscr.getkey()
+        except curses.error:
+            raise AbortOnGetkey
+        keycode = None
+        if len(key) == 1:
+            keycode = ord(key)
+            # workaround for <https://stackoverflow.com/a/56390915>
+            if self.store_widechar:
+                self.store_widechar = False
+                key = bytes([195, keycode]).decode()
+            if keycode == 195:
+                self.store_widechar = True
+                raise AbortOnGetkey
+        return key, keycode
 
 
 def msg_into_lines_of_width(msg, width):