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