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