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