1use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget::Operation;
7use crate::core::widget::tree::{self, Tree};
8use crate::core::{
9 Alignment, Element, Event, Layout, Length, Padding, Pixels, Rectangle, Shell, Size, Vector,
10 Widget,
11};
12
13pub struct Column<'a, Key, Message, Theme = crate::Theme, Renderer = crate::Renderer>
33where
34 Key: Copy + PartialEq,
35{
36 spacing: f32,
37 padding: Padding,
38 width: Length,
39 height: Length,
40 align_items: Alignment,
41 keys: Vec<Key>,
42 children: Vec<Element<'a, Message, Theme, Renderer>>,
43}
44
45impl<'a, Key, Message, Theme, Renderer> Column<'a, Key, Message, Theme, Renderer>
46where
47 Key: Copy + PartialEq,
48 Renderer: crate::core::Renderer,
49{
50 pub fn new() -> Self {
52 Self::from_vecs(Vec::new(), Vec::new())
53 }
54
55 pub fn from_vecs(keys: Vec<Key>, children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {
63 Self {
64 spacing: 0.0,
65 padding: Padding::ZERO,
66 width: Length::Fit,
67 height: Length::Fit,
68 align_items: Alignment::Start,
69 keys,
70 children,
71 }
72 }
73
74 pub fn with_capacity(capacity: usize) -> Self {
76 Self::from_vecs(Vec::with_capacity(capacity), Vec::with_capacity(capacity))
77 }
78
79 pub fn with_children(
81 children: impl IntoIterator<Item = (Key, Element<'a, Message, Theme, Renderer>)>,
82 ) -> Self {
83 let iterator = children.into_iter();
84
85 Self::with_capacity(iterator.size_hint().0).extend(iterator)
86 }
87
88 pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {
94 self.spacing = amount.into().0;
95 self
96 }
97
98 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
100 self.padding = padding.into();
101 self
102 }
103
104 pub fn width(mut self, width: impl Into<Length>) -> Self {
106 self.width = width.into();
107 self
108 }
109
110 pub fn height(mut self, height: impl Into<Length>) -> Self {
112 self.height = height.into();
113 self
114 }
115
116 pub fn align_items(mut self, align: Alignment) -> Self {
118 self.align_items = align;
119 self
120 }
121
122 pub fn push(
124 mut self,
125 key: Key,
126 child: impl Into<Element<'a, Message, Theme, Renderer>>,
127 ) -> Self {
128 let child = child.into();
129
130 if !child.as_widget().is_void() {
131 self.keys.push(key);
132 self.children.push(child);
133 }
134
135 self
136 }
137
138 pub fn push_maybe(
140 self,
141 key: Key,
142 child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,
143 ) -> Self {
144 if let Some(child) = child {
145 self.push(key, child)
146 } else {
147 self
148 }
149 }
150
151 pub fn extend(
153 self,
154 children: impl IntoIterator<Item = (Key, Element<'a, Message, Theme, Renderer>)>,
155 ) -> Self {
156 children
157 .into_iter()
158 .fold(self, |column, (key, child)| column.push(key, child))
159 }
160}
161
162impl<Key, Message, Renderer> Default for Column<'_, Key, Message, Renderer>
163where
164 Key: Copy + PartialEq,
165 Renderer: crate::core::Renderer,
166{
167 fn default() -> Self {
168 Self::new()
169 }
170}
171
172struct State<Key>
173where
174 Key: Copy + PartialEq,
175{
176 keys: Vec<Key>,
177}
178
179impl<Key, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
180 for Column<'_, Key, Message, Theme, Renderer>
181where
182 Renderer: crate::core::Renderer,
183 Key: Copy + PartialEq + 'static,
184{
185 fn tag(&self) -> tree::Tag {
186 tree::Tag::of::<State<Key>>()
187 }
188
189 fn state(&self) -> tree::State {
190 tree::State::new(State {
191 keys: self.keys.clone(),
192 })
193 }
194
195 fn diff(&mut self, tree: &mut Tree) {
196 let Tree {
197 state, children, ..
198 } = tree;
199
200 let state = state.downcast_mut::<State<Key>>();
201
202 tree::diff_children_custom_with_search(
203 children,
204 &mut self.children,
205 |tree, child| child.as_widget_mut().diff(tree),
206 |index| {
207 self.keys.get(index).or_else(|| self.keys.last()).copied()
208 != Some(state.keys[index])
209 },
210 |child| Tree::new(child.as_widget()),
211 );
212
213 if state.keys != self.keys {
214 state.keys.clone_from(&self.keys);
215 }
216
217 if self.width.is_fit() || self.height.is_fit() {
218 for child in &self.children {
219 let size = child.as_widget().size();
220
221 self.width = self.width.cross(size.width);
222 self.height = self.height.stack(size.height);
223 }
224 }
225 }
226
227 fn size(&self) -> Size<Length> {
228 Size {
229 width: self.width,
230 height: self.height,
231 }
232 }
233
234 fn layout(
235 &mut self,
236 tree: &mut Tree,
237 renderer: &Renderer,
238 limits: &layout::Limits,
239 ) -> layout::Node {
240 layout::flex::resolve(
241 layout::flex::Axis::Vertical,
242 renderer,
243 limits,
244 self.width,
245 self.height,
246 self.padding,
247 self.spacing,
248 self.align_items,
249 &mut self.children,
250 &mut tree.children,
251 )
252 }
253
254 fn operate(
255 &mut self,
256 tree: &mut Tree,
257 layout: Layout<'_>,
258 renderer: &Renderer,
259 operation: &mut dyn Operation,
260 ) {
261 operation.container(None, layout.bounds());
262 operation.traverse(&mut |operation| {
263 self.children
264 .iter_mut()
265 .zip(&mut tree.children)
266 .zip(layout.children())
267 .for_each(|((child, state), layout)| {
268 child
269 .as_widget_mut()
270 .operate(state, layout, renderer, operation);
271 });
272 });
273 }
274
275 fn update(
276 &mut self,
277 tree: &mut Tree,
278 event: &Event,
279 layout: Layout<'_>,
280 cursor: mouse::Cursor,
281 renderer: &Renderer,
282 shell: &mut Shell<'_, Message>,
283 viewport: &Rectangle,
284 ) {
285 for ((child, tree), layout) in self
286 .children
287 .iter_mut()
288 .zip(&mut tree.children)
289 .zip(layout.children())
290 {
291 child
292 .as_widget_mut()
293 .update(tree, event, layout, cursor, renderer, shell, viewport);
294 }
295 }
296
297 fn mouse_interaction(
298 &self,
299 tree: &Tree,
300 layout: Layout<'_>,
301 cursor: mouse::Cursor,
302 viewport: &Rectangle,
303 renderer: &Renderer,
304 ) -> mouse::Interaction {
305 self.children
306 .iter()
307 .zip(&tree.children)
308 .zip(layout.children())
309 .map(|((child, tree), layout)| {
310 child
311 .as_widget()
312 .mouse_interaction(tree, layout, cursor, viewport, renderer)
313 })
314 .max()
315 .unwrap_or_default()
316 }
317
318 fn draw(
319 &self,
320 tree: &Tree,
321 renderer: &mut Renderer,
322 theme: &Theme,
323 style: &renderer::Style,
324 layout: Layout<'_>,
325 cursor: mouse::Cursor,
326 viewport: &Rectangle,
327 ) {
328 for ((child, state), layout) in self
329 .children
330 .iter()
331 .zip(&tree.children)
332 .zip(layout.children())
333 {
334 child
335 .as_widget()
336 .draw(state, renderer, theme, style, layout, cursor, viewport);
337 }
338 }
339
340 fn overlay<'b>(
341 &'b mut self,
342 tree: &'b mut Tree,
343 layout: Layout<'b>,
344 renderer: &Renderer,
345 viewport: &Rectangle,
346 translation: Vector,
347 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
348 overlay::from_children(
349 &mut self.children,
350 tree,
351 layout,
352 renderer,
353 viewport,
354 translation,
355 )
356 }
357}
358
359impl<'a, Key, Message, Theme, Renderer> From<Column<'a, Key, Message, Theme, Renderer>>
360 for Element<'a, Message, Theme, Renderer>
361where
362 Key: Copy + PartialEq + 'static,
363 Message: 'a,
364 Theme: 'a,
365 Renderer: crate::core::Renderer + 'a,
366{
367 fn from(column: Column<'a, Key, Message, Theme, Renderer>) -> Self {
368 Self::new(column)
369 }
370}