home · contact · privacy
Add initial stage of curses client.
authorChristian Heller <c.heller@plomlompom.de>
Mon, 2 Nov 2020 04:54:43 +0000 (05:54 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Mon, 2 Nov 2020 04:54:43 +0000 (05:54 +0100)
new2/rogue_chat_curses.py [new file with mode: 0755]

diff --git a/new2/rogue_chat_curses.py b/new2/rogue_chat_curses.py
new file mode 100755 (executable)
index 0000000..bdafe21
--- /dev/null
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+import curses
+import socket
+import queue
+import threading
+from plomrogue.io_tcp import PlomSocket
+
+def recv_loop(plom_socket, q):
+    for msg in plom_socket.recv():
+        q.put(msg)
+
+class TUI:
+
+    def __init__(self, socket, q):
+        self.queue = q
+        self.socket = socket
+        self.log = []
+        self.log_msg("hallo")
+        self.log_msg("welt")
+        self.do_refresh = True
+        curses.wrapper(self.loop)
+
+    def log_msg(self, msg):
+        self.log += [msg]
+        if len(self.log) > 100:
+            self.log = self.log[-100:]
+
+    def loop(self, stdscr):
+
+        def msg_into_lines_of_width(msg, width):
+            chunk = ''
+            lines = []
+            x = 0
+            for i in range(len(msg)):
+                x += 1
+                if x >= width or msg[i] == "\n":
+                    lines += [chunk]
+                    chunk = ''
+                    x = 0
+                if msg[i] != "\n":
+                    chunk += msg[i]
+            lines += [chunk]
+            return lines
+
+        def reset_screen_size():
+            self.rows, self.cols = stdscr.getmaxyx()
+            self.cols -= 1  # ugly TODO ncurses bug workaround, FIXME
+            self.window_width = self.cols // 2
+
+        def recalc_input_lines():
+            self.input_lines = msg_into_lines_of_width(input_prompt +input_,
+                                                       self.window_width)
+
+        def draw_history():
+            lines = []
+            for line in self.log:
+                lines += msg_into_lines_of_width(line, self.window_width)
+            lines.reverse()
+            max_y = self.rows - len(self.input_lines)
+            for i in range(len(lines)):
+                if (i >= max_y):
+                    break
+                stdscr.addstr(max_y - i - 1, self.window_width, lines[i])
+
+        def draw_input():
+            y = self.rows - len(self.input_lines)
+            for i in range(len(self.input_lines)):
+                stdscr.addstr(y, self.window_width, self.input_lines[i])
+                y += 1
+
+        curses.curs_set(False)  # hide cursor
+        stdscr.timeout(10)
+        reset_screen_size()
+        input_ = ''
+        input_prompt = '> '
+        while True:
+
+            if self.do_refresh:
+                self.do_refresh = False
+                stdscr.clear()
+                recalc_input_lines()
+
+                draw_input()
+                draw_history()
+
+            while True:
+                try:
+                    msg = self.queue.get(block=False)
+                    self.log_msg(msg)
+                    self.do_refresh = True
+                except queue.Empty:
+                    break
+
+            try:
+                key = stdscr.getkey()
+            except curses.error:
+                continue
+            self.do_refresh = True
+
+            if key == 'KEY_RESIZE':
+                reset_screen_size()
+            elif key == 'KEY_BACKSPACE':
+                input_ = input_[:-1]
+            elif key == '\n':  # Return key
+                self.socket.send(input_)
+                input_ = ""
+            else:
+                input_ += key
+                # TODO find out why - 1 is necessary here
+                max_length = self.window_width * self.rows - len(input_prompt) - 1
+                if len(input_) > max_length:
+                    input_ = input_[:max_length]
+
+s = socket.create_connection(('127.0.0.1', 5000))
+plom_socket = PlomSocket(s)
+q = queue.Queue()
+t = threading.Thread(target=recv_loop, args=(plom_socket, q))
+t.start()
+TUI(plom_socket, q)