Files
war-in-tunnels/src/app/app.rs
T
GarandPLG 71b9d44a77 Refactor keybindings with groups and symbols
Introduce a `Group` enum to categorize actions and add `group` and
`symbol`
fields to `KeyBinding`. Extend `Action` with `Up`, `Down`, `Space`, and
`Esc`, updating all keybinding definitions accordingly.

Update `binding_for_view` to return the new actions per view and handle
`Esc` by returning to the main menu.

Rewrite the keybindings widget as a custom `Widget` that renders grouped
paragraphs with proper layout.

Adjust the main menu layout percentages to accommodate the new widget.
2026-03-12 16:00:45 +01:00

133 lines
3.2 KiB
Rust

use crate::{
app::{
GameStates,
keybindings::{Action, event_to_action, main_menu_keybindings},
},
cli::Cli,
};
use clap::ValueEnum;
use ratatui::{
DefaultTerminal, Frame,
crossterm::event::{self, KeyEvent},
};
use std::{
io::Result,
sync::mpsc::{self, Receiver},
};
pub enum Event {
Input(KeyEvent),
}
pub struct App {
pub exit: bool,
pub view: View,
pub game_states: GameStates,
pub username: String,
pub game_mode: GameMode,
pub map_width: u8,
pub map_height: u8,
pub perk_deck: PerkDecks,
pub starting_wood: u8,
pub starting_iron: u8,
pub supply_limit: u8,
pub xp_modifier: f32,
pub skill_points_limit: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
pub enum View {
MainMenu,
Skirmish,
PerkDecks,
SkillsConfig,
Settings,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
pub enum GameMode {
LastManStanding,
Frontlines,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
pub enum PerkDecks {
Silesian,
BogeyMan,
Anteater,
}
impl App {
pub fn new(args: Cli) -> Self {
Self {
exit: false,
game_states: GameStates::new(),
view: args.view,
username: args.username,
game_mode: args.game_mode,
map_width: args.map_width,
map_height: args.map_height,
perk_deck: args.perk_deck,
starting_wood: args.starting_wood,
starting_iron: args.starting_iron,
supply_limit: args.supply_limit,
xp_modifier: args.xp_modifier,
skill_points_limit: args.skill_points_limit,
}
}
pub fn run(&mut self, terminal: &mut DefaultTerminal, rx: Receiver<Event>) -> Result<()> {
while !self.exit {
terminal.draw(|frame: &mut Frame<'_>| self.draw(frame))?;
let event: Event = match rx.recv() {
Ok(ev) => ev,
Err(_) => break,
};
match event {
Event::Input(key_event) => self.handle_key_event(key_event)?,
}
}
Ok(())
}
fn draw(&self, frame: &mut Frame<'_>) {
frame.render_widget(self, frame.area());
}
fn handle_key_event(&mut self, key_event: KeyEvent) -> Result<()> {
match self.view {
View::MainMenu => main_menu_keybindings(self, &key_event),
_ => {
if let Some(action) = event_to_action(&key_event) {
match action {
Action::Quit => self.exit = true,
Action::Esc => self.view = View::MainMenu,
_ => (),
}
}
}
}
Ok(())
}
}
pub fn handle_input_events(tx: mpsc::Sender<Event>) {
loop {
match event::read() {
Ok(ev) => {
if let event::Event::Key(key_event) = ev {
if tx.send(Event::Input(key_event)).is_err() {
break;
}
}
}
Err(_) => {
continue;
}
}
}
}