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