zng_app/widget/node/
extend.rs

1use std::sync::Arc;
2
3use parking_lot::Mutex;
4use zng_app_proc_macros::ui_node;
5
6use crate::widget::WidgetUpdateMode;
7
8use super::*;
9
10/// Create a widget node that wraps the `widget` with any number of other non-widget nodes and
11/// still delegates [`with_context`] to the `widget`.
12///
13/// Note that the [`with_context`] is called in the context of `widget`, not in the context of the `build_extension` nodes.
14/// Other node operations are delegated to the `build_extension` nodes, and they in turn must delegate to the input child
15/// node that is `widget`.
16///
17/// [`with_context`]: UiNode::with_context
18pub fn extend_widget(widget: impl UiNode, build_extension: impl FnOnce(BoxedUiNode) -> BoxedUiNode) -> impl UiNode {
19    let widget = Arc::new(Mutex::new(widget.boxed()));
20    let child = build_extension(ExtendWidgetChildNode { widget: widget.clone() }.boxed());
21    ExtendWidgetNode { widget, child }
22}
23
24struct ExtendWidgetChildNode {
25    widget: Arc<Mutex<BoxedUiNode>>,
26}
27#[ui_node(delegate = self.widget.lock())]
28impl UiNode for ExtendWidgetChildNode {
29    fn is_widget(&self) -> bool {
30        self.widget.lock().is_widget()
31    }
32
33    fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
34    where
35        F: FnOnce() -> R,
36    {
37        self.widget.lock().with_context(update_mode, f)
38    }
39}
40
41struct ExtendWidgetNode {
42    widget: Arc<Mutex<BoxedUiNode>>,
43    child: BoxedUiNode,
44}
45#[ui_node(child)]
46impl UiNode for ExtendWidgetNode {
47    fn is_widget(&self) -> bool {
48        self.widget.lock().is_widget()
49    }
50
51    fn with_context<R, F>(&mut self, update_mode: WidgetUpdateMode, f: F) -> Option<R>
52    where
53        F: FnOnce() -> R,
54    {
55        self.widget.lock().with_context(update_mode, f)
56    }
57}