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 Renderer: crate::core::Renderer,
179 Key: Copy + PartialEq + 'static,
180 W: Widget<Message, Theme, Renderer>,
181{
182 fn tag(&self) -> tree::Tag {
183 tree::Tag::of::<State<Key>>()
184 }
185
186 fn state(&self) -> tree::State {
187 tree::State::new(State {
188 keys: self.keys.clone(),
189 cache: layout::flex::Cache::default(),
190 })
191 }
192
193 fn diff(&mut self, tree: &mut Tree) {
194 let Tree {
195 state, children, ..
196 } = tree;
197
198 let state = state.downcast_mut::<State<Key>>();
199
200 tree::diff_children_custom_with_search(
201 children,
202 &mut self.children,
203 Tree::diff,
204 |index| {
205 self.keys.get(index).or_else(|| self.keys.last()).copied()
206 != Some(state.keys[index])
207 },
208 |child| Tree::new(child),
209 );
210
211 if state.keys != self.keys {
212 state.keys.clone_from(&self.keys);
213 }
214
215 if self.width.is_fit() || self.height.is_fit() {
216 for child in &self.children {
217 let size = child.size();
218
219 self.width = self.width.cross(size.width);
220 self.height = self.height.stack(size.height);
221 }
222 }
223 }
224
225 fn size(&self) -> Size<Length> {
226 Size {
227 width: self.width,
228 height: self.height,
229 }
230 }
231
232 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
233 let state = tree.state.downcast_mut::<State<Key>>();
234
235 tree.size = layout::flex::resolve(
236 layout::flex::Axis::Vertical,
237 renderer,
238 limits,
239 self.width,
240 self.height,
241 self.padding,
242 self.spacing,
243 self.align_items,
244 &mut tree.children,
245 &mut self.children,
246 &mut state.cache,
247 );
248 }
249
250 fn operate(
251 &mut self,
252 tree: &mut Tree,
253 layout: Layout,
254 viewport: &Rectangle,
255 renderer: &Renderer,
256 operation: &mut dyn Operation,
257 ) {
258 operation.container(None, layout.bounds(), viewport);
259 operation.traverse(&mut |operation| {
260 self.children
261 .iter_mut()
262 .zip(layout.iter_mut(&mut tree.children))
263 .for_each(|(child, (layout, state))| {
264 child.operate(state, layout, viewport, renderer, operation);
265 });
266 });
267 }
268
269 fn update(
270 &mut self,
271 tree: &mut Tree,
272 event: &Event,
273 layout: Layout,
274 cursor: mouse::Cursor,
275 renderer: &Renderer,
276 shell: &mut Shell<'_, Message>,
277 viewport: &Rectangle,
278 ) {
279 for (child, (layout, tree)) in self
280 .children
281 .iter_mut()
282 .zip(layout.iter_mut(&mut tree.children))
283 {
284 child.update(tree, event, layout, cursor, renderer, shell, viewport);
285 }
286 }
287
288 fn mouse_interaction(
289 &self,
290 tree: &Tree,
291 layout: Layout,
292 cursor: mouse::Cursor,
293 viewport: &Rectangle,
294 renderer: &Renderer,
295 ) -> mouse::Interaction {
296 self.children
297 .iter()
298 .zip(layout.iter(&tree.children))
299 .map(|(child, (layout, tree))| {
300 child.mouse_interaction(tree, layout, cursor, viewport, renderer)
301 })
302 .max()
303 .unwrap_or_default()
304 }
305
306 fn draw(
307 &self,
308 tree: &Tree,
309 renderer: &mut Renderer,
310 theme: &Theme,
311 style: &renderer::Style,
312 layout: Layout,
313 cursor: mouse::Cursor,
314 viewport: &Rectangle,
315 ) {
316 for (child, (layout, state)) in self.children.iter().zip(layout.iter(&tree.children)) {
317 child.draw(state, renderer, theme, style, layout, cursor, viewport);
318 }
319 }
320
321 fn overlay<'b>(
322 &'b mut self,
323 tree: &'b mut Tree,
324 layout: Layout,
325 renderer: &Renderer,
326 viewport: &Rectangle,
327 translation: Vector,
328 window: Size,
329 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
330 overlay::from_children(
331 &mut self.children,
332 tree,
333 layout,
334 renderer,
335 viewport,
336 translation,
337 window,
338 )
339 }
340}