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 renderer: &Renderer,
219 operation: &mut dyn Operation,
220 ) {
221 operation.container(None, layout.bounds());
222 operation.traverse(&mut |operation| {
223 self.children
224 .iter_mut()
225 .zip(&mut tree.children)
226 .zip(layout.children())
227 .for_each(|((child, state), layout)| {
228 child
229 .as_widget_mut()
230 .operate(state, layout, renderer, operation);
231 });
232 });
233 }
234
235 fn update(
236 &mut self,
237 tree: &mut Tree,
238 event: &Event,
239 layout: Layout<'_>,
240 cursor: mouse::Cursor,
241 renderer: &Renderer,
242 shell: &mut Shell<'_, Message>,
243 viewport: &Rectangle,
244 ) {
245 for ((child, tree), layout) in self
246 .children
247 .iter_mut()
248 .zip(&mut tree.children)
249 .zip(layout.children())
250 {
251 child
252 .as_widget_mut()
253 .update(tree, event, layout, cursor, renderer, shell, viewport);
254 }
255 }
256
257 fn mouse_interaction(
258 &self,
259 tree: &Tree,
260 layout: Layout<'_>,
261 cursor: mouse::Cursor,
262 viewport: &Rectangle,
263 renderer: &Renderer,
264 ) -> mouse::Interaction {
265 self.children
266 .iter()
267 .zip(&tree.children)
268 .zip(layout.children())
269 .map(|((child, tree), layout)| {
270 child
271 .as_widget()
272 .mouse_interaction(tree, layout, cursor, viewport, renderer)
273 })
274 .max()
275 .unwrap_or_default()
276 }
277
278 fn draw(
279 &self,
280 tree: &Tree,
281 renderer: &mut Renderer,
282 theme: &Theme,
283 style: &renderer::Style,
284 layout: Layout<'_>,
285 cursor: mouse::Cursor,
286 viewport: &Rectangle,
287 ) {
288 if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
289 let viewport = if self.clip {
290 &clipped_viewport
291 } else {
292 viewport
293 };
294
295 for ((child, tree), layout) in self
296 .children
297 .iter()
298 .zip(&tree.children)
299 .zip(layout.children())
300 .filter(|(_, layout)| layout.bounds().intersects(viewport))
301 {
302 child
303 .as_widget()
304 .draw(tree, renderer, theme, style, layout, cursor, viewport);
305 }
306 }
307 }
308
309 fn overlay<'b>(
310 &'b mut self,
311 tree: &'b mut Tree,
312 layout: Layout<'b>,
313 renderer: &Renderer,
314 viewport: &Rectangle,
315 translation: Vector,
316 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
317 overlay::from_children(
318 &mut self.children,
319 tree,
320 layout,
321 renderer,
322 viewport,
323 translation,
324 )
325 }
326}
327
328impl<'a, Message, Theme, Renderer> From<Column<'a, Message, Theme, Renderer>>
329 for Element<'a, Message, Theme, Renderer>
330where
331 Message: 'a,
332 Theme: 'a,
333 Renderer: crate::core::Renderer + 'a,
334{
335 fn from(column: Column<'a, Message, Theme, Renderer>) -> Self {
336 Self::new(column)
337 }
338}
339
340#[allow(missing_debug_implementations)]
347pub struct Wrapping<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
348 column: Column<'a, Message, Theme, Renderer>,
349 horizontal_spacing: Option<f32>,
350 align_y: alignment::Vertical,
351}
352
353impl<Message, Theme, Renderer> Wrapping<'_, Message, Theme, Renderer> {
354 pub fn horizontal_spacing(mut self, amount: impl Into<Pixels>) -> Self {
356 self.horizontal_spacing = Some(amount.into().0);
357 self
358 }
359
360 pub fn align_y(mut self, align_y: impl Into<alignment::Vertical>) -> Self {
362 self.align_y = align_y.into();
363 self
364 }
365}
366
367impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
368 for Wrapping<'_, Message, Theme, Renderer>
369where
370 Renderer: crate::core::Renderer,
371{
372 fn diff(&mut self, tree: &mut Tree) {
373 self.column.diff(tree);
374 }
375
376 fn size(&self) -> Size<Length> {
377 self.column.size()
378 }
379
380 fn layout(
381 &mut self,
382 tree: &mut Tree,
383 renderer: &Renderer,
384 limits: &layout::Limits,
385 ) -> layout::Node {
386 let limits = limits
387 .width(self.column.width)
388 .height(self.column.height)
389 .shrink(self.column.padding);
390
391 let child_limits = limits.loose();
392 let spacing = self.column.spacing;
393 let horizontal_spacing = self.horizontal_spacing.unwrap_or(spacing);
394 let max_height = limits.max().height;
395
396 let mut children: Vec<layout::Node> = Vec::new();
397 let mut intrinsic_size = Size::ZERO;
398 let mut column_start = 0;
399 let mut column_width = 0.0;
400 let mut x = 0.0;
401 let mut y = 0.0;
402
403 let align_factor = match self.column.align {
404 Alignment::Start => 0.0,
405 Alignment::Center => 2.0,
406 Alignment::End => 1.0,
407 };
408
409 let align_x = |column_start: std::ops::Range<usize>,
410 column_width: f32,
411 children: &mut Vec<layout::Node>| {
412 if align_factor != 0.0 {
413 for node in &mut children[column_start] {
414 let width = node.size().width;
415
416 node.translate_mut(Vector::new((column_width - width) / align_factor, 0.0));
417 }
418 }
419 };
420
421 for (i, child) in self.column.children.iter_mut().enumerate() {
422 let node = child
423 .as_widget_mut()
424 .layout(&mut tree.children[i], renderer, &child_limits);
425
426 let child_size = node.size();
427
428 if y != 0.0 && y + child_size.height > max_height {
429 intrinsic_size.height = intrinsic_size.height.max(y - spacing);
430
431 align_x(column_start..i, column_width, &mut children);
432
433 x += column_width + horizontal_spacing;
434 y = 0.0;
435 column_start = i;
436 column_width = 0.0;
437 }
438
439 column_width = column_width.max(child_size.width);
440
441 children
442 .push(node.move_to((x + self.column.padding.left, y + self.column.padding.top)));
443
444 y += child_size.height + spacing;
445 }
446
447 if y != 0.0 {
448 intrinsic_size.height = intrinsic_size.height.max(y - spacing);
449 }
450
451 intrinsic_size.width = x + column_width;
452 align_x(column_start..children.len(), column_width, &mut children);
453
454 let align_factor = match self.align_y {
455 alignment::Vertical::Top => 0.0,
456 alignment::Vertical::Center => 2.0,
457 alignment::Vertical::Bottom => 1.0,
458 };
459
460 if align_factor != 0.0 {
461 let total_height = intrinsic_size.height;
462
463 let mut column_start = 0;
464
465 for i in 0..children.len() {
466 let bounds = children[i].bounds();
467 let column_height = bounds.y + bounds.height;
468
469 let next_y = children
470 .get(i + 1)
471 .map(|node| node.bounds().y)
472 .unwrap_or_default();
473
474 if next_y == 0.0 {
475 let translation =
476 Vector::new(0.0, (total_height - column_height) / align_factor);
477
478 for node in &mut children[column_start..=i] {
479 node.translate_mut(translation);
480 }
481
482 column_start = i + 1;
483 }
484 }
485 }
486
487 let size = limits.resolve(self.column.width, self.column.height, intrinsic_size);
488
489 layout::Node::with_children(size.expand(self.column.padding), children)
490 }
491
492 fn operate(
493 &mut self,
494 tree: &mut Tree,
495 layout: Layout<'_>,
496 renderer: &Renderer,
497 operation: &mut dyn Operation,
498 ) {
499 self.column.operate(tree, layout, renderer, operation);
500 }
501
502 fn update(
503 &mut self,
504 tree: &mut Tree,
505 event: &Event,
506 layout: Layout<'_>,
507 cursor: mouse::Cursor,
508 renderer: &Renderer,
509 shell: &mut Shell<'_, Message>,
510 viewport: &Rectangle,
511 ) {
512 self.column
513 .update(tree, event, layout, cursor, renderer, shell, viewport);
514 }
515
516 fn mouse_interaction(
517 &self,
518 tree: &Tree,
519 layout: Layout<'_>,
520 cursor: mouse::Cursor,
521 viewport: &Rectangle,
522 renderer: &Renderer,
523 ) -> mouse::Interaction {
524 self.column
525 .mouse_interaction(tree, layout, cursor, viewport, renderer)
526 }
527
528 fn draw(
529 &self,
530 tree: &Tree,
531 renderer: &mut Renderer,
532 theme: &Theme,
533 style: &renderer::Style,
534 layout: Layout<'_>,
535 cursor: mouse::Cursor,
536 viewport: &Rectangle,
537 ) {
538 self.column
539 .draw(tree, renderer, theme, style, layout, cursor, viewport);
540 }
541
542 fn overlay<'b>(
543 &'b mut self,
544 tree: &'b mut Tree,
545 layout: Layout<'b>,
546 renderer: &Renderer,
547 viewport: &Rectangle,
548 translation: Vector,
549 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
550 self.column
551 .overlay(tree, layout, renderer, viewport, translation)
552 }
553}
554
555impl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>>
556 for Element<'a, Message, Theme, Renderer>
557where
558 Message: 'a,
559 Theme: 'a,
560 Renderer: crate::core::Renderer + 'a,
561{
562 fn from(column: Wrapping<'a, Message, Theme, Renderer>) -> Self {
563 Self::new(column)
564 }
565}