use crate::{
core_item::{AnyExtractCoreItem, CoreItem, DynItem},
utils::rate_functions::linear,
};
use std::fmt::Debug;
pub trait Eval<T> {
fn eval_alpha(&self, alpha: f64) -> T;
fn into_animation_cell(self) -> AnimationCell<T>
where
Self: Sized + 'static,
{
AnimationCell {
inner: Box::new(self),
info: AnimationInfo::default(),
anim_name: std::any::type_name::<Self>().to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct AnimationInfo {
pub rate_func: fn(f64) -> f64,
pub start_sec: f64,
pub duration_secs: f64,
pub enabled: bool,
}
impl Default for AnimationInfo {
fn default() -> Self {
Self {
rate_func: linear,
start_sec: 0.0,
duration_secs: 1.0,
enabled: true,
}
}
}
impl AnimationInfo {
pub fn range(&self) -> std::ops::Range<f64> {
self.start_sec..self.start_sec + self.duration_secs
}
pub fn range_inclusive(&self) -> std::ops::RangeInclusive<f64> {
self.start_sec..=self.start_sec + self.duration_secs
}
pub fn map_alpha(&self, alpha: f64) -> f64 {
(self.rate_func)(alpha)
}
pub fn map_sec_to_alpha(&self, sec: f64) -> Option<f64> {
if self.range_inclusive().contains(&sec) {
let alpha = (sec - self.start_sec) / self.duration_secs;
let alpha = if alpha.is_nan() { 1.0 } else { alpha };
Some(alpha)
} else {
None
}
}
}
impl AnimationInfo {
pub fn at(mut self, at_sec: f64) -> Self {
self.start_sec = at_sec;
self
}
pub fn with_rate_func(mut self, rate_func: fn(f64) -> f64) -> Self {
self.rate_func = rate_func;
self
}
pub fn with_duration(mut self, secs: f64) -> Self {
self.duration_secs = secs;
self
}
pub fn with_enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
}
pub struct AnimationCell<T> {
inner: Box<dyn Eval<T>>,
pub info: AnimationInfo,
anim_name: String,
}
impl<T> AnimationCell<T> {
pub fn at(mut self, at_sec: f64) -> Self {
self.info = self.info.at(at_sec);
self
}
pub fn with_rate_func(mut self, rate_func: fn(f64) -> f64) -> Self {
self.info = self.info.with_rate_func(rate_func);
self
}
pub fn with_duration(mut self, duration_secs: f64) -> Self {
self.info = self.info.with_duration(duration_secs);
self
}
pub fn with_enabled(mut self, enabled: bool) -> Self {
self.info = self.info.with_enabled(enabled);
self
}
pub fn apply_to(self, item: &mut T) -> Self {
self.apply_alpha_to(item, 1.0)
}
pub fn apply_alpha_to(self, item: &mut T, alpha: f64) -> Self {
*item = self.eval_alpha(alpha);
self
}
}
impl<T> Eval<T> for AnimationCell<T> {
fn eval_alpha(&self, alpha: f64) -> T {
self.inner.eval_alpha(self.info.map_alpha(alpha))
}
}
pub trait CoreItemAnimation {
fn anim_info(&self) -> &AnimationInfo;
fn anim_name(&self) -> &str;
fn eval_alpha_dyn(&self, alpha: f64) -> DynItem;
fn eval_global_sec_dyn(&self, sec: f64) -> Option<DynItem> {
self.anim_info()
.map_sec_to_alpha(sec)
.map(|alpha| self.eval_alpha_dyn(alpha))
}
fn eval_alpha_core_item(&self, alpha: f64) -> Vec<CoreItem>;
fn eval_global_sec_core_item(&self, sec: f64) -> Option<Vec<CoreItem>> {
self.anim_info()
.map_sec_to_alpha(sec)
.map(|alpha| self.eval_alpha_core_item(alpha))
}
}
impl<T: AnyExtractCoreItem> CoreItemAnimation for AnimationCell<T> {
fn eval_alpha_dyn(&self, alpha: f64) -> DynItem {
DynItem(Box::new(self.eval_alpha(alpha)))
}
fn eval_alpha_core_item(&self, alpha: f64) -> Vec<CoreItem> {
self.eval_alpha(alpha).extract()
}
fn anim_info(&self) -> &AnimationInfo {
&self.info
}
fn anim_name(&self) -> &str {
&self.anim_name
}
}
pub trait StaticAnimRequirement: Clone {}
impl<T: Clone> StaticAnimRequirement for T {}
pub trait StaticAnim: StaticAnimRequirement {
fn show(&self) -> AnimationCell<Self>;
fn hide(&self) -> AnimationCell<Self>;
}
impl<T: StaticAnimRequirement + 'static> StaticAnim for T {
fn show(&self) -> AnimationCell<Self> {
Static(self.clone())
.into_animation_cell()
.with_duration(0.0)
}
fn hide(&self) -> AnimationCell<Self> {
Static(self.clone())
.into_animation_cell()
.with_enabled(false)
.with_duration(0.0)
}
}
pub struct Static<T>(pub T);
impl<T: Clone> Eval<T> for Static<T> {
fn eval_alpha(&self, _alpha: f64) -> T {
self.0.clone()
}
}