use bevy::prelude::*;
use smol_str::SmolStr;
use crate::prelude::*;
use crate::sickle::*;
#[derive(Reflect, Default, Clone, Debug, Eq, PartialEq)]
pub struct ControlRoot;
impl Instruction for ControlRoot
{
fn apply(self, entity: Entity, world: &mut World)
{
let Ok(mut emut) = world.get_entity_mut(entity) else { return };
if let Some(mut control_map) = emut.get_mut::<ControlMap>() {
if control_map.is_anonymous() {
control_map.set_anonymous(false);
control_map.remove_all_labels().count();
}
emut.remove::<ControlMapDying>();
} else {
emut.insert(ControlMap::default());
#[cfg(feature = "hot_reload")]
if emut.contains::<Children>() {
if let Some((_, control_map)) =
get_ancestor_mut_filtered::<ControlMap>(world, entity, |cm| !cm.is_anonymous())
{
let labels: Vec<_> = control_map.remove_all_labels().collect();
for (label, label_entity) in labels {
ControlMember { id: label }.apply(label_entity, world);
}
}
let mut dangling = vec![];
iter_descendants_filtered(
world,
entity,
|world, entity| world.get::<ControlMap>(entity).is_none(),
|world, entity| {
if world.get::<ControlMember>(entity).is_some() {
dangling.push(entity);
}
},
);
let mut scene_buffer = world.resource_mut::<SceneBuffer>();
for controlled_entity in dangling {
scene_buffer.request_reload(controlled_entity);
}
}
}
ControlMember::from(SmolStr::default()).apply(entity, world);
}
fn revert(entity: Entity, world: &mut World)
{
let Ok(mut emut) = world.get_entity_mut(entity) else { return };
if emut.contains::<ControlMap>() {
emut.insert(ControlMapDying);
}
ControlMember::revert(entity, world);
}
}
#[derive(Component, Reflect, Default, Clone, Debug, Deref, DerefMut, Eq, PartialEq)]
pub struct ControlMember
{
#[reflect(default)]
pub id: SmolStr,
}
impl ControlMember
{
pub fn new(label: &'static str) -> Self
{
Self { id: SmolStr::new_static(label) }
}
}
impl<T: Into<SmolStr>> From<T> for ControlMember
{
fn from(string: T) -> Self
{
Self { id: string.into() }
}
}
impl Instruction for ControlMember
{
fn apply(mut self, entity: Entity, world: &mut World)
{
let Ok(mut emut) = world.get_entity_mut(entity) else { return };
if self.id.len() == 0 {
self.id = SmolStr::from(format!("_anon-{}v{}", entity.index(), entity.generation()));
}
let label_str = self.id.clone();
if let Some(mut existing_member) = emut.get_mut::<ControlMember>() {
if existing_member.id != self.id {
tracing::warn!("updating control label on {entity:?} from {existing_member:?} to {self:?}");
existing_member.id = self.id;
}
} else {
emut.insert(self);
}
if let Some(mut control_map) = emut.get_mut::<ControlMap>() {
if control_map.is_anonymous() {
emut.remove::<ControlMap>();
} else {
control_map.insert(label_str, entity);
return;
}
}
if let Some((_, control_map)) =
get_ancestor_mut_filtered::<ControlMap>(world, entity, |cm| !cm.is_anonymous())
{
control_map.insert(label_str, entity);
return;
}
tracing::error!(
"error while inserting ControlMember({label_str}) to {entity:?}, no ancestor with ControlMap \
(see ControlRoot)",
);
}
fn revert(entity: Entity, world: &mut World)
{
let Ok(mut emut) = world.get_entity_mut(entity) else { return };
emut.remove::<(DynamicStyle, DynamicStyleStopwatch)>();
if let Some(mut control_map) = emut.get_mut::<ControlMap>() {
if control_map.is_anonymous() {
emut.remove::<ControlMap>();
} else {
control_map.remove(entity);
}
} else {
if let Some((_, control_map)) =
get_ancestor_mut_filtered::<ControlMap>(world, entity, |cm| !cm.is_anonymous())
{
control_map.remove(entity);
}
}
let mut emut = world.entity_mut(entity);
emut.remove::<ControlMember>();
}
}
pub(crate) struct ControlPlugin;
impl Plugin for ControlPlugin
{
fn build(&self, app: &mut App)
{
app.register_instruction_type::<ControlRoot>()
.register_instruction_type::<ControlMember>();
}
}