zng_app/widget/node/
adopt.rs

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