Skip to main content

ferroui_base/animation/
i_page_transition.rs

1use crate::animation::AnimationTask;
2use crate::threading::{
3    CancellationToken, Dispatcher, DispatcherPriority, DispatcherTask, FerroSynchronizationContext,
4};
5use std::future::Future;
6use crate::{Ref, Visual};
7
8/// Interface for animations that transition between two pages.
9pub trait IPageTransition: 'static {
10    /// Starts the animation.
11    ///
12    /// `from` is the control that is being transitioned away from, if any,
13    /// and `to` the control that is being transitioned to, if any. `forward`
14    /// tells whether the transition goes forwards or backwards. The
15    /// transition stops as it is when `cancellation_token` is cancelled.
16    ///
17    /// The result tracks the progress of the animation: it completes when
18    /// the transition has ended or was cancelled, and it fails (re-raising
19    /// the failure to whoever observes it) when an animation of the
20    /// transition could not be run.
21    fn start(
22        &self,
23        from: Option<&Ref<Visual>>,
24        to: Option<&Ref<Visual>>,
25        forward: bool,
26        cancellation_token: CancellationToken,
27    ) -> DispatcherTask<()>;
28
29    /// The transition as a progress-driven transition, if it is one.
30    fn as_progress_page_transition(&self) -> Option<&dyn crate::animation::IProgressPageTransition> {
31        None
32    }
33
34    /// The transition as a page slide, if it is one.
35    fn as_page_slide(&self) -> Option<&crate::animation::PageSlide> {
36        None
37    }
38
39    /// The transition as a composite page transition, if it is one.
40    fn as_composite_page_transition(&self) -> Option<&crate::animation::CompositePageTransition> {
41        None
42    }
43}
44
45impl PartialEq for dyn IPageTransition {
46    #[inline]
47    fn eq(&self, other: &Self) -> bool {
48        std::ptr::addr_eq(self as *const dyn IPageTransition, other as *const dyn IPageTransition)
49    }
50}
51
52/// The synchronization context that asynchronous code started on the calling
53/// thread continues in: the current one, or the dispatcher's context for
54/// [`DispatcherPriority::NORMAL`] when the thread has none.
55pub(crate) fn continuation_context() -> std::sync::Arc<FerroSynchronizationContext> {
56    FerroSynchronizationContext::current().unwrap_or_else(|| {
57        FerroSynchronizationContext::with_dispatcher(&Dispatcher::current_dispatcher(), DispatcherPriority::NORMAL)
58    })
59}
60
61/// Runs the body of an asynchronous page transition: synchronously up to its
62/// first pending await, then resumed through the synchronization context.
63pub(crate) fn start_async(future: impl Future<Output = ()> + 'static) -> DispatcherTask<()> {
64    continuation_context().to_task_scheduler().start_local(future)
65}
66
67/// Awaits the animations of a page transition. A failure to run one of them
68/// fails the transition.
69pub(crate) async fn when_all(tasks: Vec<AnimationTask>) {
70    if let Err(error) = AnimationTask::when_all(tasks).await {
71        panic!("{error}");
72    }
73}