moly_kit/utils/makepad/
ui_runner.rs

1//! Extensions to [UiRunner] that make sense for moly kit.
2//!
3//! Async extensions could actually be part of [UiRunner] at makepad, but there is no
4//! `futures` crate there, and idk if the async channels implemented there would work
5//! propertly for this.
6
7use makepad_widgets::defer_with_redraw::DeferWithRedraw;
8use makepad_widgets::{Cx, Scope, UiRunner, Widget};
9
10pub trait DeferRedraw<W>
11where
12    Self: Sized,
13{
14    /// Requests to do a redraw and nothing else.
15    ///
16    /// Mostly a shorthand for `defer_with_redraw` with an empty closure.
17    fn defer_redraw(self) {}
18}
19
20impl<W: Widget + 'static> DeferRedraw<W> for UiRunner<W> {
21    fn defer_redraw(self) {
22        self.defer_with_redraw(|_, _, _| {});
23    }
24}
25
26pub trait AsyncDeferCallback<T, R>:
27    FnOnce(&mut T, &mut Cx, &mut Scope) -> R + Send + 'static
28where
29    R: Send + 'static,
30{
31}
32
33impl<T, R: Send + 'static, F: FnOnce(&mut T, &mut Cx, &mut Scope) -> R + Send + 'static>
34    AsyncDeferCallback<T, R> for F
35{
36}
37
38/// Async extension to [UiRunner], allowing to await until deferred closures are executed.
39#[allow(unused)]
40pub trait DeferAsync<T> {
41    /// Awaitable variant of [UiRunner::defer].
42    ///
43    /// This is actually similar to [UiRunner::block_on], but can be used inside
44    /// async contexts where is important to not block.
45    ///
46    /// The syncrhonous return value of the closure will be returned from the Future.
47    ///
48    /// The Future may give `None` if it couldn't receive a value back, because the
49    /// widget coudln't execute the closure. This can happen even without errors if
50    /// the widget is dropped before executing the pending closure.
51    fn defer_async<R>(
52        self,
53        f: impl AsyncDeferCallback<T, R>,
54    ) -> impl std::future::Future<Output = Option<R>> + Send
55    where
56        R: Send + 'static,
57        Self: Sized;
58}
59
60impl<T: 'static> DeferAsync<T> for UiRunner<T> {
61    async fn defer_async<R: Send + 'static>(self, f: impl AsyncDeferCallback<T, R>) -> Option<R> {
62        let (tx, rx) = futures::channel::oneshot::channel::<R>();
63        self.defer(move |me, cx, scope| {
64            let _ = tx.send(f(me, cx, scope));
65        });
66        rx.await.ok()
67    }
68}
69
70/// Async extension to [UiRunner], allowing to await until deferred closures with
71/// redraw are executed
72pub trait DeferWithRedrawAsync<T: 'static> {
73    /// Awaitable variant of [DeferWithRedraw::defer_with_redraw] based on [DeferAsync::defer_async].
74    ///
75    /// Return value behaves the same as [DeferAsync::defer_async].
76    fn defer_with_redraw_async<R>(
77        self,
78        f: impl AsyncDeferCallback<T, R>,
79    ) -> impl std::future::Future<Output = Option<R>> + Send
80    where
81        R: Send + 'static,
82        Self: Sized;
83}
84
85impl<W: Widget + 'static> DeferWithRedrawAsync<W> for UiRunner<W> {
86    async fn defer_with_redraw_async<R: Send + 'static>(
87        self,
88        f: impl AsyncDeferCallback<W, R>,
89    ) -> Option<R> {
90        let (tx, rx) = futures::channel::oneshot::channel::<R>();
91        self.defer_with_redraw(move |widget, cx, scope| {
92            let _ = tx.send(f(widget, cx, scope));
93        });
94        rx.await.ok()
95    }
96}