generated from GarandPLG/rust-flake-template
Add scrolling actions and board widget
Introduce directional and scroll actions, update keybindings, add scrollbar state to SkirmishState, and render the board with a new BoardWidget. Adjust CLI defaults and layout heights accordingly.
This commit is contained in:
@@ -7,6 +7,12 @@ pub enum Action {
|
|||||||
Quit2,
|
Quit2,
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
ScrollUp,
|
||||||
|
ScrollDown,
|
||||||
|
ScrollLeft,
|
||||||
|
ScrollRight,
|
||||||
Space,
|
Space,
|
||||||
Enter,
|
Enter,
|
||||||
Esc,
|
Esc,
|
||||||
@@ -17,6 +23,7 @@ pub enum Action {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
||||||
pub enum Group {
|
pub enum Group {
|
||||||
Movement,
|
Movement,
|
||||||
|
Scroll,
|
||||||
Select,
|
Select,
|
||||||
Input,
|
Input,
|
||||||
Quit,
|
Quit,
|
||||||
@@ -70,6 +77,60 @@ pub static KEYBINDINGS: &[KeyBinding] = &[
|
|||||||
symbol: "↓",
|
symbol: "↓",
|
||||||
description: "Down",
|
description: "Down",
|
||||||
},
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::Left,
|
||||||
|
code: KeyCode::Left,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::NONE,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "←",
|
||||||
|
description: "Left",
|
||||||
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::Right,
|
||||||
|
code: KeyCode::Right,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::NONE,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "→",
|
||||||
|
description: "Right",
|
||||||
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::ScrollUp,
|
||||||
|
code: KeyCode::Up,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "Ctrl + ↑",
|
||||||
|
description: "Scroll Up ",
|
||||||
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::ScrollDown,
|
||||||
|
code: KeyCode::Down,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "Ctrl + ↓",
|
||||||
|
description: "Scroll Down",
|
||||||
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::ScrollLeft,
|
||||||
|
code: KeyCode::Left,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "Ctrl + ←",
|
||||||
|
description: "Scroll Left",
|
||||||
|
},
|
||||||
|
KeyBinding {
|
||||||
|
action: Action::ScrollRight,
|
||||||
|
code: KeyCode::Right,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
group: Group::Movement,
|
||||||
|
symbol: "Ctrl + →",
|
||||||
|
description: "Scroll Right",
|
||||||
|
},
|
||||||
KeyBinding {
|
KeyBinding {
|
||||||
action: Action::Space,
|
action: Action::Space,
|
||||||
code: KeyCode::Char(' '),
|
code: KeyCode::Char(' '),
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ use ratatui::crossterm::event::KeyEvent;
|
|||||||
pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
|
pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) {
|
||||||
if let Some(action) = event_to_action(&key_event) {
|
if let Some(action) = event_to_action(&key_event) {
|
||||||
match action {
|
match action {
|
||||||
|
Action::ScrollUp => app.states.skirmish.vertical_scrollbar.prev(),
|
||||||
|
Action::ScrollDown => app.states.skirmish.vertical_scrollbar.next(),
|
||||||
|
Action::ScrollLeft => app.states.skirmish.horizontal_scrollbar.prev(),
|
||||||
|
Action::ScrollRight => app.states.skirmish.horizontal_scrollbar.next(),
|
||||||
Action::Quit => app.exit = true,
|
Action::Quit => app.exit = true,
|
||||||
Action::Quit2 => app.exit = true,
|
Action::Quit2 => app.exit = true,
|
||||||
Action::Esc => app.view = View::MainMenu,
|
Action::Esc => app.view = View::MainMenu,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use ratatui::widgets::ScrollbarState;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::states::{MainMenuState, PerkDecksState, SettingsState, SkillsConfigState, SkirmishState},
|
app::states::{MainMenuState, PerkDecksState, SettingsState, SkillsConfigState, SkirmishState},
|
||||||
cli::Cli,
|
cli::Cli,
|
||||||
@@ -23,6 +25,8 @@ impl GameStates {
|
|||||||
skirmish: SkirmishState {
|
skirmish: SkirmishState {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "Skirmish",
|
name: "Skirmish",
|
||||||
|
vertical_scrollbar: ScrollbarState::new(0),
|
||||||
|
horizontal_scrollbar: ScrollbarState::new(0),
|
||||||
},
|
},
|
||||||
perk_decks: PerkDecksState {
|
perk_decks: PerkDecksState {
|
||||||
id: 2,
|
id: 2,
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
|
use ratatui::widgets::ScrollbarState;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct SkirmishState {
|
pub struct SkirmishState {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
|
pub vertical_scrollbar: ScrollbarState,
|
||||||
|
pub horizontal_scrollbar: ScrollbarState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
|
||||||
|
|||||||
+17
-13
@@ -1,4 +1,8 @@
|
|||||||
use crate::app::{App, keybindings::Action, widgets::KeybindingsWidget};
|
use crate::app::{
|
||||||
|
App,
|
||||||
|
keybindings::Action,
|
||||||
|
widgets::{BoardWidget, KeybindingsWidget},
|
||||||
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::{Alignment, Constraint, Layout, Margin, Rect},
|
layout::{Alignment, Constraint, Layout, Margin, Rect},
|
||||||
@@ -11,7 +15,7 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
|||||||
let vertical_layout: Layout = Layout::vertical([
|
let vertical_layout: Layout = Layout::vertical([
|
||||||
Constraint::Length(4),
|
Constraint::Length(4),
|
||||||
Constraint::Fill(1),
|
Constraint::Fill(1),
|
||||||
Constraint::Length(4),
|
Constraint::Length(6),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let [title_area, main_area, keybindings_area] = vertical_layout.areas(area);
|
let [title_area, main_area, keybindings_area] = vertical_layout.areas(area);
|
||||||
@@ -65,24 +69,24 @@ pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) {
|
|||||||
let board_area: Rect = board_block.inner(main_area);
|
let board_area: Rect = board_block.inner(main_area);
|
||||||
board_block.render(main_area, buf);
|
board_block.render(main_area, buf);
|
||||||
|
|
||||||
let inner_board_area: Rect = board_area.inner(Margin {
|
let cells_area: Rect = board_area.inner(Margin {
|
||||||
horizontal: 1,
|
horizontal: 1,
|
||||||
vertical: 1,
|
vertical: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
let map_width: u16 = inner_board_area.width / (app.states.settings.map_width as u16);
|
BoardWidget::new(app, cells_area.width, cells_area.height).render(cells_area, buf);
|
||||||
let map_height: u16 = inner_board_area.height / (app.states.settings.map_height as u16);
|
|
||||||
|
|
||||||
Paragraph::new(format!(
|
|
||||||
"x = {}, y = {}, mw = {}, mh = {}",
|
|
||||||
inner_board_area.width, inner_board_area.height, map_width, map_height
|
|
||||||
))
|
|
||||||
.block(Block::default())
|
|
||||||
.render(inner_board_area, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let actions: Vec<Action> = vec![Action::Quit, Action::Quit2, Action::Esc];
|
let actions: Vec<Action> = vec![
|
||||||
|
Action::ScrollUp,
|
||||||
|
Action::ScrollDown,
|
||||||
|
Action::ScrollLeft,
|
||||||
|
Action::ScrollRight,
|
||||||
|
Action::Quit,
|
||||||
|
Action::Quit2,
|
||||||
|
Action::Esc,
|
||||||
|
];
|
||||||
|
|
||||||
KeybindingsWidget::new(actions).render(keybindings_area, buf);
|
KeybindingsWidget::new(actions).render(keybindings_area, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
use crate::app::{App, widgets::CellWidget};
|
||||||
|
use ratatui::{
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::{Constraint, Layout, Rect},
|
||||||
|
widgets::Widget,
|
||||||
|
};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct BoardWidget {
|
||||||
|
cell_width: u16,
|
||||||
|
cell_height: u16,
|
||||||
|
cols: u16,
|
||||||
|
rows: u16,
|
||||||
|
h_offset: usize,
|
||||||
|
v_offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoardWidget {
|
||||||
|
pub fn new(app: &App, area_width: u16, area_height: u16) -> Self {
|
||||||
|
let cell_width: u16 = 7;
|
||||||
|
let cell_height: u16 = 4;
|
||||||
|
|
||||||
|
let cols: u16 = area_width / cell_width;
|
||||||
|
let rows: u16 = area_height / cell_height;
|
||||||
|
|
||||||
|
let h_max_offset: u16 = if app.states.settings.map_height as u16 > rows {
|
||||||
|
app.states.settings.map_height as u16 - rows
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let v_max_offset: u16 = if app.states.settings.map_width as u16 > cols {
|
||||||
|
app.states.settings.map_width as u16 - cols
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
// let h_offset: usize = (cell_height * rows as u16 / area_height) as usize;
|
||||||
|
// let v_offset: usize = (cell_width * cols as u16 / area_width) as usize;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cell_width,
|
||||||
|
cell_height,
|
||||||
|
cols,
|
||||||
|
rows,
|
||||||
|
h_offset: h_max_offset as usize,
|
||||||
|
v_offset: v_max_offset as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for BoardWidget {
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
|
let horizontal: Rc<[Rect]> = Layout::horizontal(vec![
|
||||||
|
Constraint::Length(self.cell_width);
|
||||||
|
self.cols as usize
|
||||||
|
])
|
||||||
|
.split(area);
|
||||||
|
|
||||||
|
for (col_idx, col_area) in horizontal.iter().enumerate() {
|
||||||
|
let vertical: Rc<[Rect]> = Layout::vertical(vec![
|
||||||
|
Constraint::Length(self.cell_height);
|
||||||
|
self.rows as usize
|
||||||
|
])
|
||||||
|
.split(*col_area);
|
||||||
|
|
||||||
|
for (row_idx, cell_area) in vertical.iter().enumerate() {
|
||||||
|
let cell: CellWidget =
|
||||||
|
CellWidget::new(row_idx + self.v_offset, col_idx + self.h_offset);
|
||||||
|
|
||||||
|
cell.render(*cell_area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
use ratatui::{
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::{Alignment, Rect},
|
||||||
|
style::Stylize,
|
||||||
|
widgets::{Block, Borders, Paragraph, Widget},
|
||||||
|
};
|
||||||
|
|
||||||
|
// pub enum CellTags {
|
||||||
|
// Player,
|
||||||
|
// Enemy,
|
||||||
|
// Dirt,
|
||||||
|
// Tunnel,
|
||||||
|
// Base,
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub struct CellWidget {
|
||||||
|
pub row: usize,
|
||||||
|
pub col: usize,
|
||||||
|
// pub tags: Vec<CellTags>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CellWidget {
|
||||||
|
pub fn new(row: usize, col: usize) -> Self {
|
||||||
|
Self { row, col }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for CellWidget {
|
||||||
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
|
Paragraph::new(format!("{}/{}", self.row, self.col))
|
||||||
|
.alignment(Alignment::Center)
|
||||||
|
.block(Block::default().borders(Borders::ALL).white())
|
||||||
|
.render(area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
pub mod board;
|
||||||
|
pub mod cell;
|
||||||
pub mod keybindings;
|
pub mod keybindings;
|
||||||
|
|
||||||
|
pub use board::BoardWidget;
|
||||||
|
pub use cell::CellWidget;
|
||||||
pub use keybindings::KeybindingsWidget;
|
pub use keybindings::KeybindingsWidget;
|
||||||
|
|||||||
+2
-2
@@ -37,7 +37,7 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "Map width",
|
help = "Map width",
|
||||||
value_name = "Positive integer [20; 100]",
|
value_name = "Positive integer [20; 100]",
|
||||||
default_value = "50"
|
default_value = "27"
|
||||||
)]
|
)]
|
||||||
pub map_width: u8,
|
pub map_width: u8,
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ pub struct Cli {
|
|||||||
long,
|
long,
|
||||||
help = "Map height",
|
help = "Map height",
|
||||||
value_name = "Positive integer [11; 50]",
|
value_name = "Positive integer [11; 50]",
|
||||||
default_value = "21"
|
default_value = "11"
|
||||||
)]
|
)]
|
||||||
pub map_height: u8,
|
pub map_height: u8,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user