From 9719e1ba6b4b7be3ba164877a22b7a78a1fe2305 Mon Sep 17 00:00:00 2001 From: GarandPLG Date: Sun, 29 Mar 2026 15:12:40 +0200 Subject: [PATCH] Add block title helpers and use them in UI --- src/app/helpers/block_title.rs | 99 ++++++++++++++++++++++++++++++++++ src/app/helpers/mod.rs | 3 ++ src/app/mod.rs | 1 + src/app/views/skirmish.rs | 14 +++-- src/app/widgets/keybindings.rs | 13 +++-- 5 files changed, 115 insertions(+), 15 deletions(-) create mode 100644 src/app/helpers/block_title.rs create mode 100644 src/app/helpers/mod.rs diff --git a/src/app/helpers/block_title.rs b/src/app/helpers/block_title.rs new file mode 100644 index 0000000..5bf484f --- /dev/null +++ b/src/app/helpers/block_title.rs @@ -0,0 +1,99 @@ +use ratatui::{ + style::{Color, Style, Stylize}, + text::{Line, Span}, +}; + +/// Creates a styled title `Line` for a UI block. +/// +/// This helper builds a `Line` that looks like: +/// ```text +/// [ ... ] +/// ``` +/// where each title fragment is rendered in the color supplied by the caller, +/// and the surrounding brackets and any separator are rendered in gray. +/// +/// # Arguments +/// +/// * `texts` – A slice of tuples. Each tuple contains a title fragment (`&str`) +/// and a `Color` that should be applied to that fragment. The order of the +/// tuples determines the order of the fragments in the final line. +/// +/// * `separator` – An optional string that will be inserted (in gray) between +/// successive title fragments. If `None` the fragments are concatenated +/// directly without any separator. +/// +/// # Returns +/// +/// A `Line<'a>` that starts with a gray “\[ ”, contains the colored title +/// fragments separated (if requested) by a gray separator, and ends with a +/// gray “ \]”. The line can be passed directly to widgets such as `Block::title`. +/// +/// # Example +/// +/// ```rust +/// use ratatui::style::Color; +/// +/// let title: Line<'_> = block_title_helper( +/// &[ +/// ("Skirmish", Color::Magenta), +/// ("Map", Color::Green), +/// ], +/// Some(" - ") +/// ); +/// // `title` now represents: [ Skirmish - Map ] with the appropriate colors. +/// ``` +pub fn block_title_helper<'a>(texts: &[(&'a str, Color)], separator: Option<&'a str>) -> Line<'a> { + let mut line: Line<'a> = Line::default(); + + line.spans.push(Span::from("[ ").gray()); + + for (i, (text, color)) in texts.iter().enumerate() { + let span: Span<'a> = Span::styled(*text, Style::new().fg(*color)); + + line.spans.push(span); + + if let Some(sep) = separator { + if i + 1 < texts.len() { + line.spans.push(Span::from(sep).gray()); + } + } + } + + line.spans.push(Span::from(" ]").gray()); + + line +} + +/// Convenience wrapper for `block_title_helper` that creates a title line for a +/// single piece of text. +/// +/// This function builds a `Line` that looks like: +/// ```text +/// [ ] +/// ``` +/// where `` is rendered with the supplied color, and the surrounding +/// brackets are rendered in gray. It simply forwards the arguments to +/// `block_title_helper` with `separator` set to `None`. +/// +/// # Arguments +/// +/// * `text` – The title string to display. +/// +/// * `color` – The `Color` that should be applied to the title text. +/// +/// # Returns +/// +/// A `Line<'a>` containing the grey brackets and the coloured title text, +/// ready to be passed to widgets such as `Block::title`. +/// +/// # Example +/// +/// ```rust +/// use ratatui::style::Color; +/// +/// let title: Line<'_> = block_single_title_helper("Keybindings", Color::Magenta); +/// // `title` now represents: [ Keybindings ] with “Keybindings” coloured magenta. +/// ``` +pub fn block_single_title_helper<'a>(text: &'a str, color: Color) -> Line<'a> { + block_title_helper(&[(text, color)], None) +} diff --git a/src/app/helpers/mod.rs b/src/app/helpers/mod.rs new file mode 100644 index 0000000..5ccb37f --- /dev/null +++ b/src/app/helpers/mod.rs @@ -0,0 +1,3 @@ +pub mod block_title; + +pub use block_title::{block_single_title_helper, block_title_helper}; diff --git a/src/app/mod.rs b/src/app/mod.rs index 1f32052..a6924d3 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,4 +1,5 @@ pub mod app; +pub mod helpers; pub mod keybind; pub mod keybindings; pub mod state; diff --git a/src/app/views/skirmish.rs b/src/app/views/skirmish.rs index fe4543a..f3cfdc9 100644 --- a/src/app/views/skirmish.rs +++ b/src/app/views/skirmish.rs @@ -1,12 +1,13 @@ use crate::app::{ App, + helpers::block_title_helper, keybindings::{Action, count_largest_group}, widgets::{BoardWidget, KeybindingsWidget}, }; use ratatui::{ buffer::Buffer, layout::{Alignment, Constraint, Layout, Margin, Rect}, - style::Stylize, + style::{Color, Stylize}, text::Line, widgets::{Block, Borders, Padding, Paragraph, Widget}, }; @@ -69,13 +70,10 @@ pub fn skirmish_view(app: &mut App, area: Rect, buf: &mut Buffer) { { let board_block: Block = Block::new() .gray() - .title(Line::from_iter([ - "[ ".gray(), - "Skirmish".magenta(), - " - ".gray(), - "Map".green(), - " ]".gray(), - ])) + .title(block_title_helper( + &[("Skirmish", Color::Magenta), ("Map", Color::Green)], + Some(" - "), + )) .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT); let board_area: Rect = board_block.inner(main_area); diff --git a/src/app/widgets/keybindings.rs b/src/app/widgets/keybindings.rs index 4ced29d..ddc9814 100644 --- a/src/app/widgets/keybindings.rs +++ b/src/app/widgets/keybindings.rs @@ -1,9 +1,12 @@ -use crate::app::keybindings::{Action, Group, KeyBinding, binding_for}; +use crate::app::{ + helpers::block_single_title_helper, + keybindings::{Action, Group, KeyBinding, binding_for}, +}; use clap::ValueEnum; use ratatui::{ buffer::Buffer, layout::{Alignment, Constraint, Layout, Rect}, - style::Stylize, + style::{Color, Stylize}, text::Line, widgets::{Block, Borders, Padding, Paragraph, Widget}, }; @@ -72,11 +75,7 @@ impl Widget for KeybindingsWidget { let block: Block<'_> = Block::default() .borders(Borders::ALL) - .title(Line::from_iter([ - "[ ".gray(), - "Keybindings".magenta(), - " ]".gray(), - ])); + .title(block_single_title_helper("Keybindings", Color::Magenta)); let inner: Rect = block.inner(area);