Refactor cell marking, add undo, update keybindings

CellWidget::set_selected and set_marked now return &mut Self for method
chaining. Added BoardState::undo_marked_cell to remove the last marked
cell and restore focus. Backspace triggers undo, Delete clears marking.
This commit is contained in:
2026-04-13 16:57:44 +02:00
parent d5f4d03264
commit 1393f282e8
6 changed files with 74 additions and 34 deletions
+32 -21
View File
@@ -29,14 +29,16 @@ pub enum Action {
ScrollLeft,
/// Scroll right without moving the cursor.
ScrollRight,
/// Select the current item.
/// Toggle selecting cell.
Space,
/// Unmark last selected cell.
Backspace,
/// Cancel marking cell.
Delete,
/// Submit or confirm the current choice.
Enter,
/// Return to the main menu or previous screen.
Esc,
/// Delete the character before the cursor.
Backspace,
/// Zoom the view in.
ZoomIn,
/// Zoom the view out.
@@ -199,15 +201,33 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
symbol: "Space",
description: "Marking cells",
},
// KeyBinding {
// action: Action::Enter,
// code: KeyCode::Enter,
// kind: KeyEventKind::Press,
// modifiers: KeyModifiers::NONE,
// group: Group::Select,
// symbol: "Enter",
// description: "Submit",
// },
KeyBinding {
action: Action::Backspace,
code: KeyCode::Backspace,
kind: KeyEventKind::Press,
modifiers: KeyModifiers::NONE,
group: Group::Select,
symbol: "Backspace",
description: "Unmark cell",
},
KeyBinding {
action: Action::Delete,
code: KeyCode::Delete,
kind: KeyEventKind::Press,
modifiers: KeyModifiers::NONE,
group: Group::Select,
symbol: "Delete",
description: "Cancel marking",
},
KeyBinding {
action: Action::Enter,
code: KeyCode::Enter,
kind: KeyEventKind::Press,
modifiers: KeyModifiers::NONE,
group: Group::Select,
symbol: "Enter",
description: "Submit",
},
KeyBinding {
action: Action::Esc,
code: KeyCode::Esc,
@@ -217,15 +237,6 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
symbol: "Esc",
description: "Main menu",
},
KeyBinding {
action: Action::Backspace,
code: KeyCode::Backspace,
kind: KeyEventKind::Press,
modifiers: KeyModifiers::NONE,
group: Group::Select,
symbol: "Backspace",
description: "Cancel marking",
},
KeyBinding {
action: Action::ZoomIn,
code: KeyCode::Char(','),
+2 -1
View File
@@ -84,7 +84,8 @@ pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
ZoomLevel::ZoomedOut => {}
},
Action::Space => board.toggle_marking(),
Action::Backspace => {
Action::Backspace => board.undo_marked_cell(),
Action::Delete => {
board.marking_cells = false;
board.clear_marked_cells()
}
+26 -7
View File
@@ -116,16 +116,35 @@ impl BoardState {
}
}
pub fn set_marked_cell(&mut self, new_cell: (usize, usize), old_cell: (usize, usize)) {
pub fn set_marked_cell(&mut self, new_cell: (usize, usize)) {
let cell: &mut CellWidget = self.get_mut_cell(new_cell.0, new_cell.1);
if cell.get_marked() && old_cell != new_cell {
self.get_mut_cell(old_cell.0, old_cell.1).set_marked(false);
self.marked_cells.pop();
} else {
if !cell.get_marked() {
cell.set_marked(true);
self.marked_cells.push((new_cell.0, new_cell.1));
}
self.marked_cells.push((new_cell.0, new_cell.1));
}
pub fn undo_marked_cell(&mut self) {
if self.marked_cells.len() < 2 {
return;
}
let old: (usize, usize) = self.marked_cells[self.marked_cells.len() - 1];
let new: (usize, usize) = self.marked_cells[self.marked_cells.len() - 2];
let old_is_unique: bool = self.marked_cells.iter().filter(|x| **x == old).count() == 1;
let old_cell: &mut CellWidget = self.get_mut_cell(old.0, old.1).set_selected(false);
if old_is_unique {
old_cell.set_marked(false);
}
self.get_mut_cell(new.0, new.1).set_selected(true);
self.marked_cells.pop();
self.focused_cell.set_focused_cell(new);
}
pub fn start_marking_cells(&mut self) {
@@ -226,7 +245,7 @@ impl BoardState {
self.get_mut_cell(new_cell.0, new_cell.1).set_selected(true);
if self.marking_cells {
self.set_marked_cell(new_cell, old_cell);
self.set_marked_cell(new_cell);
}
}
}
@@ -49,4 +49,9 @@ impl FocusedCell {
(self.row, self.col)
}
pub fn set_focused_cell(&mut self, cell: (usize, usize)) {
self.row = cell.0.max(0).min(self.max_row - 1);
self.col = cell.1.max(0).min(self.max_col - 1);
}
}
+1
View File
@@ -27,6 +27,7 @@ const ACTIONS: &[Action] = &[
Action::VolumeDown,
Action::Space,
Action::Backspace,
Action::Delete,
Action::Mute,
Action::Quit,
Action::Quit2,
+8 -5
View File
@@ -48,8 +48,9 @@ impl CellWidget {
}
}
pub fn set_selected(&mut self, selected: bool) {
pub fn set_selected(&mut self, selected: bool) -> &mut Self {
self.selected = selected;
self
}
pub fn set_zoom_level(&mut self, zoom_level: ZoomLevel) {
@@ -64,8 +65,9 @@ impl CellWidget {
self.marked
}
pub fn set_marked(&mut self, marked: bool) {
self.marked = marked
pub fn set_marked(&mut self, marked: bool) -> &mut Self {
self.marked = marked;
self
}
fn col_to_letters(&self) -> String {
@@ -90,8 +92,9 @@ impl CellWidget {
fn fg_color(&self) -> Color {
match self.tag {
_ if self.marked => Color::LightMagenta,
_ if self.selected => Color::LightYellow,
_ if self.marked && self.selected => Color::Magenta,
_ if self.marked && !self.selected => Color::LightMagenta,
_ if self.selected && !self.marked => Color::LightYellow,
CellTag::Base(Players::Player) if !self.selected => Color::LightBlue,
CellTag::Base(Players::Enemy) if !self.selected => Color::LightRed,
CellTag::Tunel if !self.selected => Color::Gray,