Refactor board cells to 2D vector and auto‑scroll

Store cells as a nested vector instead of a flat list, simplifying
indexing and
rendering. Add `is_focused_cell_visible` to detect when the focused cell
is
outside the viewport and adjust vertical/horizontal offsets accordingly
in
the skirmish keybindings. Update related methods and widget rendering to
use
the new 2‑D structure.
This commit is contained in:
2026-04-08 14:25:14 +02:00
parent 4917068fb1
commit e4682f1c52
3 changed files with 45 additions and 13 deletions
+12
View File
@@ -21,15 +21,27 @@ pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
match action {
Action::Up => {
board.change_focused_cell(MoveFocusedCell::Up);
if !board.is_focused_cell_visible() {
board.vertical_offset.prev();
}
}
Action::Down => {
board.change_focused_cell(MoveFocusedCell::Down);
if !board.is_focused_cell_visible() {
board.vertical_offset.next();
}
}
Action::Left => {
board.change_focused_cell(MoveFocusedCell::Left);
if !board.is_focused_cell_visible() {
board.horizontal_offset.prev();
}
}
Action::Right => {
board.change_focused_cell(MoveFocusedCell::Right);
if !board.is_focused_cell_visible() {
board.horizontal_offset.next();
}
}
Action::ScrollUp => {
board.vertical_offset.prev();
+29 -4
View File
@@ -16,7 +16,7 @@ pub struct BoardState {
pub rows: usize,
pub vertical_offset: Offset,
pub horizontal_offset: Offset,
pub cells: Vec<CellWidget>,
pub cells: Vec<Vec<CellWidget>>,
pub zoom_level: ZoomLevel,
focused_cell: FocusedCell,
}
@@ -41,11 +41,13 @@ impl BoardState {
let focused_cell: FocusedCell =
FocusedCell::new((map_height / 2) - 1, 2, map_height, map_width);
let mut cells: Vec<CellWidget> = Vec::new();
let mut cells: Vec<Vec<CellWidget>> = Vec::new();
for row in 0..map_height {
let mut rows: Vec<CellWidget> = Vec::new();
for col in 0..map_width {
cells.push(*CellWidget::new(row, col, zoom_level).set_selected(
rows.push(*CellWidget::new(row, col, zoom_level).set_selected(
if row == focused_cell.get_row() && col == focused_cell.get_col() {
true
} else {
@@ -53,6 +55,8 @@ impl BoardState {
},
));
}
cells.push(rows);
}
Self {
@@ -72,7 +76,7 @@ impl BoardState {
}
fn get_mut_cell(&mut self, row: usize, col: usize) -> &mut CellWidget {
&mut self.cells[row * self.map_width + col]
&mut self.cells[row][col]
}
fn max_offset(map_size: usize, size: usize) -> usize {
@@ -133,4 +137,25 @@ impl BoardState {
self.get_mut_cell(old_row, old_col).set_selected(false);
self.get_mut_cell(new_row, new_col).set_selected(true);
}
pub fn is_focused_cell_visible(&self) -> bool {
let vertical_offset: usize = self.vertical_offset.get_value();
let horizontal_offset: usize = self.horizontal_offset.get_value();
let row: usize = self.focused_cell.get_row();
let col: usize = self.focused_cell.get_col();
if 0usize.saturating_add(vertical_offset) > row
|| row >= self.rows.saturating_add(vertical_offset)
{
return false;
}
if 0usize.saturating_add(horizontal_offset) > col
|| col >= self.cols.saturating_add(horizontal_offset)
{
return false;
}
true
}
}
+4 -9
View File
@@ -34,16 +34,11 @@ impl Widget for BoardWidget<'_> {
.split(*col_area);
for (row_idx, cell_area) in vertical.iter().enumerate() {
let map_row: usize = row_idx + self.state.vertical_offset.get_value();
let map_col: usize = col_idx + self.state.horizontal_offset.get_value();
if let Some(cell) = self
.state
self.state
.cells
.get(map_row * self.state.map_width + map_col)
{
cell.render(*cell_area, buf);
}
.get(row_idx + self.state.vertical_offset.get_value())
.and_then(|rows| rows.get(col_idx + self.state.horizontal_offset.get_value()))
.map(|cell| cell.render(*cell_area, buf));
}
}
}