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