1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use parking_lot::Mutex;

use super::*;
use crate::widget::ui_node;
use std::{mem, sync::Arc};

/// Represents a node setup to dynamically swap child.
///
/// Any property node can be made adoptive by wrapping it with this node.
pub struct AdoptiveNode<U> {
    child: Arc<Mutex<BoxedUiNode>>,
    node: U,
    is_inited: bool,
}
impl<U: UiNode> AdoptiveNode<U> {
    /// Create the adoptive node, the [`AdoptiveChildNode`] must be used as the child of the created node.
    ///
    /// The created node is assumed to not be inited.
    pub fn new(create: impl FnOnce(AdoptiveChildNode) -> U) -> Self {
        let ad_child = AdoptiveChildNode::nil();
        let child = ad_child.child.clone();
        let node = create(ad_child);
        Self {
            child,
            node,
            is_inited: false,
        }
    }

    /// Create the adoptive node using a closure that can fail.
    ///
    /// The created node is assumed to not be inited.
    pub fn try_new<E>(create: impl FnOnce(AdoptiveChildNode) -> Result<U, E>) -> Result<Self, E> {
        let ad_child = AdoptiveChildNode::nil();
        let child = ad_child.child.clone();
        let node = create(ad_child)?;
        Ok(Self {
            child,
            node,
            is_inited: false,
        })
    }

    /// Replaces the child node.
    ///
    /// Returns the previous child, the initial child is a [`NilUiNode`].
    ///
    /// # Panics
    ///
    /// Panics if [`is_inited`](Self::is_inited).
    pub fn replace_child(&mut self, new_child: impl UiNode) -> BoxedUiNode {
        assert!(!self.is_inited);
        mem::replace(&mut *self.child.lock(), new_child.boxed())
    }

    /// Returns `true` if this node is inited.
    pub fn is_inited(&self) -> bool {
        self.is_inited
    }

    /// Into child reference and node.
    ///
    /// # Panics
    ///
    /// Panics if [`is_inited`](Self::is_inited).
    pub fn into_parts(self) -> (Arc<Mutex<BoxedUiNode>>, U) {
        assert!(!self.is_inited);
        (self.child, self.node)
    }

    /// From parts, assumes the nodes are not inited and that `child` is the actual child of `node`.
    pub fn from_parts(child: Arc<Mutex<BoxedUiNode>>, node: U) -> Self {
        Self {
            child,
            node,
            is_inited: false,
        }
    }
}
#[ui_node(delegate = &mut self.node)]
impl<U: UiNode> UiNode for AdoptiveNode<U> {
    fn init(&mut self) {
        self.is_inited = true;
        self.node.init();
    }
    fn deinit(&mut self) {
        self.is_inited = false;
        self.node.deinit();
    }
}

/// Placeholder for the dynamic child of an adoptive node.
///
/// This node must be used as the child of the adoptive node, see [`AdoptiveNode::new`] for more details.
pub struct AdoptiveChildNode {
    child: Arc<Mutex<BoxedUiNode>>,
}
impl AdoptiveChildNode {
    fn nil() -> Self {
        Self {
            child: Arc::new(Mutex::new(NilUiNode.boxed())),
        }
    }
}
#[ui_node(delegate = self.child.lock())]
impl UiNode for AdoptiveChildNode {}