zng_app/handler.rs
1//! Handler types and macros.
2
3use std::any::Any;
4use std::marker::PhantomData;
5use std::time::Duration;
6use std::{mem, thread};
7
8#[doc(hidden)]
9pub use zng_clone_move::*;
10
11use zng_handle::{Handle, WeakHandle};
12use zng_task::{self as task, UiTask};
13
14use crate::INSTANT;
15
16/// Represents a handler in a widget context.
17///
18/// There are different flavors of handlers, you can use macros to declare then.
19/// See [`hn!`], [`hn_once!`] or [`async_hn!`], [`async_hn_once!`] to start.
20#[diagnostic::on_unimplemented(
21 note = "use `hn!(|args: &{A}| {{ }})` to declare a widget handler from a `FnMut` closure",
22 note = "use `hn_once!`, `async_hn!` or `async_hn_once!` for other closure types"
23)]
24pub trait WidgetHandler<A: Clone + 'static>: Any + Send {
25 /// Called every time the handler's event happens in the widget context.
26 ///
27 /// Returns `true` when the event handler is async and it has not finished handling the event.
28 ///
29 /// [`update`]: WidgetHandler::update
30 /// [`info`]: crate::widget::node::UiNode::info
31 fn event(&mut self, args: &A) -> bool;
32
33 /// Called every widget update.
34 ///
35 /// Returns `false` when all pending async tasks are completed. Note that event properties
36 /// will call this method every update even if it is returning `false`.
37 ///
38 /// [`update`]: WidgetHandler::update
39 fn update(&mut self) -> bool {
40 false
41 }
42
43 /// Box the handler.
44 ///
45 /// The type `Box<dyn WidgetHandler<A>>` implements `WidgetHandler<A>` and just returns itself
46 /// in this method, avoiding double boxing.
47 fn boxed(self) -> Box<dyn WidgetHandler<A>>
48 where
49 Self: Sized,
50 {
51 Box::new(self)
52 }
53}
54impl<A: Clone + 'static> WidgetHandler<A> for Box<dyn WidgetHandler<A>> {
55 #[inline(always)]
56 fn event(&mut self, args: &A) -> bool {
57 self.as_mut().event(args)
58 }
59
60 #[inline(always)]
61 fn update(&mut self) -> bool {
62 self.as_mut().update()
63 }
64
65 #[inline(always)]
66 fn boxed(self) -> Box<dyn WidgetHandler<A>>
67 where
68 Self: Sized,
69 {
70 self
71 }
72}
73
74#[doc(hidden)]
75pub struct FnMutWidgetHandler<H> {
76 handler: H,
77}
78impl<A, H> WidgetHandler<A> for FnMutWidgetHandler<H>
79where
80 A: Clone + 'static,
81 H: FnMut(&A) + Send + 'static,
82{
83 #[inline(always)]
84 fn event(&mut self, args: &A) -> bool {
85 (self.handler)(args);
86 false
87 }
88}
89
90#[doc(hidden)]
91pub fn hn<A, H>(handler: H) -> FnMutWidgetHandler<H>
92where
93 A: Clone + 'static,
94 H: FnMut(&A) + Send + 'static,
95{
96 FnMutWidgetHandler { handler }
97}
98
99///<span data-del-macro-root></span> Declare a mutable *clone-move* event handler.
100///
101/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
102/// the input is the same syntax.
103///
104/// # Examples
105///
106/// The example declares an event handler for the `on_click` property.
107///
108/// ```
109/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
110/// # use zng_app::handler::hn;
111/// # let _scope = zng_app::APP.minimal();
112/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
113/// # let
114/// on_click = hn!(|_| {
115/// println!("Clicked!");
116/// });
117/// # on_click }
118/// ```
119///
120/// The closure input is `&ClickArgs` for this property. Note that
121/// if you want to use the event args you must annotate the input type, the context type is inferred.
122///
123/// ```
124/// # #[derive(Clone)] pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize }
125/// # use zng_app::handler::hn;
126/// # let _scope = zng_app::APP.minimal();
127/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
128/// # let
129/// on_click = hn!(|args: &ClickArgs| {
130/// println!("Clicked {}!", args.click_count);
131/// });
132/// # on_click }
133/// ```
134///
135/// Internally the [`clmv!`] macro is used so you can *clone-move* variables into the handler.
136///
137/// ```
138/// # #[derive(Clone)] pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize }
139/// # use zng_txt::formatx;
140/// # use zng_var::{var, Var};
141/// # use zng_app::handler::hn;
142/// # let _scope = zng_app::APP.minimal();
143/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
144/// let foo = var(0);
145///
146/// // ..
147///
148/// # let
149/// on_click = hn!(foo, |args: &ClickArgs| {
150/// foo.set(args.click_count);
151/// });
152///
153/// // can still use after:
154/// let bar = foo.map(|c| formatx!("click_count: {c}"));
155///
156/// # on_click }
157/// ```
158///
159/// In the example above only a clone of `foo` is moved into the handler. Note that handlers always capture by move, if `foo` was not
160/// listed in the *clone-move* section it would not be available after the handler is created. See [`clmv!`] for details.
161///
162/// [`clmv!`]: zng_clone_move::clmv
163#[macro_export]
164macro_rules! hn {
165 ($($tt:tt)+) => {
166 $crate::handler::hn($crate::handler::clmv!{ $($tt)+ })
167 }
168}
169#[doc(inline)]
170pub use crate::hn;
171use crate::{AppControlFlow, HeadlessApp};
172
173#[doc(hidden)]
174pub struct FnOnceWidgetHandler<H> {
175 handler: Option<H>,
176}
177impl<A, H> WidgetHandler<A> for FnOnceWidgetHandler<H>
178where
179 A: Clone + 'static,
180 H: FnOnce(&A) + Send + 'static,
181{
182 #[inline(always)]
183 fn event(&mut self, args: &A) -> bool {
184 if let Some(handler) = self.handler.take() {
185 handler(args);
186 }
187 false
188 }
189}
190#[doc(hidden)]
191pub fn hn_once<A, H>(handler: H) -> FnOnceWidgetHandler<H>
192where
193 A: Clone + 'static,
194 H: FnOnce(&A) + Send + 'static,
195{
196 FnOnceWidgetHandler { handler: Some(handler) }
197}
198
199///<span data-del-macro-root></span> Declare a *clone-move* event handler that is only called once.
200///
201/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
202/// the input is the same syntax.
203///
204/// # Examples
205///
206/// The example captures `data` by move and then destroys it in the first call, this cannot be done using [`hn!`] because
207/// the `data` needs to be available for all event calls. In this case the closure is only called once, subsequent events
208/// are ignored by the handler.
209///
210/// ```
211/// # use zng_app::handler::hn_once;
212/// # let _scope = zng_app::APP.minimal();
213/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<()> {
214/// let data = vec![1, 2, 3];
215/// # let
216/// on_click = hn_once!(|_| {
217/// for i in data {
218/// print!("{i}, ");
219/// }
220/// });
221/// # on_click }
222/// ```
223///
224/// Other then declaring a `FnOnce` this macro behaves like [`hn!`], so the same considerations apply. You can *clone-move* variables,
225/// the type of the input is the event arguments and must be annotated.
226///
227/// ```
228/// # use zng_app::handler::hn_once;
229/// # let _scope = zng_app::APP.minimal();
230/// # #[derive(Clone)]
231/// # pub struct ClickArgs { click_count: usize }
232/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
233/// let data = vec![1, 2, 3];
234/// # let
235/// on_click = hn_once!(data, |args: &ClickArgs| {
236/// drop(data);
237/// });
238///
239/// println!("{data:?}");
240/// # on_click }
241/// ```
242///
243/// [`clmv!`]: zng_clone_move::clmv
244#[macro_export]
245macro_rules! hn_once {
246 ($($tt:tt)+) => {
247 $crate::handler::hn_once($crate::handler::clmv! { $($tt)+ })
248 }
249}
250#[doc(inline)]
251pub use crate::hn_once;
252
253#[doc(hidden)]
254pub struct AsyncFnMutWidgetHandler<H> {
255 handler: H,
256 tasks: Vec<UiTask<()>>,
257}
258impl<A, F, H> WidgetHandler<A> for AsyncFnMutWidgetHandler<H>
259where
260 A: Clone + 'static,
261 F: Future<Output = ()> + Send + 'static,
262 H: FnMut(A) -> F + Send + 'static,
263{
264 fn event(&mut self, args: &A) -> bool {
265 let handler = &mut self.handler;
266 let mut task = UiTask::new(Some(WIDGET.id()), handler(args.clone()));
267 let need_update = task.update().is_none();
268 if need_update {
269 self.tasks.push(task);
270 }
271 need_update
272 }
273
274 fn update(&mut self) -> bool {
275 self.tasks.retain_mut(|t| t.update().is_none());
276 !self.tasks.is_empty()
277 }
278}
279#[doc(hidden)]
280pub fn async_hn<A, F, H>(handler: H) -> AsyncFnMutWidgetHandler<H>
281where
282 A: Clone + 'static,
283 F: Future<Output = ()> + Send + 'static,
284 H: FnMut(A) -> F + Send + 'static,
285{
286 AsyncFnMutWidgetHandler { handler, tasks: vec![] }
287}
288
289///<span data-del-macro-root></span> Declare an async *clone-move* event handler.
290///
291/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn!`] so
292/// the input is the same syntax.
293///
294/// # Examples
295///
296/// The example declares an async event handler for the `on_click` property.
297///
298/// ```
299/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
300/// # use zng_app::handler::async_hn;
301/// # use zng_task as task;
302/// # let _scope = zng_app::APP.minimal();
303/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
304/// # let
305/// on_click = async_hn!(|_| {
306/// println!("Clicked!");
307///
308/// task::run(async {
309/// println!("In other thread!");
310/// })
311/// .await;
312///
313/// println!("Back in UI thread, in a widget update.");
314/// });
315/// # on_click }
316/// ```
317///
318/// The closure input is `ClickArgs` for this property. Note that
319/// if you want to use the event args you must annotate the input type.
320///
321/// ```
322/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
323/// # use zng_app::handler::async_hn;
324/// # use zng_app::widget::WIDGET;
325/// # let _scope = zng_app::APP.minimal();
326/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
327/// # let
328/// on_click = async_hn!(|args: ClickArgs| {
329/// println!("Clicked {} {} times!", WIDGET.id(), args.click_count);
330/// });
331/// # on_click }
332/// ```
333///
334/// Internally the [`async_clmv_fn!`] macro is used so you can *clone-move* variables into the handler.
335///
336/// ```
337/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
338/// # use zng_app::handler::async_hn;
339/// # use zng_var::{var, Var};
340/// # use zng_task as task;
341/// # use zng_txt::formatx;
342/// # let _scope = zng_app::APP.minimal();
343/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
344/// let enabled = var(true);
345///
346/// // ..
347///
348/// # let
349/// on_click = async_hn!(enabled, |args: ClickArgs| {
350/// enabled.set(false);
351///
352/// task::run(async move {
353/// println!("do something {}", args.click_count);
354/// })
355/// .await;
356///
357/// enabled.set(true);
358/// });
359///
360/// // can still use after:
361/// # let
362/// text = enabled.map(|&e| if e { "Click Me!" } else { "Busy.." });
363/// enabled;
364///
365/// # on_click }
366/// ```
367///
368/// In the example above only a clone of `enabled` is moved into the handler. Note that handlers always capture by move, if `enabled` was not
369/// listed in the *clone-move* section it would not be available after the handler is created. See [`async_clmv_fn!`] for details.
370///
371/// The example also demonstrates a common pattern with async handlers, most events are only raised when the widget is enabled, so you can
372/// disable the widget while the async task is running. This way you don't block the UI running a task but the user cannot spawn a second
373/// task while the first is still running.
374///
375/// ## Futures and Clone-Move
376///
377/// You want to always *clone-move* captures for async handlers, because they then automatically get cloned again for each event. This
378/// needs to happen because you can have more then one *handler task* running at the same type, and both want access to the captured variables.
379///
380/// This second cloning can be avoided by using the [`async_hn_once!`] macro instead, but only if you expect a single event.
381///
382/// Note that this means you are declaring a normal closure that returns a `'static` future, not an async closure, see [`async_clmv_fn!`].
383///
384/// [`async_clmv_fn!`]: zng_clone_move::async_clmv_fn
385#[macro_export]
386macro_rules! async_hn {
387 ($($tt:tt)+) => {
388 $crate::handler::async_hn($crate::handler::async_clmv_fn! { $($tt)+ })
389 }
390}
391#[doc(inline)]
392pub use crate::async_hn;
393
394enum AsyncFnOnceWhState<H> {
395 NotCalled(H),
396 Pending(UiTask<()>),
397 Done,
398}
399#[doc(hidden)]
400pub struct AsyncFnOnceWidgetHandler<H> {
401 state: AsyncFnOnceWhState<H>,
402}
403impl<A, F, H> WidgetHandler<A> for AsyncFnOnceWidgetHandler<H>
404where
405 A: Clone + 'static,
406 F: Future<Output = ()> + Send + 'static,
407 H: FnOnce(A) -> F + Send + 'static,
408{
409 fn event(&mut self, args: &A) -> bool {
410 match mem::replace(&mut self.state, AsyncFnOnceWhState::Done) {
411 AsyncFnOnceWhState::NotCalled(handler) => {
412 let mut task = UiTask::new(Some(WIDGET.id()), handler(args.clone()));
413 let is_pending = task.update().is_none();
414 if is_pending {
415 self.state = AsyncFnOnceWhState::Pending(task);
416 }
417 is_pending
418 }
419 AsyncFnOnceWhState::Pending(t) => {
420 self.state = AsyncFnOnceWhState::Pending(t);
421 false
422 }
423 AsyncFnOnceWhState::Done => false,
424 }
425 }
426
427 fn update(&mut self) -> bool {
428 let mut is_pending = false;
429 if let AsyncFnOnceWhState::Pending(t) = &mut self.state {
430 is_pending = t.update().is_none();
431 if !is_pending {
432 self.state = AsyncFnOnceWhState::Done;
433 }
434 }
435 is_pending
436 }
437}
438#[doc(hidden)]
439pub fn async_hn_once<A, F, H>(handler: H) -> AsyncFnOnceWidgetHandler<H>
440where
441 A: Clone + 'static,
442 F: Future<Output = ()> + Send + 'static,
443 H: FnOnce(A) -> F + Send + 'static,
444{
445 AsyncFnOnceWidgetHandler {
446 state: AsyncFnOnceWhState::NotCalled(handler),
447 }
448}
449
450///<span data-del-macro-root></span> Declare an async *clone-move* event handler that is only called once.
451///
452/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn_once!`] so
453/// the input is the same syntax.
454///
455/// # Examples
456///
457/// The example captures `data` by move and then moves it again to another thread. This is not something you can do using [`async_hn!`]
458/// because that handler expects to be called many times. We expect `on_open` to only be called once, so we can don't need to capture by
459/// *clone-move* here just to use `data`.
460///
461/// ```
462/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
463/// # use zng_app::handler::async_hn_once;
464/// # use zng_task as task;
465/// # let _scope = zng_app::APP.minimal();
466/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
467/// let data = vec![1, 2, 3];
468/// # let
469/// on_open = async_hn_once!(|_| {
470/// task::run(async move {
471/// for i in data {
472/// print!("{i}, ");
473/// }
474/// })
475/// .await;
476///
477/// println!("Done!");
478/// });
479/// # on_open }
480/// ```
481///
482/// You can still *clone-move* to have access to the variable after creating the handler, in this case the `data` will be cloned into the handler
483/// but will just be moved to the other thread, avoiding a needless clone.
484///
485/// ```
486/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
487/// # use zng_app::handler::async_hn_once;
488/// # use zng_task as task;
489/// # let _scope = zng_app::APP.minimal();
490/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
491/// let data = vec![1, 2, 3];
492/// # let
493/// on_open = async_hn_once!(data, |_| {
494/// task::run(async move {
495/// for i in data {
496/// print!("{i}, ");
497/// }
498/// })
499/// .await;
500///
501/// println!("Done!");
502/// });
503/// println!("{data:?}");
504/// # on_open }
505/// ```
506///
507/// [`async_clmv_fn_once!`]: zng_clone_move::async_clmv_fn_once
508#[macro_export]
509macro_rules! async_hn_once {
510 ($($tt:tt)+) => {
511 $crate::handler::async_hn_once($crate::handler::async_clmv_fn_once! { $($tt)+ })
512 }
513}
514#[doc(inline)]
515pub use crate::async_hn_once;
516
517/// Represents a weak handle to an [`AppHandler`] subscription.
518pub trait AppWeakHandle: Send {
519 /// Dynamic clone.
520 fn clone_boxed(&self) -> Box<dyn AppWeakHandle>;
521
522 /// Unsubscribes the [`AppHandler`].
523 ///
524 /// This stops the handler from being called again and causes it to be dropped in a future app update.
525 fn unsubscribe(&self);
526}
527impl<D: Send + Sync + 'static> AppWeakHandle for WeakHandle<D> {
528 fn clone_boxed(&self) -> Box<dyn AppWeakHandle> {
529 Box::new(self.clone())
530 }
531
532 fn unsubscribe(&self) {
533 if let Some(handle) = self.upgrade() {
534 handle.force_drop();
535 }
536 }
537}
538
539/// Arguments for a call of [`AppHandler::event`].
540#[non_exhaustive]
541pub struct AppHandlerArgs<'a> {
542 /// Handle to the [`AppHandler`] subscription.
543 pub handle: &'a dyn AppWeakHandle,
544 /// If the handler is invoked in a *preview* context.
545 pub is_preview: bool,
546}
547
548/// Represents an event handler in the app context.
549///
550/// There are different flavors of handlers, you can use macros to declare then.
551/// See [`app_hn!`], [`app_hn_once!`] or [`async_app_hn!`], [`async_app_hn_once!`] to start.
552#[diagnostic::on_unimplemented(
553 note = "use `app_hn!(|args: &{A}, _| {{ }})` to declare an app handler closure",
554 note = "use `app_hn_once!`, `async_app_hn!` or `async_app_hn_once!` for other closure types"
555)]
556pub trait AppHandler<A: Clone + 'static>: Any + Send {
557 /// Called every time the event happens.
558 ///
559 /// The `handler_args` can be used to unsubscribe the handler. Async handlers are expected to schedule
560 /// their tasks to run somewhere in the app, usually in the [`UPDATES.on_update`]. The `handle` is
561 /// **not** expected to cancel running async tasks, only to drop `self` before the next event happens.
562 ///
563 /// [`UPDATES.on_update`]: crate::update::UPDATES::on_update
564 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs);
565
566 /// Boxes the handler.
567 ///
568 /// The type `Box<dyn AppHandler<A>>` implements `AppHandler<A>` and just returns itself
569 /// in this method, avoiding double boxing.
570 fn boxed(self) -> Box<dyn AppHandler<A>>
571 where
572 Self: Sized,
573 {
574 Box::new(self)
575 }
576}
577impl<A: Clone + 'static> AppHandler<A> for Box<dyn AppHandler<A>> {
578 #[inline(always)]
579 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
580 self.as_mut().event(args, handler_args)
581 }
582
583 #[inline(always)]
584 fn boxed(self) -> Box<dyn AppHandler<A>> {
585 self
586 }
587}
588
589#[doc(hidden)]
590pub struct FnMutAppHandler<H> {
591 handler: H,
592}
593impl<A, H> AppHandler<A> for FnMutAppHandler<H>
594where
595 A: Clone + 'static,
596 H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
597{
598 #[inline(always)]
599 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
600 (self.handler)(args, handler_args.handle);
601 }
602}
603#[doc(hidden)]
604pub fn app_hn<A, H>(handler: H) -> FnMutAppHandler<H>
605where
606 A: Clone + 'static,
607 H: FnMut(&A, &dyn AppWeakHandle) + Send + 'static,
608{
609 FnMutAppHandler { handler }
610}
611
612///<span data-del-macro-root></span> Declare a mutable *clone-move* app event handler.
613///
614/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
615/// the input is the same syntax.
616///
617/// # Examples
618///
619/// The example declares an event handler for the `CLICK_EVENT`.
620///
621/// ```
622/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
623/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
624/// # use zng_app::handler::app_hn;
625/// # let _scope = zng_app::APP.minimal();
626/// # fn assert_type() {
627/// CLICK_EVENT
628/// .on_event(app_hn!(|_, _| {
629/// println!("Clicked Somewhere!");
630/// }))
631/// .perm();
632/// # }
633/// ```
634///
635/// The closure input is `&A, &dyn AppWeakHandle` with `&A` equaling `&ClickArgs` for this event. Note that
636/// if you want to use the event args you must annotate the input type, the context and handle type is inferred.
637///
638/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
639/// will be dropped some time before the next event update.
640///
641/// ```
642/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
643/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
644/// # use zng_app::handler::app_hn;
645/// # let _scope = zng_app::APP.minimal();
646/// # fn assert_type() {
647/// CLICK_EVENT
648/// .on_event(app_hn!(|args: &ClickArgs, handle| {
649/// println!("Clicked {}!", args.target);
650/// handle.unsubscribe();
651/// }))
652/// .perm();
653/// # }
654/// ```
655///
656/// Internally the [`clmv!`] macro is used so you can *clone-move* variables into the handler.
657///
658/// ```
659/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
660/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
661/// # use zng_txt::{formatx, ToTxt};
662/// # use zng_var::{var, Var};
663/// # use zng_app::handler::app_hn;
664/// # let _scope = zng_app::APP.minimal();
665/// # fn assert_type() {
666/// let foo = var("".to_txt());
667///
668/// CLICK_EVENT
669/// .on_event(app_hn!(foo, |args: &ClickArgs, _| {
670/// foo.set(args.target.to_txt());
671/// }))
672/// .perm();
673///
674/// // can still use after:
675/// let bar = foo.map(|c| formatx!("last click: {c}"));
676///
677/// # }
678/// ```
679///
680/// In the example above only a clone of `foo` is moved into the handler. Note that handlers always capture by move, if `foo` was not
681/// listed in the *clone-move* section it would not be available after the handler is created. See [`clmv!`] for details.
682///
683/// [`clmv!`]: zng_clone_move::clmv
684#[macro_export]
685macro_rules! app_hn {
686 ($($tt:tt)+) => {
687 $crate::handler::app_hn($crate::handler::clmv!{ $($tt)+ })
688 }
689}
690#[doc(inline)]
691pub use crate::app_hn;
692
693#[doc(hidden)]
694pub struct FnOnceAppHandler<H> {
695 handler: Option<H>,
696}
697impl<A, H> AppHandler<A> for FnOnceAppHandler<H>
698where
699 A: Clone + 'static,
700 H: FnOnce(&A) + Send + 'static,
701{
702 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
703 if let Some(handler) = self.handler.take() {
704 handler(args);
705 handler_args.handle.unsubscribe();
706 } else {
707 tracing::error!("`app_hn_once!` called after requesting unsubscribe");
708 }
709 }
710}
711#[doc(hidden)]
712pub fn app_hn_once<A, H>(handler: H) -> FnOnceAppHandler<H>
713where
714 A: Clone + 'static,
715 H: FnOnce(&A) + Send + 'static,
716{
717 FnOnceAppHandler { handler: Some(handler) }
718}
719
720///<span data-del-macro-root></span> Declare a *clone-move* app event handler that is only called once.
721///
722/// The macro input is a closure with optional *clone-move* variables, internally it uses [`clmv!`] so
723/// the input is the same syntax.
724///
725/// # Examples
726///
727/// The example captures `data` by move and then destroys it in the first call, this cannot be done using [`app_hn!`] because
728/// the `data` needs to be available for all event calls. In this case the closure is only called once, subsequent events
729/// are ignored by the handler and it automatically requests unsubscribe.
730///
731/// ```
732/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
733/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
734/// # use zng_app::handler::app_hn_once;
735/// # let _scope = zng_app::APP.minimal();
736/// # fn assert_type() {
737/// let data = vec![1, 2, 3];
738///
739/// CLICK_EVENT
740/// .on_event(app_hn_once!(|_| {
741/// for i in data {
742/// print!("{i}, ");
743/// }
744/// }))
745/// .perm();
746/// # }
747/// ```
748///
749/// Other then declaring a `FnOnce` this macro behaves like [`app_hn!`], so the same considerations apply. You can *clone-move* variables,
750/// the type of the input is the event arguments and must be annotated.
751///
752/// ```
753/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
754/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
755/// # use zng_app::handler::app_hn_once;
756/// # let _scope = zng_app::APP.minimal();
757/// # fn assert_type() {
758/// let data = vec![1, 2, 3];
759///
760/// CLICK_EVENT
761/// .on_event(app_hn_once!(data, |args: &ClickArgs| {
762/// drop(data);
763/// }))
764/// .perm();
765///
766/// println!("{data:?}");
767/// # }
768/// ```
769///
770/// [`clmv!`]: zng_clone_move::clmv
771#[macro_export]
772macro_rules! app_hn_once {
773 ($($tt:tt)+) => {
774 $crate::handler::app_hn_once($crate::handler::clmv! { $($tt)+ })
775 }
776}
777#[doc(inline)]
778pub use crate::app_hn_once;
779
780#[doc(hidden)]
781pub struct AsyncFnMutAppHandler<H> {
782 handler: H,
783}
784impl<A, F, H> AppHandler<A> for AsyncFnMutAppHandler<H>
785where
786 A: Clone + 'static,
787 F: Future<Output = ()> + Send + 'static,
788 H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
789{
790 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
791 let handler = &mut self.handler;
792 let mut task = UiTask::new(None, handler(args.clone(), handler_args.handle.clone_boxed()));
793 if task.update().is_none() {
794 if handler_args.is_preview {
795 UPDATES
796 .on_pre_update(app_hn!(|_, handle| {
797 if task.update().is_some() {
798 handle.unsubscribe();
799 }
800 }))
801 .perm();
802 } else {
803 UPDATES
804 .on_update(app_hn!(|_, handle| {
805 if task.update().is_some() {
806 handle.unsubscribe();
807 }
808 }))
809 .perm();
810 }
811 }
812 }
813}
814#[doc(hidden)]
815pub fn async_app_hn<A, F, H>(handler: H) -> AsyncFnMutAppHandler<H>
816where
817 A: Clone + 'static,
818 F: Future<Output = ()> + Send + 'static,
819 H: FnMut(A, Box<dyn AppWeakHandle>) -> F + Send + 'static,
820{
821 AsyncFnMutAppHandler { handler }
822}
823
824///<span data-del-macro-root></span> Declare an async *clone-move* app event handler.
825///
826/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn!`] so
827/// the input is the same syntax.
828///
829/// The handler generates a future for each event, the future is polled immediately if it does not finish it is scheduled
830/// to update in [`on_pre_update`](crate::update::UPDATES::on_pre_update) or [`on_update`](crate::update::UPDATES::on_update) depending
831/// on if the handler was assigned to a *preview* event or not.
832///
833/// Note that this means [`propagation`](crate::event::AnyEventArgs::propagation) can only be meaningfully stopped before the
834/// first `.await`, after, the event has already propagated.
835///
836/// # Examples
837///
838/// The example declares an async event handler for the `CLICK_EVENT`.
839///
840/// ```
841/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
842/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
843/// # use zng_app::handler::async_app_hn;
844/// # use zng_task as task;
845/// # let _scope = zng_app::APP.minimal();
846/// # fn assert_type() {
847/// CLICK_EVENT
848/// .on_event(async_app_hn!(|_, _| {
849/// println!("Clicked Somewhere!");
850///
851/// task::run(async {
852/// println!("In other thread!");
853/// })
854/// .await;
855///
856/// println!("Back in UI thread, in an app update.");
857/// }))
858/// .perm();
859/// # }
860/// ```
861///
862/// The closure input is `A, Box<dyn AppWeakHandle>` for all handlers and `A` is `ClickArgs` for this example. Note that
863/// if you want to use the event args you must annotate the input type, the context and handle types are inferred.
864///
865/// The handle can be used to unsubscribe the event handler, if [`unsubscribe`](AppWeakHandle::unsubscribe) is called the handler
866/// will be dropped some time before the next event update. Running tasks are not canceled by unsubscribing, the only way to *cancel*
867/// then is by returning early inside the async blocks.
868///
869/// ```
870/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
871/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
872/// # use zng_app::handler::async_app_hn;
873/// # use zng_task as task;
874/// # let _scope = zng_app::APP.minimal();
875/// # fn assert_type() {
876/// CLICK_EVENT
877/// .on_event(async_app_hn!(|args: ClickArgs, handle| {
878/// println!("Clicked {}!", args.target);
879/// task::run(async move {
880/// handle.unsubscribe();
881/// });
882/// }))
883/// .perm();
884/// # }
885/// ```
886///
887/// Internally the [`async_clmv_fn!`] macro is used so you can *clone-move* variables into the handler.
888///
889/// ```
890/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
891/// # zng_app::event::event! { pub static CLICK_EVENT: ClickArgs; }
892/// # use zng_app::handler::async_app_hn;
893/// # use zng_var::{var, Var};
894/// # use zng_task as task;
895/// # use zng_txt::{formatx, ToTxt};
896/// #
897/// # let _scope = zng_app::APP.minimal();
898/// # fn assert_type() {
899/// let status = var("pending..".to_txt());
900///
901/// CLICK_EVENT
902/// .on_event(async_app_hn!(status, |args: ClickArgs, _| {
903/// status.set(formatx!("processing {}..", args.target));
904///
905/// task::run(async move {
906/// println!("do something slow");
907/// })
908/// .await;
909///
910/// status.set(formatx!("finished {}", args.target));
911/// }))
912/// .perm();
913///
914/// // can still use after:
915/// let text = status;
916///
917/// # }
918/// ```
919///
920/// In the example above only a clone of `status` is moved into the handler. Note that handlers always capture by move, if `status` was not
921/// listed in the *clone-move* section it would not be available after the handler is created. See [`async_clmv_fn!`] for details.
922///
923/// ## Futures and Clone-Move
924///
925/// You may want to always *clone-move* captures for async handlers, because they then automatically get cloned again for each event. This
926/// needs to happen because you can have more then one *handler task* running at the same type, and both want access to the captured variables.
927///
928/// This second cloning can be avoided by using the [`async_hn_once!`] macro instead, but only if you expect a single event.
929///
930/// [`async_clmv_fn!`]: zng_clone_move::async_clmv_fn
931#[macro_export]
932macro_rules! async_app_hn {
933 ($($tt:tt)+) => {
934 $crate::handler::async_app_hn($crate::handler::async_clmv_fn! { $($tt)+ })
935 }
936}
937#[doc(inline)]
938pub use crate::async_app_hn;
939
940#[doc(hidden)]
941pub struct AsyncFnOnceAppHandler<H> {
942 handler: Option<H>,
943}
944
945impl<A, F, H> AppHandler<A> for AsyncFnOnceAppHandler<H>
946where
947 A: Clone + 'static,
948 F: Future<Output = ()> + Send + 'static,
949 H: FnOnce(A) -> F + Send + 'static,
950{
951 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
952 if let Some(handler) = self.handler.take() {
953 handler_args.handle.unsubscribe();
954
955 let mut task = UiTask::new(None, handler(args.clone()));
956 if task.update().is_none() {
957 if handler_args.is_preview {
958 UPDATES
959 .on_pre_update(app_hn!(|_, handle| {
960 if task.update().is_some() {
961 handle.unsubscribe();
962 }
963 }))
964 .perm();
965 } else {
966 UPDATES
967 .on_update(app_hn!(|_, handle| {
968 if task.update().is_some() {
969 handle.unsubscribe();
970 }
971 }))
972 .perm();
973 }
974 }
975 } else {
976 tracing::error!("`async_app_hn_once!` called after requesting unsubscribe");
977 }
978 }
979}
980#[doc(hidden)]
981pub fn async_app_hn_once<A, F, H>(handler: H) -> AsyncFnOnceAppHandler<H>
982where
983 A: Clone + 'static,
984 F: Future<Output = ()> + Send + 'static,
985 H: FnOnce(A) -> F + Send + 'static,
986{
987 AsyncFnOnceAppHandler { handler: Some(handler) }
988}
989
990///<span data-del-macro-root></span> Declare an async *clone-move* app event handler that is only called once.
991///
992/// The macro input is a closure with optional *clone-move* variables, internally it uses [`async_clmv_fn_once!`] so
993/// the input is the same syntax.
994///
995/// # Examples
996///
997/// The example captures `data` by move and then moves it again to another thread. This is not something you can do using [`async_app_hn!`]
998/// because that handler expects to be called many times. We want to handle `CLICK_EVENT` once in this example, so we can don't need
999/// to capture by *clone-move* just to use `data`.
1000///
1001/// ```
1002/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1003/// # use zng_app::handler::async_hn_once;
1004/// # use zng_task as task;
1005/// # let _scope = zng_app::APP.minimal();
1006/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1007/// let data = vec![1, 2, 3];
1008/// # let
1009/// on_open = async_hn_once!(|_| {
1010/// task::run(async move {
1011/// for i in data {
1012/// print!("{i}, ");
1013/// }
1014/// })
1015/// .await;
1016///
1017/// println!("Done!");
1018/// });
1019/// # on_open }
1020/// ```
1021///
1022/// You can still *clone-move* to have access to the variable after creating the handler, in this case the `data` will be cloned into the handler
1023/// but will just be moved to the other thread, avoiding a needless clone.
1024///
1025/// ```
1026/// # zng_app::event::event_args! { pub struct ClickArgs { pub target: zng_txt::Txt, pub click_count: usize, .. fn delivery_list(&self, _l: &mut UpdateDeliveryList) { } } }
1027/// # use zng_app::handler::async_hn_once;
1028/// # use zng_task as task;
1029/// # let _scope = zng_app::APP.minimal();
1030/// # fn assert_type() -> impl zng_app::handler::WidgetHandler<ClickArgs> {
1031/// let data = vec![1, 2, 3];
1032/// # let
1033/// on_open = async_hn_once!(data, |_| {
1034/// task::run(async move {
1035/// for i in data {
1036/// print!("{i}, ");
1037/// }
1038/// })
1039/// .await;
1040///
1041/// println!("Done!");
1042/// });
1043/// println!("{data:?}");
1044/// # on_open }
1045/// ```
1046///
1047/// [`async_clmv_fn_once!`]: zng_clone_move::async_clmv_fn_once
1048#[macro_export]
1049macro_rules! async_app_hn_once {
1050 ($($tt:tt)+) => {
1051 $crate::handler::async_app_hn_once($crate::handler::async_clmv_fn_once! { $($tt)+ })
1052 }
1053}
1054#[doc(inline)]
1055pub use crate::async_app_hn_once;
1056use crate::update::UPDATES;
1057use crate::widget::{UiTaskWidget, WIDGET};
1058
1059/// Widget handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1060pub struct FilterWidgetHandler<A, H, F> {
1061 _args: PhantomData<fn() -> A>,
1062 handler: H,
1063 filter: F,
1064}
1065impl<A, H, F> FilterWidgetHandler<A, H, F>
1066where
1067 A: Clone + 'static,
1068 H: WidgetHandler<A>,
1069 F: FnMut(&A) -> bool + Send + 'static,
1070{
1071 /// New filter handler.
1072 pub fn new(handler: H, filter: F) -> Self {
1073 Self {
1074 handler,
1075 filter,
1076 _args: PhantomData,
1077 }
1078 }
1079}
1080impl<A, H, F> WidgetHandler<A> for FilterWidgetHandler<A, H, F>
1081where
1082 A: Clone + 'static,
1083 H: WidgetHandler<A>,
1084 F: FnMut(&A) -> bool + Send + 'static,
1085{
1086 #[inline(always)]
1087 fn event(&mut self, args: &A) -> bool {
1088 if (self.filter)(args) { self.handler.event(args) } else { false }
1089 }
1090
1091 #[inline(always)]
1092 fn update(&mut self) -> bool {
1093 self.handler.update()
1094 }
1095}
1096
1097/// App handler wrapper that filters the events, only delegating to `self` when `filter` returns `true`.
1098pub struct FilterAppHandler<A, H, F> {
1099 _args: PhantomData<fn() -> A>,
1100 handler: H,
1101 filter: F,
1102}
1103impl<A, H, F> FilterAppHandler<A, H, F>
1104where
1105 A: Clone + 'static,
1106 H: AppHandler<A>,
1107 F: FnMut(&A) -> bool + Send + 'static,
1108{
1109 /// New filter handler.
1110 pub fn new(handler: H, filter: F) -> Self {
1111 Self {
1112 handler,
1113 filter,
1114 _args: PhantomData,
1115 }
1116 }
1117}
1118impl<A, H, F> AppHandler<A> for FilterAppHandler<A, H, F>
1119where
1120 A: Clone + 'static,
1121 H: AppHandler<A>,
1122 F: FnMut(&A) -> bool + Send + 'static,
1123{
1124 #[inline(always)]
1125 fn event(&mut self, args: &A, handler_args: &AppHandlerArgs) {
1126 if (self.filter)(args) {
1127 self.handler.event(args, handler_args);
1128 }
1129 }
1130}
1131
1132impl HeadlessApp {
1133 /// Calls an [`AppHandler<A>`] once and blocks until the update tasks started during the call complete.
1134 ///
1135 /// This function *spins* until all update tasks are completed. Timers or send events can
1136 /// be received during execution but the loop does not sleep, it just spins requesting an update
1137 /// for each pass.
1138 pub fn block_on<A>(&mut self, handler: &mut dyn AppHandler<A>, args: &A, timeout: Duration) -> Result<(), String>
1139 where
1140 A: Clone + 'static,
1141 {
1142 self.block_on_multi(vec![handler], args, timeout)
1143 }
1144
1145 /// Calls multiple [`AppHandler<A>`] once each and blocks until all update tasks are complete.
1146 ///
1147 /// This function *spins* until all update tasks are completed. Timers or send events can
1148 /// be received during execution but the loop does not sleep, it just spins requesting an update
1149 /// for each pass.
1150 pub fn block_on_multi<A>(&mut self, handlers: Vec<&mut dyn AppHandler<A>>, args: &A, timeout: Duration) -> Result<(), String>
1151 where
1152 A: Clone + 'static,
1153 {
1154 let (pre_len, pos_len) = UPDATES.handler_lens();
1155
1156 let handler_args = AppHandlerArgs {
1157 handle: &Handle::dummy(()).downgrade(),
1158 is_preview: false,
1159 };
1160 for handler in handlers {
1161 handler.event(args, &handler_args);
1162 }
1163
1164 let mut pending = UPDATES.new_update_handlers(pre_len, pos_len);
1165
1166 if !pending.is_empty() {
1167 let start_time = INSTANT.now();
1168 while {
1169 pending.retain(|h| h());
1170 !pending.is_empty()
1171 } {
1172 UPDATES.update(None);
1173 let flow = self.update(false);
1174 if INSTANT.now().duration_since(start_time) >= timeout {
1175 return Err(format!(
1176 "block_on reached timeout of {timeout:?} before the handler task could finish",
1177 ));
1178 }
1179
1180 match flow {
1181 AppControlFlow::Poll => continue,
1182 AppControlFlow::Wait => {
1183 thread::yield_now();
1184 continue;
1185 }
1186 AppControlFlow::Exit => return Ok(()),
1187 }
1188 }
1189 }
1190
1191 Ok(())
1192 }
1193
1194 /// Polls a `future` and updates the app repeatedly until it completes or the `timeout` is reached.
1195 pub fn block_on_fut<F: Future>(&mut self, future: F, timeout: Duration) -> Result<F::Output, String> {
1196 let future = task::with_deadline(future, timeout);
1197 let mut future = std::pin::pin!(future);
1198
1199 let waker = UPDATES.waker(None);
1200 let mut cx = std::task::Context::from_waker(&waker);
1201
1202 loop {
1203 let mut fut_poll = future.as_mut().poll(&mut cx);
1204 let flow = self.update_observe(
1205 || {
1206 if fut_poll.is_pending() {
1207 fut_poll = future.as_mut().poll(&mut cx);
1208 }
1209 },
1210 true,
1211 );
1212
1213 match fut_poll {
1214 std::task::Poll::Ready(r) => match r {
1215 Ok(r) => return Ok(r),
1216 Err(e) => return Err(e.to_string()),
1217 },
1218 std::task::Poll::Pending => {}
1219 }
1220
1221 match flow {
1222 AppControlFlow::Poll => continue,
1223 AppControlFlow::Wait => {
1224 thread::yield_now();
1225 continue;
1226 }
1227 AppControlFlow::Exit => return Err("app exited".to_owned()),
1228 }
1229 }
1230 }
1231
1232 /// Calls the `handler` once and [`block_on`] it with a 60 seconds timeout using the minimal headless app.
1233 ///
1234 /// [`block_on`]: Self::block_on
1235 #[track_caller]
1236 #[cfg(any(test, doc, feature = "test_util"))]
1237 pub fn doc_test<A, H>(args: A, mut handler: H)
1238 where
1239 A: Clone + 'static,
1240 H: AppHandler<A>,
1241 {
1242 let mut app = crate::APP.minimal().run_headless(false);
1243 app.block_on(&mut handler, &args, DOC_TEST_BLOCK_ON_TIMEOUT).unwrap();
1244 }
1245
1246 /// Calls the `handlers` once each and [`block_on_multi`] with a 60 seconds timeout.
1247 ///
1248 /// [`block_on_multi`]: Self::block_on_multi
1249 #[track_caller]
1250 #[cfg(any(test, doc, feature = "test_util"))]
1251 pub fn doc_test_multi<A>(args: A, mut handlers: Vec<Box<dyn AppHandler<A>>>)
1252 where
1253 A: Clone + 'static,
1254 {
1255 let mut app = crate::APP.minimal().run_headless(false);
1256 app.block_on_multi(handlers.iter_mut().map(|h| h.as_mut()).collect(), &args, DOC_TEST_BLOCK_ON_TIMEOUT)
1257 .unwrap()
1258 }
1259}
1260
1261#[cfg(any(test, doc, feature = "test_util"))]
1262const DOC_TEST_BLOCK_ON_TIMEOUT: Duration = Duration::from_secs(60);