1use crate::draw::Primitive;
2use crate::event::Event;
3use crate::layout::{Rectangle, Size};
4use crate::node::{GenericNode, IntoNode, Node};
5use crate::style::Stylesheet;
6use crate::widget::Context;
7
8use super::Widget;
9
10pub struct Row<'a, T> {
12 children: Vec<Node<'a, T>>,
13 layout: Vec<Rectangle>,
14}
15
16impl<'a, T: 'a> Row<'a, T> {
17 pub fn new() -> Self {
19 Default::default()
20 }
21
22 pub fn push<I: IntoNode<'a, T> + 'a>(mut self, item: I) -> Self {
24 self.children.push(item.into_node());
25 self
26 }
27
28 pub fn extend<I: IntoIterator<Item = N>, N: IntoNode<'a, T> + 'a>(mut self, iter: I) -> Self {
30 self.children.extend(iter.into_iter().map(IntoNode::into_node));
31 self
32 }
33
34 fn layout(&mut self, layout: Rectangle, style: &Stylesheet) -> impl Iterator<Item = (&mut Node<'a, T>, Rectangle)> {
35 let layout = style.background.content_rect(layout, style.padding);
36 if self.layout.len() != self.children.len() {
37 let align = style.align_vertical;
38 let available_parts = self.children.iter().map(|c| c.size().0.parts()).sum();
39 let available_space = layout.width() - self.children.iter().map(|c| c.size().0.min_size()).sum::<f32>();
40 let mut cursor = 0.0;
41 self.layout = self
42 .children
43 .iter()
44 .map(|child| {
45 let (w, h) = child.size();
46 let w = w.resolve(available_space, available_parts).min(layout.width() - cursor);
47 let h = h.resolve(layout.height(), h.parts());
48 let x = cursor;
49 let y = align.resolve_start(h, layout.height());
50
51 cursor += w;
52 Rectangle::from_xywh(x, y, w, h)
53 })
54 .collect();
55 }
56 self.children.iter_mut().zip(
57 self.layout
58 .iter()
59 .map(move |relative| relative.translate(layout.left, layout.top)),
60 )
61 }
62}
63
64impl<'a, T: 'a> Default for Row<'a, T> {
65 fn default() -> Self {
66 Self {
67 children: Vec::new(),
68 layout: Vec::new(),
69 }
70 }
71}
72
73impl<'a, T: 'a> Widget<'a, T> for Row<'a, T> {
74 type State = ();
75
76 fn mount(&self) {}
77
78 fn widget(&self) -> &'static str {
79 "row"
80 }
81
82 fn visit_children(&mut self, visitor: &mut dyn FnMut(&mut dyn GenericNode<'a, T>)) {
83 self.children.iter_mut().for_each(|child| visitor(&mut **child));
84 }
85
86 fn len(&self) -> usize {
87 self.children.len()
88 }
89
90 fn size(&self, _: &(), style: &Stylesheet) -> (Size, Size) {
91 let width = match style.width {
92 Size::Shrink => Size::Exact(self.children.iter().fold(0.0, |size, child| match child.size().0 {
93 Size::Exact(child_size) => size + child_size,
94 _ => size,
95 })),
96 other => other,
97 };
98 let height = match style.height {
99 Size::Shrink => Size::Exact(self.children.iter().fold(0.0, |size, child| match child.size().1 {
100 Size::Exact(child_size) => size.max(child_size),
101 _ => size,
102 })),
103 other => other,
104 };
105 style
106 .background
107 .resolve_size((style.width, style.height), (width, height), style.padding)
108 }
109
110 fn focused(&self, _: &()) -> bool {
111 self.children.iter().any(|child| child.focused())
112 }
113
114 fn event(
115 &mut self,
116 _: &mut (),
117 layout: Rectangle,
118 clip: Rectangle,
119 stylesheet: &Stylesheet,
120 event: Event,
121 context: &mut Context<T>,
122 ) {
123 let focused = self.children.iter().position(|child| child.focused());
124
125 for (index, (child, layout)) in self.layout(layout, stylesheet).enumerate() {
126 if Some(index) == focused {
127 child.event(layout, clip, event, context);
128 } else if focused.is_none() {
129 if let Some(clip) = clip.intersect(&layout) {
130 child.event(layout, clip, event, context);
131 }
132 }
133 }
134 }
135
136 fn draw(&mut self, _: &mut (), layout: Rectangle, clip: Rectangle, stylesheet: &Stylesheet) -> Vec<Primitive<'a>> {
137 let mut result = Vec::new();
138
139 result.extend(stylesheet.background.render(layout));
140
141 result = self
142 .layout(layout, stylesheet)
143 .fold(result, |mut result, (child, layout)| {
144 result.extend(child.draw(layout, clip));
145 result
146 });
147
148 result
149 }
150}
151
152impl<'a, T: 'a> IntoNode<'a, T> for Row<'a, T> {
153 fn into_node(self) -> Node<'a, T> {
154 Node::from_widget(self)
155 }
156}