tui_framework_experiment/
stack_container.rs

1use ratatui::layout::Flex;
2use ratatui::prelude::*;
3use ratatui::widgets::WidgetRef;
4use std::fmt;
5
6/// A container that stacks widgets in a given direction
7///
8/// # Examples
9///
10/// ```rust
11/// use ratatui::prelude::*;
12/// use ratatui::widgets::*;
13/// use tui_framework_experiment::StackContainer;
14///
15/// let mut stack = StackContainer::horizontal();
16/// stack.push(Box::new(Paragraph::new("Left")), Constraint::Fill(1));
17/// stack.push(Box::new(Paragraph::new("Center")), Constraint::Fill(2));
18/// stack.push(Box::new(Paragraph::new("Right")), Constraint::Fill(1));
19///
20/// // or
21///
22/// let stack = StackContainer::horizontal().with_widgets(vec![
23///     (Box::new(Paragraph::new("Left")), Constraint::Fill(1)),
24///     (Box::new(Paragraph::new("Center")), Constraint::Fill(2)),
25///     (Box::new(Paragraph::new("Right")), Constraint::Fill(1)),
26/// ]);
27/// ```
28#[derive(Default)]
29pub struct StackContainer {
30    direction: Direction,
31    flex: Flex,
32    margin: u16,
33    spacing: u16,
34    widgets: Vec<(Box<dyn WidgetRef>, Constraint)>,
35}
36
37impl fmt::Debug for StackContainer {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.debug_struct("StackContainer")
40            .field("direction", &self.direction)
41            .finish_non_exhaustive()
42    }
43}
44
45impl StackContainer {
46    pub fn new(direction: Direction) -> Self {
47        Self {
48            direction,
49            ..Default::default()
50        }
51    }
52
53    pub fn horizontal() -> Self {
54        Self::new(Direction::Horizontal)
55    }
56
57    pub fn vertical() -> Self {
58        Self::new(Direction::Vertical)
59    }
60
61    pub fn with_margin(mut self, margin: u16) -> Self {
62        self.margin = margin;
63        self
64    }
65
66    pub fn with_spacing(mut self, spacing: u16) -> Self {
67        self.spacing = spacing;
68        self
69    }
70
71    pub fn with_flex(mut self, flex: Flex) -> Self {
72        self.flex = flex;
73        self
74    }
75
76    pub fn with_widget(mut self, widget: Box<dyn WidgetRef>, constraint: Constraint) -> Self {
77        self.widgets.push((widget, constraint));
78        self
79    }
80
81    pub fn with_widgets(mut self, widgets: Vec<(Box<dyn WidgetRef>, Constraint)>) -> Self {
82        self.widgets = widgets;
83        self
84    }
85
86    pub fn push(&mut self, widget: Box<dyn WidgetRef>, constraint: Constraint) {
87        self.widgets.push((widget, constraint));
88    }
89
90    pub fn remove(&mut self, index: usize) {
91        self.widgets.remove(index);
92    }
93}
94
95impl Widget for &StackContainer {
96    fn render(self, area: Rect, buf: &mut Buffer) {
97        let layout = Layout::default()
98            .direction(self.direction)
99            .flex(self.flex)
100            .margin(self.margin)
101            .spacing(self.spacing)
102            .constraints(self.widgets.iter().map(|(_, c)| *c));
103        let areas = layout.split(area);
104        let widgets = self.widgets.iter().map(|(w, _)| w);
105        for (widget, area) in widgets.zip(areas.iter()) {
106            widget.render_ref(*area, buf);
107        }
108    }
109}