From: Christian Heller Date: Mon, 2 Nov 2020 04:54:43 +0000 (+0100) Subject: Add initial stage of curses client. X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/%7B%7B%20web_path%20%7D%7D/static/git-favicon.png?a=commitdiff_plain;h=e6a78872ee29c0e893a01d06b7b467e339bc80ec;p=plomrogue2-experiments Add initial stage of curses client. --- diff --git a/new2/rogue_chat_curses.py b/new2/rogue_chat_curses.py new file mode 100755 index 0000000..bdafe21 --- /dev/null +++ b/new2/rogue_chat_curses.py @@ -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)