generated from GarandPLG/rust-flake-template
Track window area and refactor keybinding APIs
- Track terminal size in `App::window_area` and update on resize - Accept action slices in `count_largest_group` and `KeybindingsWidget::new` - Add ACTIONS slices and layout helpers for default, main_menu, skirmish - Add `main_menu_option_helper` for formatting menu strings and export it
This commit is contained in:
+12
-1
@@ -5,6 +5,7 @@ use crate::{
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
crossterm::event::{self, KeyEvent},
|
||||
layout::Rect,
|
||||
};
|
||||
use std::{
|
||||
io::Result,
|
||||
@@ -20,6 +21,7 @@ pub enum Event {
|
||||
pub struct App {
|
||||
pub exit: bool,
|
||||
pub view: View,
|
||||
pub window_area: Rect,
|
||||
pub states: GameStates,
|
||||
}
|
||||
|
||||
@@ -31,6 +33,7 @@ impl App {
|
||||
Self {
|
||||
exit: false,
|
||||
view: args.view,
|
||||
window_area: Rect::default(),
|
||||
states,
|
||||
}
|
||||
}
|
||||
@@ -56,7 +59,15 @@ impl App {
|
||||
}
|
||||
|
||||
fn draw(&mut self, frame: &mut Frame<'_>) {
|
||||
frame.render_widget(self, frame.area());
|
||||
let window_area: Rect = frame.area();
|
||||
|
||||
if window_area.width != self.window_area.width
|
||||
|| window_area.height != self.window_area.height
|
||||
{
|
||||
self.window_area = window_area;
|
||||
}
|
||||
|
||||
frame.render_widget(self, window_area);
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, key_event: KeyEvent) -> Result<()> {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
pub fn main_menu_option_helper(s: String) -> String {
|
||||
if let Some(pos) = s
|
||||
.char_indices()
|
||||
.filter(|(_, c)| c.is_ascii_uppercase())
|
||||
.nth(1)
|
||||
.map(|(i, _)| i)
|
||||
{
|
||||
let (first, second) = s.split_at(pos);
|
||||
format!("{first} {second}")
|
||||
} else {
|
||||
s
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod block_title;
|
||||
pub mod main_menu_option;
|
||||
pub mod zoom_level;
|
||||
|
||||
pub use block_title::{block_single_title_helper, block_title_helper};
|
||||
pub use main_menu_option::main_menu_option_helper;
|
||||
pub use zoom_level::{CellSizes, cell_size_helper};
|
||||
|
||||
@@ -284,7 +284,7 @@ pub fn event_to_action(event: &KeyEvent) -> Option<Action> {
|
||||
/// It counts how many times each group appears in the supplied actions and
|
||||
/// returns the highest count. This can be used, for example, to size UI
|
||||
/// elements that display groups of bindings.
|
||||
pub fn count_largest_group(actions: &Vec<Action>) -> u16 {
|
||||
pub fn count_largest_group(actions: &[Action]) -> u16 {
|
||||
let mut group_counts: HashMap<Group, u16> = HashMap::new();
|
||||
|
||||
for action in actions {
|
||||
|
||||
@@ -9,15 +9,18 @@ use ratatui::{
|
||||
widgets::{Block, Borders, Paragraph, Widget},
|
||||
};
|
||||
|
||||
pub fn default_view(area: Rect, buf: &mut Buffer) {
|
||||
let actions: Vec<Action> = vec![Action::Quit, Action::Quit2, Action::Esc];
|
||||
const ACTIONS: &[Action] = &[Action::Quit, Action::Quit2, Action::Esc];
|
||||
|
||||
let vertical_layout: Layout = Layout::vertical([
|
||||
fn default_view_layout(area: Rect) -> [Rect; 2] {
|
||||
Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(count_largest_group(&actions) + 2),
|
||||
]);
|
||||
Constraint::Length(count_largest_group(&ACTIONS) + 2),
|
||||
])
|
||||
.areas(area)
|
||||
}
|
||||
|
||||
let [main_area, keybindings_area] = vertical_layout.areas(area);
|
||||
pub fn default_view(area: Rect, buf: &mut Buffer) {
|
||||
let [main_area, keybindings_area] = default_view_layout(area);
|
||||
|
||||
{
|
||||
Paragraph::new("Work in progress")
|
||||
@@ -32,6 +35,6 @@ pub fn default_view(area: Rect, buf: &mut Buffer) {
|
||||
}
|
||||
|
||||
{
|
||||
KeybindingsWidget::new(actions).render(keybindings_area, buf);
|
||||
KeybindingsWidget::new(ACTIONS).render(keybindings_area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-28
@@ -1,5 +1,6 @@
|
||||
use crate::app::{
|
||||
App, View,
|
||||
helpers::main_menu_option_helper,
|
||||
keybindings::{Action, count_largest_group},
|
||||
widgets::KeybindingsWidget,
|
||||
};
|
||||
@@ -12,35 +13,24 @@ use ratatui::{
|
||||
widgets::{Block, Borders, Paragraph, Widget},
|
||||
};
|
||||
|
||||
fn format_view_string(s: String) -> String {
|
||||
if let Some(pos) = s
|
||||
.char_indices()
|
||||
.filter(|(_, c)| c.is_ascii_uppercase())
|
||||
.nth(1)
|
||||
.map(|(i, _)| i)
|
||||
{
|
||||
let (first, second) = s.split_at(pos);
|
||||
format!("{first} {second}")
|
||||
} else {
|
||||
s
|
||||
}
|
||||
const ACTIONS: &[Action] = &[
|
||||
Action::Up,
|
||||
Action::Down,
|
||||
Action::Space,
|
||||
Action::Quit,
|
||||
Action::Quit2,
|
||||
];
|
||||
|
||||
fn main_menu_layout(area: Rect) -> [Rect; 2] {
|
||||
Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(count_largest_group(&ACTIONS) + 2),
|
||||
])
|
||||
.areas(area)
|
||||
}
|
||||
|
||||
pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
let actions: Vec<Action> = 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);
|
||||
let [main_menu_area, keybindings_area] = main_menu_layout(area);
|
||||
|
||||
Block::new()
|
||||
.borders(Borders::LEFT | Borders::TOP | Borders::RIGHT)
|
||||
@@ -78,7 +68,7 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
.enumerate()
|
||||
.filter(|(_, v)| v != &&View::MainMenu)
|
||||
.map(|(i, view)| {
|
||||
let view_string: String = format_view_string(format!("{:?}", view));
|
||||
let view_string: String = main_menu_option_helper(format!("{:?}", view));
|
||||
|
||||
let styled: Line<'_> = if app.states.main_menu.selected_view == i {
|
||||
Line::from_iter(["> ".cyan(), view_string.yellow()]).yellow()
|
||||
@@ -98,6 +88,6 @@ pub fn main_menu_view(app: &App, area: Rect, buf: &mut Buffer) {
|
||||
}
|
||||
|
||||
{
|
||||
KeybindingsWidget::new(actions).render(keybindings_area, buf);
|
||||
KeybindingsWidget::new(ACTIONS).render(keybindings_area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
+24
-21
@@ -12,30 +12,33 @@ use ratatui::{
|
||||
widgets::{Block, Borders, Padding, Paragraph, Widget},
|
||||
};
|
||||
|
||||
pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) {
|
||||
let actions: Vec<Action> = vec![
|
||||
Action::Up,
|
||||
Action::Down,
|
||||
Action::Left,
|
||||
Action::Right,
|
||||
Action::ScrollUp,
|
||||
Action::ScrollDown,
|
||||
Action::ScrollLeft,
|
||||
Action::ScrollRight,
|
||||
Action::ZoomIn,
|
||||
Action::ZoomOut,
|
||||
Action::Quit,
|
||||
Action::Quit2,
|
||||
Action::Esc,
|
||||
];
|
||||
const ACTIONS: &[Action] = &[
|
||||
Action::Up,
|
||||
Action::Down,
|
||||
Action::Left,
|
||||
Action::Right,
|
||||
Action::ScrollUp,
|
||||
Action::ScrollDown,
|
||||
Action::ScrollLeft,
|
||||
Action::ScrollRight,
|
||||
Action::ZoomIn,
|
||||
Action::ZoomOut,
|
||||
Action::Quit,
|
||||
Action::Quit2,
|
||||
Action::Esc,
|
||||
];
|
||||
|
||||
let vertical_layout: Layout = Layout::vertical([
|
||||
fn skirmish_layout(area: Rect) -> [Rect; 3] {
|
||||
Layout::vertical([
|
||||
Constraint::Length(4),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(count_largest_group(&actions) + 2),
|
||||
]);
|
||||
Constraint::Length(count_largest_group(&ACTIONS) + 2),
|
||||
])
|
||||
.areas(area)
|
||||
}
|
||||
|
||||
let [title_area, main_area, keybindings_area] = vertical_layout.areas(area);
|
||||
pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) {
|
||||
let [title_area, main_area, keybindings_area] = skirmish_layout(area);
|
||||
|
||||
{
|
||||
let lines: Vec<Line<'_>> = Vec::from_iter([
|
||||
@@ -92,6 +95,6 @@ pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) {
|
||||
}
|
||||
|
||||
{
|
||||
KeybindingsWidget::new(actions).render(keybindings_area, buf);
|
||||
KeybindingsWidget::new(ACTIONS).render(keybindings_area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ impl KeybindingsWidget {
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `actions` – A vector of actions for which keybindings should be shown.
|
||||
/// * `actions` – A slice of actions for which keybindings should be shown.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A fully‑initialised `KeybindingsWidget` ready for rendering.
|
||||
pub fn new(actions: Vec<Action>) -> Self {
|
||||
pub fn new(actions: &[Action]) -> Self {
|
||||
let keybindings: Vec<Option<&'static KeyBinding>> =
|
||||
actions.iter().map(|a| binding_for(*a)).collect();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user