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 {
141 for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate()
142 {
143 let (fill_main_factor, fill_cross_factor) = {
144 let size = child.as_widget().size();
145
146 axis.pack(size.width.fill_factor(), size.height.fill_factor())
147 };
148
149 if fill_main_factor == 0 && fill_cross_factor != 0 {
150 let (max_width, max_height) = axis.pack(available, cross);
151
152 let child_limits =
153 Limits::new(Size::ZERO, Size::new(max_width, max_height));
154
155 let layout =
156 child.as_widget().layout(tree, renderer, &child_limits);
157 let size = layout.size();
158
159 available -= axis.main(size);
160 cross = cross.max(axis.cross(size));
161
162 nodes[i] = layout;
163 }
164 }
165 }
166
167 let remaining = match axis {
168 Axis::Horizontal => match width {
169 Length::Shrink => 0.0,
170 _ => available.max(0.0),
171 },
172 Axis::Vertical => match height {
173 Length::Shrink => 0.0,
174 _ => available.max(0.0),
175 },
176 };
177
178 for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
182 let (fill_main_factor, fill_cross_factor) = {
183 let size = child.as_widget().size();
184
185 axis.pack(size.width.fill_factor(), size.height.fill_factor())
186 };
187
188 if fill_main_factor != 0 {
189 let max_main =
190 remaining * fill_main_factor as f32 / fill_main_sum as f32;
191
192 let max_main = if max_main.is_nan() {
193 f32::INFINITY
194 } else {
195 max_main
196 };
197
198 let min_main = if max_main.is_infinite() {
199 0.0
200 } else {
201 max_main
202 };
203
204 let (min_width, min_height) = axis.pack(min_main, 0.0);
205 let (max_width, max_height) = axis.pack(
206 max_main,
207 if fill_cross_factor == 0 {
208 max_cross
209 } else {
210 cross
211 },
212 );
213
214 let child_limits = Limits::new(
215 Size::new(min_width, min_height),
216 Size::new(max_width, max_height),
217 );
218
219 let layout =
220 child.as_widget().layout(tree, renderer, &child_limits);
221 cross = cross.max(axis.cross(layout.size()));
222
223 nodes[i] = layout;
224 }
225 }
226
227 let pad = axis.pack(padding.left, padding.top);
228 let mut main = pad.0;
229
230 for (i, node) in nodes.iter_mut().enumerate() {
233 if i > 0 {
234 main += spacing;
235 }
236
237 let (x, y) = axis.pack(main, pad.1);
238
239 node.move_to_mut(Point::new(x, y));
240
241 match axis {
242 Axis::Horizontal => {
243 node.align_mut(
244 Alignment::Start,
245 align_items,
246 Size::new(0.0, cross),
247 );
248 }
249 Axis::Vertical => {
250 node.align_mut(
251 align_items,
252 Alignment::Start,
253 Size::new(cross, 0.0),
254 );
255 }
256 }
257
258 let size = node.size();
259
260 main += axis.main(size);
261 }
262
263 let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);
264 let size = limits.resolve(
265 width,
266 height,
267 Size::new(intrinsic_width, intrinsic_height),
268 );
269
270 Node::with_children(size.expand(padding), nodes)
271}