home · contact · privacy
More TUI client refactoring.
[plomrogue2] / plomrogue_client / tui.py
index ec04304b0b0358b1083b62b90038ab5096dab8a3..758d7f76b036926770acd07c68e71814c6340181 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,11 +33,49 @@ 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 log(self, msg):
+        self._log += [msg]
+        self.do_refresh = True
+
+    def init_loop(self):
         curses.curs_set(0)  # hide cursor
-        stdscr.timeout(10)
-        loop()
+        self.stdscr.timeout(10)
+        self.reset_size()
+
+    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 run_loop(self, stdscr):
+        self.stdscr = stdscr
+        self.init_loop()
+        while True:
+            self.on_each_loop_start()
+            for msg in self.socket.get_message():
+                self.handle_server_message(msg)
+            if self.do_refresh:
+                self.stdscr.clear()
+                self.draw_screen()
+                self.do_refresh = False
+            try:
+                key, keycode = self.get_key_and_keycode()
+            except AbortOnGetkey:
+                continue
+            self.on_key(key, keycode)
+            self.do_refresh = True