1use crate::{
2 component::{IntoParameter, Parameter, RenderCtx, Renderer},
3 layout::{Bounds, Padding, Size},
4 CharmResult, Color, Component,
5};
6
7pub struct VStack<Store> {
8 children: Vec<Box<dyn Component<Store>>>,
9 size: Option<Parameter<Size, Store>>,
10 padding: Option<Parameter<Padding, Store>>,
11 background: Option<Parameter<Color, Store>>,
12}
13
14impl<Store> VStack<Store> {
15 pub fn new() -> Self {
16 Self {
17 children: Vec::new(),
18 size: None,
19 padding: None,
20 background: None,
21 }
22 }
23
24 pub fn add_child<C>(mut self, component: C) -> Self
25 where
26 C: Component<Store> + 'static,
27 {
28 self.children.push(Box::new(component));
29
30 self
31 }
32
33 pub fn size(mut self, size: Parameter<Size, Store>) -> Self {
34 self.size = Some(size);
35
36 self
37 }
38
39 pub fn padding(mut self, padding: Parameter<Padding, Store>) -> Self {
40 self.padding = Some(padding);
41
42 self
43 }
44
45 pub fn background(mut self, fill: Parameter<Color, Store>) -> Self {
46 self.background = Some(fill);
47
48 self
49 }
50}
51
52impl<Store> Component<Store> for VStack<Store> {
53 fn render<'a>(&self, ctx: RenderCtx, r: &mut Renderer, store: &Store) -> CharmResult<Bounds> {
54 let Bounds { x, y, .. } = ctx.bounds.clone();
55 let Size { width, height } = self
56 .size
57 .as_ref()
58 .map(|s| s.resolve(store))
59 .unwrap_or(ctx.bounds.into());
60
61 if let Some(ref background_fill) = self.background {
62 r.fill_rect((x, y, width, height), background_fill.resolve(&store))?;
63 }
64
65 let mut child_ctx = ctx.clone();
66 child_ctx.bounds.width = width;
67 child_ctx.bounds.height = height;
68
69 if let Some(ref padding) = self.padding {
70 let padding = padding.resolve(&store);
71 child_ctx.bounds.x += padding.left;
72 child_ctx.bounds.y += padding.top;
73 child_ctx.bounds.width -= padding.left + padding.right;
74 child_ctx.bounds.height -= padding.top + padding.bottom;
75 }
76
77 for child in &self.children {
78 let bounds = child.render(child_ctx.clone(), r, &store)?;
79
80 child_ctx.bounds.y += bounds.height;
81 child_ctx.bounds.height -= bounds.height;
82 }
83
84 Ok(Bounds {
85 x,
86 y,
87 width,
88 height,
89 })
90 }
91}