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