rsnaker/graphics/menus/
layout_utils.rs

1use ratatui::layout::{Constraint, Direction, Layout, Rect};
2use ratatui::prelude::{Color, Style};
3use ratatui::widgets::{Block, Paragraph};
4use ratatui::Frame;
5
6/// Creates a vertically centered rectangle within the given area with the specified number of lines.
7#[must_use]
8pub fn frame_vertically_centered_rect(area: Rect, lines: usize) -> Rect {
9    // Auto center vertically, elsewhere could be manually calculated with y offset
10    // by taking height from frame.area
11    Layout::default()
12        .direction(Direction::Vertical)
13        .constraints([
14            Constraint::Fill(1),                                          // top space
15            Constraint::Length(u16::try_from(lines).unwrap_or(u16::MAX)), // content
16            Constraint::Fill(1),                                          // bottom space
17        ])
18        // take second rect to render content
19        .split(area)[1]
20    // if we want to do manual center horizontally also
21    /*Layout::default()
22    .direction(Direction::Horizontal)
23    .constraints([
24        Constraint::Fill(1),                                            // top space
25        Constraint::Length(lines.lines().last().unwrap().len() as u16), // content
26        Constraint::Fill(1),                                            // bottom space
27    ])
28    // take second rect to render content
29    .split(vertical_layout)[1]*/
30}
31/// Render a horizontally and vertically centered paragraph with text and color style
32/// With the game external border set to the same color as the text
33pub fn render_full_centered_paragraph(frame: &mut Frame, text: &'static str, color: Option<Color>) {
34    let area = frame_vertically_centered_rect(frame.area(), text.lines().count());
35    // ensure that all cells under the popup are cleared to avoid leaking content: no useful, and ugly
36    //frame.render_widget(Clear, area);
37    frame.render_widget(
38        Paragraph::new(text)
39            //.style(Style::default().fg(color))
40            .alignment(ratatui::layout::Alignment::Center),
41        area,
42    );
43    // Set all screen items in the same color as the menu.
44    // Applying style break position of emojis
45    // even by previously setting a full style to item to avoid them to inherit the overall one
46    // so keep global style to the final situations without the snake moving after
47    if let Some(color) = color {
48        frame.render_widget(
49            Block::default().style(Style::default().fg(color)),
50            frame.area(),
51        );
52    }
53}