1use crate::Element;
20
21use crate::layout::{Limits, Node};
22use crate::widget;
23use crate::{Alignment, Length, Padding, Point, Size};
24
25#[derive(Debug)]
27pub enum Axis {
28 Horizontal,
30
31 Vertical,
33}
34
35impl Axis {
36 fn main(&self, size: Size) -> f32 {
37 match self {
38 Axis::Horizontal => size.width,
39 Axis::Vertical => size.height,
40 }
41 }
42
43 fn cross(&self, size: Size) -> f32 {
44 match self {
45 Axis::Horizontal => size.height,
46 Axis::Vertical => size.width,
47 }
48 }
49
50 fn pack<T>(&self, main: T, cross: T) -> (T, T) {
51 match self {
52 Axis::Horizontal => (main, cross),
53 Axis::Vertical => (cross, main),
54 }
55 }
56}
57
58pub fn resolve<Message, Theme, Renderer>(
63 axis: Axis,
64 renderer: &Renderer,
65 limits: &Limits,
66 width: Length,
67 height: Length,
68 padding: Padding,
69 spacing: f32,
70 align_items: Alignment,
71 items: &[Element<'_, Message, Theme, Renderer>],
72 trees: &mut [widget::Tree],
73) -> Node
74where
75 Renderer: crate::Renderer,
76{
77 let limits = limits.width(width).height(height).shrink(padding);
78 let total_spacing = spacing * items.len().saturating_sub(1) as f32;
79 let max_cross = axis.cross(limits.max());
80
81 let mut fill_main_sum = 0;
82 let (mut cross, cross_compress) = match axis {
83 Axis::Vertical if width == Length::Shrink => (0.0, true),
84 Axis::Horizontal if height == Length::Shrink => (0.0, true),
85 _ => (max_cross, false),
86 };
87
88 let mut available = axis.main(limits.max()) - total_spacing;
89
90 let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
91 nodes.resize(items.len(), Node::default());
92
93 for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {
94 let (fill_main_factor, fill_cross_factor) = {
95 let size = child.as_widget().size();
96
97 axis.pack(size.width.fill_factor(), size.height.fill_factor())
98 };
99
100 if fill_main_factor == 0 && (!cross_compress || fill_cross_factor == 0)
101 {
102 let (max_width, max_height) = axis.pack(
103 available,
104 if fill_cross_factor == 0 {
105 max_cross
106 } else {
107 cross
108 },
109 );
110
111 let child_limits =
112 Limits::new(Size::ZERO, Size::new(max_width, max_height));
113
114 let layout =
115 child.as_widget().layout(tree, renderer, &child_limits);
116 let size = layout.size();
117
118 available -= axis.main(size);
119 cross = cross.max(axis.cross(size));
120
121 nodes[i] = layout;
122 } else {
123 fill_main_sum += fill_main_factor;
124 }
125 }
126
127 let remaining = match axis {
128 Axis::Horizontal => match width {
129 Length::Shrink => 0.0,
130 _ => available.max(0.0),
131 },
132 Axis::Vertical => match height {
133 Length::Shrink => 0.0,
134 _ => available.max(0.0),
135 },
136 };
137
138 for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
139 let (fill_main_factor, fill_cross_factor) = {
140 let size = child.as_widget().size();
141
142 axis.pack(size.width.fill_factor(), size.height.fill_factor())
143 };
144
145 if fill_main_factor != 0 || (cross_compress && fill_cross_factor != 0) {
146 let max_main =
147 remaining * fill_main_factor as f32 / fill_main_sum as f32;
148
149 let min_main = if max_main.is_infinite() {
150 0.0
151 } else {
152 max_main
153 };
154
155 let (min_width, min_height) = axis.pack(min_main, 0.0);
156 let (max_width, max_height) = axis.pack(
157 max_main,
158 if fill_cross_factor == 0 {
159 max_cross
160 } else {
161 cross
162 },
163 );
164
165 let child_limits = Limits::new(
166 Size::new(min_width, min_height),
167 Size::new(max_width, max_height),
168 );
169
170 let layout =
171 child.as_widget().layout(tree, renderer, &child_limits);
172 cross = cross.max(axis.cross(layout.size()));
173
174 nodes[i] = layout;
175 }
176 }
177
178 let pad = axis.pack(padding.left, padding.top);
179 let mut main = pad.0;
180
181 for (i, node) in nodes.iter_mut().enumerate() {
182 if i > 0 {
183 main += spacing;
184 }
185
186 let (x, y) = axis.pack(main, pad.1);
187
188 node.move_to_mut(Point::new(x, y));
189
190 match axis {
191 Axis::Horizontal => {
192 node.align_mut(
193 Alignment::Start,
194 align_items,
195 Size::new(0.0, cross),
196 );
197 }
198 Axis::Vertical => {
199 node.align_mut(
200 align_items,
201 Alignment::Start,
202 Size::new(cross, 0.0),
203 );
204 }
205 }
206
207 let size = node.size();
208
209 main += axis.main(size);
210 }
211
212 let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);
213 let size = limits.resolve(
214 width,
215 height,
216 Size::new(intrinsic_width, intrinsic_height),
217 );
218
219 Node::with_children(size.expand(padding), nodes)
220}