use bevy::{
ecs::{
component::HookContext,
world::{DeferredWorld, Mut},
},
prelude::{Component, Entity},
};
use crate::{
styling::SegmentStyle, Text3dBounds, Text3dDimensionOut, Text3dStyling, TextAtlasHandle,
};
#[derive(Debug, Component)]
#[require(Text3dDimensionOut, Text3dBounds, TextAtlasHandle, Text3dStyling)]
#[component(on_remove = text_3d_on_remove)]
pub struct Text3d {
pub segments: Vec<(Text3dSegment, SegmentStyle)>,
}
#[derive(Debug)]
pub enum Text3dSegment {
String(String),
Extract(Entity),
}
fn text_3d_on_remove(mut world: DeferredWorld, cx: HookContext) {
let Ok(entity) = world.get_entity(cx.entity) else {
return;
};
let Some(text) = entity.get::<Text3d>() else {
return;
};
let to_be_dropped: Vec<_> = text
.segments
.iter()
.filter_map(|x| match &x.0 {
Text3dSegment::String(_) => None,
Text3dSegment::Extract(entity) => Some(*entity),
})
.collect();
let mut commands = world.commands();
for entity in to_be_dropped {
commands.entity(entity).try_despawn();
}
}
impl Text3d {
pub fn new(s: impl ToString) -> Self {
let string = s.to_string();
Self {
segments: vec![(Text3dSegment::String(string), Default::default())],
}
}
pub fn from_extract(entity: Entity) -> Self {
Self {
segments: vec![(Text3dSegment::Extract(entity), Default::default())],
}
}
pub fn get_single(&self) -> Option<&str> {
if self.segments.len() != 1 {
None
} else if let Some((Text3dSegment::String(s), _)) = self.segments.first() {
Some(s)
} else {
None
}
}
pub fn get_single_mut(&mut self) -> Option<&mut String> {
if self.segments.len() != 1 {
None
} else if let Some((Text3dSegment::String(s), _)) = self.segments.get_mut(0) {
Some(s)
} else {
None
}
}
pub fn map_single_mut<'a>(this: &'a mut Mut<Self>) -> Option<Mut<'a, String>> {
this.reborrow().filter_map_unchanged(Self::get_single_mut)
}
}