Skip to main content

vizia_core/events/
event.rs

1use crate::entity::Entity;
2use std::time::Instant;
3use std::{any::Any, cmp::Ordering, fmt::Debug};
4use vizia_id::GenerationalId;
5
6/// Determines how an event propagates through the tree.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub enum Propagation {
9    // /// Events propagate down the tree to the target entity, e.g. from grand-parent to parent to child (target)
10    // Down,
11    /// Events propagate up the tree from the target entity from ancestor to ancestor, e.g. from child (target) to parent to grand-parent etc.
12    Up,
13    // /// Events propagate down the tree to the target entity and then back up to the root
14    // DownUp,
15    /// Events propagate starting at the target entity and visiting every entity that is a descendent of the target.
16    Subtree,
17    /// Events propagate directly to the target entity and to no others.
18    Direct,
19}
20
21/// A wrapper around a message, providing metadata on how the event travels through the view tree.
22pub struct Event {
23    /// The meta data of the event
24    pub(crate) meta: EventMeta,
25    /// The message of the event
26    pub(crate) message: Option<Box<dyn Any>>,
27}
28
29/// A sendable event payload used by context proxies to forward events from non-UI threads.
30pub struct ProxyEvent {
31    /// The meta data of the event
32    pub(crate) meta: EventMeta,
33    /// The sendable message payload
34    pub(crate) message: Option<Box<dyn Any + Send>>,
35}
36
37impl Debug for Event {
38    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        Ok(())
40    }
41}
42
43impl Debug for ProxyEvent {
44    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        Ok(())
46    }
47}
48
49impl Event {
50    /// Creates a new event with a specified message.
51    pub fn new<M>(message: M) -> Self
52    where
53        M: Any,
54    {
55        Event { meta: Default::default(), message: Some(Box::new(message)) }
56    }
57
58    /// Sets the target of the event.
59    pub fn target(mut self, entity: Entity) -> Self {
60        self.meta.target = entity;
61        self
62    }
63
64    /// Sets the origin of the event.
65    pub fn origin(mut self, entity: Entity) -> Self {
66        self.meta.origin = entity;
67        self
68    }
69
70    /// Sets the propagation of the event.
71    pub fn propagate(mut self, propagation: Propagation) -> Self {
72        self.meta.propagation = propagation;
73        self
74    }
75
76    /// Sets the propagation to directly target the `entity`.
77    pub fn direct(mut self, entity: Entity) -> Self {
78        self.meta.propagation = Propagation::Direct;
79        self.meta.target = entity;
80        self
81    }
82
83    /// Consumes the event to prevent it from continuing on its propagation path.
84    pub fn consume(&mut self) {
85        self.meta.consume();
86    }
87
88    /// Tries to downcast the event message to the specified type. If the downcast was successful,
89    /// the message and the event metadata get passed into `f`.
90    ///
91    /// # Example
92    /// ```no_run
93    /// # use vizia_core::prelude::*;
94    /// # let cx = &mut Context::default();
95    /// # use vizia_winit::application::Application;
96    /// # pub struct AppData {
97    /// #     count: i32,
98    /// # }
99    /// # pub enum AppEvent {
100    /// #     Increment,
101    /// #     Decrement,    
102    /// # }
103    /// # impl Model for AppData {
104    /// #     fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
105    /// event.map(|app_event, _| match app_event {
106    ///     AppEvent::Increment => {
107    ///         self.count += 1;
108    ///     }
109    ///
110    ///     AppEvent::Decrement => {
111    ///         self.count -= 1;
112    ///     }
113    /// });
114    /// #     }
115    /// # }
116    /// ```
117    pub fn map<M, F>(&mut self, f: F)
118    where
119        M: Any,
120        F: FnOnce(&M, &mut EventMeta),
121    {
122        if let Some(message) = &self.message {
123            if let Some(message) = message.as_ref().downcast_ref() {
124                (f)(message, &mut self.meta);
125            }
126        }
127    }
128
129    /// Tries to downcast the event message to the specified type. If the downcast was successful,
130    /// return the message by value and consume the event. Otherwise, do nothing.
131    ///
132    /// # Example
133    /// ```
134    /// # use vizia_core::prelude::*;
135    /// # let cx = &mut Context::default();
136    /// # use vizia_winit::application::Application;
137    /// # pub struct AppData {
138    /// #     count: i32,
139    /// # }
140    /// # pub enum AppEvent {
141    /// #     Increment,
142    /// #     Decrement,
143    /// # }
144    /// # impl Model for AppData {
145    /// #     fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
146    /// event.take(|app_event, meta| match app_event {
147    ///     AppEvent::Increment => {
148    ///         self.count += 1;
149    ///     }
150    ///
151    ///     AppEvent::Decrement => {
152    ///         self.count -= 1;
153    ///     }
154    /// });
155    /// #     }
156    /// # }
157    /// ```
158    pub fn take<M: Any, F>(&mut self, f: F)
159    where
160        F: FnOnce(M, &mut EventMeta),
161    {
162        if let Some(message) = &self.message {
163            if message.as_ref().is::<M>() {
164                // Safe to unwrap because we already checked it exists
165                let m = self.message.take().unwrap();
166                // Safe to unwrap because we already checked it can be cast to M
167                let v = m.downcast().unwrap();
168                self.meta.consume();
169                (f)(*v, &mut self.meta);
170            }
171        }
172    }
173}
174
175impl ProxyEvent {
176    /// Creates a new proxy event with a sendable message.
177    pub fn new<M>(message: M) -> Self
178    where
179        M: Any + Send,
180    {
181        ProxyEvent { meta: Default::default(), message: Some(Box::new(message)) }
182    }
183
184    /// Sets the target of the event.
185    pub fn target(mut self, entity: Entity) -> Self {
186        self.meta.target = entity;
187        self
188    }
189
190    /// Sets the origin of the event.
191    pub fn origin(mut self, entity: Entity) -> Self {
192        self.meta.origin = entity;
193        self
194    }
195
196    /// Sets the propagation of the event.
197    pub fn propagate(mut self, propagation: Propagation) -> Self {
198        self.meta.propagation = propagation;
199        self
200    }
201
202    /// Converts a proxy event into a normal event on the UI thread.
203    pub fn into_event(self) -> Event {
204        Event { meta: self.meta, message: self.message.map(|message| message as Box<dyn Any>) }
205    }
206}
207
208/// The metadata of an [`Event`].
209#[derive(Debug, Clone, Copy)]
210pub struct EventMeta {
211    /// The entity that produced the event.
212    pub origin: Entity,
213    /// The entity the event should be sent to (or from in the case of subtree propagation).
214    pub target: Entity,
215    /// How the event propagates through the tree.
216    pub propagation: Propagation,
217    /// Determines whether the event should continue to be propagated.
218    pub(crate) consumed: bool,
219}
220
221impl EventMeta {
222    /// Consumes the event to prevent it from continuing on its propagation path.
223    pub fn consume(&mut self) {
224        self.consumed = true;
225    }
226}
227
228impl Default for EventMeta {
229    fn default() -> Self {
230        Self {
231            origin: Entity::null(),
232            target: Entity::root(),
233            propagation: Propagation::Up,
234            consumed: false,
235        }
236    }
237}
238
239/// A handle used to cancel a scheduled event before it is sent with `cx.cancel_scheduled`.
240#[derive(Debug, PartialEq, Eq, Copy, Clone)]
241pub struct TimedEventHandle(pub usize);
242
243#[derive(Debug)]
244pub(crate) struct TimedEvent {
245    pub ident: TimedEventHandle,
246    pub event: Event,
247    pub time: Instant,
248}
249
250impl PartialEq<Self> for TimedEvent {
251    fn eq(&self, other: &Self) -> bool {
252        self.time.eq(&other.time)
253    }
254}
255
256impl Eq for TimedEvent {}
257
258impl PartialOrd for TimedEvent {
259    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
260        Some(self.cmp(other))
261    }
262}
263
264impl Ord for TimedEvent {
265    fn cmp(&self, other: &Self) -> Ordering {
266        self.time.cmp(&other.time).reverse()
267    }
268}