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