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 some_fill_cross = false;
83 let (mut cross, cross_compress) = match axis {
84 Axis::Vertical if width == Length::Shrink => (0.0, true),
85 Axis::Horizontal if height == Length::Shrink => (0.0, true),
86 _ => (max_cross, false),
87 };
88
89 let mut available = axis.main(limits.max()) - total_spacing;
90
91 let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
92 nodes.resize(items.len(), Node::default());
93
94 for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {
99 let (fill_main_factor, fill_cross_factor) = {
100 let size = child.as_widget().size();
101
102 axis.pack(size.width.fill_factor(), size.height.fill_factor())
103 };
104
105 if fill_main_factor == 0 && (!cross_compress || fill_cross_factor == 0)
106 {
107 let (max_width, max_height) = axis.pack(
108 available,
109 if fill_cross_factor == 0 {
110 max_cross
111 } else {
112 cross
113 },
114 );
115
116 let child_limits =
117 Limits::new(Size::ZERO, Size::new(max_width, max_height));
118
119 let layout =
120 child.as_widget().layout(tree, renderer, &child_limits);
121 let size = layout.size();
122
123 available -= axis.main(size);
124 cross = cross.max(axis.cross(size));
125
126 nodes[i] = layout;
127 } else {
128 fill_main_sum += fill_main_factor;
129 some_fill_cross = some_fill_cross || fill_cross_factor != 0;
130 }
131 }
132
133 if cross_compress && some_fill_cross {
144 for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate()
145 {
146 let (main_size, cross_size) = {
147 let size = child.as_widget().size();
148
149 axis.pack(size.width, size.height)
150 };
151
152 if main_size.fill_factor() == 0 && cross_size.fill_factor() != 0 {
153 if let Length::Fixed(main) = main_size {
154 available -= main;
155 continue;
156 }
157
158 let (max_width, max_height) = axis.pack(available, cross);
159
160 let child_limits =
161 Limits::new(Size::ZERO, Size::new(max_width, max_height));
162
163 let layout =
164 child.as_widget().layout(tree, renderer, &child_limits);
165 let size = layout.size();
166
167 available -= axis.main(size);
168 cross = cross.max(axis.cross(size));
169
170 nodes[i] = layout;
171 }
172 }
173 }
174
175 let remaining = match axis {
176 Axis::Horizontal => match width {
177 Length::Shrink => 0.0,
178 _ => available.max(0.0),
179 },
180 Axis::Vertical => match height {
181 Length::Shrink => 0.0,
182 _ => available.max(0.0),
183 },
184 };
185
186 for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {
190 let (fill_main_factor, fill_cross_factor) = {
191 let size = child.as_widget().size();
192
193 axis.pack(size.width.fill_factor(), size.height.fill_factor())
194 };
195
196 if fill_main_factor != 0 {
197 let max_main =
198 remaining * fill_main_factor as f32 / fill_main_sum as f32;
199
200 let max_main = if max_main.is_nan() {
201 f32::INFINITY
202 } else {
203 max_main
204 };
205
206 let min_main = if max_main.is_infinite() {
207 0.0
208 } else {
209 max_main
210 };
211
212 let (min_width, min_height) = axis.pack(min_main, 0.0);
213 let (max_width, max_height) = axis.pack(
214 max_main,
215 if fill_cross_factor == 0 {
216 max_cross
217 } else {
218 cross
219 },
220 );
221
222 let child_limits = Limits::new(
223 Size::new(min_width, min_height),
224 Size::new(max_width, max_height),
225 );
226
227 let layout =
228 child.as_widget().layout(tree, renderer, &child_limits);
229 cross = cross.max(axis.cross(layout.size()));
230
231 nodes[i] = layout;
232 }
233 }
234
235 if cross_compress && some_fill_cross {
240 for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
241 let (main_size, cross_size) = {
242 let size = child.as_widget().size();
243
244 axis.pack(size.width, size.height)
245 };
246
247 if cross_size.fill_factor() != 0 {
248 let Length::Fixed(main) = main_size else {
249 continue;
250 };
251
252 let (max_width, max_height) = axis.pack(main, cross);
253
254 let child_limits =
255 Limits::new(Size::ZERO, Size::new(max_width, max_height));
256
257 let layout =
258 child.as_widget().layout(tree, renderer, &child_limits);
259 let size = layout.size();
260
261 cross = cross.max(axis.cross(size));
262
263 nodes[i] = layout;
264 }
265 }
266 }
267
268 let pad = axis.pack(padding.left, padding.top);
269 let mut main = pad.0;
270
271 for (i, node) in nodes.iter_mut().enumerate() {
274 if i > 0 {
275 main += spacing;
276 }
277
278 let (x, y) = axis.pack(main, pad.1);
279
280 node.move_to_mut(Point::new(x, y));
281
282 match axis {
283 Axis::Horizontal => {
284 node.align_mut(
285 Alignment::Start,
286 align_items,
287 Size::new(0.0, cross),
288 );
289 }
290 Axis::Vertical => {
291 node.align_mut(
292 align_items,
293 Alignment::Start,
294 Size::new(cross, 0.0),
295 );
296 }
297 }
298
299 let size = node.size();
300
301 main += axis.main(size);
302 }
303
304 let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);
305 let size = limits.resolve(
306 width,
307 height,
308 Size::new(intrinsic_width, intrinsic_height),
309 );
310
311 Node::with_children(size.expand(padding), nodes)
312}