1use crate::core::alignment::{self, Alignment};
3use crate::core::layout;
4use crate::core::mouse;
5use crate::core::overlay;
6use crate::core::renderer;
7use crate::core::widget::{Operation, Tree};
8use crate::core::{
9 Element, Event, Layout, Length, Padding, Pixels, Rectangle, Shell, Size, Vector, Widget,
10};
11
12pub struct Column<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
35 spacing: f32,
36 padding: Padding,
37 width: Length,
38 height: Length,
39 align: Alignment,
40 clip: bool,
41 children: Vec<Element<'a, Message, Theme, Renderer>>,
42}
43
44impl<'a, Message, Theme, Renderer> Column<'a, Message, Theme, Renderer>
45where
46 Renderer: crate::core::Renderer,
47{
48 pub fn new() -> Self {
50 Self::from_vec(Vec::new())
51 }
52
53 pub fn with_capacity(capacity: usize) -> Self {
55 Self::from_vec(Vec::with_capacity(capacity))
56 }
57
58 pub fn with_children(
60 children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
61 ) -> Self {
62 let iterator = children.into_iter();
63
64 Self::with_capacity(iterator.size_hint().0).extend(iterator)
65 }
66
67 pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {
69 Self {
70 spacing: 0.0,
71 padding: Padding::ZERO,
72 width: Length::Fit,
73 height: Length::Fit,
74 align: Alignment::Start,
75 clip: false,
76 children,
77 }
78 }
79
80 pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {
86 self.spacing = amount.into().0;
87 self
88 }
89
90 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
92 self.padding = padding.into();
93 self
94 }
95
96 pub fn width(mut self, width: impl Into<Length>) -> Self {
98 self.width = width.into();
99 self
100 }
101
102 pub fn height(mut self, height: impl Into<Length>) -> Self {
104 self.height = height.into();
105 self
106 }
107
108 pub fn align_x(mut self, align: impl Into<alignment::Horizontal>) -> Self {
110 self.align = Alignment::from(align.into());
111 self
112 }
113
114 pub fn clip(mut self, clip: bool) -> Self {
117 self.clip = clip;
118 self
119 }
120
121 pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
123 let child = child.into();
124
125 if !child.as_widget().is_void() {
126 self.children.push(child);
127 }
128
129 self
130 }
131
132 pub fn extend(
134 self,
135 children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
136 ) -> Self {
137 children.into_iter().fold(self, Self::push)
138 }
139
140 pub fn wrap(self) -> Wrapping<'a, Message, Theme, Renderer> {
144 Wrapping {
145 column: self,
146 horizontal_spacing: None,
147 align_y: alignment::Vertical::Top,
148 }
149 }
150}
151
152impl<Message, Renderer> Default for Column<'_, Message, Renderer>
153where
154 Renderer: crate::core::Renderer,
155{
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161impl<'a, Message, Theme, Renderer: crate::core::Renderer>
162 FromIterator<Element<'a, Message, Theme, Renderer>> for Column<'a, Message, Theme, Renderer>
163{
164 fn from_iter<T: IntoIterator<Item = Element<'a, Message, Theme, Renderer>>>(iter: T) -> Self {
165 Self::with_children(iter)
166 }
167}
168
169impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
170 for Column<'_, Message, Theme, Renderer>
171where
172 Renderer: crate::core::Renderer,
173{
174 fn diff(&mut self, tree: &mut Tree) {
175 tree.diff_children(&mut self.children);
176
177 if self.width.is_fit() || self.height.is_fit() {
178 for child in &self.children {
179 let size = child.as_widget().size();
180
181 self.width = self.width.cross(size.width);
182 self.height = self.height.stack(size.height);
183 }
184 }
185 }
186
187 fn size(&self) -> Size<Length> {
188 Size {
189 width: self.width,
190 height: self.height,
191 }
192 }
193
194 fn layout(
195 &mut self,
196 tree: &mut Tree,
197 renderer: &Renderer,
198 limits: &layout::Limits,
199 ) -> layout::Node {
200 layout::flex::resolve(
201 layout::flex::Axis::Vertical,
202 renderer,
203 limits,
204 self.width,
205 self.height,
206 self.padding,
207 self.spacing,
208 self.align,
209 &mut self.children,
210 &mut tree.children,
211 )
212 }
213
214 fn operate(
215 &mut self,
216 tree: &mut Tree,
217 layout: Layout<'_>,
218 viewport: &Rectangle,
219 renderer: &Renderer,
220 operation: &mut dyn Operation,
221 ) {
222 operation.container(None, layout.bounds(), viewport);
223 operation.traverse(&mut |operation| {
224 self.children
225 .iter_mut()
226 .zip(&mut tree.children)
227 .zip(layout.children())
228 .for_each(|((child, state), layout)| {
229 child
230 .as_widget_mut()
231 .operate(state, layout, viewport, renderer, operation);
232 });
233 });
234 }
235
236 fn update(
237 &mut self,
238 tree: &mut Tree,
239 event: &Event,
240 layout: Layout<'_>,
241 cursor: mouse::Cursor,
242 renderer: &Renderer,
243 shell: &mut Shell<'_, Message>,
244 viewport: &Rectangle,
245 ) {
246 for ((child, tree), layout) in self
247 .children
248 .iter_mut()
249 .zip(&mut tree.children)
250 .zip(layout.children())
251 {
252 child
253 .as_widget_mut()
254 .update(tree, event, layout, cursor, renderer, shell, viewport);
255 }
256 }
257
258 fn mouse_interaction(
259 &self,
260 tree: &Tree,
261 layout: Layout<'_>,
262 cursor: mouse::Cursor,
263 viewport: &Rectangle,
264 renderer: &Renderer,
265 ) -> mouse::Interaction {
266 self.children
267 .iter()
268 .zip(&tree.children)
269 .zip(layout.children())
270 .map(|((child, tree), layout)| {
271 child
272 .as_widget()
273 .mouse_interaction(tree, layout, cursor, viewport, renderer)
274 })
275 .max()
276 .unwrap_or_default()
277 }
278
279 fn draw(
280 &self,
281 tree: &Tree,
282 renderer: &mut Renderer,
283 theme: &Theme,
284 style: &renderer::Style,
285 layout: Layout<'_>,
286 cursor: mouse::Cursor,
287 viewport: &Rectangle,
288 ) {
289 if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
290 let viewport = if self.clip {
291 &clipped_viewport
292 } else {
293 viewport
294 };
295
296 for ((child, tree), layout) in self
297 .children
298 .iter()
299 .zip(&tree.children)
300 .zip(layout.children())
301 .filter(|(_, layout)| layout.bounds().intersects(viewport))
302 {
303 child
304 .as_widget()
305 .draw(tree, renderer, theme, style, layout, cursor, viewport);
306 }
307 }
308 }
309
310 fn overlay<'b>(
311 &'b mut self,
312 tree: &'b mut Tree,
313 layout: Layout<'b>,
314 renderer: &Renderer,
315 viewport: &Rectangle,
316 translation: Vector,
317 window: Size,
318 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
319 overlay::from_children(
320 &mut self.children,
321 tree,
322 layout,
323 renderer,
324 viewport,
325 translation,
326 window,
327 )
328 }
329}
330
331impl<'a, Message, Theme, Renderer> From<Column<'a, Message, Theme, Renderer>>
332 for Element<'a, Message, Theme, Renderer>
333where
334 Message: 'a,
335 Theme: 'a,
336 Renderer: crate::core::Renderer + 'a,
337{
338 fn from(column: Column<'a, Message, Theme, Renderer>) -> Self {
339 Self::new(column)
340 }
341}
342
343#[allow(missing_debug_implementations)]
350pub struct Wrapping<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
351 column: Column<'a, Message, Theme, Renderer>,
352 horizontal_spacing: Option<f32>,
353 align_y: alignment::Vertical,
354}
355
356impl<Message, Theme, Renderer> Wrapping<'_, Message, Theme, Renderer> {
357 pub fn horizontal_spacing(mut self, amount: impl Into<Pixels>) -> Self {
359 self.horizontal_spacing = Some(amount.into().0);
360 self
361 }
362
363 pub fn align_y(mut self, align_y: impl Into<alignment::Vertical>) -> Self {
365 self.align_y = align_y.into();
366 self
367 }
368}
369
370impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
371 for Wrapping<'_, Message, Theme, Renderer>
372where
373 Renderer: crate::core::Renderer,
374{
375 fn diff(&mut self, tree: &mut Tree) {
376 self.column.diff(tree);
377 }
378
379 fn size(&self) -> Size<Length> {
380 self.column.size()
381 }
382
383 fn layout(
384 &mut self,
385 tree: &mut Tree,
386 renderer: &Renderer,
387 limits: &layout::Limits,
388 ) -> layout::Node {
389 let limits = limits
390 .width(self.column.width)
391 .height(self.column.height)
392 .shrink(self.column.padding);
393
394 let child_limits = limits.loose();
395 let spacing = self.column.spacing;
396 let horizontal_spacing = self.horizontal_spacing.unwrap_or(spacing);
397 let max_height = limits.bounds().height;
398
399 let mut children: Vec<layout::Node> = Vec::new();
400 let mut intrinsic_size = Size::ZERO;
401 let mut column_start = 0;
402 let mut column_width = 0.0;
403 let mut x = 0.0;
404 let mut y = 0.0;
405
406 let align_factor = match self.column.align {
407 Alignment::Start => 0.0,
408 Alignment::Center => 2.0,
409 Alignment::End => 1.0,
410 };
411
412 let align_x = |column_start: std::ops::Range<usize>,
413 column_width: f32,
414 children: &mut Vec<layout::Node>| {
415 if align_factor != 0.0 {
416 for node in &mut children[column_start] {
417 let width = node.size().width;
418
419 node.translate_mut(Vector::new((column_width - width) / align_factor, 0.0));
420 }
421 }
422 };
423
424 for (i, child) in self.column.children.iter_mut().enumerate() {
425 let node = child
426 .as_widget_mut()
427 .layout(&mut tree.children[i], renderer, &child_limits);
428
429 let child_size = node.size();
430
431 if y != 0.0 && y + child_size.height > max_height {
432 intrinsic_size.height = intrinsic_size.height.max(y - spacing);
433
434 align_x(column_start..i, column_width, &mut children);
435
436 x += column_width + horizontal_spacing;
437 y = 0.0;
438 column_start = i;
439 column_width = 0.0;
440 }
441
442 column_width = column_width.max(child_size.width);
443
444 children
445 .push(node.move_to((x + self.column.padding.left, y + self.column.padding.top)));
446
447 y += child_size.height + spacing;
448 }
449
450 if y != 0.0 {
451 intrinsic_size.height = intrinsic_size.height.max(y - spacing);
452 }
453
454 intrinsic_size.width = x + column_width;
455 align_x(column_start..children.len(), column_width, &mut children);
456
457 let align_factor = match self.align_y {
458 alignment::Vertical::Top => 0.0,
459 alignment::Vertical::Center => 2.0,
460 alignment::Vertical::Bottom => 1.0,
461 };
462
463 if align_factor != 0.0 {
464 let total_height = intrinsic_size.height;
465
466 let mut column_start = 0;
467
468 for i in 0..children.len() {
469 let bounds = children[i].bounds();
470 let column_height = bounds.y + bounds.height;
471
472 let next_y = children
473 .get(i + 1)
474 .map(|node| node.bounds().y)
475 .unwrap_or_default();
476
477 if next_y == 0.0 {
478 let translation =
479 Vector::new(0.0, (total_height - column_height) / align_factor);
480
481 for node in &mut children[column_start..=i] {
482 node.translate_mut(translation);
483 }
484
485 column_start = i + 1;
486 }
487 }
488 }
489
490 let size = limits.resolve(self.column.width, self.column.height, intrinsic_size);
491
492 layout::Node::with_children(size.expand(self.column.padding), children)
493 }
494
495 fn operate(
496 &mut self,
497 tree: &mut Tree,
498 layout: Layout<'_>,
499 viewport: &Rectangle,
500 renderer: &Renderer,
501 operation: &mut dyn Operation,
502 ) {
503 self.column
504 .operate(tree, layout, viewport, renderer, operation);
505 }
506
507 fn update(
508 &mut self,
509 tree: &mut Tree,
510 event: &Event,
511 layout: Layout<'_>,
512 cursor: mouse::Cursor,
513 renderer: &Renderer,
514 shell: &mut Shell<'_, Message>,
515 viewport: &Rectangle,
516 ) {
517 self.column
518 .update(tree, event, layout, cursor, renderer, shell, viewport);
519 }
520
521 fn mouse_interaction(
522 &self,
523 tree: &Tree,
524 layout: Layout<'_>,
525 cursor: mouse::Cursor,
526 viewport: &Rectangle,
527 renderer: &Renderer,
528 ) -> mouse::Interaction {
529 self.column
530 .mouse_interaction(tree, layout, cursor, viewport, renderer)
531 }
532
533 fn draw(
534 &self,
535 tree: &Tree,
536 renderer: &mut Renderer,
537 theme: &Theme,
538 style: &renderer::Style,
539 layout: Layout<'_>,
540 cursor: mouse::Cursor,
541 viewport: &Rectangle,
542 ) {
543 self.column
544 .draw(tree, renderer, theme, style, layout, cursor, viewport);
545 }
546
547 fn overlay<'b>(
548 &'b mut self,
549 tree: &'b mut Tree,
550 layout: Layout<'b>,
551 renderer: &Renderer,
552 viewport: &Rectangle,
553 translation: Vector,
554 window: Size,
555 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
556 self.column
557 .overlay(tree, layout, renderer, viewport, translation, window)
558 }
559}
560
561impl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>>
562 for Element<'a, Message, Theme, Renderer>
563where
564 Message: 'a,
565 Theme: 'a,
566 Renderer: crate::core::Renderer + 'a,
567{
568 fn from(column: Wrapping<'a, Message, Theme, Renderer>) -> Self {
569 Self::new(column)
570 }
571}