chiark / gitweb /
Actually show keypresses in menus
authorSimon Tatham <anakin@pobox.com>
Thu, 7 Dec 2023 07:34:35 +0000 (07:34 +0000)
committerSimon Tatham <anakin@pobox.com>
Thu, 7 Dec 2023 07:45:27 +0000 (07:45 +0000)
cursesclient.py
text.py

index 421957aac3ff6c6162b95d9b4511afc4a2224fc1..58fc2ec32ee86484f58c34bd199b4f2d3cfe749b 100644 (file)
@@ -207,10 +207,27 @@ class CursesUI(client.Client):
             self.curses_shutdown()
 
 class Menu:
+    status_extra_text = None
+
     def __init__(self, cc):
         self.cc = cc
+        self.items = []
+        self.normalised = False
+
+    def normalise(self):
+        if self.normalised:
+            return
+
+        maxw = 0
+        for _ in range(2):
+            for item in self.items:
+                if isinstance(item, text.MenuKeypressLine):
+                    maxw = item.expand_key_width(maxw)
+
+        self.normalised = True
 
     def render(self):
+        self.normalise()
         y = 0
         header = text.FileHeader(self.title)
 
@@ -218,7 +235,15 @@ class Menu:
             self.cc.print_at(y, 0, line)
             y += 1
 
-        sl = text.FileStatusLine()
+        # FIXME: handle menus too large for the screen, so that you
+        # have to add > and < keypresses to scroll them
+        y += 1
+        for item in self.items:
+            for line in item.render(self.cc.scr_w):
+                self.cc.print_at(y, 0, line)
+                y += 1
+
+        sl = text.FileStatusLine(self.status_extra_text)
         self.add_keys(sl)
         sl_rendered = util.exactly_one(sl.render(self.cc.scr_w))
         self.cc.print_at(self.cc.scr_h - 1, 0, sl_rendered)
@@ -238,15 +263,23 @@ class Menu:
             return 'quit'
 
 class MainMenu(Menu):
+    status_extra_text = text.ColouredString("Select an option")
+
     def __init__(self, cc):
         super().__init__(cc)
         self.title = text.ColouredString(
             "Mastodonochrome Main Menu", 'H')
+        self.items.append(text.MenuKeypressLine(
+            'H', text.ColouredString("Home timeline",
+                                     "K            ")))
+        self.items.append(text.BlankLine())
+        self.items.append(text.MenuKeypressLine(
+            'ESC', text.ColouredString("Utilities and Exit")))
 
     def add_keys(self, sl):
         # intentionally don't call the base class, because [Q] doesn't
         # do anything on this menu
-        sl.keys.append(('ESC', 'Utilities'))
+        pass
 
     def handle_key(self, ch):
         if ch in {ord('h'), ord('H')}:
@@ -260,6 +293,13 @@ class EscMenu(Menu):
         self.title = text.ColouredString(
             "Utilities [ESC]",
             "HHHHHHHHHHHKKKH")
+        self.items.append(text.MenuKeypressLine(
+            'L', text.ColouredString("Logs menu",
+                                     "K        ")))
+        self.items.append(text.BlankLine())
+        self.items.append(text.MenuKeypressLine(
+            'X', text.ColouredString("EXit Mastodonochrome",
+                                     " K                  ")))
 
     def handle_key(self, ch):
         if ch in {ord('r'), ord('R')}:
@@ -279,6 +319,9 @@ class LogMenu(Menu):
         self.title = text.ColouredString(
             "Client Logs [ESC][L]",
             "HHHHHHHHHHHHHKKKHHKH")
+        self.items.append(text.MenuKeypressLine(
+            'L', text.ColouredString("Server Logs",
+                                     "       K   ")))
 
     def handle_key(self, ch):
         if ch in {ord('l'), ord('L')}:
@@ -292,6 +335,9 @@ class LogMenu2(Menu):
         self.title = text.ColouredString(
             "Server Logs [ESC][L][L]",
             "HHHHHHHHHHHHHKKKHHKHHKH")
+        self.items.append(text.MenuKeypressLine(
+            'E', text.ColouredString("Ego Log (Boosts, Follows and Faves)",
+                                     "K                                  ")))
 
     def handle_key(self, ch):
         if ch in {ord('e'), ord('E')}:
@@ -305,6 +351,9 @@ class ExitMenu(Menu):
         self.title = text.ColouredString(
             "Exit Mastodonochrome [ESC][X]",
             "HHHHHHHHHHHHHHHHHHHHHHKKKHHKH")
+        self.items.append(text.MenuKeypressLine(
+            'X', text.ColouredString("Confirm eXit",
+                                     "         K  ")))
 
     def handle_key(self, ch):
         if ch in {ord('x'), ord('X')}:
diff --git a/text.py b/text.py
index f18e30e668862140164d02ad52f946acc42264ff..91e14c5a476843bb18f94f9ff95d7927ba1abbf0 100644 (file)
--- a/text.py
+++ b/text.py
@@ -223,14 +223,18 @@ class ExtendableIndicator:
         yield ColouredString("")
 
 class FileStatusLine:
-    def __init__(self):
+    def __init__(self, text=None):
         self.keys = []
         self.proportion = None
+        self.text = text
 
     def render(self, width):
         message = ColouredString('')
         sep = ColouredString('')
         sep2 = ColouredString('  ')
+        if self.text is not None:
+            message += sep + self.text
+            sep = sep2
         for key, action in self.keys:
             message += (
                 sep + ColouredString('[') + ColouredString(key, 'k') +
@@ -249,6 +253,31 @@ class FileStatusLine:
 
         yield (ColouredString(" " * lspace) + message)
 
+class MenuKeypressLine:
+    def __init__(self, key, description):
+        self.key = ColouredString(key)
+        self.description = ColouredString(description)
+        self.max_key_width = self.key.width
+
+    def expand_key_width(self, new_max):
+        self.max_key_width = max(self.max_key_width, new_max)
+        return self.max_key_width
+
+    def render(self, width):
+        equalpos = (width - 1) // 2 - 1
+        lspace = equalpos - self.max_key_width - 3
+        kspace = self.max_key_width - self.key.width
+        klspace = kspace // 2
+        krspace = kspace - klspace
+        yield (ColouredString(" " * lspace) +
+               ColouredString(" " * klspace) +
+               ColouredString("[") +
+               ColouredString(self.key, 'k') +
+               ColouredString("]") +
+               ColouredString(" " * krspace) +
+               ColouredString(" = ") +
+               self.description)
+
 class Paragraph:
     def __init__(self):
         self.words = []