diff --git a/src/tui.rs b/src/tui.rs index 87d2b4a28c63..f89f16775735 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -259,11 +259,32 @@ pub enum Overflow { TruncateTail, } +/// If specified, a checkmark 🗹 / ☐ to be prepended to the button text +#[derive(Default, Clone, Copy, PartialEq, Eq)] +enum Checkmark { + /// No checkmark (or space for it) + #[default] + Absent, + /// Add whitespace where a checkmark would be + /// (to keep aligned with checkmark'd buttons) + AlignOnly, + /// Add a 🗹 prefix + Checked, + /// Add a ☐ prefix + Unchecked, +} + +impl From for Checkmark { + fn from(checked: bool) -> Self { + if checked { Checkmark::Checked } else { Checkmark::Unchecked } + } +} + /// Controls the style with which a button label renders #[derive(Clone, Copy)] pub struct ButtonStyle { accelerator: Option, - checked: Option, + checkmark: Checkmark, bracketed: bool, } @@ -274,21 +295,23 @@ impl ButtonStyle { pub fn accelerator(self, char: char) -> Self { Self { accelerator: Some(char), ..self } } - /// Draw a checkbox prefix: `[🗹 Example Button]` - pub fn checked(self, checked: bool) -> Self { - Self { checked: Some(checked), ..self } - } /// Draw with or without brackets: `[Example Button]` or `Example Button` pub fn bracketed(self, bracketed: bool) -> Self { Self { bracketed, ..self } } + /// Draw a checkbox prefix: `[🗹 Example Button]` + /// + /// Note: use `checkbox` or `menubar_menu_checkbox` + fn checkmark(self, checkmark: Checkmark) -> Self { + Self { checkmark, ..self } + } } impl Default for ButtonStyle { fn default() -> Self { Self { accelerator: None, - checked: None, + checkmark: Checkmark::Absent, bracketed: true, // Default style for most buttons. Brackets may be disabled e.g. for buttons in menus } } @@ -2004,17 +2027,9 @@ impl<'a> Context<'a, '_> { /// Creates a checkbox with the given text. /// Returns true if the checkbox was activated. pub fn checkbox(&mut self, classname: &'static str, text: &str, checked: &mut bool) -> bool { - self.styled_label_begin(classname); - self.attr_focusable(); - if self.is_focused() { - self.attr_reverse(); - } - self.styled_label_add_text(if *checked { "[🗹 " } else { "[☐ " }); - self.styled_label_add_text(text); - self.styled_label_add_text("]"); - self.styled_label_end(); + let activated = + self.button(classname, text, ButtonStyle::default().checkmark((*checked).into())); - let activated = self.button_activated(); if activated { *checked = !*checked; } @@ -3142,7 +3157,7 @@ impl<'a> Context<'a, '_> { accelerator: char, shortcut: InputKey, ) -> bool { - self.menubar_menu_checkbox(text, accelerator, shortcut, false) + self.menubar_menu_item(text, accelerator, shortcut, Checkmark::AlignOnly) } /// Appends a checkbox to the current menu. @@ -3153,6 +3168,17 @@ impl<'a> Context<'a, '_> { accelerator: char, shortcut: InputKey, checked: bool, + ) -> bool { + self.menubar_menu_item(text, accelerator, shortcut, checked.into()) + } + + /// Appends a button or checkbox to the current menu, + fn menubar_menu_item( + &mut self, + text: &str, + accelerator: char, + shortcut: InputKey, + checkmark: Checkmark, ) -> bool { self.table_next_row(); self.attr_focusable(); @@ -3173,7 +3199,7 @@ impl<'a> Context<'a, '_> { self.button_label( "menu_checkbox", text, - ButtonStyle::default().bracketed(false).checked(checked).accelerator(accelerator), + ButtonStyle::default().bracketed(false).checkmark(checkmark).accelerator(accelerator), ); self.menubar_shortcut(shortcut); @@ -3227,8 +3253,11 @@ impl<'a> Context<'a, '_> { if style.bracketed { self.styled_label_add_text("["); } - if let Some(checked) = style.checked { - self.styled_label_add_text(if checked { "🗹 " } else { " " }); + match style.checkmark { + Checkmark::Absent => {} + Checkmark::AlignOnly => self.styled_label_add_text(" "), + Checkmark::Checked => self.styled_label_add_text("🗹 "), + Checkmark::Unchecked => self.styled_label_add_text("☐ "), } // Label text match style.accelerator {