use crate::{cx::Cx, tracking_scope::TrackingScope, AnyViewAdapter, View, ViewThunk};
use bevy::{
core::Name,
ecs::world::DeferredWorld,
hierarchy::{BuildChildren, BuildWorldChildren},
prelude::{Component, Entity, World},
};
use std::sync::{Arc, Mutex};
#[cfg(feature = "verbose")]
use bevy::log::info;
pub trait ViewTemplate: Send + Sync + 'static {
type View: View;
fn create(&self, cx: &mut Cx) -> Self::View;
}
impl<VT: ViewTemplate + Clone + PartialEq> View for VT {
type State = (Entity, Vec<Entity>);
fn nodes(&self, world: &World, state: &Self::State, out: &mut Vec<Entity>) {
#[cfg(feature = "verbose")]
info!("nodes() {}", state.0);
let entity = state.0;
let entt = world.entity(entity);
let cell = entt.get::<ViewTemplateStateCell<VT>>().unwrap();
let inner = cell.0.lock().unwrap();
inner.nodes(world, out);
}
fn build(&self, cx: &mut Cx) -> Self::State {
let tick = cx.world_mut().change_tick();
let parent = cx.owner();
let child_entity = cx
.world_mut()
.spawn_empty()
.insert(Name::new(std::any::type_name::<Self>()))
.set_parent(parent)
.id();
#[cfg(feature = "verbose")]
info!("build() {}", child_entity);
let mut scope = TrackingScope::new(tick);
let mut cx_inner = Cx::new(cx.world_mut(), child_entity, &mut scope);
let view = self.create(&mut cx_inner);
let state = view.build(&mut cx_inner);
let mut nodes: Vec<Entity> = Vec::new();
view.nodes(cx.world(), &state, &mut nodes);
let cell = ViewTemplateState::new(self.clone(), view, state);
let thunk = cell.create_thunk();
cx.world_mut().entity_mut(child_entity).insert((
ViewTemplateStateCell(Arc::new(Mutex::new(cell))),
scope,
thunk,
));
(child_entity, nodes)
}
fn rebuild(&self, cx: &mut Cx, state: &mut Self::State) -> bool {
let entity = state.0;
#[cfg(feature = "verbose")]
info!("rebuild() {}", entity);
let mut entt = cx.world_mut().entity_mut(entity);
let cell = entt.get::<ViewTemplateStateCell<VT>>().unwrap();
let mut inner = cell.0.lock().unwrap();
if inner.template != *self {
inner.template = self.clone();
drop(inner);
let scope = entt.get_mut::<TrackingScope>().unwrap();
scope.set_changed();
}
false
}
fn attach_children(&self, world: &mut World, state: &mut Self::State) -> bool {
let entity = state.0;
#[cfg(feature = "verbose")]
info!("attach_children() {}", entity);
assert!(world.get_entity(entity).is_some());
let entt = world.entity_mut(entity);
let cell = entt.get::<ViewTemplateStateCell<VT>>().unwrap();
let inner = cell.0.clone();
let mut nodes: Vec<Entity> = Vec::new();
inner.lock().unwrap().nodes(world, &mut nodes);
if state.1 != nodes {
state.1 = nodes;
true
} else {
false
}
}
fn raze(&self, world: &mut DeferredWorld, state: &mut Self::State) {
let entity = state.0;
#[cfg(feature = "verbose")]
info!("raze() {}", entity);
let entt = world.entity_mut(entity);
let cell = entt.get::<ViewTemplateStateCell<VT>>().unwrap().0.clone();
let mut inner = cell.lock().unwrap();
inner.raze(world);
world.commands().entity(entity).remove_parent().despawn();
}
}
struct ViewTemplateState<VT: ViewTemplate> {
template: VT,
view: VT::View,
state: <VT::View as View>::State,
}
impl<VT: ViewTemplate> ViewTemplateState<VT> {
fn new(template: VT, view: VT::View, state: <VT::View as View>::State) -> Self {
Self {
template,
view,
state,
}
}
fn nodes(&self, world: &World, out: &mut Vec<Entity>) {
self.view.nodes(world, &self.state, out);
}
fn rebuild(&mut self, cx: &mut Cx) -> bool {
self.view = self.template.create(cx);
self.view.rebuild(cx, &mut self.state)
}
fn raze(&mut self, world: &mut DeferredWorld) {
self.view.raze(world, &mut self.state);
}
fn attach_children(&mut self, world: &mut World) -> bool {
self.view.attach_children(world, &mut self.state)
}
pub fn create_thunk(&self) -> ViewThunk {
ViewThunk(&ViewTemplateAdapter::<VT> {
marker: std::marker::PhantomData,
})
}
}
#[derive(Component)]
pub struct ViewTemplateStateCell<VF: ViewTemplate>(Arc<Mutex<ViewTemplateState<VF>>>);
impl<VT: ViewTemplate> ViewTemplateStateCell<VT> {
fn nodes(&self, world: &World, out: &mut Vec<Entity>) {
self.0.lock().unwrap().nodes(world, out);
}
pub fn raze(&self, world: &mut DeferredWorld) {
self.0.lock().unwrap().raze(world);
}
pub fn attach_children(&self, world: &mut World) -> bool {
self.0.lock().unwrap().attach_children(world)
}
}
pub struct ViewTemplateAdapter<VF: ViewTemplate> {
marker: std::marker::PhantomData<VF>,
}
impl<VF: ViewTemplate> AnyViewAdapter for ViewTemplateAdapter<VF> {
fn nodes(&self, world: &mut World, entity: Entity, out: &mut Vec<Entity>) {
if let Some(view_cell) = world.entity(entity).get::<ViewTemplateStateCell<VF>>() {
view_cell.nodes(world, out)
}
}
fn rebuild(&self, world: &mut World, entity: Entity, scope: &mut TrackingScope) -> bool {
let mut cx = Cx::new(world, entity, scope);
if let Some(view_cell) = cx
.world_mut()
.entity(entity)
.get::<ViewTemplateStateCell<VF>>()
{
let vs = view_cell.0.clone();
let mut inner = vs.lock().unwrap();
inner.rebuild(&mut cx)
} else {
false
}
}
fn attach_children(&self, world: &mut World, entity: Entity) -> bool {
if let Some(view_cell) = world.entity(entity).get::<ViewTemplateStateCell<VF>>() {
let vs = view_cell.0.clone();
let mut inner = vs.lock().unwrap();
inner.attach_children(world)
} else {
false
}
}
fn raze(&self, world: &mut DeferredWorld, entity: Entity) {
if let Some(view_cell) = world.entity_mut(entity).get::<ViewTemplateStateCell<VF>>() {
let inner = view_cell.0.clone();
inner.lock().unwrap().raze(world);
}
}
}