use std::cell::{Cell, RefCell};
use std::rc::Rc;
use crate::easing::Easing;
use crate::shape::TextPos;
use crate::signal::Tweenable;
use super::Action;
pub(crate) trait TweenObj {
fn duration(&self) -> f64;
fn start(&self) -> f64;
fn set_start(&self, start: f64);
fn reset(&self);
fn capture_from(&self);
fn apply(&self, t: f64);
fn morph_group(&self) -> Option<*const ()> {
None
}
fn morph_from(&self) -> Option<String> {
None
}
fn morph_new(&self) -> Option<String> {
None
}
fn rebase(&self, _old: &str, _new: &str) {}
fn highlight_group(&self) -> Option<*const ()> {
None
}
fn highlight_from(&self) -> Option<Vec<(TextPos, TextPos)>> {
None
}
fn highlight_to(&self) -> Option<Vec<(TextPos, TextPos)>> {
None
}
fn highlight_rebase(&self, _from: Vec<(TextPos, TextPos)>, _to: Vec<(TextPos, TextPos)>) {}
}
struct TweenLeaf<T: Tweenable> {
cell: Rc<RefCell<T>>,
baseline: T,
from: RefCell<T>,
to: T,
start: Cell<f64>,
duration: f64,
easing: Easing,
}
impl<T: Tweenable> TweenObj for TweenLeaf<T> {
fn duration(&self) -> f64 {
self.duration
}
fn start(&self) -> f64 {
self.start.get()
}
fn set_start(&self, start: f64) {
self.start.set(start);
}
fn reset(&self) {
*self.cell.borrow_mut() = self.baseline.clone();
}
fn capture_from(&self) {
*self.from.borrow_mut() = self.cell.borrow().clone();
}
fn apply(&self, t: f64) {
let local = if self.duration <= 0.0 {
1.0
} else {
(((t - self.start.get()) / self.duration).clamp(0.0, 1.0)) as f32
};
let eased = self.easing.apply(local);
let from = self.from.borrow().clone();
*self.cell.borrow_mut() = T::lerp(&from, &self.to, eased);
}
}
pub(crate) fn new_tween<T: Tweenable>(
cell: Rc<RefCell<T>>,
baseline: T,
to: T,
duration: f64,
easing: Easing,
) -> Action {
let leaf = TweenLeaf {
cell,
baseline: baseline.clone(),
from: RefCell::new(baseline),
to,
start: Cell::new(0.0),
duration: duration.max(0.0),
easing,
};
Action::from_tween(Rc::new(leaf))
}