use std::str::FromStr;
use bevy::ecs::{
change_detection::DetectChanges,
component::Component,
entity::Entity,
query::Without,
system::Query,
world::{EntityRef, Mut},
};
#[cfg(feature = "reflect")]
use bevy::prelude::{Reflect, ReflectComponent, ReflectDefault};
#[derive(Debug, Component, Default)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[cfg_attr(feature = "reflect", reflect(Component, Default))]
pub struct SharedTextSegment;
#[derive(Debug, Component, Default)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[cfg_attr(feature = "reflect", reflect(Component, Default))]
pub struct FetchedTextSegment(pub String);
impl FetchedTextSegment {
pub const EMPTY: Self = Self(String::new());
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub fn set_if_changed(mut this: Mut<Self>, value: impl AsRef<str> + ToString) {
if this.0 != value.as_ref() {
this.0 = value.to_string()
}
}
pub fn write_if_changed<T: ToString + FromStr + Eq>(mut this: Mut<Self>, value: T) {
if let Ok(val) = this.0.parse::<T>() {
if val == value {
return;
}
}
this.0 = value.to_string()
}
}
#[derive(Component)]
#[require(FetchedTextSegment)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[cfg_attr(feature = "reflect", reflect(Component))]
pub struct TextFetch {
entity: Entity,
fetch: Box<dyn FnMut(EntityRef) -> Option<String> + Send + Sync>,
}
impl TextFetch {
pub fn fetch_component<C: Component>(
entity: Entity,
mut fetch: impl (FnMut(&C) -> String) + Send + Sync + 'static,
) -> Self {
TextFetch {
entity,
fetch: Box::new(move |entity: EntityRef| {
if let Some(component) = entity.get_ref::<C>() {
if component.is_changed() {
return Some(fetch(&component));
}
}
None
}),
}
}
pub fn fetch_entity_ref(
entity: Entity,
fetch: impl (FnMut(EntityRef) -> Option<String>) + Send + Sync + 'static,
) -> Self {
TextFetch {
entity,
fetch: Box::new(fetch),
}
}
}
pub fn text_fetch_system(
mut channels: Query<(&mut TextFetch, &mut FetchedTextSegment)>,
other: Query<EntityRef, Without<TextFetch>>,
) {
for (mut channel, mut text) in channels.iter_mut() {
if let Ok(entity_ref) = other.get(channel.entity) {
if let Some(output) = (channel.fetch)(entity_ref) {
text.0 = output;
}
}
}
}