zng/
event.rs

1//! Event and command API.
2//!
3//! Events are represented by a static instance of [`Event<A>`] with name suffix `_EVENT`. Events have
4//! custom argument types that implement [`EventArgs`], this means that all event arg types have a timestamp, propagation
5//! handle and can define their own delivery list.
6//!
7//! # Notify
8//!
9//! An event update is requested using [`Event::notify`] the notification is pending until the end of the current update,
10//! at that moment the pending notifications apply, in the order they where requested. Each event notifies in this order:
11//!
12//! 1 - All [`AppExtension::event_preview`](crate::app::AppExtension::event_preview).
13//! 2 - All [`Event::on_pre_event`] handlers.
14//! 3 - All [`AppExtension::event_ui`](crate::app::AppExtension::event_ui).
15//! 3.1 - Preview route from window root to each target widget.
16//! 3.2 - Main route from target widget to window root.
17//! 4 - All [`AppExtension::event`](crate::app::AppExtension::event).
18//! 5 - All [``Event::on_event`] handlers.
19//!
20//! Each event args has an [`EventPropagationHandle`] that can be used to signal later handlers that the event
21//! is already handled. The event notification always makes the full route, low level handlers must check if propagation
22//! is stopped or can deliberately ignore it. Event properties automatically check propagation.
23//!
24//! The two event routes in widgets are an emergent property of nested nodes. There is only a method for events, [`UiNode::event`],
25//! if a node handles the event before propagating to the child node it handled it in the preview route (also called tunnel route),
26//! if it handles the event after it propagated it to the child node it handled it in the main route (also called bubble route).
27//!
28//! [`UiNode::event`]: crate::widget::node::UiNode::event
29//!
30//! # Subscribe
31//!
32//! The high-level way to subscribe to an event is by using an event property. These are properties named with prefix
33//! `on_` and `on_pre_`, these properties handle subscription for the widget, filter out propagation stopped events and
34//! also filter into specific aspects of an underlying event.
35//!
36//! ```
37//! use zng::prelude::*;
38//!
39//! # fn example() {
40//! # let _ =
41//! Button! {
42//!     child = Text!("Button");
43//!
44//!     gesture::on_pre_single_click = hn!(|args| {
45//!         assert!(args.is_single());
46//!         println!("single click");
47//!         args.propagation().stop();
48//!     });
49//!     on_click = hn!(|args| {
50//!         assert!(!args.is_single());
51//!         println!("click {:?}", args.click_count.get());
52//!     });
53//! }
54//! # ; }
55//! ```
56//!
57//! In the example above the [`gesture::on_pre_single_click`] and [`gesture::on_click`] are handled, both properties
58//! operate on the same underlying [`gesture::CLICK_EVENT`]. The `on_pre_single_click` property only accepts clicks
59//! with the primary button that are not double-clicks (or triple, etc.), the `on_click` only accepts clicks with
60//! the primary button. In the example `on_click` is never called for single clicks because the `on_pre_single_click` handler
61//! stopped propagation for those events in the preview route, before the click handler.
62//!
63//! ## Subscribe in Nodes
64//!
65//! Widget and properties can subscribe to events directly. When the event [`UpdateDeliveryList`] is build only widgets
66//! selected by the event arguments that are also subscribers to the event are added to the list.
67//!
68//! The [`WIDGET.sub_event`] method can be used to subscribe for the lifetime of the widget, the [`Event::subscribe`]
69//! method can be used to subscribe for an arbitrary lifetime. The [`Event::on`] or [`Event::on_unhandled`] can be
70//! used to match and receive the event.
71//!
72//! [`WIDGET.sub_event`]: crate::widget::WIDGET::sub_event
73//! [`UpdateDeliveryList`]: crate::update::UpdateDeliveryList
74//!
75//! ```
76//! # fn main() { }
77//! use zng::prelude::*;
78//! use zng::prelude_wgt::*;
79//!
80//! #[property(EVENT)]
81//! pub fn print_click(child: impl IntoUiNode, preview: impl IntoVar<bool>) -> UiNode {
82//!     let preview = preview.into_var();
83//!     match_node(child, move |child, op| match op {
84//!         UiNodeOp::Init => {
85//!             WIDGET.sub_event(&gesture::CLICK_EVENT);
86//!         }
87//!         UiNodeOp::Event { update } => {
88//!             if let Some(args) = gesture::CLICK_EVENT.on(update) {
89//!                 if preview.get() {
90//!                     println!("preview click {:?}", args.propagation().is_stopped());
91//!                     child.event(update);
92//!                 } else {
93//!                     child.event(update);
94//!                     println!("click {:?}", args.propagation().is_stopped());
95//!                 }
96//!             }
97//!         }
98//!         _ => {}
99//!     })
100//! }
101//! ```
102//!
103//! The example above declares a property that prints the `CLICK_EVENT` propagation status, the preview/main
104//! routes are defined merely by the position of `child.event(update)` in relation with the handling code.
105//!
106//! ## App Extensions
107//!
108//! App extensions don't need to subscribe to events, they all receive all events.
109//!
110//! ```
111//! use zng::{app::AppExtension, gesture::CLICK_EVENT, update::EventUpdate};
112//!
113//! #[derive(Default)]
114//! struct PrintClickManager {}
115//!
116//! impl AppExtension for PrintClickManager {
117//!     fn event_preview(&mut self, update: &mut EventUpdate) {
118//!         if let Some(args) = CLICK_EVENT.on(update) {
119//!             println!("click, before all UI handlers");
120//!         }
121//!     }
122//!
123//!     fn event(&mut self, update: &mut EventUpdate) {
124//!         if let Some(args) = CLICK_EVENT.on(update) {
125//!             println!("click, after all UI handlers");
126//!         }
127//!     }
128//! }
129//! ```
130//!
131//! ## Direct Handlers
132//!
133//! Event handlers can be set directly on the events using [`Event::on_event`] and [`Event::on_pre_event`].
134//! The handlers run in the app scope (same as app extensions). These event handlers are only called if
135//! propagation is not stopped.
136//!
137//! ```
138//! use zng::prelude::*;
139//! # fn example() {
140//!
141//! gesture::CLICK_EVENT
142//!     .on_pre_event(hn!(|_| {
143//!         println!("click, before all UI handlers");
144//!     }))
145//!     .perm();
146//!
147//! gesture::CLICK_EVENT
148//!     .on_event(hn!(|_| {
149//!         println!("click, after all UI handlers");
150//!     }))
151//!     .perm();
152//! # }
153//! ```
154//!
155//! [`gesture::on_pre_single_click`]: fn@crate::gesture::on_pre_single_click
156//! [`gesture::on_click`]: fn@crate::gesture::on_click
157//! [`gesture::CLICK_EVENT`]: crate::gesture::CLICK_EVENT
158//!
159//! # Event Macros
160//!
161//! Events can be declared using the [`event!`] macro, event arguments using the [`event_args!`]. Event properties
162//! can be declared using [`event_property!`].
163//!
164//! ```
165//! # fn main() { }
166//! use zng::prelude_wgt::*;
167//!
168//! event_args! {
169//!     pub struct FooArgs {
170//!         pub target: WidgetPath,
171//!
172//!         ..
173//!
174//!         fn delivery_list(&self, list: &mut UpdateDeliveryList) {
175//!             list.insert_wgt(&self.target);
176//!         }
177//!     }
178//! }
179//!
180//! event! {
181//!     pub static FOO_EVENT: FooArgs;
182//! }
183//!
184//! event_property! {
185//!     pub fn foo {
186//!         event: FOO_EVENT,
187//!         args: FooArgs,
188//!     }
189//! }
190//!
191//! # fn usage() -> UiNode {
192//! zng::widget::Wgt! {
193//!     zng::widget::on_info_init = hn!(|_| {
194//!         let this_wgt = WIDGET.info().path();
195//!         FOO_EVENT.notify(FooArgs::now(this_wgt));
196//!     });
197//!
198//!     on_pre_foo = hn!(|_| {
199//!         println!("on_pre_foo!");
200//!     });
201//!     on_foo = hn!(|_| {
202//!         println!("on_foo!");
203//!     });
204//! }
205//! # }
206//! ```
207//!
208//! The example above declares `FooArgs`, `FOO_EVENT`, `on_pre_foo` and `on_foo`. The example then declares
209//! a widget that sends the `FOO_EVENT` to itself on init and receives it using the event properties.
210//!
211//! # Commands
212//!
213//! Command events are represented by a static instance of [`Command`] with name suffix `_CMD`. Commands have
214//! custom argument type [`CommandArgs`]. Every command event is also an `Event<CommandArgs>`, commands extend
215//! the event type to provide associated metadata, scope and *enabled* control.
216//!
217//! ## Command Macros
218//!
219//! Commands can be declared using the [`command!`] macro. Command properties can be declared using [`command_property!`].
220//!
221//! ```
222//! # fn main() { }
223//! use zng::prelude_wgt::*;
224//!
225//! command! {
226//!     /// Foo docs.
227//!     pub static FOO_CMD = {
228//!         l10n!: true,
229//!         name: "Foo",
230//!         info: "foo bar",
231//!         shortcut: shortcut![CTRL + 'F'],
232//!     };
233//! }
234//!
235//! command_property! {
236//!     pub fn foo {
237//!         cmd: FOO_CMD.scoped(WIDGET.id()),
238//!     }
239//! }
240//!
241//! # fn usage() -> UiNode {
242//! zng::widget::Wgt! {
243//!     zng::widget::on_info_init = hn!(|_| {
244//!         FOO_CMD.scoped(WIDGET.id()).notify();
245//!     });
246//!
247//!     on_pre_foo = hn!(|_| {
248//!         println!("on_pre_foo!");
249//!     });
250//!     on_foo = hn!(|_| {
251//!         println!("on_foo!");
252//!     });
253//! }
254//! # }
255//! ```
256//!
257//! The example above declares `FOO_CMD`, `on_pre_foo`, `on_foo`, `can_foo` and `CAN_FOO_VAR`. The example then declares
258//! a widget that sends the `FOO_CMD` to itself on init and receives it using the event properties.
259//!
260//! ## Metadata
261//!
262//! All commands provide an [`Command::with_meta`] access point for reading and writing arbitrary metadata. Usually
263//! metadata is declared following the [command extensions] pattern. In the example above the `name`, `info` and `shortcut`
264//! are actually command extensions declared as [`CommandNameExt`], [`CommandInfoExt`] and [`CommandShortcutExt`].
265//!
266//! [command extensions]: Command#extensions
267//! [`CommandShortcutExt`]: crate::gesture::CommandShortcutExt
268//!
269//! ### Localization
270//!
271//! The special `l10n!:` metadata enables localization for the other text metadata of the command. It must be the first
272//! metadata assign and the value must be a literal `bool` or string `""`, the string defines the localization file.
273//!
274//! See the [`l10n`](crate::zng::l10n#commands) module docs om commands for more details.
275//!
276//! ## Scopes
277//!
278//! Commands can be scoped to a window or widget, a scoped command is a different instance of [`Command`], it
279//! inherits metadata from the main command (app scoped), but metadata can be set for a specific scope.
280//!
281//! ```
282//! use zng::prelude::*;
283//! use zng::{clipboard, event::CommandArgs};
284//!
285//! # fn example() {
286//! # let _ =
287//! Stack!(
288//!     top_to_bottom,
289//!     5,
290//!     ui_vec![
291//!         SelectableText! {
292//!             id = "print-copy";
293//!             txt = "Print Copy";
294//!
295//!             widget::on_init = hn!(|_| {
296//!                 let cmd = clipboard::COPY_CMD.scoped(WIDGET.id());
297//!                 cmd.name().set(r#"Print "copy!""#);
298//!                 cmd.info().set("");
299//!             });
300//!             clipboard::on_pre_copy = hn!(|args| {
301//!                 args.propagation().stop();
302//!                 println!("copy!");
303//!             });
304//!         },
305//!         SelectableText! {
306//!             id = "default-copy";
307//!             txt = "Default Copy";
308//!         },
309//!         Button!(clipboard::COPY_CMD.scoped(WidgetId::named("print-copy"))),
310//!         Button!(clipboard::COPY_CMD.scoped(WidgetId::named("default-copy"))),
311//!         Button! {
312//!             cmd = clipboard::COPY_CMD.focus_scoped();
313//!             zng::focus::alt_focus_scope = true;
314//!         },
315//!     ]
316//! )
317//! # ; }
318//! ```
319//!
320//! The example above overrides the metadata and implementation of the copy command for the "print-copy" widget, buttons
321//! targeting that widget show the new metadata.
322//!
323//! Widgets should prefer subscribing only to the command scoped to the widget. App scoped commands target all subscribers,
324//! widget scoped commands target the widget only.
325//!
326//! # Full API
327//!
328//! See [`zng_app::event`] for the full event API.
329
330pub use zng_app::event::{
331    AnyEvent, AnyEventArgs, AppCommandArgs, Command, CommandArgs, CommandHandle, CommandInfoExt, CommandMeta, CommandMetaVar,
332    CommandMetaVarId, CommandNameExt, CommandParam, CommandScope, EVENTS, Event, EventArgs, EventHandle, EventHandles,
333    EventPropagationHandle, EventReceiver, command, event, event_args,
334};
335pub use zng_wgt::node::{command_property, event_property, on_command, on_event, on_pre_command, on_pre_event};