From 363baa1c1ac4a3a02a305087c4c3c25ecca1e421 Mon Sep 17 00:00:00 2001 From: GarandPLG Date: Sun, 29 Mar 2026 22:03:22 +0200 Subject: [PATCH] Add navigation and selection for skirmish cells Reclassify Escape key as Quit and add directional actions to move the focused cell. --- src/app/keybindings/keybindings.rs | 4 ++-- src/app/keybindings/skirmish.rs | 10 ++++++++++ src/app/state.rs | 4 +++- src/app/states/mod.rs | 2 +- src/app/states/skirmish.rs | 31 +++++++++++++++++++++++++++++- src/app/views/skirmish.rs | 4 ++++ src/app/widgets/board.rs | 22 +++++++++++++++++---- src/app/widgets/cell.rs | 17 ++++++++++++---- 8 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/app/keybindings/keybindings.rs b/src/app/keybindings/keybindings.rs index efe8024..6f7191f 100644 --- a/src/app/keybindings/keybindings.rs +++ b/src/app/keybindings/keybindings.rs @@ -205,9 +205,9 @@ pub static KEYBINDINGS: &[KeyBinding] = &[ code: KeyCode::Esc, kind: KeyEventKind::Press, modifiers: KeyModifiers::NONE, - group: Group::Movement, + group: Group::Quit, symbol: "Esc", - description: "Go back to main menu", + description: "Main menu", }, KeyBinding { action: Action::Backspace, diff --git a/src/app/keybindings/skirmish.rs b/src/app/keybindings/skirmish.rs index 8825d95..9628ec7 100644 --- a/src/app/keybindings/skirmish.rs +++ b/src/app/keybindings/skirmish.rs @@ -9,6 +9,16 @@ pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) { if let Some(action) = event_to_action(&key_event) { common_keybindings(app, action); match action { + Action::Up => { + app.states.skirmish.focused_cell.move_up(); + + // if app.states.skirmish.horizontal_offset.get_value() { + + // } + } + Action::Down => app.states.skirmish.focused_cell.move_down(), + Action::Left => app.states.skirmish.focused_cell.move_left(), + Action::Right => app.states.skirmish.focused_cell.move_right(), Action::ScrollUp => app.states.skirmish.vertical_offset.prev(), Action::ScrollDown => app.states.skirmish.vertical_offset.next(), Action::ScrollLeft => app.states.skirmish.horizontal_offset.prev(), diff --git a/src/app/state.rs b/src/app/state.rs index c046b43..64ecbc6 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -1,6 +1,7 @@ use crate::{ app::states::{ - MainMenuState, Offset, PerkDecksState, SettingsState, SkillsConfigState, SkirmishState, + FocusedCell, MainMenuState, Offset, PerkDecksState, SettingsState, SkillsConfigState, + SkirmishState, }, cli::Cli, }; @@ -31,6 +32,7 @@ impl GameStates { map_height: args.map_height as usize, board_cells: Vec::new(), zoom_level: args.zoom_level, + focused_cell: FocusedCell::new(0, 0), }, perk_decks: PerkDecksState { id: 2, diff --git a/src/app/states/mod.rs b/src/app/states/mod.rs index 6fb5fcb..89512e9 100644 --- a/src/app/states/mod.rs +++ b/src/app/states/mod.rs @@ -8,4 +8,4 @@ pub use main_menu::MainMenuState; pub use perk_decks::{PerkDecks, PerkDecksState}; pub use settings::SettingsState; pub use skills_config::SkillsConfigState; -pub use skirmish::{GameMode, Offset, SkirmishState, ZoomLevel}; +pub use skirmish::{FocusedCell, GameMode, Offset, SkirmishState, ZoomLevel}; diff --git a/src/app/states/skirmish.rs b/src/app/states/skirmish.rs index 4414ff8..5a47d13 100644 --- a/src/app/states/skirmish.rs +++ b/src/app/states/skirmish.rs @@ -50,6 +50,34 @@ impl Offset { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct FocusedCell { + pub row: usize, + pub col: usize, +} + +impl FocusedCell { + pub fn new(row: usize, col: usize) -> Self { + Self { row, col } + } + + pub fn move_up(&mut self) { + self.row = self.row.saturating_sub(1); + } + + pub fn move_down(&mut self) { + self.row = self.row.saturating_add(1); + } + + pub fn move_left(&mut self) { + self.col = self.col.saturating_sub(1); + } + + pub fn move_right(&mut self) { + self.col = self.col.saturating_add(1); + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct SkirmishState { pub id: usize, @@ -60,6 +88,7 @@ pub struct SkirmishState { pub horizontal_offset: Offset, pub board_cells: Vec, pub zoom_level: ZoomLevel, + pub focused_cell: FocusedCell, } impl SkirmishState { @@ -70,7 +99,7 @@ impl SkirmishState { for row in 0..self.map_height { for col in 0..self.map_width { - self.board_cells.push(CellWidget::new(row, col)); + self.board_cells.push(CellWidget::new(row, col, false)); } } } diff --git a/src/app/views/skirmish.rs b/src/app/views/skirmish.rs index f3cfdc9..60cb2a7 100644 --- a/src/app/views/skirmish.rs +++ b/src/app/views/skirmish.rs @@ -14,6 +14,10 @@ use ratatui::{ pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) { let actions: Vec = vec![ + Action::Up, + Action::Down, + Action::Left, + Action::Right, Action::ScrollUp, Action::ScrollDown, Action::ScrollLeft, diff --git a/src/app/widgets/board.rs b/src/app/widgets/board.rs index 6496c36..7376c57 100644 --- a/src/app/widgets/board.rs +++ b/src/app/widgets/board.rs @@ -1,4 +1,8 @@ -use crate::app::{App, states::ZoomLevel, widgets::CellWidget}; +use crate::app::{ + App, + states::{FocusedCell, ZoomLevel}, + widgets::CellWidget, +}; use ratatui::{ buffer::Buffer, layout::{Constraint, Layout, Rect}, @@ -14,7 +18,8 @@ pub struct BoardWidget<'a> { rows: u16, h_offset: usize, v_offset: usize, - cells: &'a Vec, + cells: &'a mut Vec, + focused_cell: &'a FocusedCell, } impl<'a> BoardWidget<'a> { @@ -63,7 +68,8 @@ impl<'a> BoardWidget<'a> { rows, h_offset: app.states.skirmish.horizontal_offset.get_value(), v_offset: app.states.skirmish.vertical_offset.get_value(), - cells: &app.states.skirmish.board_cells, + cells: &mut app.states.skirmish.board_cells, + focused_cell: &app.states.skirmish.focused_cell, } } } @@ -86,8 +92,16 @@ impl Widget for BoardWidget<'_> { for (row_idx, cell_area) in vertical.iter().enumerate() { if let Some(cell) = self .cells - .get((row_idx + self.v_offset) * self.map_width + (col_idx + self.h_offset)) + .get_mut((row_idx + self.v_offset) * self.map_width + (col_idx + self.h_offset)) { + if row_idx + self.v_offset == self.focused_cell.row + && col_idx + self.h_offset == self.focused_cell.col + { + cell.selected = true; + } else { + cell.selected = false; + } + cell.render(*cell_area, buf); } } diff --git a/src/app/widgets/cell.rs b/src/app/widgets/cell.rs index b24a37f..e462e81 100644 --- a/src/app/widgets/cell.rs +++ b/src/app/widgets/cell.rs @@ -1,7 +1,7 @@ use ratatui::{ buffer::Buffer, layout::{Alignment, Rect}, - style::Stylize, + style::{Color, Style, Stylize}, widgets::{Block, Borders, Paragraph, Widget}, }; @@ -17,12 +17,13 @@ use ratatui::{ pub struct CellWidget { pub row: usize, pub col: usize, + pub selected: bool, // pub tags: Vec, } impl CellWidget { - pub fn new(row: usize, col: usize) -> Self { - Self { row, col } + pub fn new(row: usize, col: usize, selected: bool) -> Self { + Self { row, col, selected } } fn col_to_letters(&self) -> String { @@ -40,6 +41,14 @@ impl CellWidget { pub fn display_coords(&self) -> String { format!("{}{}", self.col_to_letters(), self.row) } + + fn is_selected(&self) -> Color { + if self.selected { + Color::Red + } else { + Color::White + } + } } impl Widget for CellWidget { @@ -49,7 +58,7 @@ impl Widget for CellWidget { .block( Block::default() .borders(Borders::ALL) - .white() + .style(Style::default().fg(self.is_selected())) .title(self.display_coords().green()), ) .render(area, buf);