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
107
108
109
110
111
112
113
114
115
116
use std::iter;
use std::rc::Rc;

use pax_runtime_api::{borrow, borrow_mut, use_RefCell, Property};

use_RefCell!();
use crate::api::{Layer, Timeline};
use crate::{
    BaseInstance, ExpandedNode, InstanceFlags, InstanceNode, InstanceNodePtrList,
    InstantiationArgs, RuntimeContext,
};

/// A render node with its own runtime context.  Will push a frame
/// to the runtime stack including the specified `slot_children` and
/// a `PaxType` properties object.  `Component` is used at the root of
/// applications, at the root of reusable components like `Stacker`, and
/// in special applications like `Repeat` where it houses the `RepeatItem`
/// properties attached to each of Repeat's virtual nodes.
pub struct ComponentInstance {
    pub template: InstanceNodePtrList,
    pub timeline: Option<Rc<RefCell<Timeline>>>,
    base: BaseInstance,
}

// #[derive(Default)]
// pub struct ComponentProperties {
//     pub slot_children: BTreeSet<Rc<ExpandedNode>>,
// }

impl InstanceNode for ComponentInstance {
    fn instantiate(mut args: InstantiationArgs) -> Rc<Self> {
        let component_template = args.component_template.take();
        let template = component_template.unwrap_or_default();
        let base = BaseInstance::new(
            args,
            InstanceFlags {
                invisible_to_slot: false,
                invisible_to_raycasting: true,
                layer: Layer::DontCare,
                is_component: true,
            },
        );
        Rc::new(ComponentInstance {
            base,
            template,
            timeline: None,
        })
    }

    fn handle_mount(
        self: Rc<Self>,
        expanded_node: &Rc<ExpandedNode>,
        context: &Rc<RuntimeContext>,
    ) {
        if let Some(containing_component) = expanded_node.containing_component.upgrade() {
            let env = Rc::clone(&expanded_node.stack);
            let children = borrow!(self.base().get_instance_children());
            let children_with_env = children.iter().cloned().zip(iter::repeat(env));
            *borrow_mut!(expanded_node.expanded_slot_children) =
                Some(containing_component.create_children_detached(
                    children_with_env,
                    context,
                    &Rc::downgrade(expanded_node),
                ));
        }
        let properties_scope = borrow!(expanded_node.properties_scope);
        let new_env = expanded_node.stack.push(
            properties_scope.clone(),
            &*borrow!(expanded_node.properties),
        );
        let children = borrow!(self.template);
        let children_with_envs = children.iter().cloned().zip(iter::repeat(new_env));
        expanded_node.children.replace_with(Property::new_with_name(
            expanded_node.generate_children(
                children_with_envs,
                context,
                &expanded_node.parent_frame,
            ),
            &format!("component (node id: {})", expanded_node.id.0),
        ));
        // update slot children
    }

    fn handle_unmount(&self, expanded_node: &Rc<ExpandedNode>, context: &Rc<RuntimeContext>) {
        if let Some(slot_children) = borrow_mut!(expanded_node.expanded_slot_children).take() {
            for slot_child in slot_children {
                slot_child.recurse_unmount(context);
            }
        }
    }

    fn update(self: Rc<Self>, expanded_node: &Rc<ExpandedNode>, context: &Rc<RuntimeContext>) {
        if let Some(slot_children) = borrow_mut!(expanded_node.expanded_slot_children).as_ref() {
            for slot_child in slot_children {
                slot_child.recurse_update(context);
            }
        }
        expanded_node.compute_flattened_slot_children();
    }

    fn resolve_debug(
        &self,
        f: &mut std::fmt::Formatter,
        _expanded_node: Option<&ExpandedNode>,
    ) -> std::fmt::Result {
        f.debug_struct("Component").finish()
    }

    fn base(&self) -> &BaseInstance {
        &self.base
    }

    fn get_template(&self) -> Option<&InstanceNodePtrList> {
        Some(&self.template)
    }
}