cranpose_animation/
color.rs1#![allow(non_snake_case)]
11
12use cranpose_core::{Owned, State, with_current_composer};
13use cranpose_ui_graphics::Color;
14
15use crate::animation::{Animatable, AnimationType, Lerp, SpringScalar};
16
17impl Lerp for Color {
18 fn lerp(&self, target: &Self, fraction: f32) -> Self {
19 Color(
20 self.0.lerp(&target.0, fraction).clamp(0.0, 1.0),
21 self.1.lerp(&target.1, fraction).clamp(0.0, 1.0),
22 self.2.lerp(&target.2, fraction).clamp(0.0, 1.0),
23 self.3.lerp(&target.3, fraction).clamp(0.0, 1.0),
24 )
25 }
26}
27
28impl SpringScalar for Color {
33 const DIMENSIONS: usize = 4;
34
35 fn dimension(&self, index: usize) -> f32 {
36 match index {
37 0 => self.0,
38 1 => self.1,
39 2 => self.2,
40 _ => self.3,
41 }
42 }
43
44 fn from_dimensions(dimensions: [f32; crate::animation::SPRING_MAX_DIMENSIONS]) -> Self {
45 Color(
46 dimensions[0].clamp(0.0, 1.0),
47 dimensions[1].clamp(0.0, 1.0),
48 dimensions[2].clamp(0.0, 1.0),
49 dimensions[3].clamp(0.0, 1.0),
50 )
51 }
52}
53
54#[track_caller]
64pub fn animateColorAsState(target: Color, animation: AnimationType, label: &str) -> State<Color> {
65 let _ = label;
66 let caller = cranpose_core::caller_location_key();
67 with_current_composer(|composer| {
68 let runtime = composer.runtime_handle();
69 let anim: Owned<Animatable<Color>> =
70 composer.remember_at(caller, || Animatable::new(target, runtime));
71 anim.update(|animatable| {
72 let is_new_target = animatable.target() != target;
73 let is_new_animation = animatable.animation_type() != animation;
74 if is_new_target || is_new_animation {
75 animatable.animateTo(target, animation);
76 }
77 });
78 anim.with(|animatable| animatable.state())
79 })
80}
81
82#[cfg(test)]
83#[path = "tests/color_tests.rs"]
84mod tests;