1use std::{any::Any, fmt, sync::Arc, time::Duration};
4
5use parking_lot::Mutex;
6use smallbox::SmallBox;
7use zng_app_context::context_local;
8use zng_handle::{Handle, HandleOwner, WeakHandle};
9use zng_time::{DInstant, Deadline};
10use zng_unit::Factor;
11
12use crate::{
13 Var, VarHandle, VarHandlerOwner, VarValue,
14 animation::easing::{EasingStep, EasingTime},
15};
16
17pub mod easing;
18pub use zng_var_proc_macros::Transitionable;
19
20pub trait AnimationTimer {
22 fn elapsed(&mut self, deadline: Deadline) -> bool;
25
26 fn register(&mut self, deadline: Deadline);
28
29 fn now(&self) -> DInstant;
31}
32
33pub trait AnimationController: Send + Sync + Any {
39 fn on_start(&self, animation: &Animation) {
43 let _ = animation;
44 }
45
46 fn on_stop(&self, animation: &Animation) {
50 let _ = animation;
51 }
52}
53
54impl AnimationController for () {}
55
56pub struct ForceAnimationController;
58impl AnimationController for ForceAnimationController {
59 fn on_start(&self, animation: &Animation) {
60 animation.force_enable();
61 }
62}
63
64context_local! {
65 pub(crate) static VARS_ANIMATION_CTRL_CTX: Box<dyn AnimationController> = {
66 let r: Box<dyn AnimationController> = Box::new(());
67 r
68 };
69}
70
71#[derive(Clone)]
77pub struct Animation(Arc<Mutex<AnimationData>>);
78struct AnimationData {
79 start_time: DInstant,
80 restarted_count: usize,
81 stop: bool,
82 sleep: Option<Deadline>,
83 restart_next: bool,
84 animations_enabled: bool,
85 force_enabled: bool,
86 now: DInstant,
87 time_scale: Factor,
88}
89
90impl Animation {
91 pub(super) fn new(animations_enabled: bool, now: DInstant, time_scale: Factor) -> Self {
92 Animation(Arc::new(Mutex::new(AnimationData {
93 start_time: now,
94 restarted_count: 0,
95 stop: false,
96 now,
97 sleep: None,
98 restart_next: false,
99 animations_enabled,
100 force_enabled: false,
101 time_scale,
102 })))
103 }
104
105 pub fn start_time(&self) -> DInstant {
107 self.0.lock().start_time
108 }
109
110 pub fn now(&self) -> DInstant {
117 self.0.lock().now
118 }
119
120 pub fn time_scale(&self) -> Factor {
122 self.0.lock().time_scale
123 }
124
125 pub(crate) fn reset_state(&self, enabled: bool, now: DInstant, time_scale: Factor) {
126 let mut m = self.0.lock();
127 if !m.force_enabled {
128 m.animations_enabled = enabled;
129 }
130 m.now = now;
131 m.time_scale = time_scale;
132 m.sleep = None;
133
134 if std::mem::take(&mut m.restart_next) {
135 m.start_time = now;
136 m.restarted_count += 1;
137 }
138 }
139
140 pub(crate) fn reset_sleep(&self) {
141 self.0.lock().sleep = None;
142 }
143
144 pub fn sleep(&self, duration: Duration, restart: bool) {
153 let mut me = self.0.lock();
154 me.sleep = Some(Deadline(me.now + duration));
155 me.restart_next = restart;
156 }
157
158 pub(crate) fn sleep_deadline(&self) -> Option<Deadline> {
159 self.0.lock().sleep
160 }
161
162 pub fn animations_enabled(&self) -> bool {
166 self.0.lock().animations_enabled
167 }
168
169 pub fn force_enable(&self) {
175 let mut me = self.0.lock();
176 me.force_enabled = true;
177 me.animations_enabled = true;
178 }
179
180 pub fn elapsed_dur(&self) -> Duration {
185 let me = self.0.lock();
186 me.now - me.start_time
187 }
188
189 pub fn elapsed(&self, duration: Duration) -> EasingTime {
195 let me = self.0.lock();
196 if me.animations_enabled {
197 EasingTime::elapsed(duration, me.now - me.start_time, me.time_scale)
198 } else {
199 EasingTime::end()
200 }
201 }
202
203 pub fn elapsed_stop(&self, duration: Duration) -> EasingTime {
207 let t = self.elapsed(duration);
208 if t.is_end() {
209 self.stop()
210 }
211 t
212 }
213
214 pub fn elapsed_restart(&self, duration: Duration) -> EasingTime {
218 let t = self.elapsed(duration);
219 if t.is_end() {
220 self.restart()
221 }
222 t
223 }
224
225 pub fn elapsed_restart_stop(&self, duration: Duration, max_restarts: usize) -> EasingTime {
230 let t = self.elapsed(duration);
231 if t.is_end() {
232 if self.count() < max_restarts {
233 self.restart();
234 } else {
235 self.stop();
236 }
237 }
238 t
239 }
240
241 pub fn stop(&self) {
243 self.0.lock().stop = true;
244 }
245
246 pub fn stop_requested(&self) -> bool {
248 self.0.lock().stop
249 }
250
251 pub fn restart(&self) {
253 let mut me = self.0.lock();
254 me.start_time = me.now;
255 me.restarted_count += 1;
256 }
257
258 #[doc(hidden)]
259 #[deprecated = "use `count`"]
260 pub fn restart_count(&self) -> usize {
261 self.0.lock().restarted_count
262 }
263
264 pub fn count(&self) -> usize {
266 self.0.lock().restarted_count
267 }
268
269 pub fn set_start_time(&self, instant: DInstant) {
273 self.0.lock().start_time = instant;
274 }
275
276 pub fn set_elapsed(&self, elapsed: EasingTime, duration: Duration) {
281 let now = self.0.lock().now;
282 self.set_start_time(now.checked_sub(duration * elapsed.fct()).unwrap());
283 }
284
285 pub fn set_count(&self, count: usize) {
287 self.0.lock().restarted_count = count;
288 }
289}
290
291#[derive(Clone)]
293pub struct ModifyInfo {
294 pub(crate) handle: Option<WeakAnimationHandle>,
295 pub(crate) importance: usize,
296}
297impl ModifyInfo {
298 pub fn never() -> Self {
300 ModifyInfo {
301 handle: None,
302 importance: 0,
303 }
304 }
305
306 pub fn importance(&self) -> usize {
312 self.importance
313 }
314
315 pub fn is_animating(&self) -> bool {
323 self.handle.as_ref().map(|h| h.upgrade().is_some()).unwrap_or(false)
324 }
325
326 pub fn animation_eq(&self, other: &Self) -> bool {
328 self.handle == other.handle
329 }
330
331 pub fn hook_animation_stop(&self, handler: AnimationStopFn) -> VarHandle {
335 if let Some(h) = &self.handle
336 && let Some(h) = h.upgrade()
337 {
338 return h.hook_animation_stop(handler);
339 }
340 VarHandle::dummy()
341 }
342}
343impl fmt::Debug for ModifyInfo {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 f.debug_struct("ModifyInfo")
346 .field("is_animating()", &self.is_animating())
347 .field("importance()", &self.importance)
348 .finish()
349 }
350}
351
352pub(crate) type AnimationStopFn = SmallBox<dyn FnMut() + Send + 'static, smallbox::space::S4>;
353
354#[derive(Default)]
355pub(super) struct AnimationHandleData {
356 on_drop: Mutex<Vec<(AnimationStopFn, VarHandlerOwner)>>,
357}
358impl Drop for AnimationHandleData {
359 fn drop(&mut self) {
360 for (mut f, h) in self.on_drop.get_mut().drain(..) {
361 if h.is_alive() {
362 f()
363 }
364 }
365 }
366}
367#[derive(Clone, PartialEq, Eq, Hash, Debug)]
374#[repr(transparent)]
375#[must_use = "the animation stops if the handle is dropped"]
376pub struct AnimationHandle(Handle<AnimationHandleData>);
377impl Default for AnimationHandle {
378 fn default() -> Self {
380 Self::dummy()
381 }
382}
383impl AnimationHandle {
384 pub(super) fn new() -> (HandleOwner<AnimationHandleData>, Self) {
385 let (owner, handle) = Handle::new(AnimationHandleData::default());
386 (owner, AnimationHandle(handle))
387 }
388
389 pub fn dummy() -> Self {
393 AnimationHandle(Handle::dummy(AnimationHandleData::default()))
394 }
395
396 pub fn perm(self) {
400 self.0.perm();
401 }
402
403 pub fn is_permanent(&self) -> bool {
407 self.0.is_permanent()
408 }
409
410 pub fn stop(self) {
412 self.0.force_drop();
413 }
414
415 pub fn is_stopped(&self) -> bool {
419 self.0.is_dropped()
420 }
421
422 pub fn downgrade(&self) -> WeakAnimationHandle {
424 WeakAnimationHandle(self.0.downgrade())
425 }
426
427 pub fn hook_animation_stop(&self, handler: AnimationStopFn) -> VarHandle {
433 if !self.is_stopped() {
434 let (owner, handle) = VarHandle::new();
435 self.0.data().on_drop.lock().push((handler, owner));
436 handle
437 } else {
438 VarHandle::dummy()
439 }
440 }
441}
442
443#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
445pub struct WeakAnimationHandle(pub(super) WeakHandle<AnimationHandleData>);
446impl WeakAnimationHandle {
447 pub fn new() -> Self {
449 Self(WeakHandle::new())
450 }
451
452 pub fn upgrade(&self) -> Option<AnimationHandle> {
454 self.0.upgrade().map(AnimationHandle)
455 }
456}
457
458pub trait Transitionable: VarValue {
465 fn lerp(self, to: &Self, step: EasingStep) -> Self;
467}
468
469#[non_exhaustive]
471pub struct Transition<T> {
472 pub from: T,
474 pub to: T,
477}
478impl<T> Transition<T>
479where
480 T: Transitionable,
481{
482 pub fn new(from: T, to: T) -> Self {
484 Self { from, to }
485 }
486
487 pub fn sample(&self, step: EasingStep) -> T {
489 self.from.clone().lerp(&self.to, step)
490 }
491}
492
493#[derive(Clone, Debug)]
495pub struct TransitionKeyed<T> {
496 keys: Vec<(Factor, T)>,
497}
498impl<T> TransitionKeyed<T>
499where
500 T: Transitionable,
501{
502 pub fn new(mut keys: Vec<(Factor, T)>) -> Option<Self> {
506 if keys.is_empty() {
507 return None;
508 }
509
510 for i in 1..keys.len() {
512 if keys[i].0 < keys[i - 1].0 {
513 keys[i].0 = keys[i - 1].0;
514 }
515 }
516
517 Some(TransitionKeyed { keys })
518 }
519
520 pub fn keys(&self) -> &[(Factor, T)] {
522 &self.keys
523 }
524
525 pub fn sample(&self, step: EasingStep) -> T {
527 if let Some(i) = self.keys.iter().position(|(f, _)| *f > step) {
528 if i == 0 {
529 self.keys[0].1.clone()
531 } else {
532 let (from_step, from_value) = self.keys[i - 1].clone();
533 if from_step == step {
534 from_value
536 } else {
537 let (_, to_value) = &self.keys[i];
540 let step = step - from_step;
541
542 from_value.lerp(to_value, step)
543 }
544 }
545 } else {
546 self.keys[self.keys.len() - 1].1.clone()
548 }
549 }
550}
551
552pub struct ChaseAnimation<T: VarValue + Transitionable> {
554 pub(super) target: T,
555 pub(super) var: Var<T>,
556 pub(super) handle: AnimationHandle,
557}
558impl<T> fmt::Debug for ChaseAnimation<T>
559where
560 T: VarValue + Transitionable,
561{
562 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563 f.debug_struct("ChaseAnimation")
564 .field("target", &self.target)
565 .finish_non_exhaustive()
566 }
567}
568impl<T> ChaseAnimation<T>
569where
570 T: VarValue + Transitionable,
571{
572 pub fn target(&self) -> &T {
574 &self.target
575 }
576
577 pub fn modify(&mut self, modify: impl FnOnce(&mut T), duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + 'static) {
579 if self.handle.is_stopped() {
580 self.target = self.var.get();
582 }
583 modify(&mut self.target);
584 self.handle = self.var.ease(self.target.clone(), duration, easing);
585 }
586
587 pub fn set(&mut self, value: impl Into<T>, duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + 'static) {
589 self.target = value.into();
590 self.handle = self.var.ease(self.target.clone(), duration, easing);
591 }
592}
593
594pub fn slerp_sampler<T: Transitionable>(t: &Transition<T>, step: EasingStep) -> T {
605 slerp_enabled(true, || t.sample(step))
606}
607
608pub fn is_slerp_enabled() -> bool {
612 SLERP_ENABLED.get_clone()
613}
614
615pub fn slerp_enabled<R>(enabled: bool, f: impl FnOnce() -> R) -> R {
619 SLERP_ENABLED.with_context(&mut Some(Arc::new(enabled)), f)
620}
621
622context_local! {
623 static SLERP_ENABLED: bool = false;
624}
625
626#[expect(non_camel_case_types)]
628pub struct TRANSITIONABLE_APP;