maycoon_widgets/
container.rs

1use maycoon_core::app::context::AppContext;
2use maycoon_core::app::info::AppInfo;
3use maycoon_core::app::update::Update;
4use maycoon_core::layout::{LayoutNode, LayoutStyle, StyleNode};
5use maycoon_core::signal::MaybeSignal;
6use maycoon_core::vgi::Scene;
7use maycoon_core::widget::{BoxedWidget, Widget, WidgetChildrenExt, WidgetLayoutExt};
8use maycoon_theme::id::WidgetId;
9use maycoon_theme::theme::Theme;
10
11/// A container widget that can display and layout multiple child widgets.
12///
13/// The layout of the children (row, column, etc.) depends on the [LayoutStyle] of the container.
14///
15/// See the [counter](https://github.com/maycoon-ui/maycoon/blob/master/examples/counter/src/main.rs) example for how to use it in practice.
16///
17/// ### Theming
18/// The container widget doesn't actually draw anything but the child widgets, so theming is useless.
19#[derive(Default)]
20pub struct Container {
21    style: MaybeSignal<LayoutStyle>,
22    children: Vec<BoxedWidget>,
23}
24
25impl Container {
26    /// Creates a new container with given children.
27    pub fn new(children: Vec<BoxedWidget>) -> Self {
28        Self {
29            style: LayoutStyle::default().into(),
30            children: children.into_iter().collect(),
31        }
32    }
33}
34
35impl WidgetChildrenExt for Container {
36    fn set_children(&mut self, children: Vec<BoxedWidget>) {
37        self.children = children.into_iter().collect();
38    }
39
40    fn add_child(&mut self, child: impl Widget + 'static) {
41        self.children.push(Box::new(child));
42    }
43}
44
45impl WidgetLayoutExt for Container {
46    fn set_layout_style(&mut self, layout_style: impl Into<MaybeSignal<LayoutStyle>>) {
47        self.style = layout_style.into();
48    }
49}
50
51impl Widget for Container {
52    fn render(
53        &mut self,
54        scene: &mut dyn Scene,
55        theme: &mut dyn Theme,
56        layout_node: &LayoutNode,
57        info: &AppInfo,
58        context: AppContext,
59    ) {
60        for (i, child) in self.children.iter_mut().enumerate() {
61            child.render(
62                scene,
63                theme,
64                &layout_node.children[i],
65                info,
66                context.clone(),
67            );
68        }
69    }
70
71    fn layout_style(&self) -> StyleNode {
72        let style = self.style.get().clone();
73
74        let mut children = Vec::with_capacity(self.children.len());
75
76        for child in &self.children {
77            children.push(child.layout_style());
78        }
79
80        StyleNode { style, children }
81    }
82
83    fn update(&mut self, layout: &LayoutNode, context: AppContext, info: &AppInfo) -> Update {
84        let mut update = Update::empty();
85
86        for (i, child) in self.children.iter_mut().enumerate() {
87            update.insert(child.update(&layout.children[i], context.clone(), info));
88        }
89
90        update
91    }
92
93    fn widget_id(&self) -> WidgetId {
94        WidgetId::new("maycoon-widgets", "Container")
95    }
96}