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