From a6b0821c112122e0ea6f7c2b0f84630aa99287f3 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 26 Dec 2023 12:52:22 +0000 Subject: [PATCH] MenuKeypressLine --- src/text.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/src/text.rs b/src/text.rs index 00c99b6..dc5b5c8 100644 --- a/src/text.rs +++ b/src/text.rs @@ -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; 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 { + 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 { + 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 "), + }); +} -- 2.30.2