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///
20/// The [WidgetId] is equal to `maycoon-widgets:Container`.
21#[derive(Default)]
22pub struct Container {
23    style: MaybeSignal<LayoutStyle>,
24    children: Vec<BoxedWidget>,
25}
26
27impl Container {
28    /// Creates a new container with given children.
29    #[inline(always)]
30    pub fn new(children: Vec<BoxedWidget>) -> Self {
31        Self {
32            style: LayoutStyle::default().into(),
33            children: children.into_iter().collect(),
34        }
35    }
36}
37
38impl WidgetChildrenExt for Container {
39    #[inline(always)]
40    fn set_children(&mut self, children: Vec<BoxedWidget>) {
41        self.children = children.into_iter().collect();
42    }
43
44    #[inline(always)]
45    fn add_child(&mut self, child: impl Widget + 'static) {
46        self.children.push(Box::new(child));
47    }
48}
49
50impl WidgetLayoutExt for Container {
51    #[inline(always)]
52    fn set_layout_style(&mut self, layout_style: impl Into<MaybeSignal<LayoutStyle>>) {
53        self.style = layout_style.into();
54    }
55}
56
57impl Widget for Container {
58    #[inline(always)]
59    fn render(
60        &mut self,
61        scene: &mut dyn Scene,
62        theme: &mut dyn Theme,
63        layout_node: &LayoutNode,
64        info: &AppInfo,
65        context: AppContext,
66    ) {
67        for (i, child) in self.children.iter_mut().enumerate() {
68            child.render(
69                scene,
70                theme,
71                &layout_node.children[i],
72                info,
73                context.clone(),
74            );
75        }
76    }
77
78    #[inline(always)]
79    fn layout_style(&self) -> StyleNode {
80        let style = self.style.get().clone();
81
82        let mut children = Vec::with_capacity(self.children.len());
83
84        for child in &self.children {
85            children.push(child.layout_style());
86        }
87
88        StyleNode { style, children }
89    }
90
91    #[inline(always)]
92    fn update(&mut self, layout: &LayoutNode, context: AppContext, info: &AppInfo) -> Update {
93        let mut update = Update::empty();
94
95        for (i, child) in self.children.iter_mut().enumerate() {
96            update.insert(child.update(&layout.children[i], context.clone(), info));
97        }
98
99        update
100    }
101
102    #[inline(always)]
103    fn widget_id(&self) -> WidgetId {
104        WidgetId::new("maycoon-widgets", "Container")
105    }
106}