use std::rc::Rc;
use std::{cell::RefCell, iter};
use crate::api::{Layer, Timeline};
use crate::{
BaseInstance, ExpandedNode, ExpressionTable, Globals, InstanceFlags, InstanceNode,
InstanceNodePtrList, InstantiationArgs, RuntimeContext,
};
pub struct ComponentInstance {
pub template: InstanceNodePtrList,
pub timeline: Option<Rc<RefCell<Timeline>>>,
pub compute_properties_fn: Box<dyn Fn(&ExpandedNode, &ExpressionTable, &Globals)>,
base: BaseInstance,
}
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 compute_properties_fn = args.compute_properties_fn.take();
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,
compute_properties_fn: compute_properties_fn
.expect("must pass a compute_properties_fn to a Component instance"),
timeline: None,
})
}
fn update(self: Rc<Self>, expanded_node: &Rc<ExpandedNode>, context: &mut RuntimeContext) {
(*self.compute_properties_fn)(
&expanded_node,
context.expression_table(),
context.globals(),
);
if let Some(slot_children) = expanded_node.expanded_slot_children.borrow().as_ref() {
for slot_child in slot_children {
slot_child.recurse_update(context);
}
}
expanded_node.compute_flattened_slot_children();
}
fn handle_mount(&self, expanded_node: &Rc<ExpandedNode>, context: &mut RuntimeContext) {
if let Some(containing_component) = expanded_node.containing_component.upgrade() {
let env = Rc::clone(&expanded_node.stack);
let children = self.base().get_instance_children().borrow();
let children_with_env = children.iter().cloned().zip(iter::repeat(env));
*expanded_node.expanded_slot_children.borrow_mut() =
Some(containing_component.create_children_detached(children_with_env, context));
}
let new_env = expanded_node.stack.push(&expanded_node.properties.borrow());
let children = self.template.borrow();
let children_with_envs = children.iter().cloned().zip(iter::repeat(new_env));
expanded_node.set_children(children_with_envs, context);
}
#[cfg(debug_assertions)]
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)
}
}