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