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