1use std::sync::Arc;
2
3use crate::builder::LayoutBuilder;
4use crate::error::PaneError;
5use crate::layout::Layout;
6use crate::panel::grow;
7use crate::preset::{
8 col_style, collect_kinds, row_style, validate_f32_param, validate_kinds, validate_share_param,
9};
10
11pub struct Dwindle {
13 kinds: Arc<[Arc<str>]>,
14 ratio: f32,
15 gap: f32,
16}
17
18impl Dwindle {
19 pub(crate) fn new(kinds: impl IntoIterator<Item = impl Into<Arc<str>>>) -> Self {
20 Self {
21 kinds: collect_kinds(kinds),
22 ratio: 0.5,
23 gap: 0.0,
24 }
25 }
26
27 crate::macros::builder_setters!(
28 ratio(ratio: f32);
30 gap(gap: f32)
32 );
33
34 pub fn build(&self) -> Result<Layout, PaneError> {
36 validate_kinds(&self.kinds)?;
37 validate_share_param("ratio", self.ratio)?;
38 validate_f32_param("gap", self.gap)?;
39
40 let mut b = LayoutBuilder::new();
41 let kinds = &self.kinds;
42 let ratio = self.ratio;
43 let gap_px = self.gap;
44
45 b.row_gap(gap_px, |r| {
46 build_recursive(r, kinds, 0, ratio, gap_px, false);
47 })?;
48
49 b.build()
50 }
51}
52
53pub(crate) fn build_recursive(
56 ctx: &mut crate::ContainerCtx,
57 kinds: &[Arc<str>],
58 depth: usize,
59 ratio: f32,
60 gap_px: f32,
61 reverse_even: bool,
62) {
63 match kinds.len() {
64 0 => {}
65 1 => {
66 ctx.panel(Arc::clone(&kinds[0]));
67 }
68 2 => add_pair(ctx, kinds, depth, ratio, reverse_even),
69 _ => add_nested(ctx, kinds, depth, ratio, gap_px, reverse_even),
70 }
71}
72
73fn add_pair(
74 ctx: &mut crate::ContainerCtx,
75 kinds: &[Arc<str>],
76 depth: usize,
77 ratio: f32,
78 reverse_even: bool,
79) {
80 let (first, second) = (Arc::clone(&kinds[0]), Arc::clone(&kinds[1]));
81 let should_reverse = reverse_even && depth >= 2 && depth.is_multiple_of(2);
82 match should_reverse {
83 true => {
84 ctx.panel_with(second, grow(1.0 - ratio));
85 ctx.panel_with(first, grow(ratio));
86 }
87 false => {
88 ctx.panel_with(first, grow(ratio));
89 ctx.panel_with(second, grow(1.0 - ratio));
90 }
91 }
92}
93
94fn add_nested(
95 ctx: &mut crate::ContainerCtx,
96 kinds: &[Arc<str>],
97 depth: usize,
98 ratio: f32,
99 gap_px: f32,
100 reverse_even: bool,
101) {
102 let first = Arc::clone(&kinds[0]);
103 let rest = &kinds[1..];
104 let should_reverse = reverse_even && depth >= 2 && depth.is_multiple_of(2);
105 let next_depth = depth + 1;
106
107 let nest_style = match next_depth.is_multiple_of(2) {
109 true => row_style(1.0 - ratio, gap_px),
110 false => col_style(1.0 - ratio, gap_px),
111 };
112
113 match should_reverse {
114 true => {
115 ctx.taffy_node(nest_style, |inner| {
116 build_recursive(inner, rest, next_depth, ratio, gap_px, reverse_even);
117 });
118 ctx.panel_with(first, grow(ratio));
119 }
120 false => {
121 ctx.panel_with(first, grow(ratio));
122 ctx.taffy_node(nest_style, |inner| {
123 build_recursive(inner, rest, next_depth, ratio, gap_px, reverse_even);
124 });
125 }
126 }
127}
128
129super::impl_preset!(
130 Dwindle,
131 runtime(kinds, |this| crate::strategy::StrategyKind::BinarySplit {
132 spiral: false,
133 ratio: this.ratio,
134 gap: this.gap,
135 })
136);