tui-journal 0.17.0

Tui app allows writing and managing journals/notes from within the terminal With different local back-ends
Documentation
use ratatui::{
    Frame,
    layout::{Alignment, Constraint, Direction, Layout, Rect},
    widgets::{Block, BorderType, Borders, Clear, Paragraph},
};

pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints(
            [
                Constraint::Percentage((100 - percent_y) / 2),
                Constraint::Percentage(percent_y),
                Constraint::Percentage((100 - percent_y) / 2),
            ]
            .as_ref(),
        )
        .split(r);

    Layout::default()
        .direction(Direction::Horizontal)
        .constraints(
            [
                Constraint::Percentage((100 - percent_x) / 2),
                Constraint::Percentage(percent_x),
                Constraint::Percentage((100 - percent_x) / 2),
            ]
            .as_ref(),
        )
        .split(popup_layout[1])[1]
}

pub fn centered_rect_exact_height(percent_x: u16, height: u16, r: Rect) -> Rect {
    let height_percentage = ((height as f32 / r.height as f32) * 100f32) as u16;
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints(
            [
                Constraint::Percentage((100 - height_percentage) / 2),
                Constraint::Length(height),
                Constraint::Percentage((100 - height_percentage) / 2),
            ]
            .as_ref(),
        )
        .split(r);

    Layout::default()
        .direction(Direction::Horizontal)
        .constraints(
            [
                Constraint::Percentage((100 - percent_x) / 2),
                Constraint::Percentage(percent_x),
                Constraint::Percentage((100 - percent_x) / 2),
            ]
            .as_ref(),
        )
        .split(popup_layout[1])[1]
}

pub fn centered_rect_exact_dimensions(width: u16, height: u16, r: Rect) -> Rect {
    let height_percentage = ((height as f32 / r.height as f32) * 100f32) as u16;
    let width_percentage = ((width as f32 / r.width as f32) * 100f32) as u16;
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints(
            [
                Constraint::Percentage((100 - height_percentage) / 2),
                Constraint::Length(height),
                Constraint::Percentage((100 - height_percentage) / 2),
            ]
            .as_ref(),
        )
        .split(r);

    Layout::default()
        .direction(Direction::Horizontal)
        .constraints(
            [
                Constraint::Percentage((100 - width_percentage) / 2),
                Constraint::Length(width),
                Constraint::Percentage((100 - width_percentage) / 2),
            ]
            .as_ref(),
        )
        .split(popup_layout[1])[1]
}

pub fn render_message_centered(frame: &mut Frame, message: &str) {
    const TEXT_MARGIN: u16 = 4;
    const HEIGHT_MARGIN: u16 = 2;

    let width = message.len() as u16 + TEXT_MARGIN;
    let height = message.lines().count() as u16 + HEIGHT_MARGIN;

    let area = centered_rect_exact_dimensions(width, height, frame.area());

    let paragraph = Paragraph::new(message)
        .block(
            Block::default()
                .borders(Borders::ALL)
                .border_type(BorderType::Rounded),
        )
        .alignment(Alignment::Center);

    frame.render_widget(Clear, area);
    frame.render_widget(paragraph, area);
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_rect_percentage() {
        let rect = Rect::new(10, 10, 20, 16);
        assert_eq!(centered_rect(100, 100, rect), rect);
        assert_eq!(centered_rect(50, 50, rect), Rect::new(15, 14, 10, 8));
    }

    #[test]
    fn test_rect_exact_height() {
        let rect = Rect::new(10, 10, 20, 16);
        assert_eq!(centered_rect_exact_height(100, 16, rect), rect);
        assert_eq!(
            centered_rect_exact_height(50, 8, rect),
            Rect::new(15, 14, 10, 8)
        );
    }

    #[test]
    fn test_rect_exact_dimensions() {
        let rect = Rect::new(10, 10, 20, 16);
        assert_eq!(centered_rect_exact_dimensions(20, 16, rect), rect);
        assert_eq!(
            centered_rect_exact_dimensions(10, 8, rect),
            Rect::new(15, 14, 10, 8)
        );
    }
}