ratatui_toolkit/primitives/split_layout/methods/layout_panes.rs
1use ratatui::layout::Rect;
2
3use crate::primitives::split_layout::enums::layout_node::LayoutNode;
4use crate::primitives::split_layout::pane_layout::PaneLayout;
5use crate::primitives::split_layout::SplitAxis;
6use crate::primitives::split_layout::SplitLayout;
7
8impl SplitLayout {
9 /// Calculates pane rectangles for the current split tree.
10 ///
11 /// # Arguments
12 /// - `area`: The available rectangle to divide among panes.
13 ///
14 /// # Returns
15 /// A vector of `PaneLayout` values for each leaf pane.
16 ///
17 /// # Errors
18 /// - None.
19 ///
20 /// # Panics
21 /// - Does not panic.
22 ///
23 /// # Safety
24 /// - No safety requirements.
25 ///
26 /// # Performance
27 /// - O(n) where n is the number of nodes.
28 ///
29 /// # Example
30 /// ```rust
31 /// use ratatui::layout::Rect;
32 /// use ratatui_toolkit::primitives::split_layout::SplitLayout;
33 ///
34 /// let layout = SplitLayout::new(0);
35 /// let panes = layout.layout_panes(Rect::new(0, 0, 120, 40));
36 /// ```
37 pub fn layout_panes(&self, area: Rect) -> Vec<PaneLayout> {
38 let mut layouts = Vec::new();
39 let mut stack = vec![(self.root_index, area)];
40
41 while let Some((node_index, node_area)) = stack.pop() {
42 let Some(node) = self.nodes.get(node_index) else {
43 continue;
44 };
45
46 match node {
47 LayoutNode::Pane { id } => {
48 layouts.push(PaneLayout::new(*id, node_area));
49 }
50 LayoutNode::Split {
51 axis,
52 ratio,
53 first,
54 second,
55 } => match axis {
56 SplitAxis::Vertical => {
57 let first_width = ((node_area.width as u32 * *ratio as u32) / 100) as u16;
58 let second_width = node_area.width.saturating_sub(first_width);
59 let first_area = Rect {
60 x: node_area.x,
61 y: node_area.y,
62 width: first_width,
63 height: node_area.height,
64 };
65 let second_area = Rect {
66 x: node_area.x.saturating_add(first_width),
67 y: node_area.y,
68 width: second_width,
69 height: node_area.height,
70 };
71 stack.push((*second, second_area));
72 stack.push((*first, first_area));
73 }
74 SplitAxis::Horizontal => {
75 let first_height = ((node_area.height as u32 * *ratio as u32) / 100) as u16;
76 let second_height = node_area.height.saturating_sub(first_height);
77 let first_area = Rect {
78 x: node_area.x,
79 y: node_area.y,
80 width: node_area.width,
81 height: first_height,
82 };
83 let second_area = Rect {
84 x: node_area.x,
85 y: node_area.y.saturating_add(first_height),
86 width: node_area.width,
87 height: second_height,
88 };
89 stack.push((*second, second_area));
90 stack.push((*first, first_area));
91 }
92 },
93 }
94 }
95
96 layouts
97 }
98}