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 let (fill_main_factor, fill_cross_factor) = {
105 let size = child.as_widget().size();
106
107 axis.pack(size.width.fill_factor(), size.height.fill_factor())
108 };
109
110 if (main_compress || fill_main_factor == 0) && (!cross_compress || fill_cross_factor == 0) {
111 let (max_width, max_height) = axis.pack(
112 available,
113 if fill_cross_factor == 0 {
114 max_cross
115 } else {
116 cross
117 },
118 );
119
120 let child_limits =
121 Limits::with_compression(Size::ZERO, Size::new(max_width, max_height), compression);
122
123 let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
124 let size = layout.size();
125
126 available -= axis.main(size);
127 cross = cross.max(axis.cross(size));
128
129 nodes[i] = layout;
130 } else {
131 fill_main_sum += fill_main_factor;
132 some_fill_cross = some_fill_cross || fill_cross_factor != 0;
133 }
134 }
135
136 if cross_compress && some_fill_cross {
147 for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate() {
148 let (main_size, cross_size) = {
149 let size = child.as_widget().size();
150
151 axis.pack(size.width, size.height)
152 };
153
154 if (main_compress || main_size.fill_factor() == 0) && cross_size.fill_factor() != 0 {
155 if let Length::Fixed(main) = main_size {
156 available -= main;
157 continue;
158 }
159
160 let (max_width, max_height) = axis.pack(available, cross);
161
162 let child_limits = Limits::with_compression(
163 Size::ZERO,
164 Size::new(max_width, max_height),
165 compression,
166 );
167
168 let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
169 let size = layout.size();
170
171 available -= axis.main(size);
172 cross = cross.max(axis.cross(size));
173
174 nodes[i] = layout;
175 }
176 }
177 }
178
179 let remaining = available.max(0.0);
180
181 if !main_compress {
185 for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate() {
186 let (fill_main_factor, fill_cross_factor) = {
187 let size = child.as_widget().size();
188
189 axis.pack(size.width.fill_factor(), size.height.fill_factor())
190 };
191
192 if fill_main_factor != 0 {
193 let max_main = remaining * fill_main_factor as f32 / fill_main_sum as f32;
194
195 let max_main = if max_main.is_nan() {
196 f32::INFINITY
197 } else {
198 max_main
199 };
200
201 let min_main = if max_main.is_infinite() {
202 0.0
203 } else {
204 max_main
205 };
206
207 let (min_width, min_height) = axis.pack(min_main, 0.0);
208 let (max_width, max_height) = axis.pack(
209 max_main,
210 if fill_cross_factor == 0 {
211 max_cross
212 } else {
213 cross
214 },
215 );
216
217 let child_limits = Limits::with_compression(
218 Size::new(min_width, min_height),
219 Size::new(max_width, max_height),
220 compression,
221 );
222
223 let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
224 cross = cross.max(axis.cross(layout.size()));
225
226 nodes[i] = layout;
227 }
228 }
229 }
230
231 if cross_compress && some_fill_cross {
236 for (i, (child, tree)) in items.iter_mut().zip(trees).enumerate() {
237 let (main_size, cross_size) = {
238 let size = child.as_widget().size();
239
240 axis.pack(size.width, size.height)
241 };
242
243 if cross_size.fill_factor() != 0 {
244 let Length::Fixed(main) = main_size else {
245 continue;
246 };
247
248 let (max_width, max_height) = axis.pack(main, cross);
249
250 let child_limits = Limits::new(Size::ZERO, Size::new(max_width, max_height));
251
252 let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
253 let size = layout.size();
254
255 cross = cross.max(axis.cross(size));
256
257 nodes[i] = layout;
258 }
259 }
260 }
261
262 let pad = axis.pack(padding.left, padding.top);
263 let mut main = pad.0;
264
265 for (i, node) in nodes.iter_mut().enumerate() {
268 if i > 0 {
269 main += spacing;
270 }
271
272 let (x, y) = axis.pack(main, pad.1);
273
274 node.move_to_mut(Point::new(x, y));
275
276 match axis {
277 Axis::Horizontal => {
278 node.align_mut(Alignment::Start, align_items, Size::new(0.0, cross));
279 }
280 Axis::Vertical => {
281 node.align_mut(align_items, Alignment::Start, Size::new(cross, 0.0));
282 }
283 }
284
285 let size = node.size();
286
287 main += axis.main(size);
288 }
289
290 let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);
291 let size = limits.resolve(width, height, Size::new(intrinsic_width, intrinsic_height));
292
293 Node::with_children(size.expand(padding), nodes)
294}