Implement menubar checkboxes

This commit is contained in:
Leonard Hecker
2025-04-17 21:02:33 +02:00
parent c7dcf97208
commit 67b9a9fecd
3 changed files with 59 additions and 26 deletions

View File

@@ -354,10 +354,12 @@ impl TextBuffer {
// NOTE: It's expected that the tui code calls `set_width()` sometime after this.
// This will then trigger the actual recalculation of the cursor position.
pub fn toggle_word_wrap(&mut self) {
self.word_wrap_enabled = !self.word_wrap_enabled;
self.width = 0; // Force a reflow.
self.make_cursor_visible();
pub fn set_word_wrap(&mut self, enabled: bool) {
if self.word_wrap_enabled != enabled {
self.word_wrap_enabled = enabled;
self.width = 0; // Force a reflow.
self.make_cursor_visible();
}
}
pub fn set_width(&mut self, width: CoordType) -> bool {

View File

@@ -528,46 +528,46 @@ fn draw_menubar(ctx: &mut Context, state: &mut State) {
}
fn draw_menu_file(ctx: &mut Context, state: &mut State) {
if ctx.menubar_menu_item(loc(LocId::FileOpen), 'O', kbmod::CTRL | vk::O) {
if ctx.menubar_menu_button(loc(LocId::FileOpen), 'O', kbmod::CTRL | vk::O) {
state.wants_file_picker = StateFilePicker::Open;
}
if ctx.menubar_menu_item(loc(LocId::FileSave), 'S', kbmod::CTRL | vk::S) {
if ctx.menubar_menu_button(loc(LocId::FileSave), 'S', kbmod::CTRL | vk::S) {
state.wants_file_picker = StateFilePicker::Save;
}
if ctx.menubar_menu_item(loc(LocId::FileSaveAs), 'A', vk::NULL) {
if ctx.menubar_menu_button(loc(LocId::FileSaveAs), 'A', vk::NULL) {
state.wants_file_picker = StateFilePicker::SaveAs;
}
if ctx.menubar_menu_item(loc(LocId::FileExit), 'X', kbmod::CTRL | vk::Q) {
if ctx.menubar_menu_button(loc(LocId::FileExit), 'X', kbmod::CTRL | vk::Q) {
state.wants_exit = true;
}
ctx.menubar_menu_end();
}
fn draw_menu_edit(ctx: &mut Context, state: &mut State) {
if ctx.menubar_menu_item(loc(LocId::EditUndo), 'U', kbmod::CTRL | vk::Z) {
if ctx.menubar_menu_button(loc(LocId::EditUndo), 'U', kbmod::CTRL | vk::Z) {
state.buffer.borrow_mut().undo();
ctx.needs_rerender();
}
if ctx.menubar_menu_item(loc(LocId::EditRedo), 'R', kbmod::CTRL | vk::Y) {
if ctx.menubar_menu_button(loc(LocId::EditRedo), 'R', kbmod::CTRL | vk::Y) {
state.buffer.borrow_mut().redo();
ctx.needs_rerender();
}
if ctx.menubar_menu_item(loc(LocId::EditCut), 'T', kbmod::CTRL | vk::X) {
if ctx.menubar_menu_button(loc(LocId::EditCut), 'T', kbmod::CTRL | vk::X) {
ctx.set_clipboard(state.buffer.borrow_mut().extract_selection(true));
}
if ctx.menubar_menu_item(loc(LocId::EditCopy), 'C', kbmod::CTRL | vk::C) {
if ctx.menubar_menu_button(loc(LocId::EditCopy), 'C', kbmod::CTRL | vk::C) {
ctx.set_clipboard(state.buffer.borrow_mut().extract_selection(false));
}
if ctx.menubar_menu_item(loc(LocId::EditPaste), 'P', kbmod::CTRL | vk::V) {
if ctx.menubar_menu_button(loc(LocId::EditPaste), 'P', kbmod::CTRL | vk::V) {
state.buffer.borrow_mut().write(ctx.get_clipboard(), true);
ctx.needs_rerender();
}
if state.wants_search.kind != StateSearchKind::Disabled {
if ctx.menubar_menu_item(loc(LocId::EditFind), 'F', kbmod::CTRL | vk::F) {
if ctx.menubar_menu_button(loc(LocId::EditFind), 'F', kbmod::CTRL | vk::F) {
state.wants_search.kind = StateSearchKind::Search;
state.wants_search.focus = true;
}
if ctx.menubar_menu_item(loc(LocId::EditReplace), 'R', kbmod::CTRL | vk::R) {
if ctx.menubar_menu_button(loc(LocId::EditReplace), 'R', kbmod::CTRL | vk::R) {
state.wants_search.kind = StateSearchKind::Replace;
state.wants_search.focus = true;
}
@@ -576,18 +576,21 @@ fn draw_menu_edit(ctx: &mut Context, state: &mut State) {
}
fn draw_menu_view(ctx: &mut Context, state: &mut State) {
if ctx.menubar_menu_item(loc(LocId::ViewFocusStatusbar), 'S', vk::NULL) {
let mut tb = state.buffer.borrow_mut();
let word_wrap = tb.is_word_wrap_enabled();
if ctx.menubar_menu_button(loc(LocId::ViewFocusStatusbar), 'S', vk::NULL) {
state.wants_statusbar_focus = true;
}
if ctx.menubar_menu_item(loc(LocId::ViewWordWrap), 'W', kbmod::ALT | vk::Z) {
state.buffer.borrow_mut().toggle_word_wrap();
if ctx.menubar_menu_checkbox(loc(LocId::ViewWordWrap), 'W', kbmod::ALT | vk::Z, word_wrap) {
tb.set_word_wrap(!word_wrap);
ctx.needs_rerender();
}
ctx.menubar_menu_end();
}
fn draw_menu_help(ctx: &mut Context, state: &mut State) {
if ctx.menubar_menu_item(loc(LocId::HelpAbout), 'A', vk::NULL) {
if ctx.menubar_menu_button(loc(LocId::HelpAbout), 'A', vk::NULL) {
state.wants_about = true;
}
ctx.menubar_menu_end();

View File

@@ -2140,7 +2140,7 @@ impl<'a> Context<'a, '_> {
vk::Z => match modifiers {
kbmod::CTRL => tb.undo(),
kbmod::CTRL_SHIFT => tb.redo(),
kbmod::ALT => tb.toggle_word_wrap(),
kbmod::ALT => tb.set_word_wrap(tb.is_word_wrap_enabled()),
_ => return false,
},
_ => return false,
@@ -2458,7 +2458,7 @@ impl<'a> Context<'a, '_> {
pub fn menubar_menu_begin(&mut self, text: &str, accelerator: char) -> bool {
self.next_block_id_mixin(self.tree.current_node.borrow().child_count as u64);
self.menubar_label(text, accelerator);
self.menubar_label(text, accelerator, None);
self.attr_focusable();
self.attr_padding(Rect::two(0, 1));
@@ -2485,7 +2485,22 @@ impl<'a> Context<'a, '_> {
false
}
pub fn menubar_menu_item(&mut self, text: &str, accelerator: char, shortcut: InputKey) -> bool {
pub fn menubar_menu_button(
&mut self,
text: &str,
accelerator: char,
shortcut: InputKey,
) -> bool {
self.menubar_menu_checkbox(text, accelerator, shortcut, false)
}
pub fn menubar_menu_checkbox(
&mut self,
text: &str,
accelerator: char,
shortcut: InputKey,
checked: bool,
) -> bool {
self.table_next_row();
self.attr_focusable();
if self.is_focused() {
@@ -2496,7 +2511,7 @@ impl<'a> Context<'a, '_> {
let clicked =
self.button_activated() || self.consume_shortcut(InputKey::new(accelerator as u32));
self.menubar_label(text, accelerator);
self.menubar_label(text, accelerator, Some(checked));
self.menubar_shortcut(shortcut);
if clicked {
@@ -2573,7 +2588,7 @@ impl<'a> Context<'a, '_> {
self.set_input_consumed();
}
fn menubar_label(&mut self, text: &str, accelerator: char) {
fn menubar_label(&mut self, text: &str, accelerator: char, checked: Option<bool>) {
if !accelerator.is_ascii_uppercase() {
self.label("label", Overflow::Clip, text);
return;
@@ -2594,6 +2609,9 @@ impl<'a> Context<'a, '_> {
}
self.styled_label_begin("label", Overflow::Clip);
if let Some(checked) = checked {
self.styled_label_add_text(if checked { "" } else { " " });
}
if off < text.len() {
// Highlight the accelerator in red.
@@ -2614,7 +2632,12 @@ impl<'a> Context<'a, '_> {
}
self.styled_label_end();
self.attr_padding(Rect::two(0, 1));
self.attr_padding(Rect {
left: 0,
top: 0,
right: 2,
bottom: 0,
});
}
fn menubar_shortcut(&mut self, shortcut: InputKey) {
@@ -2633,11 +2656,16 @@ impl<'a> Context<'a, '_> {
shortcut_text.push(shortcut_letter);
self.label("shortcut", Overflow::Clip, &shortcut_text);
self.attr_padding(Rect::two(0, 1));
} else {
self.block_begin("shortcut");
self.block_end();
}
self.attr_padding(Rect {
left: 0,
top: 0,
right: 2,
bottom: 0,
});
}
fn arena(&self) -> &'a Arena {