Add base tags, adjust margins, update CLI defaults

Introduce `CellTag` and `Players` enums and extend `CellWidget` to carry
a tag.
Store player and enemy base coordinates in `BoardState` and tag those
cells.
Reduce horizontal margin from 3 to 1 in board layout helpers.
Change CLI defaults: map width default 42, map height min 11 and default
11.
Adjust offset calculation and render constraints to match the new
layout.
This commit is contained in:
2026-04-09 18:16:26 +02:00
parent 6e6181887c
commit b45c300bc3
6 changed files with 97 additions and 44 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ pub fn cells_area_helper(area: &Rect) -> Rect {
.borders(Borders::LEFT | Borders::TOP | Borders::RIGHT) .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT)
.inner(skirmish_layout(*area)[1]) .inner(skirmish_layout(*area)[1])
.inner(Margin { .inner(Margin {
horizontal: 3, horizontal: 1,
vertical: 1, vertical: 1,
}) })
} }
+22 -9
View File
@@ -1,7 +1,7 @@
use crate::app::{ use crate::app::{
helpers::{CellSizes, cell_size_helper, cells_area_helper}, helpers::{CellSizes, cell_size_helper, cells_area_helper},
states::{FocusedCell, Offset, ZoomLevel, skirmish_states::MoveFocusedCell}, states::{FocusedCell, Offset, ZoomLevel, skirmish_states::MoveFocusedCell},
widgets::CellWidget, widgets::{CellTag, CellWidget, Players},
}; };
use ratatui::layout::Rect; use ratatui::layout::Rect;
@@ -19,6 +19,8 @@ pub struct BoardState {
pub cells: Vec<Vec<CellWidget>>, pub cells: Vec<Vec<CellWidget>>,
pub zoom_level: ZoomLevel, pub zoom_level: ZoomLevel,
focused_cell: FocusedCell, focused_cell: FocusedCell,
player_base_coords: (usize, usize),
enemy_base_coords: (usize, usize),
} }
impl BoardState { impl BoardState {
@@ -35,25 +37,34 @@ impl BoardState {
let h_max_offset: usize = Self::max_offset(map_width, cols); let h_max_offset: usize = Self::max_offset(map_width, cols);
let vertical_offset: Offset = Offset::new( let vertical_offset: Offset = Offset::new(
Some((map_height - rows as usize) / 2 + 1), Some((map_height - rows as usize + 1) / 2),
Some(v_max_offset), Some(v_max_offset),
); );
let horizontal_offset: Offset = Offset::new(None, Some(h_max_offset)); let horizontal_offset: Offset = Offset::new(None, Some(h_max_offset));
let focused_cell: FocusedCell = FocusedCell::new(map_height / 2, 2, map_height, map_width); let focused_cell: FocusedCell =
FocusedCell::new((map_height) / 2, 2, map_height, map_width);
let mut cells: Vec<Vec<CellWidget>> = Vec::new(); let mut cells: Vec<Vec<CellWidget>> = Vec::new();
let player_base_coords: (usize, usize) = ((map_height) / 2, 1);
let enemy_base_coords: (usize, usize) = ((map_height) / 2, map_width - 2);
for row in 0..map_height { for row in 0..map_height {
let mut rows: Vec<CellWidget> = Vec::new(); let mut rows: Vec<CellWidget> = Vec::new();
for col in 0..map_width { for col in 0..map_width {
rows.push(CellWidget::new( let selected: bool = row == focused_cell.get_row() && col == focused_cell.get_col();
row,
col, let tag: CellTag = if row == player_base_coords.0 && col == player_base_coords.1 {
row == focused_cell.get_row() && col == focused_cell.get_col(), CellTag::Base(Players::Player)
zoom_level, } else if row == enemy_base_coords.0 && col == enemy_base_coords.1 {
)); CellTag::Base(Players::Enemy)
} else {
CellTag::Stone
};
rows.push(CellWidget::new(row, col, zoom_level, selected, tag));
} }
cells.push(rows); cells.push(rows);
@@ -72,6 +83,8 @@ impl BoardState {
cells, cells,
zoom_level, zoom_level,
focused_cell, focused_cell,
player_base_coords,
enemy_base_coords,
} }
} }
+13 -2
View File
@@ -89,11 +89,22 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
board_block.render(main_area, buf); board_block.render(main_area, buf);
let cells_area: Rect = board_area.inner(Margin { let cells_area: Rect = board_area.inner(Margin {
horizontal: 3, horizontal: 1,
vertical: 1, vertical: 1,
}); });
BoardWidget::new(&states.skirmish.board).render(cells_area, buf); // TODO: add actual (effective) board sizes as Constraints
BoardWidget::new(&states.skirmish.board).render(
cells_area.centered(
Constraint::Length(
(states.skirmish.board.cell_width * states.skirmish.board.cols) as u16,
),
Constraint::Length(
(states.skirmish.board.cell_height * states.skirmish.board.rows) as u16,
),
),
buf,
);
} }
{ {
+55 -26
View File
@@ -3,17 +3,22 @@ use ratatui::{
buffer::Buffer, buffer::Buffer,
layout::{Alignment, Rect}, layout::{Alignment, Rect},
style::{Color, Style, Stylize}, style::{Color, Style, Stylize},
text::Line, text::{Line, Span, ToSpan},
widgets::{Block, Borders, Paragraph, Widget}, widgets::{Block, Borders, Paragraph, Widget},
}; };
// pub enum CellTags { #[derive(Debug, Clone, Copy, PartialEq, Eq)]
// Player, pub enum CellTag {
// Enemy, Base(Players),
// Dirt, Tunel,
// Tunnel, Stone,
// Base, }
// }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Players {
Player,
Enemy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CellWidget { pub struct CellWidget {
@@ -21,16 +26,23 @@ pub struct CellWidget {
col: usize, col: usize,
selected: bool, selected: bool,
zoom_level: ZoomLevel, zoom_level: ZoomLevel,
// pub tags: Vec<CellTags>, tag: CellTag,
} }
impl CellWidget { impl CellWidget {
pub fn new(row: usize, col: usize, selected: bool, zoom_level: ZoomLevel) -> Self { pub fn new(
row: usize,
col: usize,
zoom_level: ZoomLevel,
selected: bool,
tag: CellTag,
) -> Self {
Self { Self {
row, row,
col, col,
selected, selected,
zoom_level, zoom_level,
tag,
} }
} }
@@ -42,6 +54,10 @@ impl CellWidget {
self.zoom_level = zoom_level; self.zoom_level = zoom_level;
} }
pub fn set_tag(&mut self, tag: CellTag) {
self.tag = tag;
}
fn col_to_letters(&self) -> String { fn col_to_letters(&self) -> String {
let mut col: usize = self.col + 1; let mut col: usize = self.col + 1;
let mut letters: Vec<char> = Vec::new(); let mut letters: Vec<char> = Vec::new();
@@ -54,36 +70,49 @@ impl CellWidget {
letters.iter().rev().collect() letters.iter().rev().collect()
} }
fn display_coords(&self) -> String { fn display_coords(&self) -> Span<'_> {
format!("{}{}", self.col_to_letters(), self.row) if self.selected || self.tag != CellTag::Stone {
format!("{}{}", self.col_to_letters(), self.row).green()
} else {
"".to_span()
}
} }
fn fg_color(&self) -> Color { fn fg_color(&self) -> Color {
if self.selected { match self.tag {
Color::Red _ if self.selected => Color::LightYellow,
} else { CellTag::Base(Players::Player) if !self.selected => Color::LightBlue,
Color::White CellTag::Base(Players::Enemy) if !self.selected => Color::LightRed,
CellTag::Tunel if !self.selected => Color::Gray,
_ => Color::White,
} }
} }
fn get_text_area(&self) -> Vec<Line<'_>> { fn get_text_area(&self) -> Vec<Line<'_>> {
let tag: &str = match self.tag {
CellTag::Base(_) => "B",
CellTag::Tunel => "T",
CellTag::Stone => " ",
};
let units: &str = " "; // TODO: units count on that cell
let mut text_area: Vec<Line<'_>> = Vec::new(); let mut text_area: Vec<Line<'_>> = Vec::new();
match self.zoom_level { match self.zoom_level {
ZoomLevel::ZoomedIn => { ZoomLevel::ZoomedIn => {
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" {}", units)));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" ")));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" {} ", tag)));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" ")));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" ")));
} }
ZoomLevel::Default => { ZoomLevel::Default => {
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" {}", units)));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" {} ", tag)));
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" ")));
} }
ZoomLevel::ZoomedOut => { ZoomLevel::ZoomedOut => {
text_area.push(Line::from(" ")); text_area.push(Line::from(format!(" {} ", tag)));
} }
} }
@@ -94,7 +123,7 @@ impl CellWidget {
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.style(Style::default().fg(self.fg_color())) .style(Style::default().fg(self.fg_color()))
.title(self.display_coords().green()) .title(self.display_coords())
} }
} }
+1 -1
View File
@@ -3,5 +3,5 @@ pub mod cell;
pub mod keybindings; pub mod keybindings;
pub use board::BoardWidget; pub use board::BoardWidget;
pub use cell::CellWidget; pub use cell::{CellTag, CellWidget, Players};
pub use keybindings::KeybindingsWidget; pub use keybindings::KeybindingsWidget;
+5 -5
View File
@@ -49,18 +49,18 @@ pub struct Cli {
long, long,
help = "Map width", help = "Map width",
value_name = "Positive integer [36; 108]", value_name = "Positive integer [36; 108]",
default_value = "36", default_value = "42",
value_parser = value_parser!(u8).range(36..=108) value_parser = value_parser!(u8).range(36..=108)
)] )]
pub map_width: u8, pub map_width: u8,
/// Height of the generated map (1350 tiles). /// Height of the generated map (1150 tiles).
#[arg( #[arg(
long, long,
help = "Map height", help = "Map height",
value_name = "Positive integer [13; 39]", value_name = "Positive integer [11; 39]",
default_value = "13", default_value = "11",
value_parser = value_parser!(u8).range(13..=39) value_parser = value_parser!(u8).range(11..=39)
)] )]
pub map_height: u8, pub map_height: u8,