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
13#[allow(missing_debug_implementations)]
33pub struct Column<
34 'a,
35 Key,
36 Message,
37 Theme = crate::Theme,
38 Renderer = crate::Renderer,
39> where
40 Key: Copy + PartialEq,
41{
42 spacing: f32,
43 padding: Padding,
44 width: Length,
45 height: Length,
46 max_width: f32,
47 align_items: Alignment,
48 keys: Vec<Key>,
49 children: Vec<Element<'a, Message, Theme, Renderer>>,
50}
51
52impl<'a, Key, Message, Theme, Renderer>
53 Column<'a, Key, Message, Theme, Renderer>
54where
55 Key: Copy + PartialEq,
56 Renderer: crate::core::Renderer,
57{
58 pub fn new() -> Self {
60 Self::from_vecs(Vec::new(), Vec::new())
61 }
62
63 pub fn from_vecs(
71 keys: Vec<Key>,
72 children: Vec<Element<'a, Message, Theme, Renderer>>,
73 ) -> Self {
74 Self {
75 spacing: 0.0,
76 padding: Padding::ZERO,
77 width: Length::Shrink,
78 height: Length::Shrink,
79 max_width: f32::INFINITY,
80 align_items: Alignment::Start,
81 keys,
82 children,
83 }
84 }
85
86 pub fn with_capacity(capacity: usize) -> Self {
88 Self::from_vecs(
89 Vec::with_capacity(capacity),
90 Vec::with_capacity(capacity),
91 )
92 }
93
94 pub fn with_children(
96 children: impl IntoIterator<
97 Item = (Key, Element<'a, Message, Theme, Renderer>),
98 >,
99 ) -> Self {
100 let iterator = children.into_iter();
101
102 Self::with_capacity(iterator.size_hint().0).extend(iterator)
103 }
104
105 pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {
111 self.spacing = amount.into().0;
112 self
113 }
114
115 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
117 self.padding = padding.into();
118 self
119 }
120
121 pub fn width(mut self, width: impl Into<Length>) -> Self {
123 self.width = width.into();
124 self
125 }
126
127 pub fn height(mut self, height: impl Into<Length>) -> Self {
129 self.height = height.into();
130 self
131 }
132
133 pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {
135 self.max_width = max_width.into().0;
136 self
137 }
138
139 pub fn align_items(mut self, align: Alignment) -> Self {
141 self.align_items = align;
142 self
143 }
144
145 pub fn push(
147 mut self,
148 key: Key,
149 child: impl Into<Element<'a, Message, Theme, Renderer>>,
150 ) -> Self {
151 let child = child.into();
152 let child_size = child.as_widget().size_hint();
153
154 self.width = self.width.enclose(child_size.width);
155 self.height = self.height.enclose(child_size.height);
156
157 self.keys.push(key);
158 self.children.push(child);
159 self
160 }
161
162 pub fn push_maybe(
164 self,
165 key: Key,
166 child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,
167 ) -> Self {
168 if let Some(child) = child {
169 self.push(key, child)
170 } else {
171 self
172 }
173 }
174
175 pub fn extend(
177 self,
178 children: impl IntoIterator<
179 Item = (Key, Element<'a, Message, Theme, Renderer>),
180 >,
181 ) -> Self {
182 children
183 .into_iter()
184 .fold(self, |column, (key, child)| column.push(key, child))
185 }
186}
187
188impl<Key, Message, Renderer> Default for Column<'_, Key, Message, Renderer>
189where
190 Key: Copy + PartialEq,
191 Renderer: crate::core::Renderer,
192{
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198struct State<Key>
199where
200 Key: Copy + PartialEq,
201{
202 keys: Vec<Key>,
203}
204
205impl<Key, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
206 for Column<'_, Key, Message, Theme, Renderer>
207where
208 Renderer: crate::core::Renderer,
209 Key: Copy + PartialEq + 'static,
210{
211 fn tag(&self) -> tree::Tag {
212 tree::Tag::of::<State<Key>>()
213 }
214
215 fn state(&self) -> tree::State {
216 tree::State::new(State {
217 keys: self.keys.clone(),
218 })
219 }
220
221 fn children(&self) -> Vec<Tree> {
222 self.children.iter().map(Tree::new).collect()
223 }
224
225 fn diff(&self, tree: &mut Tree) {
226 let Tree {
227 state, children, ..
228 } = tree;
229
230 let state = state.downcast_mut::<State<Key>>();
231
232 tree::diff_children_custom_with_search(
233 children,
234 &self.children,
235 |tree, child| child.as_widget().diff(tree),
236 |index| {
237 self.keys.get(index).or_else(|| self.keys.last()).copied()
238 != Some(state.keys[index])
239 },
240 |child| Tree::new(child.as_widget()),
241 );
242
243 if state.keys != self.keys {
244 state.keys.clone_from(&self.keys);
245 }
246 }
247
248 fn size(&self) -> Size<Length> {
249 Size {
250 width: self.width,
251 height: self.height,
252 }
253 }
254
255 fn layout(
256 &self,
257 tree: &mut Tree,
258 renderer: &Renderer,
259 limits: &layout::Limits,
260 ) -> layout::Node {
261 let limits = limits
262 .max_width(self.max_width)
263 .width(self.width)
264 .height(self.height);
265
266 layout::flex::resolve(
267 layout::flex::Axis::Vertical,
268 renderer,
269 &limits,
270 self.width,
271 self.height,
272 self.padding,
273 self.spacing,
274 self.align_items,
275 &self.children,
276 &mut tree.children,
277 )
278 }
279
280 fn operate(
281 &self,
282 tree: &mut Tree,
283 layout: Layout<'_>,
284 renderer: &Renderer,
285 operation: &mut dyn Operation,
286 ) {
287 operation.container(None, layout.bounds(), &mut |operation| {
288 self.children
289 .iter()
290 .zip(&mut tree.children)
291 .zip(layout.children())
292 .for_each(|((child, state), layout)| {
293 child
294 .as_widget()
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<'_>,
371 renderer: &Renderer,
372 translation: Vector,
373 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
374 overlay::from_children(
375 &mut self.children,
376 tree,
377 layout,
378 renderer,
379 translation,
380 )
381 }
382}
383
384impl<'a, Key, Message, Theme, Renderer>
385 From<Column<'a, Key, Message, Theme, Renderer>>
386 for Element<'a, Message, Theme, Renderer>
387where
388 Key: Copy + PartialEq + 'static,
389 Message: 'a,
390 Theme: 'a,
391 Renderer: crate::core::Renderer + 'a,
392{
393 fn from(column: Column<'a, Key, Message, Theme, Renderer>) -> Self {
394 Self::new(column)
395 }
396}