1use std::rc::{Rc, Weak};
2
3use_RefCell!();
4use crate::{
5 node_interface::NodeLocal, ExpandedNode, RuntimeContext, RuntimePropertiesStackFrame,
6 TransformAndBounds,
7};
8
9pub use pax_runtime_api::*;
10use pax_runtime_api::{cursor::CursorStyle, math::Point2, properties::UntypedProperty};
11
12use crate::node_interface::NodeInterface;
13#[cfg(feature = "designtime")]
14use {pax_designtime::DesigntimeManager, pax_manifest::UniqueTemplateNodeIdentifier};
15
16#[derive(Clone)]
17pub struct NodeContext {
18 pub expanded_node: Weak<ExpandedNode>,
19 pub slot_index: Property<Option<usize>>,
21 pub local_stack_frame: Rc<RuntimePropertiesStackFrame>,
23 pub containing_component: Weak<ExpandedNode>,
25 pub frames_elapsed: Property<u64>,
27 pub bounds_parent: Property<(f64, f64)>,
29 pub bounds_self: Property<(f64, f64)>,
31 pub platform: Platform,
33 pub os: OS,
35 pub slot_children_count: Property<usize>,
37 pub(crate) runtime_context: Rc<RuntimeContext>,
39 pub node_transform_and_bounds: TransformAndBounds<NodeLocal, Window>,
41 pub slot_children: Property<Vec<Rc<ExpandedNode>>>,
43 pub slot_children_attached_listener: Property<()>,
45
46 #[cfg(feature = "designtime")]
47 pub designtime: Rc<RefCell<DesigntimeManager>>,
48 pub(crate) get_elapsed_millis: Rc<dyn Fn() -> u128>,
49}
50
51impl NodeContext {
52 pub fn push_local_store<T: Store>(&self, store: T) {
53 self.local_stack_frame.insert_stack_local_store(store);
54 }
55
56 pub fn peek_local_store<T: Store, V>(&self, f: impl FnOnce(&mut T) -> V) -> Result<V, String> {
57 self.local_stack_frame.peek_stack_local_store(f)
58 }
59
60 pub fn local_point(&self, p: Point2<Window>) -> Point2<NodeLocal> {
61 self.node_transform_and_bounds.as_transform().inverse() * p
62 }
63
64 pub fn get_node_interface(&self) -> Option<NodeInterface> {
65 Weak::upgrade(&self.containing_component).map(|v| v.into())
66 }
67
68 pub fn elapsed_time_millis(&self) -> u128 {
70 (self.get_elapsed_millis)()
71 }
72
73 pub fn subscribe(&self, dependencies: &[UntypedProperty], f: impl Fn() + 'static) {
74 let subscription_prop = Property::computed(f, dependencies);
75 match self.expanded_node.upgrade() {
76 Some(expanded_node) => borrow_mut!(expanded_node.subscriptions).push(subscription_prop),
77 None => log::warn!("couldn't add subscription: node doesn't exist anymore"),
78 }
79 }
80
81 pub fn clear_subscriptions(&self) {
82 match self.expanded_node.upgrade() {
83 Some(expanded_node) => borrow_mut!(expanded_node.subscriptions).clear(),
84 None => log::warn!("couldn't clear subscriptions: node doesn't exist anymore"),
85 }
86 }
87
88 pub fn navigate_to(&self, url: &str, target: NavigationTarget) {
89 self.runtime_context
90 .enqueue_native_message(NativeMessage::Navigate(NavigationPatch {
91 url: url.to_string(),
92 target: match target {
93 NavigationTarget::Current => "current",
94 NavigationTarget::New => "new",
95 }
96 .to_string(),
97 }))
98 }
99
100 pub fn dispatch_event(&self, identifier: &'static str) -> Result<(), String> {
101 let component_origin = self
102 .containing_component
103 .upgrade()
104 .ok_or_else(|| "can't dispatch from root component".to_owned())?;
105
106 {
108 let component_origin_instance = borrow!(component_origin.instance_node);
109 let registry = component_origin_instance
110 .base()
111 .handler_registry
112 .as_ref()
113 .ok_or_else(|| "no registry present".to_owned())?;
114 borrow!(registry).handlers.get(identifier).ok_or_else(|| {
115 format!("no registered handler with name \"{}\" exists", identifier)
116 })?;
117 }
118
119 self.runtime_context
121 .queue_custom_event(Rc::clone(&component_origin), identifier);
122
123 Ok(())
124 }
125
126 pub fn set_cursor(&self, cursor: CursorStyle) {
127 self.runtime_context
128 .enqueue_native_message(NativeMessage::SetCursor(SetCursorPatch {
129 cursor: cursor.to_string(),
130 }));
131 }
132}
133
134#[cfg(feature = "designtime")]
135impl NodeContext {
136 pub fn raycast(&self, point: Point2<Window>, hit_invisible: bool) -> Vec<NodeInterface> {
137 let expanded_nodes = self.runtime_context.get_elements_beneath_ray(
138 self.runtime_context.get_userland_root_expanded_node(),
139 point,
140 false,
141 vec![],
142 hit_invisible,
143 );
144 expanded_nodes
145 .into_iter()
146 .map(Into::<NodeInterface>::into)
147 .collect()
148 }
149
150 pub fn get_nodes_by_global_id(&self, uni: UniqueTemplateNodeIdentifier) -> Vec<NodeInterface> {
151 let expanded_nodes = self.runtime_context.get_expanded_nodes_by_global_ids(&uni);
152 expanded_nodes
153 .into_iter()
154 .map(Into::<NodeInterface>::into)
155 .collect()
156 }
157
158 pub fn get_userland_root_expanded_node(&self) -> Option<NodeInterface> {
159 #[cfg(feature = "designtime")]
160 let expanded_node = self.runtime_context.get_userland_root_expanded_node()?;
161 #[cfg(not(feature = "designtime"))]
162 let expanded_node = self.runtime_context.get_root_expanded_node()?;
163 Some(expanded_node.into())
164 }
165
166 pub fn get_root_expanded_node(&self) -> Option<NodeInterface> {
167 let expanded_node = self.runtime_context.get_root_expanded_node()?;
168 Some(expanded_node.into())
169 }
170
171 pub fn get_nodes_by_id(&self, id: &str) -> Vec<NodeInterface> {
172 let expanded_nodes = self.runtime_context.get_expanded_nodes_by_id(id);
173 expanded_nodes
174 .into_iter()
175 .map(Into::<NodeInterface>::into)
176 .collect()
177 }
178}