use crate::curve::Curve;
use crate::duration::Duration;
use crate::geometry::Point;
use crate::id::IconId;
use crate::overlay_plan::OverlayRenderOptions;
#[derive(Clone, Debug)]
pub struct AnimationPreset {
pub movement: Curve,
pub envelope: Curve,
pub duration: Duration,
}
impl Default for AnimationPreset {
fn default() -> Self {
Self {
movement: Curve::ease_in_out(),
envelope: Curve::keyframes(
vec![
crate::Keyframe::new(0.0, 0.0),
crate::Keyframe::new(0.15, 1.0),
crate::Keyframe::new(0.85, 1.0),
crate::Keyframe::new(1.0, 0.0),
],
crate::KeyframeInterp::SmoothStep,
).expect("valid default preset envelope"),
duration: Duration::fixed(std::time::Duration::from_secs(2)),
}
}
}
#[derive(Clone, Debug)]
pub struct IconAnimationSpec {
pub id: IconId,
pub target: Point,
pub duration: Duration,
pub curve_x: Curve,
pub curve_y: Curve,
pub effect: Option<crate::Effect>,
}
impl IconAnimationSpec {
pub fn new(id: IconId, target: Point, duration: Duration, curve: Curve) -> Self {
Self {
id,
target,
duration,
curve_x: curve.clone(),
curve_y: curve,
effect: None,
}
}
pub fn with_axes(
id: IconId,
target: Point,
duration: Duration,
curve_x: Curve,
curve_y: Curve,
) -> Self {
Self {
id,
target,
duration,
curve_x,
curve_y,
effect: None,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct AnimationOptions {
pub snap_to_grid: bool,
pub tick_hz: Option<u32>,
pub position_tolerance_px: Option<i32>,
pub before_flags: Option<FolderFlagOp>,
pub after_flags: Option<FolderFlagOp>,
pub force_fallback: bool,
pub render_options: OverlayRenderOptions,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FolderFlagOp {
Set(u32),
Exactly(u32),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Duration, IconId};
#[test]
fn animation_preset_defaults_are_independent() {
use crate::AnimationCurve;
let mut preset = AnimationPreset::default();
assert_eq!(preset.movement, Curve::ease_in_out());
assert_eq!(preset.duration.resolve(Point::ZERO, Point::ZERO).unwrap(), std::time::Duration::from_secs(2));
for (progress, expected) in [(0.0, 0.0), (0.15, 1.0), (0.5, 1.0), (0.85, 1.0), (1.0, 0.0)] {
assert_eq!(preset.envelope.eval(progress), expected);
}
preset.movement = Curve::linear();
assert_eq!(AnimationPreset::default().movement, Curve::ease_in_out());
fn assert_send_sync<Value: Send + Sync>() {}
assert_send_sync::<AnimationPreset>();
}
#[test]
fn spec_new_shares_curve_between_axes() {
let c = Curve::linear();
let s = IconAnimationSpec::new(
IconId::from("x"),
Point::new(10, 20),
Duration::fixed(std::time::Duration::from_millis(500)),
c.clone(),
);
assert_eq!(s.curve_x, c);
assert_eq!(s.curve_y, c);
}
#[test]
fn options_default_leaves_everything_none() {
let o = AnimationOptions::default();
assert!(o.tick_hz.is_none());
assert!(o.position_tolerance_px.is_none());
assert!(o.before_flags.is_none());
assert!(o.after_flags.is_none());
assert!(!o.force_fallback);
assert_eq!(o.render_options, OverlayRenderOptions::all_enabled());
}
}