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