zng/
handler.rs

1//! Event handler API.
2//!
3//! A handler is a closure that takes a *context* and *arguments*, the context can be [`WIDGET`] or the app. The [`Handler<A>`]
4//! type supports both synchronous and asynchronous handlers. The handler is not usually instantiated directly, macros are provided
5//! for declaring handlers.
6//!
7//! The handler macros are [`hn!`], [`hn_once!`], [`async_hn!`], [`async_hn_once!`].
8//! These macros are built on top of the primitive macros [`clmv!`], [`async_clmv_fn!`] and [`async_clmv_fn_once!`] to
9//! provide a very easy way to *clone-move* captured variables into the handler.
10//!
11//! ```
12//! use zng::prelude::*;
13//! # fn example() {
14//!
15//! let last_clicked = var(Txt::from(""));
16//! # let _ =
17//! Stack!(
18//!     top_to_bottom,
19//!     5,
20//!     ui_vec![
21//!         Button! {
22//!             child = Text!("hn!");
23//!             on_click = hn!(last_clicked, |_| {
24//!                 last_clicked.set("hn!");
25//!             });
26//!         },
27//!         Button! {
28//!             child = Text!("hn_once!");
29//!             on_click = hn_once!(last_clicked, |_| {
30//!                 last_clicked.set("hn_once!");
31//!             });
32//!         },
33//!         {
34//!             let enabled = var(true);
35//!             Button! {
36//!                 child = Text!("async_hn!");
37//!                 on_click = async_hn!(last_clicked, enabled, |_| {
38//!                     last_clicked.set("async_hn!");
39//!                     enabled.set(false);
40//!                     task::deadline(1.secs()).await;
41//!                     enabled.set(true);
42//!                 });
43//!                 widget::enabled;
44//!             }
45//!         },
46//!         Text!(last_clicked),
47//!     ]
48//! )
49//! # ; }
50//! ```
51//!
52//! # App Context
53//!
54//! When a handler is not set in a widget the [`APP_HANDLER`] contextual service is available, it can be used to unsubscribe
55//! the event from within.
56//!
57//! ```
58//! # use zng::prelude::*;
59//! # use zng::focus::FOCUS_CHANGED_EVENT;
60//! # fn example() {
61//! FOCUS_CHANGED_EVENT
62//!     .on_pre_event(
63//!         true,
64//!         hn!(|args| {
65//!             println!("focused: {:?}", args.new_focus);
66//!             if args.new_focus.is_none() {
67//!                 zng::handler::APP_HANDLER.unsubscribe();
68//!             }
69//!         }),
70//!     )
71//!     .perm();
72//! # }
73//! ```
74//!
75//! In the example above the event subscription is made `perm`, but inside the handler `unsubscribe` is called when a
76//! condition is met, causing the handler to be dropped. This is a common pattern for app level event handlers that
77//! can manage their own subscription.
78//!
79//! The [`APP_HANDLER`] will also be available after each `await` point in async handlers, after an async task unsubscribes
80//! all running handler tasks will run to the end and no new tasks will be started.
81//!
82//! # Args Type Inference
83//!
84//! The [`Handler<A>`] type is an alias for `Box<dyn FnMut(&A + Clone + 'static) ...>` by necessity as this is the only way to have a type where
85//! the closure args is inferred. Unfortunately this has some limitations, documentation shows the raw box type, the `A` bounds is not enforced
86//! on type declaration too.
87//!
88//! These limitations enable type inference for the arguments of [`hn!`] and [`async_hn!`] set directly on a property, reducing the need to
89//! track down exact event args types, unfortunately as of this release the [`hn_once!`] and [`async_hn_once!`] handlers will still need
90//! and explicit args type if the handler uses the arg.
91//!
92//! [`WIDGET`]: crate::widget::WIDGET
93//! [`clmv!`]: crate::clmv
94//! [`async_clmv_fn!`]: crate::async_clmv_fn
95//! [`async_clmv_fn_once!`]: crate::async_clmv_fn_once
96//!
97//! # Full API
98//!
99//! See [`zng_app::handler`] for the full handler API.
100
101pub use zng_app::handler::{APP_HANDLER, AppWeakHandle, ArcHandler, Handler, HandlerExt, async_hn, async_hn_once, hn, hn_once};