use std::borrow::Cow;
use bevy::prelude::*;
use jackdaw_feathers::tooltip::Tooltip;
use jackdaw_runtime::EditorDescription;
#[derive(Component, Clone, Debug)]
pub struct ReflectedTypeTooltip {
pub type_path: Cow<'static, str>,
}
impl ReflectedTypeTooltip {
pub fn new(type_path: impl Into<Cow<'static, str>>) -> Self {
Self {
type_path: type_path.into(),
}
}
}
pub(super) fn plugin(app: &mut App) {
app.add_observer(auto_attach_reflected_type_tooltip);
}
fn auto_attach_reflected_type_tooltip(
trigger: On<Add, ReflectedTypeTooltip>,
sources: Query<&ReflectedTypeTooltip>,
type_registry: Res<AppTypeRegistry>,
mut commands: Commands,
) {
let entity = trigger.event_target();
let Ok(source) = sources.get(entity) else {
return;
};
let registry = type_registry.read();
let Some(registration) = registry.get_with_type_path(source.type_path.as_ref()) else {
return;
};
let info = registration.type_info();
let title = info.type_path_table().short_path().to_string();
let attrs = match info {
bevy::reflect::TypeInfo::Struct(s) => Some(s.custom_attributes()),
bevy::reflect::TypeInfo::TupleStruct(s) => Some(s.custom_attributes()),
bevy::reflect::TypeInfo::Enum(e) => Some(e.custom_attributes()),
_ => None,
};
let description = attrs
.and_then(|a| a.get::<EditorDescription>())
.map(|d| d.0.to_string())
.or_else(|| {
info.docs()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
})
.unwrap_or_default();
let footer = source.type_path.to_string();
commands.entity(entity).insert(
Tooltip::title(title)
.with_description(description)
.with_footer(footer),
);
}