Add side panel and refactor title helpers

Introduce a `side_panel` flag throughout the skirmish state, board
creation,
and cell area calculation to enable a detachable side panel. Refactor
the
title helper to own its strings and use a static separator, updating the
single‑title helper accordingly. Add a new `SidePanelWidget` and expose
the
`skirmish_main_area_layout` helper. Extend keybindings with `Tab` and
`ShiftTab` actions under a new `Opener` group. Update structures and
units
to implement a `get_name` method and adjust related traits and imports.
This commit is contained in:
2026-04-24 11:41:09 +02:00
parent 06a439ff88
commit cf843057c3
23 changed files with 302 additions and 123 deletions
+1
View File
@@ -6,6 +6,7 @@ pub struct SkirmishState {
pub id: usize,
pub name: &'static str,
pub board: BoardState,
pub side_panel: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
+20 -6
View File
@@ -33,8 +33,14 @@ pub struct BoardState {
}
impl BoardState {
pub fn new(area: &Rect, map_width: usize, map_height: usize, zoom_level: ZoomLevel) -> Self {
let cells_area: Rect = cells_area_helper(area);
pub fn new(
area: &Rect,
map_width: usize,
map_height: usize,
zoom_level: ZoomLevel,
side_panel: bool,
) -> Self {
let cells_area: Rect = cells_area_helper(area, side_panel);
let cell_width: usize = zoom_level.get_cell_size(CellSizes::Width);
let cell_height: usize = zoom_level.get_cell_size(CellSizes::Height);
@@ -114,6 +120,10 @@ impl BoardState {
}
}
pub fn get_ref_cell(&self, row: usize, col: usize) -> &CellWidget {
&self.cells[row][col]
}
fn get_mut_cell(&mut self, row: usize, col: usize) -> &mut CellWidget {
&mut self.cells[row][col]
}
@@ -188,6 +198,10 @@ impl BoardState {
if map_size > size { map_size - size } else { 0 }
}
pub fn get_focused_cell(&self) -> &FocusedCell {
&self.focused_cell
}
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();
@@ -209,14 +223,14 @@ impl BoardState {
true
}
pub fn change_resize(&mut self, area: &Rect) {
self.cells_area = cells_area_helper(area);
pub fn change_resize(&mut self, area: &Rect, side_panel: bool) {
self.cells_area = cells_area_helper(area, side_panel);
self.cols = (self.cells_area.width / self.cell_width as u16) as usize;
self.rows = (self.cells_area.height / self.cell_height as u16) as usize;
let h_max_offset: usize = Self::max_offset(self.map_height, self.cols);
let v_max_offset: usize = Self::max_offset(self.map_width, self.rows);
let v_max_offset: usize = Self::max_offset(self.map_height, self.rows);
let h_max_offset: usize = Self::max_offset(self.map_width, self.cols);
self.horizontal_offset =
Offset::new(Some(self.horizontal_offset.get_value()), Some(h_max_offset));
@@ -47,4 +47,8 @@ impl Structure for BaseBuilding {
fn get_stress(&self) -> u8 {
self.stress
}
fn get_name(&self) -> &'static str {
"Base"
}
}
@@ -36,4 +36,8 @@ impl Structure for Stone {
fn get_stress(&self) -> u8 {
self.stress
}
fn get_name(&self) -> &'static str {
"Stone"
}
}
@@ -8,28 +8,52 @@ pub enum Structures {
Stone(Stone),
}
impl Structures {
pub fn get_color(&self) -> Color {
impl Structure for Structures {
fn get_color(&self) -> Color {
match self {
Structures::Base(b) => b.get_color(),
Structures::Tunnel(t) => t.get_color(),
Structures::Stone(s) => s.get_color(),
Self::Base(b) => b.get_color(),
Self::Tunnel(t) => t.get_color(),
Self::Stone(s) => s.get_color(),
}
}
pub fn get_tag(&self) -> char {
fn get_tag(&self) -> char {
match self {
Structures::Base(b) => b.get_tag(),
Structures::Tunnel(t) => t.get_tag(),
Structures::Stone(s) => s.get_tag(),
Self::Base(b) => b.get_tag(),
Self::Tunnel(t) => t.get_tag(),
Self::Stone(s) => s.get_tag(),
}
}
pub fn get_level(&self) -> char {
fn get_level(&self) -> char {
match self {
Structures::Base(b) => b.get_level(),
Structures::Tunnel(t) => t.get_level(),
Structures::Stone(s) => s.get_level(),
Self::Base(b) => b.get_level(),
Self::Tunnel(t) => t.get_level(),
Self::Stone(s) => s.get_level(),
}
}
fn get_name(&self) -> &'static str {
match self {
Self::Base(b) => b.get_name(),
Self::Tunnel(t) => t.get_name(),
Self::Stone(s) => s.get_name(),
}
}
fn get_durability(&self) -> u16 {
match self {
Self::Base(b) => b.get_durability(),
Self::Tunnel(t) => t.get_durability(),
Self::Stone(s) => s.get_durability(),
}
}
fn get_stress(&self) -> u8 {
match self {
Self::Base(b) => b.get_stress(),
Self::Tunnel(t) => t.get_stress(),
Self::Stone(s) => s.get_stress(),
}
}
}
@@ -6,4 +6,5 @@ pub trait Structure {
fn get_level(&self) -> char;
fn get_stress(&self) -> u8;
fn get_durability(&self) -> u16;
fn get_name(&self) -> &'static str;
}
@@ -42,4 +42,8 @@ impl Structure for Tunnel {
fn get_stress(&self) -> u8 {
self.stress
}
fn get_name(&self) -> &'static str {
"Tunnel"
}
}
@@ -19,4 +19,8 @@ impl Unit for MinerUnit {
fn get_tag(&self) -> char {
'M'
}
fn get_name(&self) -> &'static str {
"Miner"
}
}
+1 -1
View File
@@ -4,4 +4,4 @@ mod units_trait;
pub use miner::MinerUnit;
pub use units_enum::Units;
pub use units_trait::{OptionalUnit, Unit};
pub use units_trait::Unit;
@@ -1,20 +1,43 @@
use crate::app::states::skirmish_states::units::{MinerUnit, OptionalUnit, Unit};
use crate::app::states::{
Players,
skirmish_states::units::{MinerUnit, Unit},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Units {
Miner(MinerUnit),
}
impl Units {
pub fn get_tag(&self) -> char {
impl Unit for Units {
fn get_tag(&self) -> char {
match self {
Units::Miner(m) => m.get_tag(),
Self::Miner(m) => m.get_tag(),
}
}
fn get_name(&self) -> &'static str {
match self {
Self::Miner(m) => m.get_name(),
}
}
fn get_owner(&self) -> Players {
match self {
Self::Miner(m) => m.get_owner(),
}
}
}
impl OptionalUnit for Option<Units> {
fn try_get_tag(&self) -> char {
impl Unit for Option<Units> {
fn get_tag(&self) -> char {
self.map_or(' ', |u| u.get_tag())
}
fn get_name(&self) -> &'static str {
self.map_or("", |u| u.get_name())
}
fn get_owner(&self) -> Players {
self.map_or(Players::Enemy, |u| u.get_owner())
}
}
@@ -3,8 +3,5 @@ use crate::app::states::Players;
pub trait Unit {
fn get_owner(&self) -> Players;
fn get_tag(&self) -> char;
}
pub trait OptionalUnit {
fn try_get_tag(&self) -> char;
fn get_name(&self) -> &'static str;
}