chiark / gitweb /
MenuKeypressLine
authorSimon Tatham <anakin@pobox.com>
Tue, 26 Dec 2023 12:52:22 +0000 (12:52 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 26 Dec 2023 14:06:02 +0000 (14:06 +0000)
src/text.rs

index 00c99b67c03c2a0ef0540ddcbec3589d1c58d0a6..dc5b5c8b9626a296894125fe2ca845296abbe497 100644 (file)
@@ -1,7 +1,7 @@
 use chrono::{DateTime, Local, Utc};
 #[cfg(test)]
 use chrono::NaiveDateTime;
-use core::cmp::min;
+use core::cmp::{min, max};
 use std::collections::{HashMap, BTreeMap, BTreeSet};
 use unicode_width::UnicodeWidthStr;
 
@@ -17,6 +17,9 @@ pub trait TextFragment {
     fn render(&self, width: usize) -> Vec<ColouredString>;
 
     fn as_extendable_indicator(&self) -> Option<&ExtendableIndicator> { None }
+    fn as_menu_keypress_mut(&mut self) -> Option<&mut MenuKeypressLine> {
+        None
+    }
 }
 
 pub struct BlankLine {}
@@ -791,8 +794,7 @@ impl TextFragment for ExtendableIndicator {
         }
     }
 
-    // FIXME: get rid of this silly trait method if I turn out not to need it
-    fn as_extendable_indicator(&self) -> Option<&ExtendableIndicator> {
+    fn as_extendable_indicator_mut(&self) -> Option<&ExtendableIndicator> {
         Some(self)
     }
 }
@@ -1347,5 +1349,86 @@ fn test_filestatus_render() {
         });
 }
 
-// TODO:
-// MenuKeypressLine
+pub struct MenuKeypressLine {
+    keypress: Keypress,
+    lwid: usize,
+    lmaxwid: usize,
+    rmaxwid: usize,
+}
+
+impl MenuKeypressLine {
+    pub fn new(key: Key, description: ColouredString) -> Box<dyn TextFragment> {
+        let lwid = UnicodeWidthStr::width(&key as &str) + 2; // [] around it
+        let rwid = description.width();
+        Box::new(MenuKeypressLine {
+                keypress: Keypress {
+                    key: key,
+                    description: description,
+                },
+                lwid: lwid,
+                lmaxwid: lwid,
+                rmaxwid: rwid,
+            })
+    }
+
+    pub fn get_widths(&self) -> (usize, usize) { (self.lmaxwid, self.rmaxwid) }
+    pub fn ensure_widths(&mut self, lmaxwid: usize, rmaxwid: usize) {
+        self.lmaxwid = max(self.lmaxwid, lmaxwid);
+        self.rmaxwid = max(self.rmaxwid, rmaxwid);
+    }
+}
+
+impl TextFragment for MenuKeypressLine {
+    fn render(&self, width: usize) -> Vec<ColouredString> {
+        let ourwidth = self.lmaxwid + self.rmaxwid + 3; // " = " in the middle
+        let space = width - min(width, ourwidth + 1);
+        let leftpad = min(space * 3 / 4, width - min(width, self.lmaxwid + 2));
+
+        let lspace = self.lmaxwid - self.lwid;
+        let llspace = lspace / 2;
+        let lrspace = lspace - llspace;
+
+        let line = ColouredString::plain(" ").repeat(leftpad + llspace) +
+                ColouredString::plain("[") +
+                ColouredString::uniform(&self.keypress.key, 'k') +
+                ColouredString::plain("]") +
+                ColouredString::plain(" ").repeat(lrspace) +
+                ColouredString::plain(" = ") +
+                &self.keypress.description;
+
+        vec! {
+            line.truncate(width).to_owned()
+        }
+    }
+
+    fn as_menu_keypress_mut(&mut self) -> Option<&mut MenuKeypressLine> {
+        Some(self)
+    }
+}
+
+#[test]
+fn test_menu_keypress() {
+    let mut mk = MenuKeypressLine::new("S".to_owned(), ColouredString::general(
+            "Something or other",
+            "K                 "));
+
+    assert_eq!(mk.render(40), vec! {
+            ColouredString::general(
+                "           [S] = Something or other",
+                "            k    K                 "),
+            });
+
+    assert_eq!(mk.render(29), vec! {
+            ColouredString::general(
+                "   [S] = Something or other",
+                "    k    K                 "),
+            });
+
+    mk.as_menu_keypress_mut().unwrap().ensure_widths(5, 0);
+
+    assert_eq!(mk.render(40), vec! {
+            ColouredString::general(
+                "          [S]  = Something or other",
+                "           k     K                 "),
+            });
+}