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;