Skip to main content

vizia_core/context/
mod.rs

1//! Context types for retained state, used during view building, event handling, and drawing.
2
3mod access;
4#[doc(hidden)]
5pub mod backend;
6mod draw;
7mod event;
8mod proxy;
9mod resource;
10#[cfg(feature = "tokio")]
11mod task;
12
13use log::debug;
14use skia_safe::{
15    FontMgr, svg,
16    textlayout::{FontCollection, TypefaceFontProvider},
17};
18use std::cell::RefCell;
19use std::collections::{BinaryHeap, VecDeque};
20use std::rc::Rc;
21use std::sync::Mutex;
22use std::sync::atomic::{AtomicU64, Ordering};
23use std::{
24    any::{Any, TypeId},
25    sync::Arc,
26};
27use vizia_id::IdManager;
28use vizia_window::WindowDescription;
29
30#[cfg(all(
31    feature = "clipboard",
32    not(all(
33        any(
34            target_os = "linux",
35            target_os = "dragonfly",
36            target_os = "freebsd",
37            target_os = "netbsd",
38            target_os = "openbsd"
39        ),
40        feature = "wayland",
41    ))
42))]
43use copypasta::ClipboardContext;
44#[cfg(feature = "clipboard")]
45use copypasta::{ClipboardProvider, nop_clipboard::NopClipboardContext};
46use hashbrown::{HashMap, HashSet, hash_map::Entry};
47
48pub use access::*;
49pub use draw::*;
50pub use event::*;
51pub use proxy::*;
52pub use resource::*;
53#[cfg(feature = "tokio")]
54pub use task::*;
55
56use crate::{
57    events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler},
58    model::ModelData,
59};
60
61use crate::{
62    binding::BindingHandler,
63    resource::{LoadingStatus, StoredImage},
64};
65use crate::{cache::CachedData, resource::ImageOrSvg};
66
67use crate::prelude::*;
68use crate::resource::ResourceManager;
69use crate::text::TextContext;
70use vizia_input::{ImeState, MouseState};
71use vizia_storage::{ChildIterator, LayoutTreeIterator};
72
73#[cfg(feature = "tokio")]
74pub(crate) type TaskRuntime = Arc<tokio::runtime::Runtime>;
75
76static DEFAULT_LAYOUT: &str = include_str!("../../resources/themes/default_layout.css");
77static DEFAULT_THEME: &str = include_str!("../../resources/themes/default_theme.css");
78static MARKDOWN: &str = include_str!("../../resources/themes/markdown.css");
79static DEFAULT_TRANSLATION_EN_US: &str =
80    include_str!("../../resources/translations/en-US/core.ftl");
81
82type Views = HashMap<Entity, Box<dyn ViewHandler>>;
83type Models = HashMap<Entity, HashMap<TypeId, Box<dyn ModelData>>>;
84type Bindings = HashMap<Entity, Box<dyn BindingHandler>>;
85
86static NEXT_CONTEXT_ID: AtomicU64 = AtomicU64::new(1);
87
88#[derive(Clone, Copy, PartialEq, Eq, Hash)]
89pub(crate) struct SignalRebuild {
90    pub(crate) context_id: u64,
91    pub(crate) entity: Entity,
92}
93
94#[cfg(feature = "clipboard")]
95fn default_clipboard_provider() -> Box<dyn ClipboardProvider> {
96    #[cfg(all(
97        any(
98            target_os = "linux",
99            target_os = "dragonfly",
100            target_os = "freebsd",
101            target_os = "netbsd",
102            target_os = "openbsd"
103        ),
104        feature = "wayland"
105    ))]
106    {
107        Box::new(NopClipboardContext::new().unwrap())
108    }
109
110    #[cfg(not(all(
111        any(
112            target_os = "linux",
113            target_os = "dragonfly",
114            target_os = "freebsd",
115            target_os = "netbsd",
116            target_os = "openbsd"
117        ),
118        feature = "wayland",
119    )))]
120    {
121        if let Ok(context) = ClipboardContext::new() {
122            Box::new(context)
123        } else {
124            Box::new(NopClipboardContext::new().unwrap())
125        }
126    }
127}
128
129thread_local! {
130    /// Entities for `Binding` views that need to be rebuilt because a reactive signal changed.
131    /// Signal effects push to this set; the binding system drains matching context entries each frame.
132    pub(crate) static SIGNAL_REBUILDS: RefCell<HashSet<SignalRebuild>> = RefCell::new(HashSet::new());
133}
134
135#[derive(Default, Clone)]
136pub struct WindowState {
137    pub window_description: WindowDescription,
138    pub scale_factor: f32,
139    pub needs_relayout: bool,
140    pub needs_redraw: bool,
141    pub redraw_list: HashSet<Entity>,
142    pub dirty_rect: Option<BoundingBox>,
143    pub owner: Option<Entity>,
144    pub is_modal: bool,
145    pub should_close: bool,
146    pub content: Option<Arc<dyn Fn(&mut Context)>>,
147}
148
149/// The main storage and control object for a Vizia application.
150pub struct Context {
151    pub(crate) context_id: u64,
152    pub(crate) entity_manager: IdManager<Entity>,
153    pub(crate) entity_identifiers: HashMap<String, Entity>,
154    pub tree: Tree<Entity>,
155    pub(crate) current: Entity,
156    pub(crate) views: Views,
157    pub(crate) models: Models,
158    pub(crate) bindings: Bindings,
159    pub(crate) event_queue: VecDeque<Event>,
160    pub(crate) event_schedule: BinaryHeap<TimedEvent>,
161    pub(crate) next_event_id: usize,
162    pub(crate) timers: Vec<TimerState>,
163    pub(crate) running_timers: BinaryHeap<TimerState>,
164    pub tree_updates: Vec<Option<accesskit::TreeUpdate>>,
165    pub(crate) listeners:
166        HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
167    pub(crate) global_listeners: Vec<Box<dyn Fn(&mut EventContext, &mut Event)>>,
168    pub(crate) style: Style,
169    pub(crate) cache: CachedData,
170    pub windows: HashMap<Entity, WindowState>,
171
172    pub mouse: MouseState<Entity>,
173    pub(crate) modifiers: Modifiers,
174
175    pub(crate) captured: Entity,
176    pub(crate) triggered: Entity,
177    pub(crate) hovered: Entity,
178    pub(crate) drag_hovered: Entity,
179    pub(crate) focused: Entity,
180    pub(crate) focus_stack: Vec<Entity>,
181    pub(crate) cursor_icon_locked: bool,
182
183    pub(crate) resource_manager: ResourceManager,
184
185    pub text_context: TextContext,
186
187    #[cfg(feature = "tokio")]
188    pub(crate) task_runtime: TaskRuntime,
189    #[cfg(feature = "tokio")]
190    pub(crate) named_tasks: NamedTaskMap,
191
192    pub(crate) event_proxy: Option<Box<dyn EventProxy>>,
193
194    #[cfg(feature = "clipboard")]
195    pub(crate) clipboards: HashMap<Entity, Box<dyn ClipboardProvider>>,
196
197    pub(crate) click_time: Instant,
198    pub(crate) clicks: usize,
199    pub(crate) click_pos: (f32, f32),
200    pub(crate) click_button: MouseButton,
201
202    pub ignore_default_theme: bool,
203    built_in_translations_added: bool,
204    built_in_styles_added: bool,
205    pub window_has_focus: bool,
206    pub ime_state: ImeState,
207
208    pub(crate) drop_data: Option<DropData>,
209    pub(crate) active_drag_view: Option<Entity>,
210}
211
212impl Default for Context {
213    fn default() -> Self {
214        Context::new()
215    }
216}
217
218impl Context {
219    /// Creates a new context.
220    pub fn new() -> Self {
221        let mut cache = CachedData::default();
222        cache.add(Entity::root());
223
224        let mut result = Self {
225            context_id: NEXT_CONTEXT_ID.fetch_add(1, Ordering::Relaxed),
226            entity_manager: IdManager::new(),
227            entity_identifiers: HashMap::new(),
228            tree: Tree::new(),
229            current: Entity::root(),
230            views: HashMap::default(),
231            models: HashMap::default(),
232            bindings: HashMap::default(),
233            style: Style::default(),
234            cache,
235            windows: HashMap::new(),
236            event_queue: VecDeque::new(),
237            event_schedule: BinaryHeap::new(),
238            next_event_id: 0,
239            timers: Vec::new(),
240            running_timers: BinaryHeap::new(),
241            tree_updates: Vec::new(),
242            listeners: HashMap::default(),
243            global_listeners: Vec::new(),
244            mouse: MouseState::default(),
245            modifiers: Modifiers::empty(),
246            captured: Entity::null(),
247            triggered: Entity::null(),
248            hovered: Entity::root(),
249            drag_hovered: Entity::null(),
250            focused: Entity::root(),
251            focus_stack: Vec::new(),
252            cursor_icon_locked: false,
253            resource_manager: ResourceManager::new(),
254            text_context: {
255                let mut font_collection = FontCollection::new();
256
257                let default_font_manager = FontMgr::default();
258
259                let asset_provider = TypefaceFontProvider::new();
260
261                font_collection.set_default_font_manager(default_font_manager.clone(), None);
262                let asset_font_manager: FontMgr = asset_provider.clone().into();
263                font_collection.set_asset_font_manager(asset_font_manager);
264
265                TextContext {
266                    font_collection,
267                    default_font_manager,
268                    asset_provider,
269                    text_bounds: Default::default(),
270                    text_paragraphs: Default::default(),
271                }
272            },
273            #[cfg(feature = "tokio")]
274            task_runtime: Self::new_task_runtime(),
275            #[cfg(feature = "tokio")]
276            named_tasks: new_named_task_map(),
277
278            event_proxy: None,
279
280            #[cfg(feature = "clipboard")]
281            clipboards: HashMap::new(),
282            click_time: Instant::now(),
283            clicks: 0,
284            click_pos: (0.0, 0.0),
285            click_button: MouseButton::Left,
286
287            ignore_default_theme: false,
288            built_in_translations_added: false,
289            built_in_styles_added: false,
290            window_has_focus: true,
291
292            ime_state: Default::default(),
293
294            drop_data: None,
295            active_drag_view: None,
296        };
297
298        result.tree.set_window(Entity::root(), true);
299
300        result.style.needs_restyle(Entity::root());
301        result.style.needs_relayout(Entity::root());
302        result.style.needs_retransform(Entity::root());
303        result.style.needs_reclip(Entity::root());
304        result.needs_redraw(Entity::root());
305
306        // Set the default DPI factor to 1.0.
307        result.style.dpi_factor = 1.0;
308
309        // Build the environment model at the root.
310        Environment::new(&mut result).build(&mut result);
311
312        result.entity_manager.create();
313
314        result.style.role.insert(Entity::root(), Role::Window);
315
316        result
317    }
318
319    #[cfg(feature = "tokio")]
320    fn new_task_runtime() -> TaskRuntime {
321        Arc::new(
322            tokio::runtime::Builder::new_multi_thread()
323                .enable_all()
324                .build()
325                .expect("failed to build context task runtime"),
326        )
327    }
328
329    /// The "current" entity, generally the entity which is currently being built or the entity
330    /// which is currently having an event dispatched to it.
331    pub fn current(&self) -> Entity {
332        self.current
333    }
334
335    /// Makes the above black magic more explicit
336    pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
337        let previous = self.current;
338        self.current = current;
339        let ret = f(self);
340        self.current = previous;
341        ret
342    }
343
344    /// Returns a reference to the [Environment] model.
345    pub fn environment(&self) -> &Environment {
346        self.data::<Environment>()
347    }
348
349    /// Returns the entity id of the  parent window to the current view.
350    pub fn parent_window(&self) -> Entity {
351        self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
352    }
353
354    /// Returns the scale factor of the display.
355    pub fn scale_factor(&self) -> f32 {
356        self.style.dpi_factor as f32
357    }
358
359    /// Mark the application as needing to rerun the draw method
360    pub fn needs_redraw(&mut self, entity: Entity) {
361        if self.entity_manager.is_alive(entity) {
362            // If a child window needs redrawing, add itself to the redraw list.
363            // This ensures that the entire window is redrawn: https://github.com/vizia/vizia/issues/580
364            let window = if self.tree.is_window(entity) {
365                entity
366            } else {
367                self.tree.get_parent_window(entity).unwrap_or(Entity::root())
368            };
369            if let Some(window_state) = self.windows.get_mut(&window) {
370                window_state.redraw_list.insert(entity);
371            }
372        }
373    }
374
375    /// Mark the application as needing to recompute view styles
376    pub fn needs_restyle(&mut self, entity: Entity) {
377        if entity == Entity::null() || self.style.restyle.contains(&entity) {
378            return;
379        }
380        self.style.restyle.insert(entity);
381        let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
382            LayoutTreeIterator::subtree(&self.tree, parent)
383        } else {
384            LayoutTreeIterator::subtree(&self.tree, entity)
385        };
386
387        for descendant in iter {
388            self.style.restyle.insert(descendant);
389        }
390        // self.style.needs_restyle();
391    }
392
393    pub fn needs_retransform(&mut self, entity: Entity) {
394        self.style.needs_retransform(entity);
395        let iter = LayoutTreeIterator::subtree(&self.tree, entity);
396        for descendant in iter {
397            self.style.needs_retransform(descendant);
398        }
399    }
400
401    pub fn needs_reclip(&mut self, entity: Entity) {
402        self.style.needs_reclip(entity);
403        let iter = LayoutTreeIterator::subtree(&self.tree, entity);
404        for descendant in iter {
405            self.style.needs_reclip(descendant);
406        }
407    }
408
409    /// Mark the application as needing to rerun layout computations
410    pub fn needs_relayout(&mut self) {
411        self.style.needs_relayout(Entity::root());
412    }
413
414    pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
415        if system_flags.contains(SystemFlags::RELAYOUT) {
416            self.style.needs_relayout(entity);
417        }
418
419        if system_flags.contains(SystemFlags::RESTYLE) {
420            self.needs_restyle(entity);
421        }
422
423        if system_flags.contains(SystemFlags::REDRAW) {
424            self.needs_redraw(entity);
425        }
426
427        if system_flags.contains(SystemFlags::REFLOW) {
428            self.style.needs_text_update(entity);
429        }
430
431        if system_flags.contains(SystemFlags::RETRANSFORM) {
432            self.needs_retransform(entity);
433        }
434
435        if system_flags.contains(SystemFlags::RECLIP) {
436            self.needs_reclip(entity);
437        }
438
439        if system_flags.contains(SystemFlags::REACCESS) {
440            self.style.needs_access_update(entity);
441        }
442    }
443
444    /// Enables or disables PseudoClasses for the focus of an entity
445    pub(crate) fn set_focus_pseudo_classes(
446        &mut self,
447        focused: Entity,
448        enabled: bool,
449        focus_visible: bool,
450    ) {
451        if enabled {
452            debug!(
453                "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
454                focused,
455                self.tree.get_parent(focused),
456                self.views
457                    .get(&focused)
458                    .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
459                self.cache.get_posx(focused),
460                self.cache.get_posy(focused),
461                self.cache.get_width(focused),
462                self.cache.get_height(focused),
463            );
464        }
465
466        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
467            pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
468            if !enabled || focus_visible {
469                pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
470                self.style.needs_access_update(focused);
471                self.needs_restyle(focused);
472            }
473        }
474
475        let ancestors = focused.parent_iter(&self.tree).collect::<Vec<_>>();
476        for entity in ancestors {
477            if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
478                pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
479            }
480            self.needs_restyle(entity);
481        }
482    }
483
484    /// Sets application focus to the current entity with the specified focus visiblity
485    pub fn focus_with_visibility(&mut self, focus_visible: bool) {
486        let focusable = self.current == Entity::root()
487            || self
488                .style
489                .abilities
490                .get(self.current)
491                .is_some_and(|abilities| abilities.contains(Abilities::FOCUSABLE));
492        if !focusable {
493            return;
494        }
495
496        let old_focus = self.focused;
497        let new_focus = self.current;
498        self.set_focus_pseudo_classes(old_focus, false, focus_visible);
499        if self.current != self.focused {
500            self.emit_to(old_focus, WindowEvent::FocusOut);
501            self.emit_to(new_focus, WindowEvent::FocusIn);
502            self.focused = self.current;
503        }
504        self.set_focus_pseudo_classes(new_focus, true, focus_visible);
505
506        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
507        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
508
509        self.needs_restyle(self.focused);
510        self.needs_restyle(self.current);
511        self.style.needs_access_update(self.focused);
512        self.style.needs_access_update(self.current);
513    }
514
515    /// Sets application focus to the current entity using the previous focus visibility
516    pub fn focus(&mut self) {
517        let focused = self.focused;
518        let old_focus_visible = self
519            .style
520            .pseudo_classes
521            .get_mut(focused)
522            .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
523            .is_some();
524        self.focus_with_visibility(old_focus_visible)
525    }
526
527    /// Removes the children of the provided entity from the application.
528    pub(crate) fn remove_children(&mut self, entity: Entity) {
529        let child_iter = ChildIterator::new(&self.tree, entity);
530        let children = child_iter.collect::<Vec<_>>();
531        for child in children.into_iter() {
532            self.remove(child);
533        }
534    }
535
536    /// Removes the provided entity from the application.
537    pub fn remove(&mut self, entity: Entity) {
538        let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
539
540        if !delete_list.is_empty() {
541            self.style.needs_restyle(self.current);
542            // An absolutely-positioned node is out of its parent's flow, so removing it cannot
543            // change the parent's layout — no relayout is needed (the vacated region is unioned
544            // into the window's dirty_rect below). Otherwise relayout incrementally from the parent
545            // of the removed entity so its remaining children reflow, rather than the whole tree.
546            let is_absolute = self.style.position_type.get(entity).copied().unwrap_or_default()
547                == PositionType::Absolute;
548            if !is_absolute {
549                if let Some(parent) = self.tree.get_layout_parent(entity) {
550                    self.style.needs_relayout(parent);
551                } else {
552                    self.style.needs_relayout(entity);
553                }
554            }
555            self.needs_redraw(self.current);
556        }
557
558        for entity in delete_list.iter().rev() {
559            if let Some(mut view) = self.views.remove(entity) {
560                view.event(
561                    &mut EventContext::new_with_current(self, *entity),
562                    &mut Event::new(WindowEvent::Destroyed).direct(*entity),
563                );
564
565                self.views.insert(*entity, view);
566            }
567
568            if let Some(binding) = self.bindings.remove(entity) {
569                binding.remove(self);
570
571                self.bindings.insert(*entity, binding);
572            }
573
574            for image in self.resource_manager.images.values_mut() {
575                // no need to drop them here. garbage collection happens after draw (policy based)
576                image.observers.remove(entity);
577            }
578
579            if let Some(identifier) = self.style.ids.get(*entity) {
580                self.entity_identifiers.remove(identifier);
581            }
582
583            if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
584                self.focus_stack.remove(index);
585            }
586
587            if self.focused == *entity {
588                if let Some(new_focus) = self.focus_stack.pop() {
589                    self.with_current(new_focus, |cx| cx.focus());
590                } else {
591                    self.with_current(Entity::root(), |cx| cx.focus());
592                }
593            }
594
595            if self.captured == *entity {
596                self.captured = Entity::null();
597            }
598
599            if let Some(parent) = self.tree.get_layout_parent(*entity) {
600                self.style.needs_access_update(parent);
601            }
602
603            let mut stopped_timers = Vec::new();
604
605            for timer in self.running_timers.iter() {
606                if timer.entity == *entity {
607                    stopped_timers.push(timer.id);
608                }
609            }
610
611            for timer in stopped_timers {
612                self.stop_timer(timer);
613            }
614
615            let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
616
617            if !self.tree.is_window(*entity) {
618                if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
619                    if let Some(dirty_rect) =
620                        &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
621                    {
622                        *dirty_rect = dirty_rect.union(draw_bounds);
623                    } else {
624                        self.windows.get_mut(&window_entity).unwrap().dirty_rect =
625                            Some(*draw_bounds);
626                    }
627                }
628            }
629
630            self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
631
632            if self.windows.contains_key(entity) {
633                self.windows.remove(entity);
634                #[cfg(feature = "clipboard")]
635                self.clipboards.remove(entity);
636            }
637
638            self.tree.remove(*entity).expect("");
639            self.cache.remove(*entity);
640            self.style.remove(*entity);
641            self.models.remove(entity);
642            self.views.remove(entity);
643            self.text_context.text_bounds.remove(*entity);
644            self.text_context.text_paragraphs.remove(*entity);
645            self.entity_manager.destroy(*entity);
646        }
647    }
648
649    /// Sets whether a view should have the given class name.
650    pub fn toggle_class(&mut self, name: &str, applied: impl Res<bool>) {
651        let name = name.to_owned();
652        let entity = self.current();
653        let current = self.current();
654        self.with_current(current, |cx| {
655            applied.set_or_bind(cx, move |cx, applied| {
656                let applied = applied.get_value(cx);
657                if let Some(class_list) = cx.style.classes.get_mut(entity) {
658                    if applied {
659                        class_list.insert(name.clone());
660                    } else {
661                        class_list.remove(&name);
662                    }
663                }
664
665                cx.needs_restyle(entity);
666            });
667        });
668    }
669
670    /// Add a listener to an entity.
671    ///
672    /// A listener can be used to handle events which would not normally propagate to the entity.
673    /// For example, mouse events when a different entity has captured them. Useful for things like
674    /// closing a popup when clicking outside of its bounding box.
675    pub fn add_listener<F, W>(&mut self, listener: F)
676    where
677        W: View,
678        F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
679    {
680        self.listeners.insert(
681            self.current,
682            Box::new(move |event_handler, context, event| {
683                if let Some(widget) = event_handler.downcast_mut::<W>() {
684                    (listener)(widget, context, event);
685                }
686            }),
687        );
688    }
689
690    /// Adds a global listener to the application.
691    ///
692    /// Global listeners have the first opportunity to handle every event that is sent in an
693    /// application. They will *never* be removed. If you need a listener tied to the lifetime of a
694    /// view, use `add_listener`.
695    pub fn add_global_listener<F>(&mut self, listener: F)
696    where
697        F: 'static + Fn(&mut EventContext, &mut Event),
698    {
699        self.global_listeners.push(Box::new(listener));
700    }
701
702    /// Loads a font into the application from in-memory bytes.
703    pub fn load_font_mem(&mut self, data: impl AsRef<[u8]>) {
704        self.text_context.asset_provider.register_typeface(
705            self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
706            None,
707        );
708    }
709
710    fn request_resource_if_not_loaded(
711        &mut self,
712        path: String,
713        request: crate::resource::ResourceRequest,
714        options: crate::resource::ResourceLoadOptions,
715    ) {
716        // Avoid re-issuing requests for resources that are already loading or resolved.
717        if self.resource_manager.resource_status(&path) != LoadingStatus::NotLoaded {
718            return;
719        }
720
721        self.resource_manager.queue_resource_request(request, options);
722    }
723
724    /// Returns a reactive loading-status signal for the provided resource path.
725    ///
726    /// The signal value is updated by resource loaders as the request progresses.
727    pub fn resource_status_signal(&mut self, path: impl Into<String>) -> Signal<LoadingStatus> {
728        let path = path.into();
729
730        if let Some(signal) = self.resource_manager.loading_status.get(&path).copied() {
731            return signal;
732        }
733
734        let status = self.resource_manager.resource_status(&path);
735        let signal = Signal::new(status);
736        self.resource_manager.loading_status.insert(path, signal);
737        signal
738    }
739
740    /// Returns the current loading status for the provided resource path.
741    ///
742    /// This reads from the same reactive signal used by [`Context::resource_status_signal`].
743    pub fn resource_status(&mut self, path: impl Into<String>) -> LoadingStatus {
744        self.resource_status_signal(path).get()
745    }
746
747    /// Adds a font to the application by loading it through the configured resource loaders.
748    ///
749    /// This supports local files (including `file://` URLs) and any custom loader you register.
750    pub fn add_font(
751        &mut self,
752        path: impl Into<String>,
753        options: Option<crate::resource::ResourceLoadOptions>,
754    ) {
755        let path = path.into();
756        let options = options.unwrap_or_default();
757
758        self.request_resource_if_not_loaded(
759            path.clone(),
760            crate::resource::ResourceRequest::Font(crate::resource::FontRequest { path }),
761            options,
762        );
763    }
764
765    /// Queues an image resource request and returns a reactive loading-status signal.
766    ///
767    /// `name` is the key used to reference the image from CSS and [`Image::new`].
768    /// `path` can be a filesystem path, `file://` URL, or HTTP(S) URL (with `url-loader`).
769    pub fn add_image(
770        &mut self,
771        name: impl Into<String>,
772        path: impl Into<String>,
773        policy: ImageRetentionPolicy,
774        options: Option<crate::resource::ResourceLoadOptions>,
775    ) -> Signal<LoadingStatus> {
776        let name = name.into();
777        let path = path.into();
778        let options = options.unwrap_or_default();
779
780        self.resource_manager.register_image_source(name.clone(), path.clone());
781
782        // If the path is already loaded and load_image ran before this add_image call,
783        // immediately alias the existing ImageId to the new name so it resolves without
784        // waiting for another load cycle.
785        if self.resource_manager.resource_status(&path) != crate::resource::LoadingStatus::NotLoaded
786        {
787            let existing_id = self
788                .resource_manager
789                .image_sources
790                .iter()
791                .find(|(alias, alias_path)| {
792                    *alias_path == &path && self.resource_manager.image_ids.contains_key(*alias)
793                })
794                .and_then(|(alias, _)| self.resource_manager.image_ids.get(alias).copied());
795            if let Some(id) = existing_id {
796                self.resource_manager.image_ids.entry(name.clone()).or_insert(id);
797            }
798            // If no id exists yet the path is still loading; load_image will back-fill via
799            // the alias scan above when it runs.
800        }
801
802        self.request_resource_if_not_loaded(
803            path.clone(),
804            crate::resource::ResourceRequest::Image(crate::resource::ImageRequest {
805                name,
806                path: path.clone(),
807                policy,
808            }),
809            options,
810        );
811
812        self.resource_status_signal(path)
813    }
814
815    /// Adds a translation file to the application by loading it through the configured resource
816    /// loaders.
817    ///
818    /// This supports local files (including `file://` URLs), HTTP(S) URLs when the
819    /// `url-loader` feature is enabled, and any custom loader you register.
820    pub fn add_translation_file(
821        &mut self,
822        lang: LanguageIdentifier,
823        path: impl Into<String>,
824        options: Option<crate::resource::ResourceLoadOptions>,
825    ) {
826        let path = path.into();
827        let options = options.unwrap_or_default();
828
829        self.request_resource_if_not_loaded(
830            path.clone(),
831            crate::resource::ResourceRequest::Translation(crate::resource::TranslationRequest {
832                lang,
833                path,
834            }),
835            options,
836        );
837    }
838
839    /// Returns the element name (e.g. `"textbox"`) of the currently focused
840    /// view, or `None` if the focused entity has no view or the view doesn't
841    /// declare an element name.
842    ///
843    /// Mirrors [`BackendContext::focused_element`] for use from contexts
844    /// (such as the `on_idle` application callback) that receive a
845    /// `&mut Context` directly.
846    pub fn focused_element(&self) -> Option<&'static str> {
847        self.views.get(&self.focused).and_then(|view| view.element())
848    }
849
850    pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
851        self.resource_manager.styles.push(Box::new(style));
852
853        EventContext::new(self).reload_styles().expect("Failed to reload styles");
854
855        Ok(())
856    }
857
858    /// Remove all user themes from the application.
859    pub fn add_built_in_styles(&mut self) {
860        self.add_built_in_translations();
861
862        let user_styles = if self.built_in_styles_added {
863            if self.resource_manager.styles.len() >= 3 {
864                self.resource_manager.styles.drain(3..).collect::<Vec<_>>()
865            } else {
866                Vec::new()
867            }
868        } else {
869            self.resource_manager.styles.drain(..).collect::<Vec<_>>()
870        };
871
872        self.resource_manager.styles.clear();
873
874        self.resource_manager.styles.push(Box::new(DEFAULT_LAYOUT));
875        self.resource_manager.styles.push(Box::new(MARKDOWN));
876
877        if !self.ignore_default_theme {
878            self.resource_manager.styles.push(Box::new(DEFAULT_THEME));
879            let environment = self.data::<Environment>();
880            let theme_mode = environment.effective_theme();
881            let direction = environment.direction.get();
882            self.with_current(Entity::root(), |cx| {
883                let cx = &mut EventContext::new(cx);
884                cx.toggle_class("dark", theme_mode == ThemeMode::DarkMode);
885                cx.toggle_class("rtl", direction == Direction::RightToLeft);
886            })
887        } else {
888            // Add an empty stylesheet to ensure that the list of styles contains at least three entries.
889            self.resource_manager.styles.push(Box::new(""));
890        }
891
892        self.resource_manager.styles.extend(user_styles);
893        self.built_in_styles_added = true;
894
895        EventContext::new(self).reload_styles().unwrap();
896    }
897
898    /// Adds built-in translations for default view strings.
899    pub fn add_built_in_translations(&mut self) {
900        if self.built_in_translations_added {
901            return;
902        }
903
904        self.load_translation("en-US".parse().unwrap(), DEFAULT_TRANSLATION_EN_US)
905            .expect("Failed to load built-in en-US translation resources");
906        self.built_in_translations_added = true;
907    }
908
909    pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
910        self.style.add_animation(animation)
911    }
912
913    /// Adds a resource loader to the loading chain.
914    ///
915    /// Loaders are tried in list order, and this method inserts at the front so custom
916    /// loaders take priority over built-in loaders. The first loader that returns `true`
917    /// handles the request, and subsequent loaders are skipped.
918    pub fn add_resource_loader<L: crate::resource::ResourceLoader>(&mut self, loader: L) {
919        self.resource_manager.resource_loaders.insert(0, Box::new(loader));
920    }
921
922    /// Loads a translation into the application for the provided language.
923    ///
924    /// Returns an error if the FTL syntax is invalid or the resource cannot be added to the bundle.
925    pub fn load_translation(
926        &mut self,
927        lang: LanguageIdentifier,
928        ftl: impl ToString,
929    ) -> Result<(), crate::resource::TranslationError> {
930        self.resource_manager.add_translation(lang, ftl.to_string())
931    }
932
933    /// Adds a timer to the application.
934    ///
935    /// `interval` - The time between ticks of the timer.
936    /// `duration` - An optional duration for the timer. Pass `None` for a continuos timer.
937    /// `callback` - A callback which is called on when the timer is started, ticks, and stops. Disambiguated by the `TimerAction` parameter of the callback.
938    ///
939    /// Returns a `Timer` id which can be used to start and stop the timer.  
940    ///
941    /// # Example
942    /// Creates a timer which calls the provided callback every second for 5 seconds:
943    /// ```rust
944    /// # use vizia_core::prelude::*;
945    /// # use instant::{Instant, Duration};
946    /// # let cx = &mut Context::default();
947    /// let timer = cx.add_timer(Duration::from_secs(1), Some(Duration::from_secs(5)), |cx, reason|{
948    ///     match reason {
949    ///         TimerAction::Start => {
950    ///             debug!("Start timer");
951    ///         }
952    ///     
953    ///         TimerAction::Tick(delta) => {
954    ///             debug!("Tick timer: {:?}", delta);
955    ///         }
956    ///
957    ///         TimerAction::Stop => {
958    ///             debug!("Stop timer");
959    ///         }
960    ///     }
961    /// });
962    /// ```
963    pub fn add_timer(
964        &mut self,
965        interval: Duration,
966        duration: Option<Duration>,
967        callback: impl Fn(&mut EventContext, TimerAction) + 'static,
968    ) -> Timer {
969        let id = Timer(self.timers.len());
970        self.timers.push(TimerState {
971            entity: Entity::root(),
972            id,
973            time: Instant::now(),
974            interval,
975            duration,
976            start_time: Instant::now(),
977            callback: Rc::new(callback),
978            ticking: false,
979            stopping: false,
980        });
981
982        id
983    }
984
985    /// Starts a timer with the provided timer id.
986    ///
987    /// Events sent within the timer callback provided in `add_timer()` will target the current view.
988    pub fn start_timer(&mut self, timer: Timer) {
989        let current = self.current;
990        if !self.timer_is_running(timer) {
991            let timer_state = self.timers[timer.0].clone();
992            // Copy timer state from pending to playing
993            self.running_timers.push(timer_state);
994        }
995
996        self.modify_timer(timer, |timer_state| {
997            let now = Instant::now();
998            timer_state.start_time = now;
999            timer_state.time = now;
1000            timer_state.entity = current;
1001            timer_state.ticking = false;
1002            timer_state.stopping = false;
1003        });
1004    }
1005
1006    /// Modifies the state of an existing timer with the provided `Timer` id.
1007    pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
1008        let mut running_timers = self.running_timers.clone().into_vec();
1009
1010        if let Some(timer_state) =
1011            running_timers.iter_mut().find(|timer_state| timer_state.id == timer)
1012        {
1013            (timer_function)(timer_state);
1014            self.running_timers = running_timers.into();
1015            return;
1016        }
1017
1018        for pending_timer in self.timers.iter_mut() {
1019            if pending_timer.id == timer {
1020                (timer_function)(pending_timer);
1021            }
1022        }
1023    }
1024
1025    /// Returns true if the timer with the provided timer id is currently running.
1026    pub fn timer_is_running(&mut self, timer: Timer) -> bool {
1027        for timer_state in self.running_timers.iter() {
1028            if timer_state.id == timer {
1029                return true;
1030            }
1031        }
1032
1033        false
1034    }
1035
1036    /// Stops the timer with the given timer id.
1037    ///
1038    /// 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()`.
1039    pub fn stop_timer(&mut self, timer: Timer) {
1040        let mut running_timers = self.running_timers.clone();
1041
1042        for timer_state in running_timers.iter() {
1043            if timer_state.id == timer {
1044                (timer_state.callback)(
1045                    &mut EventContext::new_with_current(self, timer_state.entity),
1046                    TimerAction::Stop,
1047                );
1048            }
1049        }
1050
1051        self.running_timers =
1052            running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
1053    }
1054
1055    // Tick all timers.
1056    pub(crate) fn tick_timers(&mut self) {
1057        let now = Instant::now();
1058        while let Some(next_timer_state) = self.running_timers.peek() {
1059            if next_timer_state.time <= now {
1060                let mut timer_state = self.running_timers.pop().unwrap();
1061
1062                if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
1063                    if !timer_state.ticking {
1064                        (timer_state.callback)(
1065                            &mut EventContext::new_with_current(self, timer_state.entity),
1066                            TimerAction::Start,
1067                        );
1068                        timer_state.ticking = true;
1069                    } else {
1070                        (timer_state.callback)(
1071                            &mut EventContext::new_with_current(self, timer_state.entity),
1072                            TimerAction::Tick(now - timer_state.time),
1073                        );
1074                    }
1075                    timer_state.time = now + timer_state.interval - (now - timer_state.time);
1076                    self.running_timers.push(timer_state);
1077                } else {
1078                    (timer_state.callback)(
1079                        &mut EventContext::new_with_current(self, timer_state.entity),
1080                        TimerAction::Stop,
1081                    );
1082                }
1083            } else {
1084                break;
1085            }
1086        }
1087    }
1088
1089    /// Loads an image from memory and associates it with the provided path.
1090    pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
1091        let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
1092            *image_id
1093        } else {
1094            let id = self.resource_manager.image_id_manager.create();
1095            self.resource_manager.image_ids.insert(path.to_owned(), id);
1096            id
1097        };
1098
1099        if let Some(image) =
1100            skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
1101        {
1102            match self.resource_manager.images.entry(id) {
1103                Entry::Occupied(mut occ) => {
1104                    occ.get_mut().image = ImageOrSvg::Image(image);
1105                    occ.get_mut().dirty = true;
1106                    occ.get_mut().retention_policy = policy;
1107                }
1108                Entry::Vacant(vac) => {
1109                    vac.insert(StoredImage {
1110                        image: ImageOrSvg::Image(image),
1111                        retention_policy: policy,
1112                        used: true,
1113                        dirty: false,
1114                        observers: HashSet::new(),
1115                    });
1116                }
1117            }
1118            let observers: Vec<Entity> = self
1119                .resource_manager
1120                .images
1121                .get(&id)
1122                .map(|img| img.observers.iter().copied().collect())
1123                .unwrap_or_default();
1124            for observer in observers {
1125                self.style.needs_relayout(observer);
1126                self.needs_redraw(observer);
1127            }
1128            self.style.needs_relayout(self.current);
1129            self.needs_redraw(self.current);
1130        }
1131    }
1132
1133    pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
1134        let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
1135            return *image_id;
1136        } else {
1137            let id = self.resource_manager.image_id_manager.create();
1138            self.resource_manager.image_ids.insert(path.to_owned(), id);
1139            id
1140        };
1141
1142        if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
1143        {
1144            match self.resource_manager.images.entry(id) {
1145                Entry::Occupied(mut occ) => {
1146                    occ.get_mut().image = ImageOrSvg::Svg(svg);
1147                    occ.get_mut().dirty = true;
1148                    occ.get_mut().retention_policy = policy;
1149                }
1150                Entry::Vacant(vac) => {
1151                    vac.insert(StoredImage {
1152                        image: ImageOrSvg::Svg(svg),
1153                        retention_policy: policy,
1154                        used: true,
1155                        dirty: false,
1156                        observers: HashSet::new(),
1157                    });
1158                }
1159            }
1160            // Relayout only the entities that display this resource (its observers) plus the
1161            // current entity (e.g. the freshly-built Svg view triggering the load), rather than
1162            // forcing a full tree relayout.
1163            let observers: Vec<Entity> = self
1164                .resource_manager
1165                .images
1166                .get(&id)
1167                .map(|img| img.observers.iter().copied().collect())
1168                .unwrap_or_default();
1169            for observer in observers {
1170                self.style.needs_relayout(observer);
1171                self.needs_redraw(observer);
1172            }
1173            self.style.needs_relayout(self.current);
1174            self.needs_redraw(self.current);
1175        }
1176
1177        id
1178    }
1179
1180    pub fn spawn<F>(&self, target: F)
1181    where
1182        F: 'static + Send + FnOnce(&mut ContextProxy),
1183    {
1184        let mut cxp = ContextProxy {
1185            current: self.current,
1186            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
1187        };
1188
1189        std::thread::spawn(move || target(&mut cxp));
1190    }
1191
1192    pub fn get_proxy(&self) -> ContextProxy {
1193        ContextProxy {
1194            current: self.current,
1195            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
1196        }
1197    }
1198
1199    #[cfg(feature = "tokio")]
1200    /// Submits a configured [`TaskBuilder`] for asynchronous execution.
1201    ///
1202    /// Tasks run on Vizia's shared Tokio runtime and complete through the
1203    /// `on_result(...)` callback attached to the builder, when one is provided.
1204    ///
1205    /// Returns a [`TaskHandle`] that can be used to request cancellation.
1206    ///
1207    /// # Example
1208    /// ```rust,no_run
1209    /// # use vizia_core::prelude::*;
1210    /// # #[cfg(feature = "tokio")]
1211    /// # {
1212    /// # let cx = Context::default();
1213    /// // Fire-and-forget:
1214    /// cx.add_task(Task::new(|_| async move { Ok::<(), &'static str>(()) }));
1215    ///
1216    /// // With completion handling:
1217    /// cx.add_task(
1218    ///     Task::new(|_| async move { Ok::<_, &'static str>("loaded") })
1219    ///         .on_result(|result, proxy| {
1220    ///             if let TaskResult::Completed(message) = result {
1221    ///                 let _ = proxy.emit(message);
1222    ///             }
1223    ///         }),
1224    /// );
1225    /// # }
1226    /// ```
1227    pub fn add_task<T, E>(&self, task: TaskBuilder<T, E>) -> TaskHandle
1228    where
1229        T: Send + 'static,
1230        E: Send + 'static,
1231    {
1232        task.add_to_context(self)
1233    }
1234
1235    /// Finds the entity that identifier identifies
1236    pub(crate) fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
1237        self.entity_identifiers.get(identity).cloned()
1238    }
1239
1240    pub fn set_ime_state(&mut self, new_state: ImeState) {
1241        self.ime_state = new_state;
1242    }
1243}
1244
1245pub(crate) enum InternalEvent {
1246    Redraw,
1247    LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
1248    LoadSvg { path: String, data: Vec<u8>, policy: ImageRetentionPolicy },
1249    LoadFont { path: String, data: Vec<u8> },
1250    LoadTranslation { lang: LanguageIdentifier, path: String, ftl: String },
1251    UpdateResourceStatus { path: String, status: LoadingStatus },
1252}
1253
1254pub struct LocalizationContext<'a> {
1255    pub(crate) current: Entity,
1256    pub(crate) resource_manager: &'a ResourceManager,
1257    pub(crate) models: &'a Models,
1258    pub(crate) views: &'a Views,
1259    pub(crate) tree: &'a Tree<Entity>,
1260}
1261
1262impl<'a> LocalizationContext<'a> {
1263    pub(crate) fn from_context(cx: &'a Context) -> Self {
1264        Self {
1265            current: cx.current,
1266            resource_manager: &cx.resource_manager,
1267            models: &cx.models,
1268            views: &cx.views,
1269            tree: &cx.tree,
1270        }
1271    }
1272
1273    pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
1274        Self {
1275            current: cx.current,
1276            resource_manager: cx.resource_manager,
1277            models: cx.models,
1278            views: cx.views,
1279            tree: cx.tree,
1280        }
1281    }
1282
1283    pub(crate) fn environment(&self) -> &Environment {
1284        self.data::<Environment>()
1285    }
1286}
1287
1288/// A trait for any Context-like object that lets you access stored model data.
1289///
1290/// This lets resource reads be generic over any of these types.
1291pub trait DataContext {
1292    /// Get model/view data from the context. Returns `None` if the data does not exist.
1293    fn try_data<T: 'static>(&self) -> Option<&T>;
1294
1295    /// Get model/view data from the context. Panics if the data does not exist.
1296    fn data<T: 'static>(&self) -> &T {
1297        self.try_data::<T>().expect("data not found in context")
1298    }
1299
1300    /// Convert the current context into a [LocalizationContext].
1301    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1302        None
1303    }
1304}
1305
1306/// A trait for any Context-like object that lets you emit events.
1307pub trait EmitContext {
1308    /// Send an event containing the provided message up the tree from the current entity.
1309    ///
1310    /// # Example
1311    /// ```rust
1312    /// # use vizia_core::prelude::*;
1313    /// # use instant::{Instant, Duration};
1314    /// # let cx = &mut Context::default();
1315    /// # enum AppEvent {Increment}
1316    /// cx.emit(AppEvent::Increment);
1317    /// ```
1318    fn emit<M: Any>(&mut self, message: M);
1319
1320    /// Send an event containing the provided message directly to a specified entity from the current entity.
1321    ///
1322    /// # Example
1323    /// ```rust
1324    /// # use vizia_core::prelude::*;
1325    /// # use instant::{Instant, Duration};
1326    /// # let cx = &mut Context::default();
1327    /// # enum AppEvent {Increment}
1328    /// cx.emit_to(Entity::root(), AppEvent::Increment);
1329    /// ```
1330    fn emit_to<M: Any>(&mut self, target: Entity, message: M);
1331
1332    /// Send a custom event with custom origin and propagation information.
1333    ///
1334    /// # Example
1335    /// ```rust
1336    /// # use vizia_core::prelude::*;
1337    /// # use instant::{Instant, Duration};
1338    /// # let cx = &mut Context::default();
1339    /// # enum AppEvent {Increment}
1340    /// cx.emit_custom(
1341    ///     Event::new(AppEvent::Increment)
1342    ///         .origin(cx.current())
1343    ///         .target(Entity::root())
1344    ///         .propagate(Propagation::Subtree)
1345    /// );
1346    /// ```
1347    fn emit_custom(&mut self, event: Event);
1348
1349    /// Send an event containing the provided message up the tree at a particular time instant.
1350    ///
1351    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1352    ///
1353    /// # Example
1354    /// Emit an event after a delay of 2 seconds:
1355    /// ```rust
1356    /// # use vizia_core::prelude::*;
1357    /// # use instant::{Instant, Duration};
1358    /// # let cx = &mut Context::default();
1359    /// # enum AppEvent {Increment}
1360    /// cx.schedule_emit(AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1361    /// ```
1362    fn schedule_emit<M: Any>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1363
1364    /// Send an event containing the provided message directly to a specified view at a particular time instant.
1365    ///
1366    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1367    ///
1368    /// # Example
1369    /// Emit an event to the root view (window) after a delay of 2 seconds:
1370    /// ```rust
1371    /// # use vizia_core::prelude::*;
1372    /// # use instant::{Instant, Duration};
1373    /// # let cx = &mut Context::default();
1374    /// # enum AppEvent {Increment}
1375    /// cx.schedule_emit_to(Entity::root(), AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1376    /// ```
1377    fn schedule_emit_to<M: Any>(
1378        &mut self,
1379        target: Entity,
1380        message: M,
1381        at: Instant,
1382    ) -> TimedEventHandle;
1383
1384    /// Send a custom event with custom origin and propagation information at a particular time instant.
1385    ///
1386    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1387    ///
1388    /// # Example
1389    /// Emit a custom event after a delay of 2 seconds:
1390    /// ```rust
1391    /// # use vizia_core::prelude::*;
1392    /// # use instant::{Instant, Duration};
1393    /// # let cx = &mut Context::default();
1394    /// # enum AppEvent {Increment}
1395    /// cx.schedule_emit_custom(    
1396    ///     Event::new(AppEvent::Increment)
1397    ///         .target(Entity::root())
1398    ///         .origin(cx.current())
1399    ///         .propagate(Propagation::Subtree),
1400    ///     Instant::now() + Duration::from_secs(2)
1401    /// );
1402    /// ```
1403    fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1404
1405    /// Cancel a scheduled event before it is sent.
1406    ///
1407    /// # Example
1408    /// ```rust
1409    /// # use vizia_core::prelude::*;
1410    /// # use instant::{Instant, Duration};
1411    /// # let cx = &mut Context::default();
1412    /// # enum AppEvent {Increment}
1413    /// let timed_event = cx.schedule_emit_to(Entity::root(), AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1414    /// cx.cancel_scheduled(timed_event);
1415    /// ```
1416    fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1417}
1418
1419impl DataContext for Context {
1420    fn try_data<T: 'static>(&self) -> Option<&T> {
1421        // return data for the static model.
1422        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1423            return Some(t);
1424        }
1425
1426        for entity in self.current.parent_iter(&self.tree) {
1427            // Return any model data.
1428            if let Some(models) = self.models.get(&entity) {
1429                if let Some(model) = models.get(&TypeId::of::<T>()) {
1430                    return model.downcast_ref::<T>();
1431                }
1432            }
1433
1434            // Return any view data.
1435            if let Some(view_handler) = self.views.get(&entity) {
1436                if let Some(data) = view_handler.downcast_ref::<T>() {
1437                    return Some(data);
1438                }
1439            }
1440        }
1441
1442        None
1443    }
1444
1445    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1446        Some(LocalizationContext::from_context(self))
1447    }
1448}
1449
1450impl DataContext for LocalizationContext<'_> {
1451    fn try_data<T: 'static>(&self) -> Option<&T> {
1452        // return data for the static model.
1453        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1454            return Some(t);
1455        }
1456
1457        for entity in self.current.parent_iter(self.tree) {
1458            // Return any model data.
1459            if let Some(models) = self.models.get(&entity) {
1460                if let Some(model) = models.get(&TypeId::of::<T>()) {
1461                    return model.downcast_ref::<T>();
1462                }
1463            }
1464
1465            // Return any view data.
1466            if let Some(view_handler) = self.views.get(&entity) {
1467                if let Some(data) = view_handler.downcast_ref::<T>() {
1468                    return Some(data);
1469                }
1470            }
1471        }
1472
1473        None
1474    }
1475}
1476
1477impl EmitContext for Context {
1478    fn emit<M: Any>(&mut self, message: M) {
1479        self.event_queue.push_back(
1480            Event::new(message)
1481                .target(self.current)
1482                .origin(self.current)
1483                .propagate(Propagation::Up),
1484        );
1485    }
1486
1487    fn emit_to<M: Any>(&mut self, target: Entity, message: M) {
1488        self.event_queue.push_back(
1489            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1490        );
1491    }
1492
1493    fn emit_custom(&mut self, event: Event) {
1494        self.event_queue.push_back(event);
1495    }
1496
1497    fn schedule_emit<M: Any>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1498        self.schedule_emit_custom(
1499            Event::new(message)
1500                .target(self.current)
1501                .origin(self.current)
1502                .propagate(Propagation::Up),
1503            at,
1504        )
1505    }
1506
1507    fn schedule_emit_to<M: Any>(
1508        &mut self,
1509        target: Entity,
1510        message: M,
1511        at: Instant,
1512    ) -> TimedEventHandle {
1513        self.schedule_emit_custom(
1514            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1515            at,
1516        )
1517    }
1518
1519    fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1520        let handle = TimedEventHandle(self.next_event_id);
1521        self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1522        self.next_event_id += 1;
1523        handle
1524    }
1525
1526    fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1527        self.event_schedule =
1528            self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1529    }
1530}