zng_app/event.rs
1//! App event and commands API.
2
3use std::{fmt, marker::PhantomData, ops, sync::Arc};
4
5use crate::{
6 handler::HandlerResult,
7 update::UPDATES,
8 widget::{AnyVarSubscribe, OnVarArgs},
9};
10use parking_lot::MappedRwLockReadGuard;
11use zng_app_context::AppLocal;
12use zng_task::channel;
13use zng_var::{AnyVar, VARS, Var, VarHandle, VarUpdateId, VarValue};
14
15use crate::{
16 handler::Handler,
17 update::UpdateOp,
18 widget::{VarSubscribe, WIDGET, WidgetId},
19};
20
21mod args;
22pub use args::*;
23
24mod events;
25pub use events::*;
26
27mod command;
28pub use command::*;
29
30/// Event notifications from the last update cycle that notified.
31#[derive(Clone, PartialEq, Debug)]
32pub struct EventUpdates<A: EventArgs> {
33 generation: VarUpdateId,
34 updates: Vec<A>,
35}
36impl<A: EventArgs> ops::Deref for EventUpdates<A> {
37 type Target = [A];
38
39 fn deref(&self) -> &Self::Target {
40 &self.updates
41 }
42}
43impl<A: EventArgs> EventUpdates<A> {
44 /// New empty.
45 pub const fn none() -> Self {
46 Self {
47 generation: VarUpdateId::never(),
48 updates: vec![],
49 }
50 }
51
52 /// Last args in the list.
53 pub fn latest(&self) -> Option<&A> {
54 self.updates.last()
55 }
56
57 /// Iterate over all arguments that target the `id` or a descendant of it.
58 ///
59 /// If `ignore_propagation` is `false` only yield args with [`propagation`] is not stopped.
60 ///
61 /// [`propagation`]: AnyEventArgs::propagation
62 pub fn iter_relevant(&self, id: WidgetId, ignore_propagation: bool) -> impl Iterator<Item = &A> {
63 self.updates
64 .iter()
65 .filter(move |a| a.is_in_target(id) && (ignore_propagation || !a.propagation().is_stopped()))
66 }
67
68 /// Referent the latest args that target the `id` or a descendant of it.
69 ///
70 /// If `ignore_propagation` is `false` only calls the handler if the [`propagation`] is not stopped.
71 ///
72 /// [`propagation`]: AnyEventArgs::propagation
73 pub fn latest_relevant(&self, id: WidgetId, ignore_propagation: bool) -> Option<&A> {
74 for args in self.updates.iter().rev() {
75 if args.is_in_target(id) {
76 if !ignore_propagation && args.propagation().is_stopped() {
77 break;
78 }
79 return Some(args);
80 }
81 }
82 None
83 }
84
85 fn notify(&mut self, args: A) {
86 let generation = VARS.update_id();
87 if generation != self.generation {
88 self.updates.clear();
89 self.generation = generation;
90 }
91
92 if self.updates.is_empty() {
93 self.updates.push(args);
94 } else {
95 let t = args.timestamp();
96 if let Some(i) = self.updates.iter().position(|a| a.timestamp() > t) {
97 self.updates.insert(i, args);
98 } else {
99 self.updates.push(args);
100 }
101 }
102 }
103}
104
105#[doc(hidden)]
106pub struct EventData {
107 var: AnyVar,
108 hook: fn(&AnyVar, Box<dyn FnMut(&dyn AnyEventArgs) -> bool + Send>) -> VarHandle,
109}
110impl EventData {
111 pub fn new<A: EventArgs>() -> Self {
112 Self {
113 var: zng_var::var(EventUpdates::<A>::none()).into(),
114 hook: Self::hook::<A>,
115 }
116 }
117
118 fn hook<A: EventArgs>(var: &AnyVar, mut handler: Box<dyn FnMut(&dyn AnyEventArgs) -> bool + Send>) -> VarHandle {
119 var.clone().downcast::<EventUpdates<A>>().unwrap().hook(move |args| {
120 for args in args.value().iter() {
121 if !handler(args) {
122 return false;
123 }
124 }
125 true
126 })
127 }
128}
129
130/// Represents a type erased event variable.
131pub struct AnyEvent(&'static AppLocal<EventData>);
132impl Clone for AnyEvent {
133 fn clone(&self) -> Self {
134 *self
135 }
136}
137impl Copy for AnyEvent {}
138impl PartialEq for AnyEvent {
139 fn eq(&self, other: &Self) -> bool {
140 self.0 == other.0
141 }
142}
143impl Eq for AnyEvent {}
144impl std::hash::Hash for AnyEvent {
145 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
146 std::ptr::from_ref(self.0).hash(state);
147 }
148}
149impl fmt::Debug for AnyEvent {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 f.debug_tuple("AnyEvent").finish_non_exhaustive()
152 }
153}
154impl AnyEvent {
155 fn read_var(&self) -> MappedRwLockReadGuard<'_, AnyVar> {
156 self.0.read_map(|v| &v.var)
157 }
158
159 /// Subscribe the widget to receive updates when events are relevant to it.
160 pub fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
161 self.hook(move |_| {
162 UPDATES.update_op(op, widget_id);
163 true
164 })
165 }
166
167 /// Variable that tracks all the args notified in the last update cycle.
168 ///
169 /// Note that the event variable is only cleared when new notifications are requested.
170 pub fn var(&self) -> AnyVar {
171 self.0.read().var.read_only()
172 }
173
174 /// Setups a callback for just after the event notifications are listed,
175 /// the closure runs in the root app context, just like var modify and hook closures.
176 ///
177 /// The closure must return true to be retained and false to be dropped.
178 ///
179 /// Any event notification or var modification done in the `handler` will apply on the same update that notifies this event.
180 pub fn hook(&self, handler: impl FnMut(&dyn AnyEventArgs) -> bool + Send + 'static) -> VarHandle {
181 let s = self.0.read();
182 (s.hook)(&s.var, Box::new(handler))
183 }
184}
185
186/// Represents an event variable.
187pub struct Event<A: EventArgs>(AnyEvent, PhantomData<fn() -> A>);
188impl<A: EventArgs> fmt::Debug for Event<A> {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 f.debug_tuple("Event").finish_non_exhaustive()
191 }
192}
193impl<A: EventArgs> ops::Deref for Event<A> {
194 type Target = AnyEvent;
195
196 fn deref(&self) -> &Self::Target {
197 &self.0
198 }
199}
200impl<A: EventArgs> Clone for Event<A> {
201 fn clone(&self) -> Self {
202 *self
203 }
204}
205impl<A: EventArgs> Copy for Event<A> {}
206impl<A: EventArgs> PartialEq for Event<A> {
207 fn eq(&self, other: &Self) -> bool {
208 self.0 == other.0
209 }
210}
211impl<A: EventArgs> std::hash::Hash for Event<A> {
212 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
213 self.0.hash(state);
214 }
215}
216impl<A: EventArgs> Eq for Event<A> {}
217impl<A: EventArgs> Event<A> {
218 #[doc(hidden)]
219 pub const fn new(local: &'static AppLocal<EventData>) -> Self {
220 Self(AnyEvent(local), PhantomData)
221 }
222
223 fn get_var(&self) -> Var<EventUpdates<A>> {
224 self.0.0.read().var.clone().downcast::<EventUpdates<A>>().unwrap()
225 }
226
227 /// Variable that tracks all the args notified in the last update cycle.
228 ///
229 /// Note that the event variable is only cleared when new notifications are requested.
230 pub fn var(&self) -> Var<EventUpdates<A>> {
231 self.get_var().read_only()
232 }
233
234 /// Variable that tracks the latest update.
235 ///
236 /// Is only `None` if this event has never notified yet.
237 pub fn var_latest(&self) -> Var<Option<A>> {
238 self.get_var().map(|l| l.latest().cloned())
239 }
240
241 /// Filter map the latest args.
242 ///
243 /// The variable tracks the latest args that passes the `filter_map`. Every event update calls the closure for each
244 /// pending args, latest first, and stops on the first args that produces a new value.
245 pub fn var_map<O: VarValue>(
246 &self,
247 mut filter_map: impl FnMut(&A) -> Option<O> + Send + 'static,
248 fallback_init: impl Fn() -> O + Send + 'static,
249 ) -> Var<O> {
250 self.read_var().filter_map(
251 move |a| {
252 for args in a.downcast_ref::<EventUpdates<A>>().unwrap().iter().rev() {
253 let r = filter_map(args);
254 if r.is_some() {
255 return r;
256 }
257 }
258 None
259 },
260 fallback_init,
261 )
262 }
263
264 /// Bind filter the latest args to the variable.
265 ///
266 /// The `other` variable will be updated with the latest args that passes the `filter_map`. Every event update calls the closure for each
267 /// pending args, latest first, and stops on the first args that produces a new value.
268 pub fn var_bind<O: VarValue>(&self, other: &Var<O>, mut filter_map: impl FnMut(&A) -> Option<O> + Send + 'static) -> VarHandle {
269 self.read_var().bind_filter_map(other, move |a| {
270 for args in a.downcast_ref::<EventUpdates<A>>().unwrap().iter().rev() {
271 let r = filter_map(args);
272 if r.is_some() {
273 return r;
274 }
275 }
276 None
277 })
278 }
279
280 /// Modify the event variable to include the `args` in the next update.
281 pub fn notify(&self, args: A) {
282 self.read_var()
283 .modify(move |a| a.downcast_mut::<EventUpdates<A>>().unwrap().notify(args));
284 }
285
286 /// Visit each new update, oldest first, that target the context widget.
287 ///
288 /// If not called inside an widget visits all updates.
289 ///
290 /// If `ignore_propagation` is `false` only calls the handler if the [`propagation`] is not stopped.
291 ///
292 /// [`propagation`]: AnyEventArgs::propagation
293 pub fn each_update(&self, ignore_propagation: bool, mut handler: impl FnMut(&A)) {
294 self.read_var().with_new(|u| {
295 let u = u.downcast_ref::<EventUpdates<A>>().unwrap();
296 if let Some(id) = WIDGET.try_id() {
297 for args in u.iter_relevant(id, ignore_propagation) {
298 handler(args);
299 }
300 } else {
301 for args in u.iter() {
302 if ignore_propagation || !args.propagation().is_stopped() {
303 handler(args);
304 }
305 }
306 }
307 });
308 }
309
310 /// Visit [`each_update`], returns on the first args that produces an `O`.
311 ///
312 /// [`each_update`]: Self::each_update
313 pub fn find_update<O>(&self, ignore_propagation: bool, mut handler: impl FnMut(&A) -> Option<O>) -> Option<O> {
314 self.read_var()
315 .with_new(|u| {
316 let u = u.downcast_ref::<EventUpdates<A>>().unwrap();
317 if let Some(id) = WIDGET.try_id() {
318 for args in u.iter_relevant(id, ignore_propagation) {
319 if let Some(o) = handler(args) {
320 return Some(o);
321 }
322 }
323 } else {
324 for args in u.iter() {
325 if (ignore_propagation || !args.propagation().is_stopped())
326 && let Some(o) = handler(args)
327 {
328 return Some(o);
329 }
330 }
331 }
332 None
333 })
334 .flatten()
335 }
336
337 /// Visit [`each_update`], returns on the first args that produces `true`.
338 ///
339 /// [`each_update`]: Self::each_update
340 pub fn any_update(&self, ignore_propagation: bool, mut handler: impl FnMut(&A) -> bool) -> bool {
341 self.find_update(ignore_propagation, move |a| if handler(a) { Some(()) } else { None })
342 .is_some()
343 }
344
345 /// Visit the latest update that targets the context widget.
346 ///
347 /// If not called inside an widget visits the latest in general.
348 ///
349 /// If `ignore_propagation` is `false` only calls the handler if the [`propagation`] is not stopped.
350 ///
351 /// [`propagation`]: AnyEventArgs::propagation
352 pub fn latest_update<O>(&self, ignore_propagation: bool, handler: impl FnOnce(&A) -> O) -> Option<O> {
353 self.read_var()
354 .with_new(|u| {
355 let u = u.downcast_ref::<EventUpdates<A>>().unwrap();
356 if let Some(id) = WIDGET.try_id() {
357 if let Some(args) = u.latest_relevant(id, ignore_propagation) {
358 return Some(handler(args));
359 }
360 None
361 } else if let Some(args) = u.latest()
362 && (ignore_propagation || !args.propagation().is_stopped())
363 {
364 Some(handler(args))
365 } else {
366 None
367 }
368 })
369 .flatten()
370 }
371
372 /// If has at least one update for the context widget.
373 ///
374 /// If `ignore_propagation` is `false` only returns `true` if any [`propagation`] is not stopped.
375 ///
376 /// [`propagation`]: AnyEventArgs::propagation
377 pub fn has_update(&self, ignore_propagation: bool) -> bool {
378 self.latest_update(ignore_propagation, |_| true).unwrap_or(false)
379 }
380
381 /// Subscribe the widget to receive updates when events are relevant to it.
382 pub fn subscribe(&self, op: UpdateOp, widget_id: WidgetId) -> VarHandle {
383 self.get_var().subscribe(op, widget_id)
384 }
385
386 /// Subscribe the widget to receive updates when events are relevant to it and the latest args passes the `predicate`.
387 pub fn subscribe_when(&self, op: UpdateOp, widget_id: WidgetId, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) -> VarHandle {
388 self.get_var().subscribe_when(op, widget_id, move |v| {
389 v.value().latest_relevant(widget_id, true).map(&predicate).unwrap_or(false)
390 })
391 }
392
393 /// Creates a preview event handler.
394 ///
395 /// The event `handler` is called for every update that has not stopped [`propagation`](AnyEventArgs::propagation).
396 /// The handler is called before widget handlers and [`on_event`](Self::on_event) handlers. The handler is called
397 /// after all previous registered preview handlers.
398 ///
399 /// If `ignore_propagation` is set also call handlers for args with stopped propagation.
400 ///
401 /// Returns a [`VarHandle`] that can be dropped to unsubscribe, you can also unsubscribe from inside the handler by calling
402 /// [`unsubscribe`](crate::handler::APP_HANDLER::unsubscribe).
403 ///
404 /// # Examples
405 ///
406 /// ```
407 /// # use zng_app::event::*;
408 /// # use zng_app::APP;
409 /// # use zng_app::handler::hn;
410 /// # event_args! { pub struct FocusChangedArgs { pub new_focus: bool, .. fn is_in_target(&self, _id: WidgetId) -> bool { true } } }
411 /// # event! { pub static FOCUS_CHANGED_EVENT: FocusChangedArgs; }
412 /// # let _scope = APP.minimal();
413 /// let handle = FOCUS_CHANGED_EVENT.on_pre_event(
414 /// false,
415 /// hn!(|args| {
416 /// println!("focused: {:?}", args.new_focus);
417 /// }),
418 /// );
419 /// ```
420 /// The example listens to all `FOCUS_CHANGED_EVENT` events, independent of widget context and before all UI handlers.
421 ///
422 /// # Handlers
423 ///
424 /// the event handler can be any [`Handler<A>`], there are multiple flavors of handlers, including
425 /// async handlers that allow calling `.await`. The handler closures can be declared using [`hn!`], [`async_hn!`],
426 /// [`hn_once!`] and [`async_hn_once!`].
427 ///
428 /// ## Async
429 ///
430 /// Note that for async handlers only the code before the first `.await` is called in the *preview* moment, code after runs in
431 /// subsequent event updates, after the event has already propagated, so stopping [`propagation`](AnyEventArgs::propagation)
432 /// only causes the desired effect before the first `.await`.
433 ///
434 /// [`hn!`]: crate::handler::hn!
435 /// [`async_hn!`]: crate::handler::async_hn!
436 /// [`hn_once!`]: crate::handler::hn_once!
437 /// [`async_hn_once!`]: crate::handler::async_hn_once!
438 pub fn on_pre_event(&self, ignore_propagation: bool, handler: Handler<A>) -> VarHandle {
439 self.get_var().on_pre_new(Self::event_handler(ignore_propagation, handler))
440 }
441
442 /// Creates an event handler.
443 ///
444 /// The event `handler` is called for every update that has not stopped [`propagation`](AnyEventArgs::propagation).
445 /// The handler is called after all [`on_pre_event`](Self::on_pre_event) all widget handlers and all [`on_event`](Self::on_event)
446 /// handlers registered before this one.
447 ///
448 /// If `ignore_propagation` is set also call handlers for args with stopped propagation.
449 ///
450 /// Returns an [`VarHandle`] that can be dropped to unsubscribe, you can also unsubscribe from inside the handler by calling
451 /// [`unsubscribe`](crate::handler::APP_HANDLER::unsubscribe) in the third parameter of [`hn!`] or [`async_hn!`].
452 ///
453 /// # Examples
454 ///
455 /// ```
456 /// # use zng_app::event::*;
457 /// # use zng_app::APP;
458 /// # use zng_app::handler::hn;
459 /// # event_args! { pub struct FocusChangedArgs { pub new_focus: bool, .. fn is_in_target(&self, _id: WidgetId) -> bool { true } } }
460 /// # event! { pub static FOCUS_CHANGED_EVENT: FocusChangedArgs; }
461 /// # let _scope = APP.minimal();
462 /// let handle = FOCUS_CHANGED_EVENT.on_event(
463 /// false,
464 /// hn!(|args| {
465 /// println!("focused: {:?}", args.new_focus);
466 /// }),
467 /// );
468 /// ```
469 /// The example listens to all `FOCUS_CHANGED_EVENT` events, independent of widget context, after the UI was notified.
470 ///
471 /// # Handlers
472 ///
473 /// the event handler can be any [`Handler<A>`], there are multiple flavors of handlers, including
474 /// async handlers that allow calling `.await`. The handler closures can be declared using [`hn!`], [`async_hn!`],
475 /// [`hn_once!`] and [`async_hn_once!`].
476 ///
477 /// ## Async
478 ///
479 /// Note that for async handlers only the code before the first `.await` is called in the *preview* moment, code after runs in
480 /// subsequent event updates, after the event has already propagated, so stopping [`propagation`](AnyEventArgs::propagation)
481 /// only causes the desired effect before the first `.await`.
482 ///
483 /// [`hn!`]: crate::handler::hn!
484 /// [`async_hn!`]: crate::handler::async_hn!
485 /// [`hn_once!`]: crate::handler::hn_once!
486 /// [`async_hn_once!`]: crate::handler::async_hn_once!
487 pub fn on_event(&self, ignore_propagation: bool, handler: Handler<A>) -> VarHandle {
488 self.get_var().on_new(Self::event_handler(ignore_propagation, handler))
489 }
490
491 fn event_handler(ignore_propagation: bool, mut handler: Handler<A>) -> Handler<OnVarArgs<EventUpdates<A>>> {
492 Box::new(move |a| {
493 let mut futs = vec![];
494 for args in a.value.iter() {
495 if !ignore_propagation && args.propagation().is_stopped() {
496 continue;
497 }
498 match handler(args) {
499 HandlerResult::Done => {}
500 HandlerResult::Continue(f) => futs.push(f),
501 }
502 }
503 if futs.is_empty() {
504 HandlerResult::Done
505 } else if futs.len() == 1 {
506 HandlerResult::Continue(futs.remove(0))
507 } else {
508 HandlerResult::Continue(Box::pin(async move {
509 for f in futs {
510 f.await;
511 }
512 }))
513 }
514 })
515 }
516
517 /// Creates a receiver channel for the event. The event updates are send on hook, before even preview handlers.
518 /// The receiver is unbounded, it will fill indefinitely if not drained. The receiver can be used in any thread,
519 /// including non-app threads.
520 ///
521 /// Drop the receiver to stop listening.
522 pub fn receiver(&self) -> channel::Receiver<A>
523 where
524 A: Send,
525 {
526 let (sender, receiver) = channel::unbounded();
527
528 self.hook(move |args| sender.send_blocking(args.clone()).is_ok()).perm();
529
530 receiver
531 }
532
533 /// Deref as [`AnyEvent`].
534 pub fn as_any(&self) -> &AnyEvent {
535 self
536 }
537
538 /// Setups a callback for just after the event notifications are listed,
539 /// the closure runs in the root app context, just like var modify and hook closures.
540 ///
541 /// The closure must return true to be retained and false to be dropped.
542 ///
543 /// Any event notification or var modification done in the `handler` will apply on the same update that notifies this event.
544 pub fn hook(&self, mut handler: impl FnMut(&A) -> bool + Send + 'static) -> VarHandle {
545 // events can be modified multiple times in the same hooks resolution, every var hook update will list all *pending*
546 // args for the next update, to avoid calling `handler` for the same args we track already called
547 let mut last_call_id = VarUpdateId::never();
548 let mut last_call_take = 0;
549 self.read_var().hook(move |a| {
550 let updates = a.downcast_value::<EventUpdates<A>>().unwrap();
551 let id = VARS.update_id();
552 let mut skip = 0;
553 if last_call_id != id {
554 last_call_id = id;
555 } else {
556 skip = last_call_take;
557 }
558 last_call_take = updates.len();
559
560 // notify
561 for args in updates[skip..].iter() {
562 if !handler(args) {
563 return false;
564 }
565 }
566 true
567 })
568 }
569
570 /// Wait until any args, current or new passes the `predicate`.
571 pub async fn wait_match(&self, predicate: impl Fn(&A) -> bool + Send + Sync + 'static) {
572 self.get_var().wait_match(move |a| a.iter().any(&predicate)).await
573 }
574
575 /// Visit the args current value of [`var`].
576 ///
577 /// [`var`]: Self::var
578 pub fn with<R>(&self, visitor: impl FnOnce(&EventUpdates<A>) -> R) -> R {
579 self.read_var().with(move |v| visitor(v.downcast_ref::<EventUpdates<A>>().unwrap()))
580 }
581}
582
583#[doc(hidden)]
584#[macro_export]
585macro_rules! event_macro_impl {
586 (
587 $(#[$attr:meta])*
588 $vis:vis static $EVENT:ident: $Args:path;
589 ) => {
590 $(#[$attr])*
591 $vis static $EVENT: $crate::event::Event<$Args> = {
592 $crate::event::app_local! {
593 static LOCAL: $crate::event::EventData = $crate::event::EventData::new::<$Args>();
594 }
595 $crate::event::Event::new(&LOCAL)
596 };
597 };
598 (
599 $(#[$attr:meta])*
600 $vis:vis static $EVENT:ident: $Args:path { $($init:tt)* };
601 ) => {
602 $(#[$attr])*
603 $vis static $EVENT: $crate::event::Event<$Args> = {
604 fn __init_event__() {
605 $($init)*
606 }
607 $crate::event::app_local! {
608 static LOCAL: $crate::event::EventData = {
609 $crate::event::EVENTS.notify("event init", __init_event__);
610 $crate::event::EventData::new::<$Args>()
611 };
612 }
613 $crate::event::Event::new(&LOCAL)
614 };
615 };
616}
617
618///<span data-del-macro-root></span> Declares new [`Event<A>`] static items.
619///
620/// Event static items represent external, app or widget events. You can also use [`command!`]
621/// to declare events specialized for commanding widgets and services.
622///
623/// # Conventions
624///
625/// Command events have the `_EVENT` suffix, for example an event representing a click is called `CLICK_EVENT`.
626///
627/// # Properties
628///
629/// If the event targets widgets you can use `event_property!` to declare properties that setup event handlers for the event.
630///
631/// # Examples
632///
633/// The example defines two events with the same arguments type.
634///
635/// ```
636/// # use zng_app::event::*;
637/// # event_args! { pub struct ClickArgs { .. fn is_in_target(&self, _id: WidgetId) -> bool { true } } }
638/// event! {
639/// /// Event docs.
640/// pub static CLICK_EVENT: ClickArgs;
641///
642/// /// Other event docs.
643/// pub static DOUBLE_CLICK_EVENT: ClickArgs;
644/// }
645/// ```
646#[macro_export]
647macro_rules! event_macro {
648 ($(
649 $(#[$attr:meta])*
650 $vis:vis static $EVENT:ident: $Args:path $({ $($init:tt)* })?;
651 )+) => {
652 $(
653 $crate::event_macro_impl! {
654 $(#[$attr])*
655 $vis static $EVENT: $Args $({ $($init)* })?;
656 }
657 )+
658 }
659}
660#[doc(inline)]
661pub use crate::event_macro as event;