Skip to main content

windows_composition/
animation.rs

1use super::*;
2use std::time::Duration;
3use windows_time::TimeSpan;
4
5fn to_time_span(duration: Duration) -> TimeSpan {
6    // Durations too large for a WinRT `TimeSpan` saturate rather than wrap.
7    TimeSpan::try_from(duration).unwrap_or(TimeSpan::MAX)
8}
9
10/// The base type shared by every composition animation. An [`Animation`] can be
11/// turned into one via [`Animation::as_animation`] to start it on a visual with
12/// [`Visual::start_animation`](crate::Visual::start_animation).
13#[derive(Clone)]
14pub struct CompositionAnimation(pub(crate) bindings::CompositionAnimation);
15
16/// An animation that can be started on a visual property.
17///
18/// This trait is sealed: only the animation types in this crate implement it.
19pub trait Animation: Sealed {
20    /// Returns this animation as the shared [`CompositionAnimation`] base type.
21    fn as_animation(&self) -> CompositionAnimation;
22}
23
24/// An easing function that shapes a key frame's interpolation curve.
25///
26/// Create one with [`Compositor::create_linear_easing_function`] or
27/// [`Compositor::create_cubic_bezier_easing_function`].
28#[derive(Clone)]
29pub struct CompositionEasingFunction(pub(crate) bindings::CompositionEasingFunction);
30
31/// A key-frame animation that interpolates a scalar (`f32`) property (such as a
32/// visual's `Opacity`) through a series of key frames.
33#[derive(Clone)]
34pub struct ScalarKeyFrameAnimation(pub(crate) bindings::ScalarKeyFrameAnimation);
35
36impl ScalarKeyFrameAnimation {
37    /// Inserts a key frame at `progress` (in `0.0..=1.0`) that eases to `value`
38    /// along `easing`.
39    pub fn insert_key_frame_with_easing(
40        &self,
41        progress: f32,
42        value: f32,
43        easing: &CompositionEasingFunction,
44    ) {
45        let animation: bindings::IScalarKeyFrameAnimation = self.0.cast().unwrap();
46        animation
47            .InsertKeyFrameWithEasingFunction(progress, value, &easing.0)
48            .unwrap();
49    }
50
51    /// Inserts a key frame at `progress` whose value is the composition
52    /// `expression` (for example `"this.FinalValue"`), eased along `easing`.
53    pub fn insert_expression_key_frame_with_easing(
54        &self,
55        progress: f32,
56        expression: &str,
57        easing: &CompositionEasingFunction,
58    ) {
59        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
60        animation
61            .InsertExpressionKeyFrameWithEasingFunction(progress, expression, &easing.0)
62            .unwrap();
63    }
64
65    /// Sets how long one iteration of the animation takes.
66    pub fn set_duration(&self, duration: Duration) {
67        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
68        animation.SetDuration(to_time_span(duration)).unwrap();
69    }
70
71    /// Sets the property this animation targets when used as an implicit
72    /// animation (for example `"Opacity"`).
73    pub fn set_target(&self, target: &str) {
74        let animation: bindings::ICompositionAnimation2 = self.0.cast().unwrap();
75        animation.SetTarget(target).unwrap();
76    }
77}
78
79impl Sealed for ScalarKeyFrameAnimation {}
80
81impl Animation for ScalarKeyFrameAnimation {
82    fn as_animation(&self) -> CompositionAnimation {
83        CompositionAnimation(self.0.cast().unwrap())
84    }
85}
86
87/// A key-frame animation that interpolates a `Vector3` property (such as a
88/// visual's `Scale`) through a series of key frames.
89#[derive(Clone)]
90pub struct Vector3KeyFrameAnimation(pub(crate) bindings::Vector3KeyFrameAnimation);
91
92impl Vector3KeyFrameAnimation {
93    /// Inserts a key frame at `progress` (in `0.0..=1.0`) with the given value.
94    pub fn insert_key_frame(&self, progress: f32, value: Vector3) {
95        self.0.InsertKeyFrame(progress, value).unwrap();
96    }
97
98    /// Inserts a key frame at `progress` that eases to `value` along `easing`.
99    pub fn insert_key_frame_with_easing(
100        &self,
101        progress: f32,
102        value: Vector3,
103        easing: &CompositionEasingFunction,
104    ) {
105        let animation: bindings::IVector3KeyFrameAnimation = self.0.cast().unwrap();
106        animation
107            .InsertKeyFrameWithEasingFunction(progress, value, &easing.0)
108            .unwrap();
109    }
110
111    /// Inserts a key frame at `progress` whose value is the composition
112    /// `expression` (for example `"this.FinalValue"`), eased along `easing`.
113    pub fn insert_expression_key_frame_with_easing(
114        &self,
115        progress: f32,
116        expression: &str,
117        easing: &CompositionEasingFunction,
118    ) {
119        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
120        animation
121            .InsertExpressionKeyFrameWithEasingFunction(progress, expression, &easing.0)
122            .unwrap();
123    }
124
125    /// Sets how long one iteration of the animation takes.
126    pub fn set_duration(&self, duration: Duration) {
127        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
128        animation.SetDuration(to_time_span(duration)).unwrap();
129    }
130
131    /// Sets how long to wait before the animation starts.
132    pub fn set_delay(&self, delay: Duration) {
133        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
134        animation.SetDelayTime(to_time_span(delay)).unwrap();
135    }
136
137    /// Sets the property this animation targets when used as an implicit
138    /// animation (for example `"Scale"`).
139    pub fn set_target(&self, target: &str) {
140        let animation: bindings::ICompositionAnimation2 = self.0.cast().unwrap();
141        animation.SetTarget(target).unwrap();
142    }
143
144    /// Sets the animation to run for a fixed number of iterations.
145    pub fn set_iteration_count(&self, count: i32) {
146        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
147        animation
148            .SetIterationBehavior(bindings::AnimationIterationBehavior::Count)
149            .unwrap();
150        animation.SetIterationCount(count).unwrap();
151    }
152
153    /// Sets the animation to repeat forever.
154    pub fn set_iterate_forever(&self) {
155        let animation: bindings::IKeyFrameAnimation = self.0.cast().unwrap();
156        animation
157            .SetIterationBehavior(bindings::AnimationIterationBehavior::Forever)
158            .unwrap();
159    }
160}
161
162impl Sealed for Vector3KeyFrameAnimation {}
163
164impl Animation for Vector3KeyFrameAnimation {
165    fn as_animation(&self) -> CompositionAnimation {
166        CompositionAnimation(self.0.cast().unwrap())
167    }
168}
169
170/// A set of animations that start together.
171#[derive(Clone)]
172pub struct CompositionAnimationGroup(pub(crate) bindings::CompositionAnimationGroup);
173
174impl CompositionAnimationGroup {
175    /// Adds an animation to the group.
176    pub fn add(&self, animation: &impl Animation) {
177        self.0.Add(&animation.as_animation().0).unwrap();
178    }
179
180    /// Returns the lifted group as an inspectable object for a WinUI host.
181    #[cfg(feature = "reactor")]
182    pub fn as_host(&self) -> windows_core::IInspectable {
183        self.0.cast().unwrap()
184    }
185}
186
187/// A map of property-name -> animation applied to a visual so that changes to
188/// those properties animate automatically.
189///
190/// Create one with [`Compositor::create_implicit_animation_collection`],
191/// populate it with [`insert`](Self::insert), and attach it with
192/// [`Visual::set_implicit_animations`](crate::Visual::set_implicit_animations).
193#[derive(Clone)]
194pub struct ImplicitAnimationCollection(pub(crate) bindings::ImplicitAnimationCollection);
195
196impl ImplicitAnimationCollection {
197    /// Associates `animation` with the property named `target` (for example
198    /// `"Opacity"`). The animation should
199    /// [target](ScalarKeyFrameAnimation::set_target) the same property.
200    pub fn insert(&self, target: &str, animation: &impl Animation) {
201        let map: windows_collections::IMap<
202            windows_core::HSTRING,
203            bindings::ICompositionAnimationBase,
204        > = self.0.cast().unwrap();
205        let base: bindings::ICompositionAnimationBase = animation.as_animation().0.cast().unwrap();
206        map.Insert(&windows_core::HSTRING::from(target), &base)
207            .unwrap();
208    }
209}