1use crate::api::math::Point2;
2use crate::api::Window;
3use pax_lang::interpreter::property_resolution::IdentifierResolver;
4use pax_manifest::UniqueTemplateNodeIdentifier;
5use pax_message::NativeMessage;
6use pax_runtime_api::pax_value::PaxAny;
7use pax_runtime_api::properties::UntypedProperty;
8use pax_runtime_api::{
9 borrow, borrow_mut, use_RefCell, Event, Interpolatable, MouseOut, MouseOver, PaxValue,
10 RenderContext, Store, Variable,
11};
12use_RefCell!();
13use std::any::{Any, TypeId};
14use std::cell::Cell;
15use std::collections::HashMap;
16use std::hash::Hash;
17use std::rc::{Rc, Weak};
18
19use crate::{ExpandedNode, Globals};
20
21#[cfg(feature = "designtime")]
22use crate::{ComponentInstance, InstanceNode};
23
24impl Interpolatable for ExpandedNodeIdentifier {}
25
26#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub struct ExpandedNodeIdentifier(pub u32);
28
29impl ExpandedNodeIdentifier {
30 pub fn to_u32(&self) -> u32 {
32 self.0
33 }
34}
35
36pub struct RuntimeContext {
38 next_uid: Cell<ExpandedNodeIdentifier>,
39 messages: RefCell<Vec<NativeMessage>>,
40 globals: RefCell<Globals>,
41 root_expanded_node: RefCell<Weak<ExpandedNode>>,
42 #[cfg(feature = "designtime")]
43 pub userland_frame_instance_node: RefCell<Rc<dyn InstanceNode>>,
44 #[cfg(feature = "designtime")]
45 pub userland_root_expanded_node: RefCell<Option<Rc<ExpandedNode>>>,
46 node_cache: RefCell<NodeCache>,
47 last_topmost_element: RefCell<Weak<ExpandedNode>>,
48 queued_custom_events: RefCell<Vec<(Rc<ExpandedNode>, &'static str)>>,
49 queued_renders: RefCell<Vec<Rc<ExpandedNode>>>,
50 pub layer_count: Cell<usize>,
51 pub dirty_canvases: RefCell<Vec<bool>>,
52}
53
54struct NodeCache {
55 eid_to_node: HashMap<ExpandedNodeIdentifier, Rc<ExpandedNode>>,
56 uni_to_eid: HashMap<UniqueTemplateNodeIdentifier, Vec<ExpandedNodeIdentifier>>,
57}
58
59impl NodeCache {
60 fn new() -> Self {
61 Self {
62 eid_to_node: Default::default(),
63 uni_to_eid: Default::default(),
64 }
65 }
66
67 fn add_to_cache(&mut self, node: &Rc<ExpandedNode>) {
69 self.eid_to_node.insert(node.id, Rc::clone(&node));
70 let uni = borrow!(node.instance_node)
71 .base()
72 .template_node_identifier
73 .clone();
74 if let Some(uni) = uni {
75 self.uni_to_eid.entry(uni).or_default().push(node.id);
76 }
77 }
78
79 fn remove_from_cache(&mut self, node: &Rc<ExpandedNode>) {
81 self.eid_to_node.remove(&node.id);
82 if let Some(uni) = &borrow!(node.instance_node).base().template_node_identifier {
83 self.uni_to_eid
84 .entry(uni.clone())
85 .or_default()
86 .retain(|&n| n != node.id);
87 }
88 }
89}
90
91impl RuntimeContext {
92 #[cfg(not(feature = "designtime"))]
93 pub fn new(globals: Globals) -> Self {
94 Self {
95 next_uid: Cell::new(ExpandedNodeIdentifier(0)),
96 messages: RefCell::new(Vec::new()),
97 globals: RefCell::new(globals),
98 root_expanded_node: RefCell::new(Weak::new()),
99 node_cache: RefCell::new(NodeCache::new()),
100 queued_custom_events: Default::default(),
101 queued_renders: Default::default(),
102 layer_count: Cell::default(),
103 last_topmost_element: Default::default(),
104 dirty_canvases: Default::default(),
105 }
106 }
107
108 #[cfg(feature = "designtime")]
109 pub fn new(globals: Globals, userland: Rc<ComponentInstance>) -> Self {
110 Self {
111 next_uid: Cell::new(ExpandedNodeIdentifier(0)),
112 messages: RefCell::new(Vec::new()),
113 globals: RefCell::new(globals),
114 root_expanded_node: RefCell::new(Weak::new()),
115 userland_frame_instance_node: RefCell::new(userland),
116 userland_root_expanded_node: Default::default(),
117 node_cache: RefCell::new(NodeCache::new()),
118 queued_custom_events: Default::default(),
119 queued_renders: Default::default(),
120 layer_count: Cell::default(),
121 last_topmost_element: Default::default(),
122 dirty_canvases: Default::default(),
123 }
124 }
125
126 pub fn register_root_expanded_node(&self, root: &Rc<ExpandedNode>) {
127 *borrow_mut!(self.root_expanded_node) = Rc::downgrade(root);
128 }
129
130 pub fn add_to_cache(&self, node: &Rc<ExpandedNode>) {
131 borrow_mut!(self.node_cache).add_to_cache(node);
132 }
133
134 pub fn remove_from_cache(&self, node: &Rc<ExpandedNode>) {
135 borrow_mut!(self.node_cache).remove_from_cache(node);
136 }
137
138 pub fn get_expanded_node_by_eid(&self, id: ExpandedNodeIdentifier) -> Option<Rc<ExpandedNode>> {
139 borrow!(self.node_cache).eid_to_node.get(&id).cloned()
140 }
141
142 pub fn add_canvas(&self, id: usize) {
143 let mut dirty_canvases = borrow_mut!(self.dirty_canvases);
144 while dirty_canvases.len() <= id + 1 {
145 dirty_canvases.push(true);
146 }
147 }
148
149 pub fn remove_canvas(&self, id: usize) {
150 let mut dirty_canvases = borrow_mut!(self.dirty_canvases);
151 while dirty_canvases.len() > id {
152 dirty_canvases.pop();
153 }
154 }
155
156 pub fn get_dirty_canvases(&self) -> Vec<usize> {
157 borrow!(self.dirty_canvases)
158 .iter()
159 .enumerate()
160 .filter_map(|(i, v)| if *v { Some(i) } else { None })
161 .collect()
162 }
163
164 pub fn clear_all_dirty_canvases(&self) {
165 let mut dirty_canvases = borrow_mut!(self.dirty_canvases);
166 for v in dirty_canvases.iter_mut() {
167 *v = false;
168 }
169 }
170
171 pub fn set_canvas_dirty(&self, id: usize) {
172 let mut dirty_canvases = borrow_mut!(self.dirty_canvases);
173 if let Some(v) = dirty_canvases.get_mut(id) {
174 *v = true;
175 }
176 }
177
178 pub fn is_canvas_dirty(&self, id: &usize) -> bool {
179 *borrow!(self.dirty_canvases).get(*id).unwrap_or(&false)
180 }
181
182 pub fn set_all_canvases_dirty(&self) {
183 let mut dirty_canvases = borrow_mut!(self.dirty_canvases);
184 for v in dirty_canvases.iter_mut() {
185 *v = true;
186 }
187 }
188
189 pub fn get_expanded_nodes_by_id(&self, id: &str) -> Vec<Rc<ExpandedNode>> {
191 borrow!(self.node_cache)
193 .eid_to_node
194 .values()
195 .filter(|val| {
196 let common_props = val.get_common_properties();
197 let common_props = borrow!(common_props);
198 common_props.id.get().is_some_and(|i| i == id)
199 })
200 .cloned()
201 .collect()
202 }
203
204 pub fn get_expanded_nodes_by_global_ids(
206 &self,
207 uni: &UniqueTemplateNodeIdentifier,
208 ) -> Vec<Rc<ExpandedNode>> {
209 let node_cache = borrow!(self.node_cache);
210 node_cache
211 .uni_to_eid
212 .get(uni)
213 .map(|eids| {
214 let mut nodes = vec![];
215 for e in eids {
216 nodes.extend(
217 node_cache
218 .eid_to_node
219 .get(e)
220 .map(|node| vec![Rc::clone(node)])
221 .unwrap_or_default(),
222 )
223 }
224 nodes
225 })
226 .unwrap_or_default()
227 }
228
229 pub fn get_elements_beneath_ray(
234 &self,
235 root: Option<Rc<ExpandedNode>>,
236 ray: Point2<Window>,
237 limit_one: bool,
238 mut accum: Vec<Rc<ExpandedNode>>,
239 hit_invisible: bool,
240 ) -> Vec<Rc<ExpandedNode>> {
241 let root_node = root.unwrap_or_else(|| borrow!(self.root_expanded_node).upgrade().unwrap());
247 let mut to_process = vec![(root_node, false)];
248 while let Some((node, clipped)) = to_process.pop() {
249 node.compute_flattened_slot_children();
251 let hit = node.ray_cast_test(ray);
252 if hit && !clipped {
253 if hit_invisible
254 || !borrow!(node.instance_node)
255 .base()
256 .flags()
257 .invisible_to_raycasting
258 {
259 if limit_one {
263 return vec![node];
264 }
265 accum.push(Rc::clone(&node));
266 }
267 }
268 let clipped = clipped || (!hit && borrow!(node.instance_node).clips_content(&node));
269 to_process.extend(
270 node.children
271 .get()
272 .iter()
273 .cloned()
274 .map(|v| {
275 let cp = v.get_common_properties();
276 let unclippable = borrow!(cp).unclippable.get().unwrap_or(false);
277 (v, clipped && !unclippable)
278 })
279 .rev(),
280 )
281 }
282 accum
283 }
284 pub fn get_topmost_element_beneath_ray(
286 self: &Rc<Self>,
287 ray: Point2<Window>,
288 ) -> Rc<ExpandedNode> {
289 let res = self.get_elements_beneath_ray(None, ray, true, vec![], false);
290 let new_topmost = res
291 .into_iter()
292 .next()
293 .unwrap_or(borrow!(self.root_expanded_node).upgrade().unwrap());
294
295 let last_topmost = borrow!(self.last_topmost_element).upgrade();
297 let new_topmost_comp = new_topmost.containing_component.upgrade();
298 if new_topmost_comp.as_ref().map(|n| n.id) != last_topmost.as_ref().map(|n| n.id) {
299 let (leaving, entering) =
300 find_paths_to_common_ancestor(&last_topmost, &new_topmost_comp);
301 for leave in leaving {
302 leave.dispatch_mouse_out(Event::new(MouseOut {}), &self.globals(), self);
303 }
304 for enter in entering {
305 enter.dispatch_mouse_over(Event::new(MouseOver {}), &self.globals(), self);
306 }
307 *borrow_mut!(self.last_topmost_element) = new_topmost_comp
308 .as_ref()
309 .map(Rc::downgrade)
310 .unwrap_or_default();
311 }
312 new_topmost
313 }
314
315 pub fn gen_uid(&self) -> ExpandedNodeIdentifier {
316 let val = self.next_uid.get();
317 let next_val = ExpandedNodeIdentifier(val.0 + 1);
318 self.next_uid.set(next_val);
319 val
320 }
321
322 pub fn enqueue_native_message(&self, message: NativeMessage) {
323 borrow_mut!(self.messages).push(message)
324 }
325
326 pub fn take_native_messages(&self) -> Vec<NativeMessage> {
327 let mut messages = borrow_mut!(self.messages);
328 std::mem::take(&mut *messages)
329 }
330
331 pub fn globals(&self) -> Globals {
332 borrow!(self.globals).clone()
333 }
334
335 pub fn edit_globals(&self, f: impl Fn(&mut Globals)) {
336 let mut globals = borrow_mut!(self.globals);
337 f(&mut globals);
338 }
339
340 pub fn queue_custom_event(&self, source_expanded_node: Rc<ExpandedNode>, name: &'static str) {
341 let mut queued_custom_events = borrow_mut!(self.queued_custom_events);
342 queued_custom_events.push((source_expanded_node, name));
343 }
344
345 pub fn flush_custom_events(self: &Rc<Self>) -> Result<(), String> {
346 let mut queued_custom_event = borrow_mut!(self.queued_custom_events);
347 let to_flush: Vec<_> = std::mem::take(queued_custom_event.as_mut());
348 for (target, ident) in to_flush {
349 target.dispatch_custom_event(ident, self)?;
350 }
351 Ok(())
352 }
353
354 #[cfg(feature = "designtime")]
355 pub fn get_userland_root_expanded_node(&self) -> Option<Rc<ExpandedNode>> {
356 borrow!(self.userland_root_expanded_node).clone()
357 }
358
359 #[cfg(feature = "designtime")]
360 pub fn get_userland_root_instance_node(&self) -> Option<Rc<dyn InstanceNode>> {
361 Some(borrow!(self.userland_frame_instance_node).clone())
362 }
363
364 pub fn get_root_expanded_node(&self) -> Option<Rc<ExpandedNode>> {
365 borrow!(self.root_expanded_node).upgrade()
366 }
367
368 pub fn queue_render(&self, expanded_node: Rc<ExpandedNode>) {
369 borrow_mut!(self.queued_renders).push(expanded_node);
370 }
371
372 pub fn recurse_flush_queued_renders(self: &Rc<RuntimeContext>, rcs: &mut dyn RenderContext) {
373 while !borrow!(self.queued_renders).is_empty() {
374 for n in std::mem::take(&mut *borrow_mut!(self.queued_renders)) {
375 n.recurse_render(self, rcs);
376 }
377 }
378 }
379}
380
381fn find_paths_to_common_ancestor(
382 last_topmost: &Option<Rc<ExpandedNode>>,
383 new_topmost_comp: &Option<Rc<ExpandedNode>>,
384) -> (Vec<Rc<ExpandedNode>>, Vec<Rc<ExpandedNode>>) {
385 let mut last_path = Vec::new();
386 let mut new_path = Vec::new();
387
388 if last_topmost.is_none() || new_topmost_comp.is_none() {
390 return (last_path, new_path);
391 }
392
393 let mut last_node = last_topmost.clone();
394 let mut new_node = new_topmost_comp.clone();
395
396 while let Some(node) = last_node.clone() {
398 last_path.push(node.clone());
399 last_node = node.containing_component.upgrade();
400 }
401
402 while let Some(node) = new_node.clone() {
403 new_path.push(node.clone());
404 new_node = node.containing_component.upgrade();
405 }
406
407 last_path.reverse();
409 new_path.reverse();
410
411 let mut common_ancestor_index = 0;
413 for (i, (last, new)) in last_path.iter().zip(new_path.iter()).enumerate() {
414 if last.id == new.id {
415 common_ancestor_index = i;
416 } else {
417 break;
418 }
419 }
420
421 last_path.drain(0..=common_ancestor_index);
423 new_path.drain(0..=common_ancestor_index);
424
425 (last_path, new_path)
426}
427
428pub struct RuntimePropertiesStackFrame {
437 symbols_within_frame: HashMap<String, Variable>,
438 local_stores: Rc<RefCell<HashMap<TypeId, Box<dyn Any>>>>,
439 parent: Weak<RuntimePropertiesStackFrame>,
440}
441
442impl RuntimePropertiesStackFrame {
443 pub fn new(symbols_within_frame: HashMap<String, Variable>) -> Rc<Self> {
444 Rc::new(Self {
445 symbols_within_frame,
446 local_stores: Default::default(),
447 parent: Weak::new(),
448 })
449 }
450
451 pub fn push(self: &Rc<Self>, symbols_within_frame: HashMap<String, Variable>) -> Rc<Self> {
452 Rc::new(RuntimePropertiesStackFrame {
453 symbols_within_frame,
454 local_stores: Default::default(),
455 parent: Rc::downgrade(&self),
456 })
457 }
458
459 pub fn pop(self: &Rc<Self>) -> Option<Rc<Self>> {
460 self.parent.upgrade()
461 }
462
463 pub fn insert_stack_local_store<T: Store>(&self, store: T) {
464 let type_id = TypeId::of::<T>();
465 borrow_mut!(self.local_stores).insert(type_id, Box::new(store));
466 }
467
468 pub fn peek_stack_local_store<T: Store, V>(
469 self: &Rc<Self>,
470 f: impl FnOnce(&mut T) -> V,
471 ) -> Result<V, String> {
472 let mut current = Rc::clone(self);
473 let type_id = TypeId::of::<T>();
474
475 while !borrow!(current.local_stores).contains_key(&type_id) {
476 current = current
477 .parent
478 .upgrade()
479 .ok_or_else(|| format!("couldn't find store in local stack"))?;
480 }
481 let v = {
482 let mut stores = borrow_mut!(current.local_stores);
483 let store = stores.get_mut(&type_id).unwrap().downcast_mut().unwrap();
484 f(store)
485 };
486 Ok(v)
487 }
488
489 pub fn resolve_symbol_as_variable(&self, symbol: &str) -> Option<Variable> {
490 if let Some(e) = self.symbols_within_frame.get(&clean_symbol(symbol)) {
491 Some(e.clone())
492 } else {
493 self.parent.upgrade()?.resolve_symbol_as_variable(symbol)
494 }
495 }
496
497 pub fn resolve_symbol_as_erased_property(&self, symbol: &str) -> Option<UntypedProperty> {
498 if let Some(e) = self.symbols_within_frame.get(&clean_symbol(symbol)) {
499 Some(e.clone().get_untyped_property().clone())
500 } else {
501 self.parent
502 .upgrade()?
503 .resolve_symbol_as_erased_property(symbol)
504 }
505 }
506
507 pub fn resolve_symbol_as_pax_value(&self, symbol: &str) -> Option<PaxValue> {
508 if let Some(e) = self.symbols_within_frame.get(&clean_symbol(symbol)) {
509 Some(e.get_as_pax_value())
510 } else {
511 self.parent.upgrade()?.resolve_symbol_as_pax_value(symbol)
512 }
513 }
514}
515
516fn clean_symbol(symbol: &str) -> String {
517 symbol.replace("self.", "").replace("this.", "")
518}
519
520impl IdentifierResolver for RuntimePropertiesStackFrame {
521 fn resolve(&self, name: String) -> Result<PaxValue, String> {
522 self.resolve_symbol_as_pax_value(&name)
523 .ok_or_else(|| format!("Could not resolve symbol {}", name))
524 }
525}
526
527pub struct ExpressionContext {
531 pub stack_frame: Rc<RuntimePropertiesStackFrame>,
532}