1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//!
//! Simple layout for dialogs.
//!
//! Calculates the content-area and the placement of buttons.
//!
use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::widgets::Block;

/// Layout produced by [layout_dialog].
#[derive(Debug)]
pub struct LayoutDialog<const N: usize> {
    /// Complete area covered by the dialog box.
    pub area: Rect,
    /// Area inside the border.
    pub inner: Rect,
    /// Area for dialog content, sans borders and buttons.
    pub content: Rect,
    /// Complete button area.
    pub button_area: Rect,
    /// Areas for each button.
    pub buttons: [Rect; N],
}

impl<const N: usize> LayoutDialog<N> {
    /// Area for the buttons.
    pub fn button(&self, n: usize) -> Rect {
        self.buttons[n]
    }
}

/// Calculates a layout for a dialog with buttons.
pub fn layout_dialog<const N: usize>(
    area: Rect,
    block: Option<&Block<'_>>,
    buttons: [Constraint; N],
    button_spacing: u16,
    button_flex: Flex,
) -> LayoutDialog<N> {
    let inner = if let Some(block) = block {
        block.inner(area)
    } else {
        area
    };
    let l_content = Layout::vertical([
        Constraint::Fill(1),
        Constraint::Length(1),
        Constraint::Length(1),
    ])
    .split(inner);

    let l_buttons = Layout::horizontal(buttons)
        .spacing(button_spacing)
        .flex(button_flex)
        .areas(l_content[2]);

    LayoutDialog {
        area,
        inner,
        content: l_content[0],
        button_area: l_content[2],
        buttons: l_buttons,
    }
}