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