1mod clock;
4mod entry;
5mod handle;
6mod policy;
7mod registration;
8mod registry;
9mod source;
10mod target;
11#[cfg(test)]
12mod tests;
13mod tick;
14
15pub use clock::{AnimationClock, SystemClock};
16pub use entry::AnimationPlaybackState;
17pub use handle::AnimationHandle;
18pub use policy::TickPolicy;
19pub use registration::AnimationRegistration;
20pub use target::{AnimationTargetId, TargetedPropertySnapshot};
21pub use tick::AnimationTick;
22
23use crate::runtime::clock::TestClock;
24use crate::runtime::{
25 entry::ActiveAnimation,
26 registry::AnimationRegistry,
27 source::{AnimationSource, PropertyTransitionSource},
28};
29use crate::{
30 keyframes::Keyframes,
31 property::{PropertySnapshot, PropertySpec, PropertyValueKind},
32 timeline::Timeline,
33 timing::{Duration, Timing},
34};
35
36#[derive(Debug, Clone)]
60pub struct AnimationRuntime<C = SystemClock> {
61 registry: AnimationRegistry,
62 clock: C,
63 motion_policy: TickPolicy,
64}
65
66impl AnimationRuntime<SystemClock> {
67 #[must_use]
69 pub fn new() -> Self {
70 Self::with_clock(SystemClock::new())
71 }
72}
73
74impl Default for AnimationRuntime<SystemClock> {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80impl AnimationRuntime<TestClock> {
81 #[must_use]
83 pub fn testing() -> Self {
84 Self::with_clock(TestClock::new())
85 }
86
87 pub const fn clock_mut(&mut self) -> &mut TestClock {
92 &mut self.clock
93 }
94}
95
96impl<C: AnimationClock> AnimationRuntime<C> {
97 #[must_use]
99 pub fn with_clock(clock: C) -> Self {
100 Self {
101 registry: AnimationRegistry::new(),
102 clock,
103 motion_policy: TickPolicy::default(),
104 }
105 }
106
107 pub(crate) fn register_target(
109 &mut self,
110 target: AnimationTargetId,
111 source: impl Into<AnimationSource>,
112 ) -> AnimationRegistration {
113 let handle = AnimationHandle::new();
114 let now = self.clock.now();
115 let source = source.into();
116 let initial_snapshot = source.sample_at(Duration::ZERO);
117 let mut entry = ActiveAnimation::new(handle, target, source, now);
118
119 entry.set_last_snapshot(initial_snapshot.clone());
120
121 if entry.source().total_duration() == Some(Duration::ZERO) {
122 let completion_snapshot = entry.source().completion_snapshot();
123
124 entry.set_last_snapshot(completion_snapshot);
125 entry.mark_completed(now);
126 }
127
128 let registration = AnimationRegistration::from_entry(&entry);
129 self.registry.insert(target, entry);
130
131 #[cfg(feature = "tracing")]
132 tracing::debug!(
133 target: "aura_anim_iced::runtime",
134 handle = registration.handle().id(),
135 target_id = ?target,
136 state = ?registration.state(),
137 completed = registration.completed_at().is_some(),
138 "registered animation"
139 );
140
141 registration
142 }
143
144 pub fn register_keyframes(
146 &mut self,
147 target: AnimationTargetId,
148 keyframes: Keyframes,
149 ) -> AnimationRegistration {
150 self.register_target(target, keyframes)
151 }
152
153 pub(crate) fn register_property_transition<K>(
154 &mut self,
155 target: AnimationTargetId,
156 property: PropertySpec<K>,
157 timing: Timing,
158 from: K::Inner,
159 to: K::Inner,
160 ) -> AnimationRegistration
161 where
162 K: PropertyValueKind,
163 {
164 self.register_target(
165 target,
166 PropertyTransitionSource::new(property.raw(), K::wrap(from), K::wrap(to), timing),
167 )
168 }
169
170 pub fn register_timeline(
172 &mut self,
173 target: AnimationTargetId,
174 timeline: Timeline,
175 ) -> AnimationRegistration {
176 self.register_target(target, timeline)
177 }
178
179 pub(crate) fn register_timeline_arc(
180 &mut self,
181 target: AnimationTargetId,
182 timeline: Arc<Timeline>,
183 ) -> AnimationRegistration {
184 self.register_target(target, timeline)
185 }
186
187 pub fn tick(&mut self) -> AnimationTick {
189 let now = self.clock.now();
190
191 tick::tick_registry(&mut self.registry, now)
192 }
193
194 pub fn tick_into(&mut self, output: &mut AnimationTick) {
196 let now = self.clock.now();
197
198 tick::tick_registry_into(&mut self.registry, now, output);
199 }
200
201 pub fn cancel_target(&mut self, target: AnimationTargetId) {
203 self.registry.cancel_target(target);
204 }
205
206 pub fn seek_target(&mut self, target: AnimationTargetId, pos: Duration) {
208 self.registry.seek_target(target, pos, self.clock.now());
209 }
210
211 pub fn pause_target(&mut self, target: AnimationTargetId) {
213 self.registry.pause_target(target, self.clock.now());
214 }
215
216 pub fn cancel(&mut self, target: AnimationTargetId, handle: AnimationHandle) -> bool {
220 self.registry.cancel(target, handle)
221 }
222
223 pub fn seek(
227 &mut self,
228 target: AnimationTargetId,
229 handle: AnimationHandle,
230 pos: Duration,
231 ) -> bool {
232 self.registry.seek(target, handle, pos, self.clock.now())
233 }
234
235 pub fn pause(&mut self, target: AnimationTargetId, handle: AnimationHandle) -> bool {
239 self.registry.pause(target, handle, self.clock.now())
240 }
241
242 pub(crate) fn last_properties(
243 &self,
244 target: AnimationTargetId,
245 handle: AnimationHandle,
246 ) -> Option<&PropertySnapshot> {
247 let entry = self.registry.get_by_handle(handle)?;
248
249 if entry.target() != target {
250 return None;
251 }
252
253 entry.last_snapshot()
254 }
255
256 pub(crate) fn contains(&self, target: AnimationTargetId, handle: AnimationHandle) -> bool {
257 self.registry
258 .get_by_handle(handle)
259 .is_some_and(|entry| entry.target() == target)
260 }
261}
262
263impl<C> AnimationRuntime<C> {
264 #[must_use]
266 pub const fn clock(&self) -> &C {
267 &self.clock
268 }
269
270 #[must_use]
272 pub const fn motion_policy(&self) -> TickPolicy {
273 self.motion_policy
274 }
275
276 pub const fn set_motion_policy(&mut self, motion_policy: TickPolicy) {
278 self.motion_policy = motion_policy;
279 }
280
281 #[must_use]
283 pub fn active_count(&self) -> usize {
284 self.registry.active_count()
285 }
286
287 #[must_use]
289 pub fn is_idle(&self) -> bool {
290 self.active_count() == 0
291 }
292
293 #[must_use]
295 pub fn should_tick(&self) -> bool {
296 self.registry
297 .entries()
298 .iter()
299 .any(ActiveAnimation::needs_tick)
300 }
301
302 #[must_use]
304 pub fn should_subscribe(&self) -> bool {
305 self.should_tick()
306 }
307}
308use std::sync::Arc;