zng_app/widget/node/
adopt.rs

1use parking_lot::Mutex;
2
3use super::*;
4use crate::widget::ui_node;
5use std::{mem, sync::Arc};
6
7/// Represents a node setup to dynamically swap child.
8///
9/// Any property node can be made adoptive by wrapping it with this node.
10pub struct AdoptiveNode<U> {
11    child: Arc<Mutex<BoxedUiNode>>,
12    node: U,
13    is_inited: bool,
14}
15impl<U: UiNode> AdoptiveNode<U> {
16    /// Create the adoptive node, the [`AdoptiveChildNode`] must be used as the child of the created node.
17    ///
18    /// The created node is assumed to not be inited.
19    pub fn new(create: impl FnOnce(AdoptiveChildNode) -> U) -> Self {
20        let ad_child = AdoptiveChildNode::nil();
21        let child = ad_child.child.clone();
22        let node = create(ad_child);
23        Self {
24            child,
25            node,
26            is_inited: false,
27        }
28    }
29
30    /// Create the adoptive node using a closure that can fail.
31    ///
32    /// The created node is assumed to not be inited.
33    pub fn try_new<E>(create: impl FnOnce(AdoptiveChildNode) -> Result<U, E>) -> Result<Self, E> {
34        let ad_child = AdoptiveChildNode::nil();
35        let child = ad_child.child.clone();
36        let node = create(ad_child)?;
37        Ok(Self {
38            child,
39            node,
40            is_inited: false,
41        })
42    }
43
44    /// Replaces the child node.
45    ///
46    /// Returns the previous child, the initial child is a [`NilUiNode`].
47    ///
48    /// # Panics
49    ///
50    /// Panics if [`is_inited`](Self::is_inited).
51    pub fn replace_child(&mut self, new_child: impl UiNode) -> BoxedUiNode {
52        assert!(!self.is_inited);
53        mem::replace(&mut *self.child.lock(), new_child.boxed())
54    }
55
56    /// Returns `true` if this node is inited.
57    pub fn is_inited(&self) -> bool {
58        self.is_inited
59    }
60
61    /// Into child reference and node.
62    ///
63    /// # Panics
64    ///
65    /// Panics if [`is_inited`](Self::is_inited).
66    pub fn into_parts(self) -> (Arc<Mutex<BoxedUiNode>>, U) {
67        assert!(!self.is_inited);
68        (self.child, self.node)
69    }
70
71    /// From parts, assumes the nodes are not inited and that `child` is the actual child of `node`.
72    pub fn from_parts(child: Arc<Mutex<BoxedUiNode>>, node: U) -> Self {
73        Self {
74            child,
75            node,
76            is_inited: false,
77        }
78    }
79}
80#[ui_node(delegate = &mut self.node)]
81impl<U: UiNode> UiNode for AdoptiveNode<U> {
82    fn init(&mut self) {
83        self.is_inited = true;
84        self.node.init();
85    }
86    fn deinit(&mut self) {
87        self.is_inited = false;
88        self.node.deinit();
89    }
90}
91
92/// Placeholder for the dynamic child of an adoptive node.
93///
94/// This node must be used as the child of the adoptive node, see [`AdoptiveNode::new`] for more details.
95pub struct AdoptiveChildNode {
96    child: Arc<Mutex<BoxedUiNode>>,
97}
98impl AdoptiveChildNode {
99    fn nil() -> Self {
100        Self {
101            child: Arc::new(Mutex::new(NilUiNode.boxed())),
102        }
103    }
104}
105#[ui_node(delegate = self.child.lock())]
106impl UiNode for AdoptiveChildNode {}