zng_wgt_panel/
lib.rs

1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3//!
4//! Panel widget and properties.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12zng_wgt::enable_widget_macros!();
13
14use zng_wgt::prelude::*;
15use zng_wgt_wrap::Wrap;
16
17/// Represents a dynamic layout panel.
18#[widget($crate::Panel)]
19pub struct Panel(WidgetBase);
20
21impl Panel {
22    fn widget_intrinsic(&mut self) {
23        self.widget_builder().push_build_action(|wgt| {
24            if let Some(p) = wgt.capture_property(property_id!(Self::children)) {
25                let list = p.args.ui_node(0).clone();
26                wgt.set_child(node(list, PANEL_FN_VAR));
27            } else {
28                wgt.set_child(node(ArcNode::new(ui_vec![]), PANEL_FN_VAR));
29            }
30        });
31    }
32}
33
34/// Panel items.
35#[property(CHILD, default(ui_vec![]), widget_impl(Panel))]
36pub fn children(wgt: &mut WidgetBuilding, children: impl IntoUiNode) {
37    let _ = children;
38    wgt.expect_property_capture();
39}
40
41context_var! {
42    /// Defines the layout widget for [`Panel!`].
43    ///
44    /// Is a [`Wrap!`] panel by default.
45    ///
46    /// [`Panel!`]: struct@Panel
47    /// [`Wrap!`]: struct@Wrap
48    pub static PANEL_FN_VAR: WidgetFn<PanelArgs> = wgt_fn!(|a: PanelArgs| {
49        Wrap! {
50            children = a.children;
51        }
52    });
53}
54
55/// Widget function that generates the panel layout widget.
56///
57/// This property can be set in any widget to affect all [`Panel!`] descendants.
58///
59/// This property sets [`PANEL_FN_VAR`].
60///
61/// [`Panel!`]: struct@Panel
62#[property(CONTEXT, default(PANEL_FN_VAR), widget_impl(Panel))]
63pub fn panel_fn(child: impl IntoUiNode, panel: impl IntoVar<WidgetFn<PanelArgs>>) -> UiNode {
64    with_context_var(child, PANEL_FN_VAR, panel)
65}
66
67/// Arguments for [`panel_fn`].
68///
69/// [`panel_fn`]: fn@panel_fn
70#[non_exhaustive]
71pub struct PanelArgs {
72    /// The panel children.
73    ///
74    /// Note that this is probably an [`ArcNode::take_on_init`] node so it may be empty until inited.
75    pub children: UiNode,
76}
77impl PanelArgs {
78    /// New args.
79    pub fn new(children: UiNode) -> Self {
80        Self { children }
81    }
82}
83
84/// Panel widget child node.
85pub fn node(children: ArcNode, panel_fn: impl IntoVar<WidgetFn<PanelArgs>>) -> UiNode {
86    let panel_fn = panel_fn.into_var();
87    match_node(UiNode::nil(), move |c, op| match op {
88        UiNodeOp::Init => {
89            WIDGET.sub_var(&panel_fn);
90            *c.node() = panel_fn.get().call(PanelArgs {
91                children: children.take_on_init(),
92            });
93            c.init();
94        }
95        UiNodeOp::Deinit => {
96            c.deinit();
97            *c.node() = UiNode::nil();
98        }
99        UiNodeOp::Update { updates } => {
100            if let Some(f) = panel_fn.get_new() {
101                c.deinit();
102                *c.node() = f(PanelArgs {
103                    children: children.take_on_init(),
104                });
105                c.init();
106            } else {
107                c.update(updates);
108            }
109        }
110        _ => {}
111    })
112}