diff --git a/src/app/keybindings/keybindings.rs b/src/app/keybindings/keybindings.rs index 4972b0c..d2ecc53 100644 --- a/src/app/keybindings/keybindings.rs +++ b/src/app/keybindings/keybindings.rs @@ -1,5 +1,6 @@ use clap::ValueEnum; use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; +use std::collections::HashMap; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Action { @@ -17,6 +18,8 @@ pub enum Action { Enter, Esc, Backspace, + ZoomIn, + ZoomOut, WildCard(char), } @@ -27,6 +30,7 @@ pub enum Group { Scroll, Select, Input, + Zoom, Quit, } @@ -168,6 +172,24 @@ pub static KEYBINDINGS: &[KeyBinding] = &[ symbol: "Backspace", description: "Delete character", }, + KeyBinding { + action: Action::ZoomIn, + code: KeyCode::Char(','), + kind: KeyEventKind::Press, + modifiers: KeyModifiers::NONE, + group: Group::Zoom, + symbol: ",", + description: "Zoom in", + }, + KeyBinding { + action: Action::ZoomOut, + code: KeyCode::Char('.'), + kind: KeyEventKind::Press, + modifiers: KeyModifiers::NONE, + group: Group::Zoom, + symbol: ".", + description: "Zoom out", + }, KeyBinding { action: Action::WildCard('_'), code: KeyCode::Char('_'), @@ -202,3 +224,15 @@ pub fn event_to_action(event: &KeyEvent) -> Option { None } + +pub fn count_largest_group(actions: &Vec) -> u16 { + let mut group_counts: HashMap = HashMap::new(); + + for action in actions { + if let Some(binding) = binding_for(*action) { + *group_counts.entry(binding.group).or_insert(0) += 1; + } + } + + group_counts.values().copied().max().map_or(0, |v| v) +} diff --git a/src/app/keybindings/mod.rs b/src/app/keybindings/mod.rs index 2696876..f6e45f7 100644 --- a/src/app/keybindings/mod.rs +++ b/src/app/keybindings/mod.rs @@ -4,6 +4,8 @@ pub mod main_menu; pub mod skirmish; pub use default::{common_keybindings, default_keybindings}; -pub use keybindings::{Action, Group, KEYBINDINGS, KeyBinding, binding_for, event_to_action}; +pub use keybindings::{ + Action, Group, KEYBINDINGS, KeyBinding, binding_for, count_largest_group, event_to_action, +}; pub use main_menu::main_menu_keybindings; pub use skirmish::skirmish_keybindings; diff --git a/src/app/keybindings/skirmish.rs b/src/app/keybindings/skirmish.rs index afa8755..8825d95 100644 --- a/src/app/keybindings/skirmish.rs +++ b/src/app/keybindings/skirmish.rs @@ -1,6 +1,7 @@ use crate::app::{ App, keybindings::{Action, common_keybindings, event_to_action}, + states::ZoomLevel, }; use ratatui::crossterm::event::KeyEvent; @@ -12,6 +13,24 @@ pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) { Action::ScrollDown => app.states.skirmish.vertical_offset.next(), Action::ScrollLeft => app.states.skirmish.horizontal_offset.prev(), Action::ScrollRight => app.states.skirmish.horizontal_offset.next(), + Action::ZoomIn => match app.states.skirmish.zoom_level { + ZoomLevel::ZoomedIn => {} + ZoomLevel::Default => { + app.states.skirmish.zoom_level = ZoomLevel::ZoomedIn; + } + ZoomLevel::ZoomedOut => { + app.states.skirmish.zoom_level = ZoomLevel::Default; + } + }, + Action::ZoomOut => match app.states.skirmish.zoom_level { + ZoomLevel::ZoomedIn => { + app.states.skirmish.zoom_level = ZoomLevel::Default; + } + ZoomLevel::Default => { + app.states.skirmish.zoom_level = ZoomLevel::ZoomedOut; + } + ZoomLevel::ZoomedOut => {} + }, _ => (), } } diff --git a/src/app/state.rs b/src/app/state.rs index 66c871f..c046b43 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -30,6 +30,7 @@ impl GameStates { map_width: args.map_width as usize, map_height: args.map_height as usize, board_cells: Vec::new(), + zoom_level: args.zoom_level, }, perk_decks: PerkDecksState { id: 2, diff --git a/src/app/states/mod.rs b/src/app/states/mod.rs index 900c2d3..6fb5fcb 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}; +pub use skirmish::{GameMode, Offset, SkirmishState, ZoomLevel}; diff --git a/src/app/states/skirmish.rs b/src/app/states/skirmish.rs index 5e98029..4414ff8 100644 --- a/src/app/states/skirmish.rs +++ b/src/app/states/skirmish.rs @@ -33,9 +33,9 @@ impl Offset { } pub fn set_max(&mut self, max: usize) { - if self.max_initiated { - return; - } + // if self.max_initiated { + // return; + // } self.max = max; self.max_initiated = true; @@ -59,6 +59,7 @@ pub struct SkirmishState { pub vertical_offset: Offset, pub horizontal_offset: Offset, pub board_cells: Vec, + pub zoom_level: ZoomLevel, } impl SkirmishState { @@ -80,3 +81,10 @@ pub enum GameMode { LastManStanding, FrontLines, } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] +pub enum ZoomLevel { + ZoomedIn, + Default, + ZoomedOut, +} diff --git a/src/app/views/default.rs b/src/app/views/default.rs index 20ecdf5..dd3fd44 100644 --- a/src/app/views/default.rs +++ b/src/app/views/default.rs @@ -1,4 +1,7 @@ -use crate::app::{keybindings::Action, widgets::KeybindingsWidget}; +use crate::app::{ + keybindings::{Action, count_largest_group}, + widgets::KeybindingsWidget, +}; use ratatui::{ buffer::Buffer, layout::{Alignment, Constraint, Layout, Rect}, @@ -7,7 +10,12 @@ use ratatui::{ }; pub fn default_view(area: Rect, buf: &mut Buffer) { - let vertical_layout: Layout = Layout::vertical([Constraint::Fill(1), Constraint::Length(4)]); + let actions: Vec = vec![Action::Quit, Action::Quit2, Action::Esc]; + + let vertical_layout: Layout = Layout::vertical([ + Constraint::Fill(1), + Constraint::Length(count_largest_group(&actions) + 2), + ]); let [main_area, keybindings_area] = vertical_layout.areas(area); @@ -24,8 +32,6 @@ pub fn default_view(area: Rect, buf: &mut Buffer) { } { - let actions: Vec = vec![Action::Quit, Action::Quit2, Action::Esc]; - KeybindingsWidget::new(actions).render(keybindings_area, buf); } } diff --git a/src/app/views/main_menu.rs b/src/app/views/main_menu.rs index 010602a..f674c90 100644 --- a/src/app/views/main_menu.rs +++ b/src/app/views/main_menu.rs @@ -1,4 +1,8 @@ -use crate::app::{App, View, keybindings::Action, widgets::KeybindingsWidget}; +use crate::app::{ + App, View, + keybindings::{Action, count_largest_group}, + widgets::KeybindingsWidget, +}; use clap::ValueEnum; use ratatui::{ buffer::Buffer, @@ -23,7 +27,18 @@ fn format_view_string(s: String) -> String { } pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) { - let vertical_layout: Layout = Layout::vertical([Constraint::Fill(1), Constraint::Length(4)]); + let actions: Vec = vec![ + Action::Up, + Action::Down, + Action::Space, + Action::Quit, + Action::Quit2, + ]; + + let vertical_layout: Layout = Layout::vertical([ + Constraint::Fill(1), + Constraint::Length(count_largest_group(&actions) + 2), + ]); let [main_menu_area, keybindings_area] = vertical_layout.areas(area); @@ -83,14 +98,6 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) { } { - let actions: Vec = vec![ - Action::Up, - Action::Down, - Action::Space, - Action::Quit, - Action::Quit2, - ]; - KeybindingsWidget::new(actions).render(keybindings_area, buf); } } diff --git a/src/app/views/skirmish.rs b/src/app/views/skirmish.rs index 79dcff9..fe4543a 100644 --- a/src/app/views/skirmish.rs +++ b/src/app/views/skirmish.rs @@ -1,6 +1,6 @@ use crate::app::{ App, - keybindings::Action, + keybindings::{Action, count_largest_group}, widgets::{BoardWidget, KeybindingsWidget}, }; use ratatui::{ @@ -12,10 +12,22 @@ use ratatui::{ }; pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) { + let actions: Vec = vec![ + Action::ScrollUp, + Action::ScrollDown, + Action::ScrollLeft, + Action::ScrollRight, + Action::ZoomIn, + Action::ZoomOut, + Action::Quit, + Action::Quit2, + Action::Esc, + ]; + let vertical_layout: Layout = Layout::vertical([ Constraint::Length(4), Constraint::Fill(1), - Constraint::Length(6), + Constraint::Length(count_largest_group(&actions) + 2), ]); let [title_area, main_area, keybindings_area] = vertical_layout.areas(area); @@ -78,16 +90,6 @@ pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) { } { - let actions: Vec = vec![ - Action::ScrollUp, - Action::ScrollDown, - Action::ScrollLeft, - Action::ScrollRight, - Action::Quit, - Action::Quit2, - Action::Esc, - ]; - KeybindingsWidget::new(actions).render(keybindings_area, buf); } } diff --git a/src/app/widgets/board.rs b/src/app/widgets/board.rs index 2f67a11..6496c36 100644 --- a/src/app/widgets/board.rs +++ b/src/app/widgets/board.rs @@ -1,4 +1,4 @@ -use crate::app::{App, widgets::CellWidget}; +use crate::app::{App, states::ZoomLevel, widgets::CellWidget}; use ratatui::{ buffer::Buffer, layout::{Constraint, Layout, Rect}, @@ -18,24 +18,32 @@ pub struct BoardWidget<'a> { } impl<'a> BoardWidget<'a> { + fn max_offset(map_size: u16, size: u16) -> usize { + if map_size > size { + (map_size - size) as usize + } else { + 0 + } + } + pub fn new(app: &'a mut App, area_width: u16, area_height: u16) -> Self { - const CELL_HIGHT: u16 = 5; - const CELL_WIDTH: u16 = 9; + let cell_height: u16 = match app.states.skirmish.zoom_level { + ZoomLevel::ZoomedIn => 7, + ZoomLevel::Default => 5, + ZoomLevel::ZoomedOut => 3, + }; - let rows: u16 = area_height / CELL_HIGHT; - let cols: u16 = area_width / CELL_WIDTH; + let cell_width: u16 = match app.states.skirmish.zoom_level { + ZoomLevel::ZoomedIn => 13, + ZoomLevel::Default => 9, + ZoomLevel::ZoomedOut => 5, + }; - let v_max_offset: usize = if app.states.skirmish.map_height as u16 > rows { - app.states.skirmish.map_height as u16 - rows - } else { - 0 - } as usize; + let rows: u16 = area_height / cell_height; + let cols: u16 = area_width / cell_width; - let h_max_offset: usize = if app.states.skirmish.map_width as u16 > cols { - app.states.skirmish.map_width as u16 - cols - } else { - 0 - } as usize; + let v_max_offset: usize = Self::max_offset(app.states.skirmish.map_height as u16, rows); + let h_max_offset: usize = Self::max_offset(app.states.skirmish.map_width as u16, cols); app.states.skirmish.horizontal_offset.set_max(h_max_offset); app.states.skirmish.vertical_offset.set_max(v_max_offset); @@ -49,8 +57,8 @@ impl<'a> BoardWidget<'a> { Self { map_width: app.states.skirmish.map_width as usize, - cell_width: CELL_WIDTH, - cell_height: CELL_HIGHT, + cell_width, + cell_height, cols, rows, h_offset: app.states.skirmish.horizontal_offset.get_value(), diff --git a/src/cli.rs b/src/cli.rs index 5b46828..2a6050d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,5 +1,5 @@ use crate::app::{ - states::{GameMode, PerkDecks}, + states::{GameMode, PerkDecks, ZoomLevel}, view::View, }; use clap::{Error, Parser, error::ErrorKind, value_parser}; @@ -52,6 +52,15 @@ pub struct Cli { )] pub map_height: u8, + #[arg( + long, + help = "Zoom level", + value_name = "...", + default_value_t = ZoomLevel::Default, + value_enum + )] + pub zoom_level: ZoomLevel, + #[arg( long, help = "Perk Deck",