Skip to main content

vizia_core/context/
event.rs

1use std::any::{Any, TypeId};
2use std::collections::{BinaryHeap, VecDeque};
3#[cfg(feature = "clipboard")]
4use std::error::Error;
5use std::rc::Rc;
6
7use hashbrown::hash_map::Entry;
8use hashbrown::{HashMap, HashSet};
9use vizia_storage::{LayoutTreeIterator, TreeIterator};
10
11use crate::animation::AnimId;
12use crate::cache::CachedData;
13use crate::events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler};
14use crate::prelude::*;
15use crate::resource::{ImageOrSvg, ResourceManager, StoredImage};
16use crate::tree::{focus_backward, focus_forward, is_navigatable};
17use vizia_input::MouseState;
18
19use skia_safe::{Matrix, Rect};
20
21use crate::text::TextContext;
22#[cfg(feature = "clipboard")]
23use copypasta::ClipboardProvider;
24
25use super::{LocalizationContext, ModelData};
26
27type Views = HashMap<Entity, Box<dyn ViewHandler>>;
28type Models = HashMap<Entity, HashMap<TypeId, Box<dyn ModelData>>>;
29
30/// A context used when handling events.
31///
32/// The [`EventContext`] is provided by the [`event`](crate::prelude::View::event) method in [`View`], or the [`event`](crate::model::Model::event) method in [`Model`], and can be used to mutably access the
33/// desired style and layout properties of the current view.
34///
35/// # Example
36/// ```
37/// # use vizia_core::prelude::*;
38/// # use vizia_core::vg;
39/// # let cx = &mut Context::default();
40///
41/// pub struct CustomView {}
42///
43/// impl CustomView {
44///     pub fn new(cx: &mut Context) -> Handle<Self> {
45///         Self{}.build(cx, |_|{})
46///     }
47/// }
48///
49/// impl View for CustomView {
50///     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
51///         event.map(|window_event, _| match window_event {
52///             WindowEvent::Press{..} => {
53///                 // Change the view background color to red when pressed.
54///                 cx.set_background_color(Color::red());
55///             }
56///
57///             _=> {}
58///         });
59///     }
60/// }
61/// ```
62pub struct EventContext<'a> {
63    pub(crate) current: Entity,
64    pub(crate) captured: &'a mut Entity,
65    pub(crate) focused: &'a mut Entity,
66    pub(crate) hovered: &'a Entity,
67    pub(crate) triggered: &'a mut Entity,
68    pub(crate) style: &'a mut Style,
69    pub(crate) entity_identifiers: &'a HashMap<String, Entity>,
70    pub cache: &'a mut CachedData,
71    pub(crate) tree: &'a Tree<Entity>,
72    pub(crate) models: &'a mut Models,
73    pub(crate) views: &'a mut Views,
74    pub(crate) listeners:
75        &'a mut HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
76    pub(crate) resource_manager: &'a mut ResourceManager,
77    pub(crate) text_context: &'a mut TextContext,
78    #[cfg(feature = "tokio")]
79    pub(crate) task_runtime: &'a super::TaskRuntime,
80    #[cfg(feature = "tokio")]
81    pub(crate) named_tasks: &'a super::NamedTaskMap,
82    pub(crate) modifiers: &'a Modifiers,
83    pub(crate) mouse: &'a MouseState<Entity>,
84    pub(crate) event_queue: &'a mut VecDeque<Event>,
85    pub(crate) event_schedule: &'a mut BinaryHeap<TimedEvent>,
86    pub(crate) next_event_id: &'a mut usize,
87    pub(crate) timers: &'a mut Vec<TimerState>,
88    pub(crate) running_timers: &'a mut BinaryHeap<TimerState>,
89    cursor_icon_locked: &'a mut bool,
90    #[cfg(feature = "clipboard")]
91    clipboards: &'a mut HashMap<Entity, Box<dyn ClipboardProvider>>,
92    pub(crate) event_proxy: &'a mut Option<Box<dyn crate::context::EventProxy>>,
93    pub(crate) drop_data: &'a mut Option<DropData>,
94    pub(crate) active_drag_view: &'a mut Option<Entity>,
95    pub windows: &'a mut HashMap<Entity, WindowState>,
96}
97
98impl<'a> EventContext<'a> {
99    /// Creates a new [EventContext].
100    pub fn new(cx: &'a mut Context) -> Self {
101        Self {
102            current: cx.current,
103            captured: &mut cx.captured,
104            focused: &mut cx.focused,
105            hovered: &cx.hovered,
106            triggered: &mut cx.triggered,
107            entity_identifiers: &cx.entity_identifiers,
108            style: &mut cx.style,
109            cache: &mut cx.cache,
110            tree: &cx.tree,
111            models: &mut cx.models,
112            views: &mut cx.views,
113            listeners: &mut cx.listeners,
114            resource_manager: &mut cx.resource_manager,
115            text_context: &mut cx.text_context,
116            #[cfg(feature = "tokio")]
117            task_runtime: &cx.task_runtime,
118            #[cfg(feature = "tokio")]
119            named_tasks: &cx.named_tasks,
120            modifiers: &cx.modifiers,
121            mouse: &cx.mouse,
122            event_queue: &mut cx.event_queue,
123            event_schedule: &mut cx.event_schedule,
124            next_event_id: &mut cx.next_event_id,
125            timers: &mut cx.timers,
126            running_timers: &mut cx.running_timers,
127            cursor_icon_locked: &mut cx.cursor_icon_locked,
128            #[cfg(feature = "clipboard")]
129            clipboards: &mut cx.clipboards,
130            event_proxy: &mut cx.event_proxy,
131            drop_data: &mut cx.drop_data,
132            active_drag_view: &mut cx.active_drag_view,
133            windows: &mut cx.windows,
134        }
135    }
136
137    /// Creates a new [EventContext] with the given current [Entity].
138    pub fn new_with_current(cx: &'a mut Context, current: Entity) -> Self {
139        Self {
140            current,
141            captured: &mut cx.captured,
142            focused: &mut cx.focused,
143            hovered: &cx.hovered,
144            triggered: &mut cx.triggered,
145            entity_identifiers: &cx.entity_identifiers,
146            style: &mut cx.style,
147            cache: &mut cx.cache,
148            tree: &cx.tree,
149            models: &mut cx.models,
150            views: &mut cx.views,
151            listeners: &mut cx.listeners,
152            resource_manager: &mut cx.resource_manager,
153            text_context: &mut cx.text_context,
154            #[cfg(feature = "tokio")]
155            task_runtime: &cx.task_runtime,
156            #[cfg(feature = "tokio")]
157            named_tasks: &cx.named_tasks,
158            modifiers: &cx.modifiers,
159            mouse: &cx.mouse,
160            event_queue: &mut cx.event_queue,
161            event_schedule: &mut cx.event_schedule,
162            next_event_id: &mut cx.next_event_id,
163            timers: &mut cx.timers,
164            running_timers: &mut cx.running_timers,
165            cursor_icon_locked: &mut cx.cursor_icon_locked,
166            #[cfg(feature = "clipboard")]
167            clipboards: &mut cx.clipboards,
168            event_proxy: &mut cx.event_proxy,
169            drop_data: &mut cx.drop_data,
170            active_drag_view: &mut cx.active_drag_view,
171            windows: &mut cx.windows,
172        }
173    }
174
175    /// Returns a reference to the current view associated with the event context.
176    pub fn get_view<V: View>(&self) -> Option<&V> {
177        self.views.get(&self.current).and_then(|view| view.downcast_ref::<V>())
178    }
179
180    /// Returns a reference to the specified view by entity.
181    pub fn get_view_with<V: View>(&self, entity: Entity) -> Option<&V> {
182        self.views.get(&entity).and_then(|view| view.downcast_ref::<V>())
183    }
184
185    pub fn close_window(&mut self) {
186        if let Some(state) = self.windows.get_mut(&self.current) {
187            state.should_close = true;
188        }
189    }
190
191    /// Returns the [Entity] id associated with the given identifier.
192    pub fn resolve_entity_identifier(&self, id: &str) -> Option<Entity> {
193        self.entity_identifiers.get(id).cloned()
194    }
195
196    /// Returns the descendant [Entity] id, of the current view, with the given element name if it exists.
197    pub fn get_entity_by_element_id(&self, element: &str) -> Option<Entity> {
198        let descendants = LayoutTreeIterator::subtree(self.tree, self.current);
199        for descendant in descendants {
200            if let Some(id) = self.views.get(&descendant).and_then(|view| view.element()) {
201                if id == element {
202                    return Some(descendant);
203                }
204            }
205        }
206
207        None
208    }
209
210    /// Returns the descendant [Entity] ids, of the current view, with the given class name.
211    pub fn get_entities_by_class(&self, class: &str) -> Vec<Entity> {
212        let mut entities = Vec::new();
213        let descendants = LayoutTreeIterator::subtree(self.tree, self.current);
214        for descendant in descendants {
215            if let Some(class_list) = self.style.classes.get(descendant) {
216                if class_list.contains(class) {
217                    entities.push(descendant);
218                }
219            }
220        }
221
222        entities
223    }
224
225    /// Returns the [Entity] id of the current view.
226    pub fn current(&self) -> Entity {
227        self.current
228    }
229
230    /// Returns a reference to the keyboard modifiers state.
231    pub fn modifiers(&self) -> &Modifiers {
232        self.modifiers
233    }
234
235    /// Returns a reference to the mouse state.
236    pub fn mouse(&self) -> &MouseState<Entity> {
237        self.mouse
238    }
239
240    pub fn nth_child(&self, n: usize) -> Option<Entity> {
241        self.tree.get_child(self.current, n)
242    }
243
244    pub fn last_child(&self) -> Option<Entity> {
245        self.tree.get_last_child(self.current).copied()
246    }
247
248    pub fn with_current<T>(&mut self, entity: Entity, f: impl FnOnce(&mut Self) -> T) -> T {
249        let prev = self.current();
250        self.current = entity;
251        let ret = (f)(self);
252        self.current = prev;
253        ret
254    }
255
256    /// Returns true if in a drop state.
257    pub fn has_drop_data(&self) -> bool {
258        self.drop_data.is_some()
259    }
260
261    /// Returns the current drop payload, if any.
262    pub fn drop_data(&self) -> Option<&DropData> {
263        self.drop_data.as_ref()
264    }
265
266    /// Returns the active drag preview view entity, if any.
267    pub fn active_drag_view(&self) -> Option<Entity> {
268        *self.active_drag_view
269    }
270
271    /// Sets the active drag preview view entity.
272    pub fn set_active_drag_view(&mut self, drag_view: Option<Entity>) {
273        *self.active_drag_view = drag_view;
274    }
275
276    /// Returns the bounds of the current view.
277    pub fn bounds(&self) -> BoundingBox {
278        self.cache.get_bounds(self.current)
279    }
280
281    /// Returns the transformed bounds of an entity in window coordinates.
282    pub fn transformed_bounds(&self, entity: Entity) -> BoundingBox {
283        let bounds = self.cache.get_bounds(entity);
284
285        if let Some(transform) = self.cache.transform.get(entity).copied() {
286            // The cache stores identity matrices for all entities by default, so skip map/rounding
287            // work when no effective transform is present.
288            if transform == Matrix::new_identity() {
289                return bounds;
290            }
291
292            let (rect, _) = transform.map_rect(Rect::from(bounds));
293            rect.into()
294        } else {
295            bounds
296        }
297    }
298
299    /// Returns transformed bounds expanded to pixel-snapped extents.
300    pub fn transformed_bounds_snapped(&self, entity: Entity) -> BoundingBox {
301        let bounds = self.transformed_bounds(entity);
302        BoundingBox::from_min_max(
303            bounds.left().floor(),
304            bounds.top().floor(),
305            bounds.right().ceil(),
306            bounds.bottom().ceil(),
307        )
308    }
309
310    /// Returns the transformed bounds of the current view's parent.
311    pub fn parent_transformed_bounds(&self) -> BoundingBox {
312        self.transformed_bounds(self.parent())
313    }
314
315    // pub fn set_bounds(&mut self, bounds: BoundingBox) {
316    //     self.cache.set_bounds(self.current, bounds);
317    // }
318
319    /// Returns the scale factor.
320    pub fn scale_factor(&self) -> f32 {
321        self.style.dpi_factor as f32
322    }
323
324    /// Converts logical points to physical pixels.
325    pub fn logical_to_physical(&self, logical: f32) -> f32 {
326        self.style.logical_to_physical(logical)
327    }
328
329    /// Convert physical pixels to logical points.
330    pub fn physical_to_logical(&self, physical: f32) -> f32 {
331        self.style.physical_to_logical(physical)
332    }
333
334    /// Returns the clip bounds of the current view.
335    pub fn clip_region(&self) -> BoundingBox {
336        let current_window = if self.tree.is_window(self.current) {
337            self.current
338        } else {
339            self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
340        };
341
342        let window_bounds = self.cache.get_bounds(current_window);
343
344        // A cached entry (including None) is authoritative for this entity.
345        if let Some(clip_path) = self.cache.clip_path.get(self.current) {
346            return clip_path
347                .clone()
348                .map(|clip_path| Into::<BoundingBox>::into(*clip_path.bounds()))
349                .unwrap_or(window_bounds);
350        }
351
352        if self.style.ignore_clipping.get(self.current).copied().unwrap_or(false) {
353            return window_bounds;
354        }
355
356        let mut current = self.current;
357        while let Some(parent) = self.tree.get_parent(current) {
358            // A cached parent entry (including None) is authoritative.
359            if let Some(clip_path) = self.cache.clip_path.get(parent) {
360                return clip_path
361                    .clone()
362                    .map(|clip_path| Into::<BoundingBox>::into(*clip_path.bounds()))
363                    .unwrap_or(window_bounds);
364            }
365
366            if self.style.ignore_clipping.get(parent).copied().unwrap_or(false) {
367                return window_bounds;
368            }
369
370            if parent == current_window {
371                break;
372            }
373
374            current = parent;
375        }
376
377        window_bounds
378    }
379
380    /// Returns the 2D transform of the current view.
381    pub fn transform(&self) -> Matrix {
382        self.cache.transform.get(self.current).copied().unwrap_or_default()
383    }
384
385    /// Trigger an animation with the given id to play on the current view.
386    pub fn play_animation(&mut self, anim_id: impl AnimId, duration: Duration, delay: Duration) {
387        if let Some(animation_id) = anim_id.get(self) {
388            self.style.enqueue_animation(self.current, animation_id, duration, delay);
389        }
390    }
391
392    /// Trigger an animation with the given id to play on a target view.
393    pub fn play_animation_for(
394        &mut self,
395        anim_id: impl AnimId,
396        target: &str,
397        duration: Duration,
398        delay: Duration,
399    ) {
400        if let Some(target_entity) = self.resolve_entity_identifier(target) {
401            if let Some(animation_id) = anim_id.get(self) {
402                self.style.enqueue_animation(target_entity, animation_id, duration, delay)
403            }
404        }
405    }
406
407    /// Returns true if the current view is currently animating with the given animation id.
408    pub fn is_animating(&self, anim_id: impl AnimId) -> bool {
409        if let Some(animation_id) = anim_id.get(self) {
410            return self.style.is_animating(self.current, animation_id);
411        }
412
413        false
414    }
415
416    /// Add a listener to an entity.
417    ///
418    /// A listener can be used to handle events which would not normally propagate to the entity.
419    /// For example, mouse events when a different entity has captured them. Useful for things like
420    /// closing a popup when clicking outside of its bounding box.
421    pub fn add_listener<F, W>(&mut self, listener: F)
422    where
423        W: View,
424        F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
425    {
426        self.listeners.insert(
427            self.current,
428            Box::new(move |event_handler, context, event| {
429                if let Some(widget) = event_handler.downcast_mut::<W>() {
430                    (listener)(widget, context, event);
431                }
432            }),
433        );
434    }
435
436    /// Sets the language used by the application for localization.
437    pub fn set_language(&mut self, lang: LanguageIdentifier) {
438        if let Some(mut models) = self.models.remove(&Entity::root()) {
439            if let Some(model) = models.get_mut(&TypeId::of::<Environment>()) {
440                model.event(self, &mut Event::new(EnvironmentEvent::SetLocale(lang)));
441            }
442
443            self.models.insert(Entity::root(), models);
444        }
445    }
446
447    /// Adds a resource loader to the loading chain.
448    ///
449    /// Loaders are tried in list order, and this method inserts at the front so custom
450    /// loaders take priority over built-in loaders. The first loader that returns `true`
451    /// handles the request, and subsequent loaders are skipped.
452    pub fn add_resource_loader<L: crate::resource::ResourceLoader>(&mut self, loader: L) {
453        self.resource_manager.resource_loaders.insert(0, Box::new(loader));
454    }
455
456    pub fn load_image_encoded(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) {
457        let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
458            *image_id
459        } else {
460            let id = self.resource_manager.image_id_manager.create();
461            self.resource_manager.image_ids.insert(path.to_owned(), id);
462            id
463        };
464
465        if let Some(image) = skia_safe::Image::from_encoded(skia_safe::Data::new_copy(data)) {
466            match self.resource_manager.images.entry(id) {
467                Entry::Occupied(mut occ) => {
468                    occ.get_mut().image = ImageOrSvg::Image(image);
469                    occ.get_mut().dirty = true;
470                    occ.get_mut().retention_policy = policy;
471                }
472                Entry::Vacant(vac) => {
473                    vac.insert(StoredImage {
474                        image: ImageOrSvg::Image(image),
475                        retention_policy: policy,
476                        used: true,
477                        dirty: false,
478                        observers: HashSet::new(),
479                    });
480                }
481            }
482            // Relayout only the entities that display this image (its observers) plus the current
483            // entity, rather than forcing a full tree relayout.
484            let observers: Vec<Entity> = self
485                .resource_manager
486                .images
487                .get(&id)
488                .map(|img| img.observers.iter().copied().collect())
489                .unwrap_or_default();
490            for observer in observers {
491                self.style.needs_relayout(observer);
492            }
493            self.style.needs_relayout(self.current);
494        }
495    }
496
497    /// Capture mouse input for the current view.
498    pub fn capture(&mut self) {
499        *self.captured = self.current;
500    }
501
502    /// Release mouse input capture for the current view.
503    pub fn release(&mut self) {
504        if self.current == *self.captured {
505            *self.captured = Entity::null();
506        }
507    }
508
509    /// Enables or disables PseudoClassFlags for the focus of an entity
510    fn set_focus_pseudo_classes(&mut self, focused: Entity, enabled: bool, focus_visible: bool) {
511        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
512            pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
513            if !enabled || focus_visible {
514                pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
515            }
516        }
517
518        for ancestor in focused.parent_iter(self.tree) {
519            let entity = ancestor;
520            if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
521                pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
522            }
523            self.style.needs_restyle(entity);
524        }
525    }
526
527    /// Sets application focus to the current view with the specified focus visibility.
528    pub fn focus_with_visibility(&mut self, focus_visible: bool) {
529        let focusable = self.current == Entity::root()
530            || self
531                .style
532                .abilities
533                .get(self.current)
534                .is_some_and(|abilities| abilities.contains(Abilities::FOCUSABLE));
535        if !focusable {
536            return;
537        }
538
539        let old_focus = self.focused();
540        let new_focus = self.current();
541        self.set_focus_pseudo_classes(old_focus, false, focus_visible);
542        if self.current() != self.focused() {
543            self.emit_to(old_focus, WindowEvent::FocusOut);
544            self.emit_to(new_focus, WindowEvent::FocusIn);
545            *self.focused = self.current();
546        }
547        self.set_focus_pseudo_classes(new_focus, true, focus_visible);
548
549        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
550        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
551
552        self.needs_restyle();
553    }
554
555    /// Sets application focus to the current view using the previous focus visibility.
556    ///
557    /// Focused elements receive keyboard input events and can be selected with the `:focus` CSS pseudo-class selector.
558    pub fn focus(&mut self) {
559        let focused = self.focused();
560        let old_focus_visible = self
561            .style
562            .pseudo_classes
563            .get_mut(focused)
564            .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
565            .is_some();
566        self.focus_with_visibility(old_focus_visible)
567    }
568
569    /// Moves the keyboard focus to the next navigable view.
570    pub fn focus_next(&mut self) {
571        let lock_focus_to = self.tree.lock_focus_within(*self.focused);
572        let next_focused = if let Some(next_focused) =
573            focus_forward(self.tree, self.style, *self.focused, lock_focus_to)
574        {
575            next_focused
576        } else {
577            TreeIterator::full(self.tree)
578                .find(|node| is_navigatable(self.tree, self.style, *node, lock_focus_to))
579                .unwrap_or(Entity::root())
580        };
581
582        if next_focused != *self.focused {
583            self.event_queue.push_back(
584                Event::new(WindowEvent::FocusOut).target(*self.focused).origin(Entity::root()),
585            );
586            self.event_queue.push_back(
587                Event::new(WindowEvent::FocusIn).target(next_focused).origin(Entity::root()),
588            );
589
590            if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(*self.triggered) {
591                pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
592            }
593            self.needs_restyle();
594            *self.triggered = Entity::null();
595        }
596    }
597
598    /// Moves the keyboard focus to the previous navigable view.
599    pub fn focus_prev(&mut self) {
600        let lock_focus_to = self.tree.lock_focus_within(*self.focused);
601        let prev_focused = if let Some(prev_focused) =
602            focus_backward(self.tree, self.style, *self.focused, lock_focus_to)
603        {
604            prev_focused
605        } else {
606            TreeIterator::full(self.tree)
607                .rfind(|node| is_navigatable(self.tree, self.style, *node, lock_focus_to))
608                .unwrap_or(Entity::root())
609        };
610
611        if prev_focused != *self.focused {
612            self.event_queue.push_back(
613                Event::new(WindowEvent::FocusOut).target(*self.focused).origin(Entity::root()),
614            );
615            self.event_queue.push_back(
616                Event::new(WindowEvent::FocusIn).target(prev_focused).origin(Entity::root()),
617            );
618
619            if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(*self.triggered) {
620                pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
621            }
622            self.needs_restyle();
623            *self.triggered = Entity::null();
624        }
625    }
626
627    /// Returns the currently hovered view.
628    pub fn hovered(&self) -> Entity {
629        *self.hovered
630    }
631
632    /// Returns the currently focused view.
633    pub fn focused(&self) -> Entity {
634        *self.focused
635    }
636
637    // PseudoClass Getters
638
639    /// Returns true if the current view is being hovered.
640    pub fn is_hovered(&self) -> bool {
641        self.hovered() == self.current
642    }
643
644    /// Returns true if the current view is active.
645    pub fn is_active(&self) -> bool {
646        if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
647            pseudo_classes.contains(PseudoClassFlags::ACTIVE)
648        } else {
649            false
650        }
651    }
652
653    /// Returns true if the mouse cursor is over the current view.
654    pub fn is_over(&self) -> bool {
655        if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
656            pseudo_classes.contains(PseudoClassFlags::OVER)
657        } else {
658            false
659        }
660    }
661
662    /// Returns true if the current view is focused.
663    pub fn is_focused(&self) -> bool {
664        self.focused() == self.current
665    }
666
667    /// Returns true if the current view can be dragged in a drag and drop operation.
668    pub fn is_draggable(&self) -> bool {
669        self.style
670            .abilities
671            .get(self.current)
672            .map(|abilities| abilities.contains(Abilities::DRAGGABLE))
673            .unwrap_or_default()
674    }
675
676    /// Returns true if the current view is disabled.
677    pub fn is_disabled(&self) -> bool {
678        self.style.disabled.get(self.current()).cloned().unwrap_or_default()
679    }
680
681    /// Returns true if the current view is checked.
682    pub fn is_checked(&self) -> bool {
683        if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
684            pseudo_classes.contains(PseudoClassFlags::CHECKED)
685        } else {
686            false
687        }
688    }
689
690    /// Returns true if the view is in a read-only state.
691    pub fn is_read_only(&self) -> bool {
692        if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
693            pseudo_classes.contains(PseudoClassFlags::READ_ONLY)
694        } else {
695            false
696        }
697    }
698
699    //
700
701    /// Prevents the cursor icon from changing until the lock is released.
702    pub fn lock_cursor_icon(&mut self) {
703        *self.cursor_icon_locked = true;
704    }
705
706    /// Releases any cursor icon lock, allowing the cursor icon to be changed.
707    pub fn unlock_cursor_icon(&mut self) {
708        *self.cursor_icon_locked = false;
709        let hovered = *self.hovered;
710        let cursor = self.style.cursor.get(hovered).cloned().unwrap_or_default();
711        self.emit(WindowEvent::SetCursor(cursor));
712    }
713
714    /// Returns true if the cursor icon is locked.
715    pub fn is_cursor_icon_locked(&self) -> bool {
716        *self.cursor_icon_locked
717    }
718
719    /// Sets the drop data of the current view.
720    pub fn set_drop_data(&mut self, data: impl Into<DropData>) {
721        *self.drop_data = Some(data.into())
722    }
723
724    /// Get the contents of the system clipboard.
725    ///
726    /// This may fail for a variety of backend-specific reasons.
727    #[cfg(feature = "clipboard")]
728    pub fn get_clipboard(&mut self) -> Result<String, Box<dyn Error + Send + Sync + 'static>> {
729        self.current_window_clipboard().get_contents()
730    }
731
732    /// Set the contents of the system clipboard.
733    ///
734    /// This may fail for a variety of backend-specific reasons.
735    #[cfg(feature = "clipboard")]
736    pub fn set_clipboard(
737        &mut self,
738        text: String,
739    ) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
740        self.current_window_clipboard().set_contents(text)
741    }
742
743    #[cfg(feature = "clipboard")]
744    fn current_window_clipboard(&mut self) -> &mut Box<dyn ClipboardProvider> {
745        let window = if self.tree.is_window(self.current) {
746            self.current
747        } else {
748            self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
749        };
750
751        self.clipboards.entry(window).or_insert_with(super::default_clipboard_provider)
752    }
753
754    /// Toggles the addition/removal of a class name for the current view.
755    ///
756    /// # Example
757    /// ```rust
758    /// # use vizia_core::prelude::*;
759    /// # let context = &mut Context::default();
760    /// # let mut cx = &mut EventContext::new(context);
761    /// cx.toggle_class("foo", true);
762    /// ```
763    pub fn toggle_class(&mut self, class_name: &str, applied: bool) {
764        let current = self.current();
765        if let Some(class_list) = self.style.classes.get_mut(current) {
766            if applied {
767                class_list.insert(class_name.to_string());
768            } else {
769                class_list.remove(class_name);
770            }
771        } else if applied {
772            let mut class_list = HashSet::new();
773            class_list.insert(class_name.to_string());
774            self.style.classes.insert(current, class_list);
775        }
776
777        self.needs_restyle();
778    }
779
780    /// Returns a reference to the [Environment] model.
781    pub fn environment(&self) -> &Environment {
782        self.data::<Environment>()
783    }
784
785    /// Marks the current view as needing to be redrawn.
786    pub fn needs_redraw(&mut self) {
787        let parent_window = self.tree.get_parent_window(self.current).unwrap_or(Entity::root());
788        if let Some(window_state) = self.windows.get_mut(&parent_window) {
789            window_state.redraw_list.insert(self.current);
790        }
791    }
792
793    /// Marks the current view as needing a layout computation.
794    pub fn needs_relayout(&mut self) {
795        self.style.needs_relayout(self.current);
796        self.needs_redraw();
797    }
798
799    /// Marks the current view as needing to be restyled.
800    pub fn needs_restyle(&mut self) {
801        if self.current == Entity::null() || self.style.restyle.contains(&self.current) {
802            return;
803        }
804
805        self.style.restyle.insert(self.current);
806        let iter = if let Some(parent) = self.tree.get_layout_parent(self.current) {
807            LayoutTreeIterator::subtree(self.tree, parent)
808        } else {
809            LayoutTreeIterator::subtree(self.tree, self.current)
810        };
811
812        for descendant in iter {
813            self.style.restyle.insert(descendant);
814        }
815        self.style.needs_restyle(self.current);
816    }
817
818    pub fn needs_retransform(&mut self) {
819        self.style.needs_retransform(self.current);
820        let iter = LayoutTreeIterator::subtree(self.tree, self.current);
821        for descendant in iter {
822            self.style.needs_retransform(descendant);
823        }
824    }
825
826    pub fn needs_reclip(&mut self) {
827        self.style.needs_reclip(self.current);
828        let iter = LayoutTreeIterator::subtree(self.tree, self.current);
829        for descendant in iter {
830            self.style.needs_reclip(descendant);
831        }
832    }
833
834    /// Reloads the stylesheets linked to the application.
835    pub fn reload_styles(&mut self) -> Result<(), std::io::Error> {
836        if self.resource_manager.styles.is_empty() {
837            return Ok(());
838        }
839
840        self.style.remove_rules();
841
842        self.style.clear_style_rules();
843
844        let mut overall_theme = String::new();
845
846        for style_string in self.resource_manager.styles.iter().flat_map(|style| style.get_style())
847        {
848            overall_theme += &style_string;
849        }
850
851        self.style.parse_theme(&overall_theme);
852
853        self.style.needs_relayout(Entity::root());
854
855        for entity in self.tree.into_iter() {
856            self.style.needs_restyle(entity);
857
858            //self.style.needs_redraw(entity);
859            self.style.needs_text_update(entity);
860        }
861
862        Ok(())
863    }
864
865    /// Spawns a thread and provides a [ContextProxy] for sending events back to the main UI thread.
866    pub fn spawn<F>(&self, target: F)
867    where
868        F: 'static + Send + FnOnce(&mut ContextProxy),
869    {
870        let mut cxp = ContextProxy {
871            current: self.current,
872            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
873        };
874
875        std::thread::spawn(move || target(&mut cxp));
876    }
877
878    /// Returns a [ContextProxy] which can be moved between threads and used to send events back to the main UI thread.
879    pub fn get_proxy(&self) -> ContextProxy {
880        ContextProxy {
881            current: self.current,
882            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
883        }
884    }
885
886    /// Submits a configured [`TaskBuilder`] for asynchronous execution.
887    ///
888    /// Tasks run on Vizia's shared Tokio runtime and complete through the
889    /// `on_result(...)` callback attached to the builder, when one is provided.
890    ///
891    /// Returns a [`TaskHandle`] that can be used to request cancellation.
892    ///
893    /// # Example
894    /// ```rust,no_run
895    /// # use vizia_core::prelude::*;
896    /// # #[cfg(feature = "tokio")]
897    /// # fn trigger(cx: &EventContext) {
898    /// // Fire-and-forget:
899    /// cx.add_task(Task::new(|_| async move { Ok::<(), &'static str>(()) }));
900    ///
901    /// // With completion handling:
902    /// cx.add_task(
903    ///     Task::new(|_| async move { Ok::<_, &'static str>(()) })
904    ///         .name("refresh")
905    ///         .on_result(|_, _| {}),
906    /// );
907    /// # }
908    /// ```
909    #[cfg(feature = "tokio")]
910    pub fn add_task<T, E>(&self, task: TaskBuilder<T, E>) -> TaskHandle
911    where
912        T: Send + 'static,
913        E: Send + 'static,
914    {
915        task.add_to_event_context(self)
916    }
917
918    pub fn modify<V: View>(&mut self, f: impl FnOnce(&mut V)) {
919        if let Some(view) = self
920            .views
921            .get_mut(&self.current)
922            .and_then(|view_handler| view_handler.downcast_mut::<V>())
923        {
924            (f)(view);
925        }
926    }
927
928    // TODO: Abstract this to shared trait for all contexts
929
930    // Getters
931
932    /// Returns the background color of the view.
933    ///
934    /// Returns a transparent color if the view does not have a background color.
935    pub fn background_color(&mut self) -> Color {
936        self.style.background_color.get(self.current).copied().unwrap_or_default()
937    }
938
939    // Setters
940
941    pub fn set_id(&mut self, id: &str) {
942        self.style.ids.insert(self.current, id.to_string())
943    }
944
945    // Pseudoclass Setters
946
947    /// Sets the hover state of the current view.
948    ///
949    /// Hovered elements can be selected with the `:hover` CSS pseudo-class selector:
950    /// ```css
951    /// element:hover {
952    ///     background-color: red;
953    /// }
954    /// ```
955    /// Typically this is set by the hover system and should not be set manually.
956    pub fn set_hover(&mut self, flag: bool) {
957        let current = self.current();
958        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
959            pseudo_classes.set(PseudoClassFlags::HOVER, flag);
960        }
961
962        self.needs_restyle();
963    }
964
965    /// Set the active state for the current view.
966    ///
967    /// Active elements can be selected with the `:active` CSS pseudo-class selector:
968    /// ```css
969    /// element:active {
970    ///     background-color: red;
971    /// }
972    /// ```
973    pub fn set_active(&mut self, active: bool) {
974        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(self.current) {
975            pseudo_classes.set(PseudoClassFlags::ACTIVE, active);
976        }
977
978        self.needs_restyle();
979    }
980
981    pub fn set_read_only(&mut self, flag: bool) {
982        let current = self.current();
983        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
984            pseudo_classes.set(PseudoClassFlags::READ_ONLY, flag);
985        }
986
987        self.needs_restyle();
988    }
989
990    pub fn set_read_write(&mut self, flag: bool) {
991        let current = self.current();
992        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
993            pseudo_classes.set(PseudoClassFlags::READ_WRITE, flag);
994        }
995
996        self.needs_restyle();
997    }
998
999    /// Sets the checked state of the current view.
1000    ///
1001    /// Checked elements can be selected with the `:checked` CSS pseudo-class selector:
1002    /// ```css
1003    /// element:checked {
1004    ///     background-color: red;
1005    /// }
1006    /// ```
1007    pub fn set_checked(&mut self, flag: bool) {
1008        let current = self.current();
1009        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
1010            pseudo_classes.set(PseudoClassFlags::CHECKED, flag);
1011        }
1012
1013        self.needs_restyle();
1014    }
1015
1016    /// Sets the valid state of the current view.
1017    ///
1018    /// Checked elements can be selected with the `:checked` CSS pseudo-class selector:
1019    /// ```css
1020    /// element:checked {
1021    ///     background-color: red;
1022    /// }
1023    /// ```
1024    pub fn set_valid(&mut self, flag: bool) {
1025        let current = self.current();
1026        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
1027            pseudo_classes.set(PseudoClassFlags::VALID, flag);
1028            pseudo_classes.set(PseudoClassFlags::INVALID, !flag);
1029        }
1030
1031        self.needs_restyle();
1032    }
1033
1034    pub fn set_placeholder_shown(&mut self, flag: bool) {
1035        let current = self.current();
1036        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
1037            pseudo_classes.set(PseudoClassFlags::PLACEHOLDER_SHOWN, flag);
1038        }
1039
1040        self.needs_restyle();
1041    }
1042
1043    // TODO: Move me
1044    pub fn is_valid(&self) -> bool {
1045        self.style
1046            .pseudo_classes
1047            .get(self.current)
1048            .map(|pseudo_classes| pseudo_classes.contains(PseudoClassFlags::VALID))
1049            .unwrap_or_default()
1050    }
1051
1052    pub fn is_placeholder_shown(&self) -> bool {
1053        self.style
1054            .pseudo_classes
1055            .get(self.current)
1056            .map(|pseudo_classes| pseudo_classes.contains(PseudoClassFlags::PLACEHOLDER_SHOWN))
1057            .unwrap_or_default()
1058    }
1059
1060    // Accessibility Properties
1061
1062    /// Sets the accessibility name of the view.
1063    pub fn set_name(&mut self, name: &str) {
1064        self.style.name.insert(self.current, name.to_string());
1065    }
1066
1067    /// Sets the accessibility role of the view.
1068    pub fn set_role(&mut self, role: Role) {
1069        self.style.role.insert(self.current, role);
1070    }
1071
1072    // /// Sets the accessibility default action verb of the view.
1073    // pub fn set_default_action_verb(&mut self, default_action_verb: DefaultActionVerb) {
1074    //     self.style.default_action_verb.insert(self.current, default_action_verb);
1075    // }
1076
1077    /// Sets the view to be an accessibility live region.
1078    pub fn set_live(&mut self, live: Live) {
1079        self.style.live.insert(self.current, live);
1080    }
1081
1082    /// Sets the view, by id name, which labels the current view for accessibility.  
1083    pub fn labelled_by(&mut self, id: &str) {
1084        self.style.labelled_by.insert(self.current, id.to_string());
1085    }
1086
1087    /// Sets the view, by id name, which describes the current view for accessibility.
1088    pub fn described_by(&mut self, id: &str) {
1089        self.style.described_by.insert(self.current, id.to_string());
1090    }
1091
1092    /// Sets the view, by id name, which is controlled by the current view for accessibility.
1093    pub fn controls(&mut self, id: &str) {
1094        self.style.controls.insert(self.current, id.to_string());
1095    }
1096
1097    /// Sets whether the view should be explicitely hidden from accessibility.
1098    pub fn set_hidden(&mut self, hidden: bool) {
1099        self.style.hidden.insert(self.current, hidden)
1100    }
1101
1102    /// Sets a text value used for accessbility for the current view.
1103    pub fn text_value(&mut self, text: &str) {
1104        self.style.text_value.insert(self.current, text.to_string());
1105    }
1106
1107    /// Sets a numeric value used for accessibility for the current view.
1108    pub fn numeric_value(&mut self, value: f64) {
1109        self.style.numeric_value.insert(self.current, value);
1110    }
1111
1112    // DISPLAY
1113
1114    /// Sets the display type of the current view.
1115    ///
1116    /// A display value of `Display::None` causes the view to be ignored by both layout and rendering.
1117    pub fn set_display(&mut self, display: Display) {
1118        self.style.display.insert(self.current, display);
1119    }
1120
1121    /// Sets the visibility of the current view.
1122    ///
1123    /// The layout system will still compute the size and position of an invisible (hidden) view.
1124    pub fn set_visibility(&mut self, visibility: Visibility) {
1125        self.style.visibility.insert(self.current, visibility);
1126    }
1127
1128    /// Sets the opacity of the current view.
1129    ///
1130    /// Expects a number between 0.0 (transparent) and 1.0 (opaque).
1131    pub fn set_opacity(&mut self, opacity: f32) {
1132        self.style.opacity.insert(self.current, Opacity(opacity));
1133    }
1134
1135    /// Sets the z-index of the current view.
1136    pub fn set_z_index(&mut self, z_index: i32) {
1137        self.style.z_index.insert(self.current, z_index);
1138    }
1139
1140    /// Sets the clip path of the current view.
1141    pub fn set_clip_path(&mut self, clip_path: ClipPath) {
1142        self.style.clip_path.insert(self.current, clip_path);
1143        self.needs_reclip();
1144        self.needs_redraw();
1145    }
1146
1147    /// Sets the overflow type on the horizontal axis of the current view.
1148    pub fn set_overflowx(&mut self, overflowx: impl Into<Overflow>) {
1149        self.style.overflowx.insert(self.current, overflowx.into());
1150        self.needs_reclip();
1151        self.needs_redraw();
1152    }
1153
1154    /// Sets the overflow type on the vertical axis of the current view.
1155    pub fn set_overflowy(&mut self, overflowy: impl Into<Overflow>) {
1156        self.style.overflowy.insert(self.current, overflowy.into());
1157        self.needs_reclip();
1158        self.needs_redraw();
1159    }
1160
1161    // TRANSFORM
1162
1163    /// Sets the transform of the current view.
1164    pub fn set_transform(&mut self, transform: impl Into<Vec<Transform>>) {
1165        self.style.transform.insert(self.current, transform.into());
1166        self.needs_retransform();
1167        self.needs_redraw();
1168    }
1169
1170    /// Sets the transform origin of the current view.
1171    pub fn set_transform_origin(&mut self, transform_origin: Translate) {
1172        self.style.transform_origin.insert(self.current, transform_origin);
1173        self.needs_retransform();
1174        self.needs_redraw();
1175    }
1176
1177    /// Sets the translation of the current view.
1178    pub fn set_translate(&mut self, translate: impl Into<Translate>) {
1179        self.style.translate.insert(self.current, translate.into());
1180        self.needs_retransform();
1181        self.needs_redraw();
1182    }
1183
1184    /// Sets the rotation of the current view.
1185    pub fn set_rotate(&mut self, angle: impl Into<Angle>) {
1186        self.style.rotate.insert(self.current, angle.into());
1187        self.needs_retransform();
1188        self.needs_redraw();
1189    }
1190
1191    /// Sets the scale of the current view.
1192    pub fn set_scale(&mut self, scale: impl Into<Scale>) {
1193        self.style.scale.insert(self.current, scale.into());
1194        self.needs_retransform();
1195        self.needs_redraw();
1196    }
1197
1198    // FILTER
1199
1200    /// Sets the filter of the current view.
1201    pub fn set_filter(&mut self, filter: Filter) {
1202        self.style.filter.insert(self.current, filter);
1203        self.needs_redraw();
1204    }
1205
1206    /// Sets the backdrop filter of the current view.
1207    pub fn set_backdrop_filter(&mut self, filter: Filter) {
1208        self.style.backdrop_filter.insert(self.current, filter);
1209        self.needs_redraw();
1210    }
1211
1212    // BOX SHADOW
1213
1214    // TODO
1215
1216    // BACKGROUND
1217
1218    pub fn set_background_color(&mut self, background_color: Color) {
1219        self.style.background_color.insert(self.current, background_color);
1220        self.needs_redraw();
1221    }
1222
1223    // SIZE
1224
1225    pub fn set_width(&mut self, width: Units) {
1226        self.style.width.insert(self.current, width);
1227        self.needs_relayout();
1228        self.needs_redraw();
1229    }
1230
1231    pub fn set_height(&mut self, height: Units) {
1232        self.style.height.insert(self.current, height);
1233        self.needs_relayout();
1234        self.needs_redraw();
1235    }
1236
1237    pub fn set_max_height(&mut self, height: Units) {
1238        self.style.max_height.insert(self.current, height);
1239        self.needs_relayout();
1240        self.needs_redraw();
1241    }
1242
1243    // SPACE
1244
1245    pub fn set_left(&mut self, left: Units) {
1246        self.style.left.insert(self.current, left);
1247        self.needs_relayout();
1248        self.needs_redraw();
1249    }
1250
1251    pub fn set_top(&mut self, top: Units) {
1252        self.style.top.insert(self.current, top);
1253        self.needs_relayout();
1254        self.needs_redraw();
1255    }
1256
1257    pub fn set_right(&mut self, right: Units) {
1258        self.style.right.insert(self.current, right);
1259        self.needs_relayout();
1260        self.needs_redraw();
1261    }
1262
1263    pub fn set_bottom(&mut self, bottom: Units) {
1264        self.style.bottom.insert(self.current, bottom);
1265        self.needs_relayout();
1266        self.needs_redraw();
1267    }
1268
1269    // PADDING
1270
1271    pub fn set_padding_left(&mut self, padding_left: Units) {
1272        self.style.padding_left.insert(self.current, padding_left);
1273        self.needs_relayout();
1274        self.needs_redraw();
1275    }
1276
1277    pub fn set_padding_top(&mut self, padding_top: Units) {
1278        self.style.padding_top.insert(self.current, padding_top);
1279        self.needs_relayout();
1280        self.needs_redraw();
1281    }
1282
1283    pub fn set_padding_right(&mut self, padding_right: Units) {
1284        self.style.padding_right.insert(self.current, padding_right);
1285        self.needs_relayout();
1286        self.needs_redraw();
1287    }
1288
1289    pub fn set_padding_bottom(&mut self, padding_bottom: Units) {
1290        self.style.padding_bottom.insert(self.current, padding_bottom);
1291        self.needs_relayout();
1292        self.needs_redraw();
1293    }
1294
1295    // TEXT
1296
1297    /// Sets the text of the current view.
1298    pub fn set_text(&mut self, text: &str) {
1299        self.style.text.insert(self.current, text.to_owned());
1300        self.style.needs_text_update(self.current);
1301        self.needs_relayout();
1302        self.needs_redraw();
1303    }
1304
1305    pub fn set_pointer_events(&mut self, pointer_events: impl Into<PointerEvents>) {
1306        self.style.pointer_events.insert(self.current, pointer_events.into());
1307    }
1308
1309    // GETTERS
1310
1311    /// Returns the top border width of the current view in physical pixels.
1312    pub fn border_top_width(&self) -> f32 {
1313        if let Some(length) = self.style.border_top_width.get(self.current) {
1314            let bounds = self.bounds();
1315            return length.to_pixels(bounds.w.min(bounds.h), self.scale_factor()).round();
1316        }
1317        0.0
1318    }
1319
1320    /// Returns the right border width of the current view in physical pixels.
1321    pub fn border_right_width(&self) -> f32 {
1322        if let Some(length) = self.style.border_right_width.get(self.current) {
1323            let bounds = self.bounds();
1324            return length.to_pixels(bounds.w.min(bounds.h), self.scale_factor()).round();
1325        }
1326        0.0
1327    }
1328
1329    /// Returns the bottom border width of the current view in physical pixels.
1330    pub fn border_bottom_width(&self) -> f32 {
1331        if let Some(length) = self.style.border_bottom_width.get(self.current) {
1332            let bounds = self.bounds();
1333            return length.to_pixels(bounds.w.min(bounds.h), self.scale_factor()).round();
1334        }
1335        0.0
1336    }
1337
1338    /// Returns the left border width of the current view in physical pixels.
1339    pub fn border_left_width(&self) -> f32 {
1340        if let Some(length) = self.style.border_left_width.get(self.current) {
1341            let bounds = self.bounds();
1342            return length.to_pixels(bounds.w.min(bounds.h), self.scale_factor()).round();
1343        }
1344        0.0
1345    }
1346
1347    /// Returns the top border width of the current view in physical pixels.
1348    /// Equivalent to `border_top_width`; kept for backward compatibility.
1349    pub fn border_width(&self) -> f32 {
1350        self.border_top_width()
1351    }
1352
1353    /// Returns the font-size of the current view in physical pixels.
1354    pub fn font_size(&self) -> f32 {
1355        self.logical_to_physical(
1356            self.style
1357                .font_size
1358                .get(self.current)
1359                .cloned()
1360                .map(|f| f.0.to_px().unwrap())
1361                .unwrap_or(16.0),
1362        )
1363    }
1364
1365    /// Adds a timer to the application.
1366    ///
1367    /// `interval` - The time between ticks of the timer.
1368    /// `duration` - An optional duration for the timer. Pass `None` for a continuos timer.
1369    /// `callback` - A callback which is called on when the timer is started, ticks, and stops. Disambiguated by the `TimerAction` parameter of the callback.
1370    ///
1371    /// Returns a `Timer` id which can be used to start and stop the timer.  
1372    ///
1373    /// # Example
1374    /// Creates a timer which calls the provided callback every second for 5 seconds:
1375    /// ```rust
1376    /// # use vizia_core::prelude::*;
1377    /// # use instant::{Instant, Duration};
1378    /// # let cx = &mut Context::default();
1379    /// let timer = cx.add_timer(Duration::from_secs(1), Some(Duration::from_secs(5)), |cx, reason|{
1380    ///     match reason {
1381    ///         TimerAction::Start => {
1382    ///             debug!("Start timer");
1383    ///         }
1384    ///     
1385    ///         TimerAction::Tick(delta) => {
1386    ///             debug!("Tick timer: {:?}", delta);
1387    ///         }
1388    ///
1389    ///         TimerAction::Stop => {
1390    ///             debug!("Stop timer");
1391    ///         }
1392    ///     }
1393    /// });
1394    /// ```
1395    pub fn add_timer(
1396        &mut self,
1397        interval: Duration,
1398        duration: Option<Duration>,
1399        callback: impl Fn(&mut EventContext, TimerAction) + 'static,
1400    ) -> Timer {
1401        let id = Timer(self.timers.len());
1402        self.timers.push(TimerState {
1403            entity: Entity::root(),
1404            id,
1405            time: Instant::now(),
1406            interval,
1407            duration,
1408            start_time: Instant::now(),
1409            callback: Rc::new(callback),
1410            ticking: false,
1411            stopping: false,
1412        });
1413
1414        id
1415    }
1416
1417    /// Starts a timer with the provided timer id.
1418    ///
1419    /// Events sent within the timer callback provided in `add_timer()` will target the current view.
1420    pub fn start_timer(&mut self, timer: Timer) {
1421        let current = self.current;
1422        if !self.timer_is_running(timer) {
1423            let timer_state = self.timers[timer.0].clone();
1424            // Copy timer state from pending to playing
1425            self.running_timers.push(timer_state);
1426        }
1427
1428        self.modify_timer(timer, |timer_state| {
1429            let now = Instant::now();
1430            timer_state.start_time = now;
1431            timer_state.time = now;
1432            timer_state.entity = current;
1433            timer_state.ticking = false;
1434            timer_state.stopping = false;
1435        });
1436    }
1437
1438    /// Modifies the state of an existing timer with the provided `Timer` id.
1439    pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
1440        let mut running_timers = self.running_timers.clone().into_vec();
1441
1442        if let Some(timer_state) =
1443            running_timers.iter_mut().find(|timer_state| timer_state.id == timer)
1444        {
1445            (timer_function)(timer_state);
1446            *self.running_timers = running_timers.into();
1447            return;
1448        }
1449
1450        for pending_timer in self.timers.iter_mut() {
1451            if pending_timer.id == timer {
1452                (timer_function)(pending_timer);
1453            }
1454        }
1455    }
1456
1457    pub fn query_timer<T>(
1458        &mut self,
1459        timer: Timer,
1460        timer_function: impl Fn(&TimerState) -> T,
1461    ) -> Option<T> {
1462        if let Some(timer_state) =
1463            self.running_timers.iter().find(|timer_state| timer_state.id == timer)
1464        {
1465            return Some(timer_function(timer_state));
1466        }
1467
1468        for pending_timer in self.timers.iter() {
1469            if pending_timer.id == timer {
1470                return Some(timer_function(pending_timer));
1471            }
1472        }
1473
1474        None
1475    }
1476
1477    /// Returns true if the timer with the provided timer id is currently running.
1478    pub fn timer_is_running(&mut self, timer: Timer) -> bool {
1479        for timer_state in self.running_timers.iter() {
1480            if timer_state.id == timer {
1481                return true;
1482            }
1483        }
1484
1485        false
1486    }
1487
1488    /// Stops the timer with the given timer id.
1489    ///
1490    /// Any events emitted in response to the timer stopping, as determined by the callback provided in `add_timer()`, will target the view which called `start_timer()`.
1491    pub fn stop_timer(&mut self, timer: Timer) {
1492        let mut running_timers = self.running_timers.clone();
1493
1494        for timer_state in running_timers.iter() {
1495            if timer_state.id == timer {
1496                self.with_current(timer_state.entity, |cx| {
1497                    (timer_state.callback)(cx, TimerAction::Stop);
1498                });
1499            }
1500        }
1501
1502        *self.running_timers =
1503            running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
1504    }
1505}
1506
1507impl DataContext for EventContext<'_> {
1508    fn try_data<T: 'static>(&self) -> Option<&T> {
1509        // Return data for the static model.
1510        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1511            return Some(t);
1512        }
1513
1514        for entity in self.current.parent_iter(self.tree) {
1515            // Return model data.
1516            if let Some(models) = self.models.get(&entity) {
1517                if let Some(model) = models.get(&TypeId::of::<T>()) {
1518                    return model.downcast_ref::<T>();
1519                }
1520            }
1521
1522            // Return view data.
1523            if let Some(view_handler) = self.views.get(&entity) {
1524                if let Some(data) = view_handler.downcast_ref::<T>() {
1525                    return Some(data);
1526                }
1527            }
1528        }
1529
1530        None
1531    }
1532
1533    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1534        Some(LocalizationContext::from_event_context(self))
1535    }
1536}
1537
1538impl EmitContext for EventContext<'_> {
1539    fn emit<M: Any>(&mut self, message: M) {
1540        self.event_queue.push_back(
1541            Event::new(message)
1542                .target(self.current)
1543                .origin(self.current)
1544                .propagate(Propagation::Up),
1545        );
1546    }
1547
1548    fn emit_to<M: Any>(&mut self, target: Entity, message: M) {
1549        self.event_queue.push_back(
1550            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1551        );
1552    }
1553
1554    fn emit_custom(&mut self, event: Event) {
1555        self.event_queue.push_back(event);
1556    }
1557
1558    fn schedule_emit<M: Any>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1559        self.schedule_emit_custom(
1560            Event::new(message)
1561                .target(self.current)
1562                .origin(self.current)
1563                .propagate(Propagation::Up),
1564            at,
1565        )
1566    }
1567    fn schedule_emit_to<M: Any>(
1568        &mut self,
1569        target: Entity,
1570        message: M,
1571        at: Instant,
1572    ) -> TimedEventHandle {
1573        self.schedule_emit_custom(
1574            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1575            at,
1576        )
1577    }
1578    fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1579        let handle = TimedEventHandle(*self.next_event_id);
1580        self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1581        *self.next_event_id += 1;
1582        handle
1583    }
1584    fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1585        *self.event_schedule =
1586            self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1587    }
1588}
1589
1590/// Trait for querying properties of the tree from a context.
1591pub trait TreeProps {
1592    /// Returns the entity id of the parent of the current view.
1593    fn parent(&self) -> Entity;
1594    /// Returns the entity id of the first_child of the current view.
1595    fn first_child(&self) -> Entity;
1596    /// Returns the entity id of the parent window of the current view.
1597    fn parent_window(&self) -> Entity;
1598}
1599
1600impl TreeProps for EventContext<'_> {
1601    fn parent(&self) -> Entity {
1602        self.tree.get_layout_parent(self.current).unwrap()
1603    }
1604
1605    fn first_child(&self) -> Entity {
1606        self.tree.get_layout_first_child(self.current).unwrap()
1607    }
1608
1609    fn parent_window(&self) -> Entity {
1610        self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
1611    }
1612}