use super::{ComponentInspector, InspectorContext, impl_simple_inspector};
use crate::ecs::prefab::resources::animation_cache_names;
use crate::prelude::*;
fn add_animation_player(world: &mut World, entity: Entity) {
world.add_components(entity, ANIMATION_PLAYER);
world.set_animation_player(entity, AnimationPlayer::default());
}
fn animation_ui(
world: &mut World,
entity: Entity,
ui: &mut egui::Ui,
_context: &mut InspectorContext,
) {
let cached_names: Vec<String> = animation_cache_names(&world.resources.animation_cache)
.cloned()
.collect();
let player_clip_names: Vec<String> = world
.get_animation_player(entity)
.map(|p| p.clips.iter().map(|c| c.name.clone()).collect())
.unwrap_or_default();
let mut clip_to_add: Option<String> = None;
if let Some(player) = world.get_animation_player_mut(entity) {
animation_player_controls_ui(ui, player);
}
ui.separator();
animation_cache_ui(ui, &cached_names, &player_clip_names, &mut clip_to_add);
if let Some(clip_name) = clip_to_add {
let clip = world
.resources
.animation_cache
.clips
.get(&clip_name)
.cloned();
if let Some(clip) = clip
&& let Some(player) = world.get_animation_player_mut(entity)
{
let index = player.clips.len();
player.clips.push(clip);
player.play(index);
}
}
}
fn animation_player_controls_ui(ui: &mut egui::Ui, player: &mut AnimationPlayer) {
ui.label(format!("Clips: {}", player.clips.len()));
let mut clip_to_play = None;
let mut clip_to_remove = None;
if !player.clips.is_empty() {
ui.horizontal(|ui| {
ui.label("Current Clip:");
egui::ComboBox::from_id_salt("animation_clip_selector")
.selected_text(
player
.current_clip
.and_then(|index| player.clips.get(index))
.map(|clip| clip.name.as_str())
.unwrap_or("None"),
)
.show_ui(ui, |ui| {
for (index, clip) in player.clips.iter().enumerate() {
let is_selected = player.current_clip == Some(index);
if ui.selectable_label(is_selected, &clip.name).clicked() {
clip_to_play = Some(index);
}
}
});
});
if let Some(clip_index) = player.current_clip
&& let Some(clip) = player.clips.get(clip_index)
{
ui.label(format!("Duration: {:.2}s", clip.duration));
ui.label(format!("Channels: {}", clip.channels.len()));
}
ui.separator();
ui.horizontal(|ui| {
ui.label("Time:");
let duration = player
.current_clip
.and_then(|index| player.clips.get(index))
.map(|clip| clip.duration)
.unwrap_or(1.0);
ui.add(egui::Slider::new(&mut player.time, 0.0..=duration).suffix("s"));
});
ui.horizontal(|ui| {
ui.label("Speed:");
ui.add(
egui::DragValue::new(&mut player.speed)
.speed(0.1)
.range(-5.0..=5.0),
);
});
ui.horizontal(|ui| {
ui.checkbox(&mut player.looping, "Looping");
});
ui.separator();
ui.horizontal(|ui| {
if player.playing {
if ui.button("Pause").clicked() {
player.pause();
}
} else if ui.button("Play").clicked() {
player.resume();
}
if ui.button("Stop").clicked() {
player.stop();
}
if ui.button("Restart").clicked()
&& let Some(clip_index) = player.current_clip
{
player.play(clip_index);
}
});
ui.label(if player.playing {
"Status: Playing"
} else {
"Status: Paused"
});
ui.separator();
ui.collapsing("Loaded Clips", |ui| {
for (index, clip) in player.clips.iter().enumerate() {
ui.horizontal(|ui| {
ui.label(format!("[{}] {}", index, clip.name));
if ui.small_button("X").clicked() {
clip_to_remove = Some(index);
}
});
}
});
}
if let Some(index) = clip_to_play {
player.play(index);
}
if let Some(index) = clip_to_remove {
player.clips.remove(index);
if player.current_clip == Some(index) {
player.current_clip = None;
player.playing = false;
} else if let Some(current) = player.current_clip
&& current > index
{
player.current_clip = Some(current - 1);
}
}
}
fn animation_cache_ui(
ui: &mut egui::Ui,
cached_names: &[String],
player_clip_names: &[String],
clip_to_add: &mut Option<String>,
) {
ui.collapsing(format!("Animation Cache ({})", cached_names.len()), |ui| {
if cached_names.is_empty() {
ui.label("No cached animations");
ui.label("Load FBX files to populate the cache");
} else {
egui::ScrollArea::vertical()
.max_height(200.0)
.show(ui, |ui| {
for name in cached_names {
let already_loaded = player_clip_names.contains(name);
ui.horizontal(|ui| {
if already_loaded {
ui.add_enabled(false, egui::Button::new("+"))
.on_disabled_hover_text("Already loaded");
} else if ui.small_button("+").clicked() {
*clip_to_add = Some(name.clone());
}
ui.label(name);
});
}
});
}
});
}
impl_simple_inspector!(AnimationInspector, "Animation Player", entity_has_animation_player, remove_animation_player, animation_ui, custom_add => add_animation_player);