Skip to main content

pax_runtime/engine/
node_interface.rs

1use std::rc::Rc;
2
3use pax_manifest::UniqueTemplateNodeIdentifier;
4use pax_runtime_api::LocalProperty;
5use pax_runtime_api::{borrow, pax_value::ToFromPaxAny, Interpolatable};
6
7use crate::{
8    api::{math::Space, Window},
9    ExpandedNode, LayoutHull, LayoutProperties, TransformAndBounds,
10};
11use crate::{ExpandedNodeIdentifier, InstanceFlags};
12
13impl Interpolatable for NodeInterface {}
14
15impl PartialEq for NodeInterface {
16    fn eq(&self, other: &Self) -> bool {
17        self.inner.id.eq(&other.inner.id)
18    }
19}
20
21impl Eq for NodeInterface {}
22
23impl PartialOrd for NodeInterface {
24    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
25        self.inner.id.partial_cmp(&other.inner.id)
26    }
27}
28
29impl Ord for NodeInterface {
30    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
31        self.inner.id.cmp(&other.inner.id)
32    }
33}
34
35#[derive(Clone)]
36/// Runtime inspection handle for an expanded node.
37pub struct NodeInterface {
38    inner: Rc<ExpandedNode>,
39}
40
41impl From<Rc<ExpandedNode>> for NodeInterface {
42    fn from(expanded_node: Rc<ExpandedNode>) -> Self {
43        Self {
44            inner: expanded_node,
45        }
46    }
47}
48
49impl std::fmt::Debug for NodeInterface {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "NodeInterface({:?})", self.inner)
52    }
53}
54
55/// Marker coordinate space for a node's local layout space.
56pub struct NodeLocal;
57
58impl Space for NodeLocal {}
59
60impl NodeInterface {
61    /// Compiler-global template id for this node, if it originated from a template node.
62    pub fn global_id(&self) -> Option<UniqueTemplateNodeIdentifier> {
63        let instance_node = borrow!(self.inner.instance_node);
64        let base = instance_node.base();
65        base.template_node_identifier.clone()
66    }
67
68    /// Runtime-expanded id for this concrete node.
69    pub fn engine_id(&self) -> ExpandedNodeIdentifier {
70        self.inner.id.clone()
71    }
72
73    /// Current layout properties after common-property collection.
74    pub fn layout_properties(&self) -> LayoutProperties {
75        self.inner.layout_properties().get()
76    }
77
78    /// Measured bounds reported by a native or text-backed node.
79    pub fn measured_size(&self) -> Option<(f64, f64)> {
80        self.inner.measured_size.get()
81    }
82
83    /// Node-local subtree hull published by the engine for container measurement.
84    pub fn subtree_layout_hull(&self) -> LocalProperty<LayoutHull> {
85        self.inner.subtree_layout_hull.clone()
86    }
87
88    #[deprecated(note = "use measured_size() instead")]
89    pub fn autosize(&self) -> Option<(f64, f64)> {
90        self.measured_size()
91    }
92
93    /// Borrow the node's typed property object if it has the requested type.
94    pub fn with_properties<V, T: ToFromPaxAny>(&self, f: impl FnOnce(&mut T) -> V) -> Option<V> {
95        self.inner.try_with_properties_unwrapped(|tp: &mut T| f(tp))
96    }
97
98    /// Check whether the node's property object is of type `T`.
99    pub fn is_of_type<T: ToFromPaxAny>(&self) -> bool {
100        self.inner
101            .try_with_properties_unwrapped::<T, _>(|_| ())
102            .is_some()
103    }
104
105    /// Static flags from the node's instance.
106    pub fn instance_flags(&self) -> InstanceFlags {
107        let instance_node = borrow!(self.inner.instance_node);
108        let base = instance_node.base();
109        base.flags().clone()
110    }
111
112    /// Test the template `id` common property.
113    pub fn has_id(&self, id: &str) -> bool {
114        let cp = borrow!(self.inner.common_properties);
115        let cp = borrow!(&*cp);
116        cp.id.read(|i| i.as_ref().is_some_and(|i| i == id))
117    }
118
119    /// Reactive transform-and-bounds property for this node.
120    pub fn transform_and_bounds(&self) -> LocalProperty<TransformAndBounds<NodeLocal, Window>> {
121        self.inner.transform_and_bounds.clone()
122    }
123
124    /// Parent in render traversal order.
125    pub fn render_parent(&self) -> Option<NodeInterface> {
126        let parent = borrow!(self.inner.render_parent);
127        Some(parent.upgrade()?.into())
128    }
129
130    /// Containing component for template scoping and slot ownership.
131    pub fn containing_component(&self) -> Option<NodeInterface> {
132        Some(self.inner.containing_component.upgrade()?.into())
133    }
134
135    /// Parent in template ownership order.
136    pub fn template_parent(&self) -> Option<NodeInterface> {
137        Some(self.inner.template_parent.upgrade()?.into())
138    }
139
140    /// True if this node is below `node` in the template-parent chain.
141    pub fn is_descendant_of(&self, node: &NodeInterface) -> bool {
142        self.inner.is_descendant_of(&node.inner.id)
143    }
144
145    /// Mounted child nodes.
146    pub fn children(&self) -> Vec<NodeInterface> {
147        let children = borrow!(self.inner.mounted_children);
148        (&*children)
149            .into_iter()
150            .map(Rc::clone)
151            .map(Into::into)
152            .collect()
153    }
154
155    /// Reactive count of slot children after repeat/conditional flattening.
156    pub fn flattened_projected_children_count(&self) -> LocalProperty<usize> {
157        self.inner.flattened_projected_children_count.clone()
158    }
159}