zng_wgt_panel/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/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_list(0).clone();
26                wgt.set_child(node(list, PANEL_FN_VAR));
27            } else {
28                wgt.set_child(node(ArcNodeList::new(ui_vec![].boxed()), PANEL_FN_VAR));
29            }
30        });
31    }
32}
33
34/// Panel items.
35#[property(CHILD, capture, default(ui_vec![]), widget_impl(Panel))]
36pub fn children(children: impl UiNodeList) {}
37
38context_var! {
39    /// Defines the layout widget for [`Panel!`].
40    ///
41    /// Is a [`Wrap!`] panel by default.
42    ///
43    /// [`Panel!`]: struct@Panel
44    /// [`Wrap!`]: struct@Wrap
45    pub static PANEL_FN_VAR: WidgetFn<PanelArgs> = wgt_fn!(|a: PanelArgs| {
46        Wrap! {
47            children = a.children;
48        }
49    });
50}
51
52/// Widget function that generates the panel layout widget.
53///
54/// This property can be set in any widget to affect all [`Panel!`] descendants.
55///
56/// This property sets [`PANEL_FN_VAR`].
57///
58/// [`Panel!`]: struct@Panel
59#[property(CONTEXT, default(PANEL_FN_VAR), widget_impl(Panel))]
60pub fn panel_fn(child: impl UiNode, panel: impl IntoVar<WidgetFn<PanelArgs>>) -> impl UiNode {
61    with_context_var(child, PANEL_FN_VAR, panel)
62}
63
64/// Arguments for [`panel_fn`].
65///
66/// [`panel_fn`]: fn@panel_fn
67pub struct PanelArgs {
68    /// The panel children.
69    ///
70    /// Note that this is probably an [`ArcNodeList`] take-on-init list so it may be empty until inited.
71    ///
72    /// [`ArcNodeList`]: zng_wgt::prelude::ArcNodeList
73    pub children: BoxedUiNodeList,
74}
75
76/// Panel widget child node.
77pub fn node(children: ArcNodeList<BoxedUiNodeList>, panel_fn: impl IntoVar<WidgetFn<PanelArgs>>) -> impl UiNode {
78    let mut child = NilUiNode.boxed();
79    let panel_fn = panel_fn.into_var();
80    match_node_leaf(move |op| match op {
81        UiNodeOp::Init => {
82            WIDGET.sub_var(&panel_fn);
83            child = panel_fn.get().call(PanelArgs {
84                children: children.take_on_init().boxed(),
85            });
86            child.init();
87        }
88        UiNodeOp::Deinit => {
89            child.deinit();
90            child = NilUiNode.boxed();
91        }
92        UiNodeOp::Update { updates } => {
93            if let Some(f) = panel_fn.get_new() {
94                child.deinit();
95                child = f(PanelArgs {
96                    children: children.take_on_init().boxed(),
97                });
98                child.init();
99            } else {
100                child.update(updates);
101            }
102        }
103        op => child.op(op),
104    })
105}