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