use std::collections::HashMap;
use bevy::prelude::*;
use crate::render::{NoesisRenderState, NoesisSet};
#[derive(Clone, Debug, PartialEq)]
pub struct AnimationSpec {
pub property: String,
pub from: Option<f32>,
pub to: f32,
pub duration_secs: f64,
}
#[derive(Component, Clone, Default, Debug)]
pub struct NoesisAnimation {
pub animations: HashMap<String, AnimationSpec>,
}
impl NoesisAnimation {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn animate(
self,
name: impl Into<String>,
property: impl Into<String>,
to: f32,
duration_secs: f64,
) -> Self {
self.insert(name, property, None, to, duration_secs)
}
#[must_use]
pub fn animate_from(
self,
name: impl Into<String>,
property: impl Into<String>,
from: f32,
to: f32,
duration_secs: f64,
) -> Self {
self.insert(name, property, Some(from), to, duration_secs)
}
fn insert(
mut self,
name: impl Into<String>,
property: impl Into<String>,
from: Option<f32>,
to: f32,
duration_secs: f64,
) -> Self {
self.animations.insert(
name.into(),
AnimationSpec {
property: property.into(),
from,
to,
duration_secs,
},
);
self
}
}
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn sync_animation_bridge(
views: Query<(Entity, Ref<NoesisAnimation>)>,
state: Option<NonSendMut<NoesisRenderState>>,
) {
let Some(mut state) = state else {
return;
};
for (entity, animation) in &views {
if animation.is_changed() {
state.begin_animations_for(entity, &animation.animations);
}
}
}
pub struct NoesisAnimationPlugin;
impl Plugin for NoesisAnimationPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PostUpdate, sync_animation_bridge.in_set(NoesisSet::Apply));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_collects_animations() {
let a = NoesisAnimation::new()
.animate("Panel", "Opacity", 0.0, 0.25)
.animate_from("Box", "Width", 10.0, 50.0, 0.1);
assert_eq!(
a.animations.get("Panel"),
Some(&AnimationSpec {
property: "Opacity".to_string(),
from: None,
to: 0.0,
duration_secs: 0.25,
}),
);
assert_eq!(
a.animations.get("Box"),
Some(&AnimationSpec {
property: "Width".to_string(),
from: Some(10.0),
to: 50.0,
duration_secs: 0.1,
}),
);
}
}