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