Skip to main content

panes/preset/
master_stack.rs

1use std::sync::Arc;
2
3use crate::builder::LayoutBuilder;
4use crate::error::PaneError;
5use crate::layout::Layout;
6use crate::panel::grow;
7use crate::preset::{collect_kinds, validate_f32_param, validate_kinds};
8
9/// Builder for the master-stack preset layout.
10pub struct MasterStack {
11    kinds: Arc<[Arc<str>]>,
12    master_ratio: f32,
13    gap: f32,
14}
15
16impl MasterStack {
17    pub(crate) fn new(kinds: impl IntoIterator<Item = impl Into<Arc<str>>>) -> Self {
18        Self {
19            kinds: collect_kinds(kinds),
20            master_ratio: 0.5,
21            gap: 0.0,
22        }
23    }
24
25    /// Set the master panel's share of the viewport.
26    pub fn master_ratio(mut self, ratio: f32) -> Self {
27        self.master_ratio = ratio;
28        self
29    }
30
31    /// Set the gap between panels.
32    pub fn gap(mut self, gap: f32) -> Self {
33        self.gap = gap;
34        self
35    }
36
37    /// Consume the builder and produce a [`Layout`].
38    pub fn build(&self) -> Result<Layout, PaneError> {
39        validate_kinds(&self.kinds)?;
40        validate_f32_param("master_ratio", self.master_ratio)?;
41        match self.kinds.len() {
42            1 => super::build_single(Arc::clone(&self.kinds[0])),
43            _ => self.build_master_stack(),
44        }
45    }
46
47    fn build_master_stack(&self) -> Result<Layout, PaneError> {
48        let mut b = LayoutBuilder::new();
49        let ratio = self.master_ratio;
50        let master_kind = Arc::clone(&self.kinds[0]);
51        let stack_style = col_style(1.0 - ratio, self.gap);
52
53        b.row_gap(self.gap, |r| {
54            r.panel_with(master_kind, grow(ratio));
55            r.taffy_node(stack_style, |c| add_panels(c, &self.kinds[1..], grow(1.0)));
56        })?;
57
58        b.build()
59    }
60}
61
62/// A column-direction taffy style with a specific grow factor and gap.
63pub(crate) fn col_style(flex_grow: f32, gap_px: f32) -> taffy::Style {
64    taffy::Style {
65        flex_direction: taffy::FlexDirection::Column,
66        flex_grow,
67        flex_basis: taffy::Dimension::length(0.0),
68        flex_shrink: 1.0,
69        gap: taffy::Size {
70            width: taffy::LengthPercentage::length(0.0),
71            height: taffy::LengthPercentage::length(gap_px),
72        },
73        ..Default::default()
74    }
75}
76
77/// A row-direction taffy style with a specific grow factor and gap.
78pub(crate) fn row_style(flex_grow: f32, gap_px: f32) -> taffy::Style {
79    taffy::Style {
80        flex_direction: taffy::FlexDirection::Row,
81        flex_grow,
82        flex_basis: taffy::Dimension::length(0.0),
83        flex_shrink: 1.0,
84        gap: taffy::Size {
85            width: taffy::LengthPercentage::length(gap_px),
86            height: taffy::LengthPercentage::length(0.0),
87        },
88        ..Default::default()
89    }
90}
91
92pub(crate) fn add_panels(
93    ctx: &mut crate::ContainerCtx,
94    kinds: &[Arc<str>],
95    constraints: crate::Constraints,
96) {
97    for kind in kinds {
98        ctx.panel_with(Arc::clone(kind), constraints);
99    }
100}
101
102impl MasterStack {
103    /// Consume the builder and produce a [`crate::runtime::LayoutRuntime`].
104    pub fn into_runtime(self) -> Result<crate::runtime::LayoutRuntime, PaneError> {
105        let strategy = crate::strategy::StrategyKind::MasterStack {
106            master_ratio: self.master_ratio,
107            gap: self.gap,
108        };
109        crate::runtime::LayoutRuntime::from_strategy(strategy, &self.kinds)
110    }
111}
112
113super::impl_preset!(MasterStack);