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