zng_app/widget/node/adopt.rs
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 {}