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
11use log::debug;
12use skia_safe::{
13    FontMgr, svg,
14    textlayout::{FontCollection, TypefaceFontProvider},
15};
16use std::cell::RefCell;
17use std::collections::{BinaryHeap, VecDeque};
18use std::rc::Rc;
19use std::sync::Mutex;
20use std::{
21    any::{Any, TypeId},
22    sync::Arc,
23};
24use vizia_id::IdManager;
25use vizia_window::WindowDescription;
26
27#[cfg(feature = "clipboard")]
28use copypasta::{ClipboardContext, ClipboardProvider, nop_clipboard::NopClipboardContext};
29use hashbrown::{HashMap, HashSet, hash_map::Entry};
30
31pub use access::*;
32pub use draw::*;
33pub use event::*;
34pub use proxy::*;
35pub use resource::*;
36
37use crate::{
38    events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler},
39    model::ModelData,
40};
41
42use crate::{binding::BindingHandler, resource::StoredImage};
43use crate::{cache::CachedData, resource::ImageOrSvg};
44
45use crate::prelude::*;
46use crate::resource::ResourceManager;
47use crate::text::TextContext;
48use vizia_input::{ImeState, MouseState};
49use vizia_storage::{ChildIterator, LayoutTreeIterator};
50
51static DEFAULT_LAYOUT: &str = include_str!("../../resources/themes/default_layout.css");
52static DEFAULT_THEME: &str = include_str!("../../resources/themes/default_theme.css");
53static MARKDOWN: &str = include_str!("../../resources/themes/markdown.css");
54static DEFAULT_TRANSLATION_EN_US: &str =
55    include_str!("../../resources/translations/en-US/core.ftl");
56
57type Views = HashMap<Entity, Box<dyn ViewHandler>>;
58type Models = HashMap<Entity, HashMap<TypeId, Box<dyn ModelData>>>;
59type Bindings = HashMap<Entity, Box<dyn BindingHandler>>;
60
61thread_local! {
62    /// Entities for `Binding` views that need to be rebuilt because a reactive signal changed.
63    /// Signal effects push to this set; the binding system drains it each frame.
64    pub(crate) static SIGNAL_REBUILDS: RefCell<HashSet<Entity>> = RefCell::new(HashSet::new());
65}
66
67#[derive(Default, Clone)]
68pub struct WindowState {
69    pub window_description: WindowDescription,
70    pub scale_factor: f32,
71    pub needs_relayout: bool,
72    pub needs_redraw: bool,
73    pub redraw_list: HashSet<Entity>,
74    pub dirty_rect: Option<BoundingBox>,
75    pub owner: Option<Entity>,
76    pub is_modal: bool,
77    pub should_close: bool,
78    pub content: Option<Arc<dyn Fn(&mut Context)>>,
79}
80
81/// The main storage and control object for a Vizia application.
82pub struct Context {
83    pub(crate) entity_manager: IdManager<Entity>,
84    pub(crate) entity_identifiers: HashMap<String, Entity>,
85    pub tree: Tree<Entity>,
86    pub(crate) current: Entity,
87    pub(crate) views: Views,
88    pub(crate) models: Models,
89    pub(crate) bindings: Bindings,
90    pub(crate) event_queue: VecDeque<Event>,
91    pub(crate) event_schedule: BinaryHeap<TimedEvent>,
92    pub(crate) next_event_id: usize,
93    pub(crate) timers: Vec<TimerState>,
94    pub(crate) running_timers: BinaryHeap<TimerState>,
95    pub tree_updates: Vec<Option<accesskit::TreeUpdate>>,
96    pub(crate) listeners:
97        HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
98    pub(crate) global_listeners: Vec<Box<dyn Fn(&mut EventContext, &mut Event)>>,
99    pub(crate) style: Style,
100    pub(crate) cache: CachedData,
101    pub windows: HashMap<Entity, WindowState>,
102
103    pub mouse: MouseState<Entity>,
104    pub(crate) modifiers: Modifiers,
105
106    pub(crate) captured: Entity,
107    pub(crate) triggered: Entity,
108    pub(crate) hovered: Entity,
109    pub(crate) focused: Entity,
110    pub(crate) focus_stack: Vec<Entity>,
111    pub(crate) cursor_icon_locked: bool,
112
113    pub(crate) resource_manager: ResourceManager,
114
115    pub text_context: TextContext,
116
117    pub(crate) event_proxy: Option<Box<dyn EventProxy>>,
118
119    #[cfg(feature = "clipboard")]
120    pub(crate) clipboard: Box<dyn ClipboardProvider>,
121
122    pub(crate) click_time: Instant,
123    pub(crate) clicks: usize,
124    pub(crate) click_pos: (f32, f32),
125    pub(crate) click_button: MouseButton,
126
127    pub ignore_default_theme: bool,
128    built_in_translations_added: bool,
129    pub window_has_focus: bool,
130    pub ime_state: ImeState,
131
132    pub(crate) drop_data: Option<DropData>,
133}
134
135impl Default for Context {
136    fn default() -> Self {
137        Context::new()
138    }
139}
140
141impl Context {
142    /// Creates a new context.
143    pub fn new() -> Self {
144        let mut cache = CachedData::default();
145        cache.add(Entity::root());
146
147        let mut result = Self {
148            entity_manager: IdManager::new(),
149            entity_identifiers: HashMap::new(),
150            tree: Tree::new(),
151            current: Entity::root(),
152            views: HashMap::default(),
153            models: HashMap::default(),
154            bindings: HashMap::default(),
155            style: Style::default(),
156            cache,
157            windows: HashMap::new(),
158            event_queue: VecDeque::new(),
159            event_schedule: BinaryHeap::new(),
160            next_event_id: 0,
161            timers: Vec::new(),
162            running_timers: BinaryHeap::new(),
163            tree_updates: Vec::new(),
164            listeners: HashMap::default(),
165            global_listeners: Vec::new(),
166            mouse: MouseState::default(),
167            modifiers: Modifiers::empty(),
168            captured: Entity::null(),
169            triggered: Entity::null(),
170            hovered: Entity::root(),
171            focused: Entity::root(),
172            focus_stack: Vec::new(),
173            cursor_icon_locked: false,
174            resource_manager: ResourceManager::new(),
175            text_context: {
176                let mut font_collection = FontCollection::new();
177
178                let default_font_manager = FontMgr::default();
179
180                let asset_provider = TypefaceFontProvider::new();
181
182                font_collection.set_default_font_manager(default_font_manager.clone(), None);
183                let asset_font_manager: FontMgr = asset_provider.clone().into();
184                font_collection.set_asset_font_manager(asset_font_manager);
185
186                TextContext {
187                    font_collection,
188                    default_font_manager,
189                    asset_provider,
190                    text_bounds: Default::default(),
191                    text_paragraphs: Default::default(),
192                }
193            },
194
195            event_proxy: None,
196
197            #[cfg(feature = "clipboard")]
198            clipboard: {
199                if let Ok(context) = ClipboardContext::new() {
200                    Box::new(context)
201                } else {
202                    Box::new(NopClipboardContext::new().unwrap())
203                }
204            },
205            click_time: Instant::now(),
206            clicks: 0,
207            click_pos: (0.0, 0.0),
208            click_button: MouseButton::Left,
209
210            ignore_default_theme: false,
211            built_in_translations_added: false,
212            window_has_focus: true,
213
214            ime_state: Default::default(),
215
216            drop_data: None,
217        };
218
219        result.tree.set_window(Entity::root(), true);
220
221        result.style.needs_restyle(Entity::root());
222        result.style.needs_relayout();
223        result.style.needs_retransform(Entity::root());
224        result.style.needs_reclip(Entity::root());
225        result.needs_redraw(Entity::root());
226
227        // Set the default DPI factor to 1.0.
228        result.style.dpi_factor = 1.0;
229
230        // Build the environment model at the root.
231        Environment::new(&mut result).build(&mut result);
232
233        result.entity_manager.create();
234
235        result.style.role.insert(Entity::root(), Role::Window);
236
237        result
238    }
239
240    /// The "current" entity, generally the entity which is currently being built or the entity
241    /// which is currently having an event dispatched to it.
242    pub fn current(&self) -> Entity {
243        self.current
244    }
245
246    /// Makes the above black magic more explicit
247    pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
248        let previous = self.current;
249        self.current = current;
250        let ret = f(self);
251        self.current = previous;
252        ret
253    }
254
255    /// Returns a reference to the [Environment] model.
256    pub fn environment(&self) -> &Environment {
257        self.data::<Environment>()
258    }
259
260    /// Returns the entity id of the  parent window to the current view.
261    pub fn parent_window(&self) -> Entity {
262        self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
263    }
264
265    /// Returns the scale factor of the display.
266    pub fn scale_factor(&self) -> f32 {
267        self.style.dpi_factor as f32
268    }
269
270    /// Mark the application as needing to rerun the draw method
271    pub fn needs_redraw(&mut self, entity: Entity) {
272        if self.entity_manager.is_alive(entity) {
273            // If a child window needs redrawing, add itself to the redraw list.
274            // This ensures that the entire window is redrawn: https://github.com/vizia/vizia/issues/580
275            let window = if self.tree.is_window(entity) {
276                entity
277            } else {
278                self.tree.get_parent_window(entity).unwrap_or(Entity::root())
279            };
280            if let Some(window_state) = self.windows.get_mut(&window) {
281                window_state.redraw_list.insert(entity);
282            }
283        }
284    }
285
286    /// Mark the application as needing to recompute view styles
287    pub fn needs_restyle(&mut self, entity: Entity) {
288        if entity == Entity::null() || self.style.restyle.contains(&entity) {
289            return;
290        }
291        self.style.restyle.insert(entity);
292        let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
293            LayoutTreeIterator::subtree(&self.tree, parent)
294        } else {
295            LayoutTreeIterator::subtree(&self.tree, entity)
296        };
297
298        for descendant in iter {
299            self.style.restyle.insert(descendant);
300        }
301        // self.style.needs_restyle();
302    }
303
304    pub fn needs_retransform(&mut self, entity: Entity) {
305        self.style.needs_retransform(entity);
306        let iter = LayoutTreeIterator::subtree(&self.tree, entity);
307        for descendant in iter {
308            self.style.needs_retransform(descendant);
309        }
310    }
311
312    pub fn needs_reclip(&mut self, entity: Entity) {
313        self.style.needs_reclip(entity);
314        let iter = LayoutTreeIterator::subtree(&self.tree, entity);
315        for descendant in iter {
316            self.style.needs_reclip(descendant);
317        }
318    }
319
320    /// Mark the application as needing to rerun layout computations
321    pub fn needs_relayout(&mut self) {
322        self.style.needs_relayout();
323    }
324
325    pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
326        if system_flags.contains(SystemFlags::RELAYOUT) {
327            self.needs_relayout();
328        }
329
330        if system_flags.contains(SystemFlags::RESTYLE) {
331            self.needs_restyle(entity);
332        }
333
334        if system_flags.contains(SystemFlags::REDRAW) {
335            self.needs_redraw(entity);
336        }
337
338        if system_flags.contains(SystemFlags::REFLOW) {
339            self.style.needs_text_update(entity);
340        }
341
342        if system_flags.contains(SystemFlags::RETRANSFORM) {
343            self.needs_retransform(entity);
344        }
345
346        if system_flags.contains(SystemFlags::RECLIP) {
347            self.needs_reclip(entity);
348        }
349
350        if system_flags.contains(SystemFlags::REACCESS) {
351            self.style.needs_access_update(entity);
352        }
353    }
354
355    /// Enables or disables PseudoClasses for the focus of an entity
356    pub(crate) fn set_focus_pseudo_classes(
357        &mut self,
358        focused: Entity,
359        enabled: bool,
360        focus_visible: bool,
361    ) {
362        if enabled {
363            debug!(
364                "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
365                focused,
366                self.tree.get_parent(focused),
367                self.views
368                    .get(&focused)
369                    .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
370                self.cache.get_posx(focused),
371                self.cache.get_posy(focused),
372                self.cache.get_width(focused),
373                self.cache.get_height(focused),
374            );
375        }
376
377        if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
378            pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
379            if !enabled || focus_visible {
380                pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
381                self.style.needs_access_update(focused);
382                self.needs_restyle(focused);
383            }
384        }
385
386        let ancestors = focused.parent_iter(&self.tree).collect::<Vec<_>>();
387        for entity in ancestors {
388            if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
389                pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
390            }
391            self.needs_restyle(entity);
392        }
393    }
394
395    /// Sets application focus to the current entity with the specified focus visiblity
396    pub fn focus_with_visibility(&mut self, focus_visible: bool) {
397        let old_focus = self.focused;
398        let new_focus = self.current;
399        self.set_focus_pseudo_classes(old_focus, false, focus_visible);
400        if self.current != self.focused {
401            self.emit_to(old_focus, WindowEvent::FocusOut);
402            self.emit_to(new_focus, WindowEvent::FocusIn);
403            self.focused = self.current;
404        }
405        self.set_focus_pseudo_classes(new_focus, true, focus_visible);
406
407        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
408        self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
409
410        self.needs_restyle(self.focused);
411        self.needs_restyle(self.current);
412        self.style.needs_access_update(self.focused);
413        self.style.needs_access_update(self.current);
414    }
415
416    /// Sets application focus to the current entity using the previous focus visibility
417    pub fn focus(&mut self) {
418        let focused = self.focused;
419        let old_focus_visible = self
420            .style
421            .pseudo_classes
422            .get_mut(focused)
423            .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
424            .is_some();
425        self.focus_with_visibility(old_focus_visible)
426    }
427
428    /// Removes the children of the provided entity from the application.
429    pub(crate) fn remove_children(&mut self, entity: Entity) {
430        let child_iter = ChildIterator::new(&self.tree, entity);
431        let children = child_iter.collect::<Vec<_>>();
432        for child in children.into_iter() {
433            self.remove(child);
434        }
435    }
436
437    /// Removes the provided entity from the application.
438    pub fn remove(&mut self, entity: Entity) {
439        let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
440
441        if !delete_list.is_empty() {
442            self.style.needs_restyle(self.current);
443            self.style.needs_relayout();
444            self.needs_redraw(self.current);
445        }
446
447        for entity in delete_list.iter().rev() {
448            if let Some(mut view) = self.views.remove(entity) {
449                view.event(
450                    &mut EventContext::new_with_current(self, *entity),
451                    &mut Event::new(WindowEvent::Destroyed).direct(*entity),
452                );
453
454                self.views.insert(*entity, view);
455            }
456
457            if let Some(binding) = self.bindings.remove(entity) {
458                binding.remove(self);
459
460                self.bindings.insert(*entity, binding);
461            }
462
463            for image in self.resource_manager.images.values_mut() {
464                // no need to drop them here. garbage collection happens after draw (policy based)
465                image.observers.remove(entity);
466            }
467
468            if let Some(identifier) = self.style.ids.get(*entity) {
469                self.entity_identifiers.remove(identifier);
470            }
471
472            if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
473                self.focus_stack.remove(index);
474            }
475
476            if self.focused == *entity {
477                if let Some(new_focus) = self.focus_stack.pop() {
478                    self.with_current(new_focus, |cx| cx.focus());
479                } else {
480                    self.with_current(Entity::root(), |cx| cx.focus());
481                }
482            }
483
484            if self.captured == *entity {
485                self.captured = Entity::null();
486            }
487
488            if let Some(parent) = self.tree.get_layout_parent(*entity) {
489                self.style.needs_access_update(parent);
490            }
491
492            let mut stopped_timers = Vec::new();
493
494            for timer in self.running_timers.iter() {
495                if timer.entity == *entity {
496                    stopped_timers.push(timer.id);
497                }
498            }
499
500            for timer in stopped_timers {
501                self.stop_timer(timer);
502            }
503
504            let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
505
506            if !self.tree.is_window(*entity) {
507                if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
508                    if let Some(dirty_rect) =
509                        &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
510                    {
511                        *dirty_rect = dirty_rect.union(draw_bounds);
512                    } else {
513                        self.windows.get_mut(&window_entity).unwrap().dirty_rect =
514                            Some(*draw_bounds);
515                    }
516                }
517            }
518
519            self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
520
521            if self.windows.contains_key(entity) {
522                self.windows.remove(entity);
523            }
524
525            self.tree.remove(*entity).expect("");
526            self.cache.remove(*entity);
527            self.style.remove(*entity);
528            self.models.remove(entity);
529            self.views.remove(entity);
530            self.text_context.text_bounds.remove(*entity);
531            self.text_context.text_paragraphs.remove(*entity);
532            self.entity_manager.destroy(*entity);
533        }
534    }
535
536    /// Sets whether a view should have the given class name.
537    pub fn toggle_class(&mut self, name: &str, applied: impl Res<bool>) {
538        let name = name.to_owned();
539        let entity = self.current();
540        let current = self.current();
541        self.with_current(current, |cx| {
542            applied.set_or_bind(cx, move |cx, applied| {
543                let applied = applied.get_value(cx);
544                if let Some(class_list) = cx.style.classes.get_mut(entity) {
545                    if applied {
546                        class_list.insert(name.clone());
547                    } else {
548                        class_list.remove(&name);
549                    }
550                }
551
552                cx.needs_restyle(entity);
553            });
554        });
555    }
556
557    /// Add a listener to an entity.
558    ///
559    /// A listener can be used to handle events which would not normally propagate to the entity.
560    /// For example, mouse events when a different entity has captured them. Useful for things like
561    /// closing a popup when clicking outside of its bounding box.
562    pub fn add_listener<F, W>(&mut self, listener: F)
563    where
564        W: View,
565        F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
566    {
567        self.listeners.insert(
568            self.current,
569            Box::new(move |event_handler, context, event| {
570                if let Some(widget) = event_handler.downcast_mut::<W>() {
571                    (listener)(widget, context, event);
572                }
573            }),
574        );
575    }
576
577    /// Adds a global listener to the application.
578    ///
579    /// Global listeners have the first opportunity to handle every event that is sent in an
580    /// application. They will *never* be removed. If you need a listener tied to the lifetime of a
581    /// view, use `add_listener`.
582    pub fn add_global_listener<F>(&mut self, listener: F)
583    where
584        F: 'static + Fn(&mut EventContext, &mut Event),
585    {
586        self.global_listeners.push(Box::new(listener));
587    }
588
589    /// Adds a font to the application from memory.
590    pub fn add_font_mem(&mut self, data: impl AsRef<[u8]>) {
591        self.text_context.asset_provider.register_typeface(
592            self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
593            None,
594        );
595    }
596
597    /// Returns the element name (e.g. `"textbox"`) of the currently focused
598    /// view, or `None` if the focused entity has no view or the view doesn't
599    /// declare an element name.
600    ///
601    /// Mirrors [`BackendContext::focused_element`] for use from contexts
602    /// (such as the `on_idle` application callback) that receive a
603    /// `&mut Context` directly.
604    pub fn focused_element(&self) -> Option<&'static str> {
605        self.views.get(&self.focused).and_then(|view| view.element())
606    }
607
608    pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
609        self.resource_manager.styles.push(Box::new(style));
610
611        EventContext::new(self).reload_styles().expect("Failed to reload styles");
612
613        Ok(())
614    }
615
616    /// Remove all user themes from the application.
617    pub fn add_built_in_styles(&mut self) {
618        self.add_built_in_translations();
619
620        let mut user_styles = Vec::new();
621        if self.resource_manager.styles.len() >= 3 {
622            user_styles = self.resource_manager.styles.drain(3..).collect::<Vec<_>>();
623        }
624
625        self.resource_manager.styles.clear();
626
627        self.add_stylesheet(DEFAULT_LAYOUT).unwrap();
628        self.add_stylesheet(MARKDOWN).unwrap();
629
630        if !self.ignore_default_theme {
631            self.add_stylesheet(DEFAULT_THEME).unwrap();
632            let environment = self.data::<Environment>();
633            let theme_mode = environment.effective_theme();
634            let direction = environment.direction.get();
635            self.with_current(Entity::root(), |cx| {
636                let cx = &mut EventContext::new(cx);
637                cx.toggle_class("dark", theme_mode == ThemeMode::DarkMode);
638                cx.toggle_class("rtl", direction == Direction::RightToLeft);
639            })
640        } else {
641            // Add an empty stylesheet to ensure that the list of styles contains at least three entries.
642            self.add_stylesheet("").unwrap();
643        }
644
645        self.resource_manager.styles.extend(user_styles);
646
647        EventContext::new(self).reload_styles().unwrap();
648    }
649
650    /// Adds built-in translations for default view strings.
651    pub fn add_built_in_translations(&mut self) {
652        if self.built_in_translations_added {
653            return;
654        }
655
656        self.add_translation("en-US".parse().unwrap(), DEFAULT_TRANSLATION_EN_US)
657            .expect("Failed to load built-in en-US translation resources");
658        self.built_in_translations_added = true;
659    }
660
661    pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
662        self.style.add_animation(animation)
663    }
664
665    pub fn set_image_loader<F: 'static + Fn(&mut ResourceContext, &str)>(&mut self, loader: F) {
666        self.resource_manager.image_loader = Some(Box::new(loader));
667    }
668
669    /// Adds a translation to the application for the provided language.
670    ///
671    /// Returns an error if the FTL syntax is invalid or the resource cannot be added to the bundle.
672    pub fn add_translation(
673        &mut self,
674        lang: LanguageIdentifier,
675        ftl: impl ToString,
676    ) -> Result<(), crate::resource::TranslationError> {
677        self.resource_manager.add_translation(lang, ftl.to_string())
678    }
679
680    /// Adds a timer to the application.
681    ///
682    /// `interval` - The time between ticks of the timer.
683    /// `duration` - An optional duration for the timer. Pass `None` for a continuos timer.
684    /// `callback` - A callback which is called on when the timer is started, ticks, and stops. Disambiguated by the `TimerAction` parameter of the callback.
685    ///
686    /// Returns a `Timer` id which can be used to start and stop the timer.  
687    ///
688    /// # Example
689    /// Creates a timer which calls the provided callback every second for 5 seconds:
690    /// ```rust
691    /// # use vizia_core::prelude::*;
692    /// # use instant::{Instant, Duration};
693    /// # let cx = &mut Context::default();
694    /// let timer = cx.add_timer(Duration::from_secs(1), Some(Duration::from_secs(5)), |cx, reason|{
695    ///     match reason {
696    ///         TimerAction::Start => {
697    ///             debug!("Start timer");
698    ///         }
699    ///     
700    ///         TimerAction::Tick(delta) => {
701    ///             debug!("Tick timer: {:?}", delta);
702    ///         }
703    ///
704    ///         TimerAction::Stop => {
705    ///             debug!("Stop timer");
706    ///         }
707    ///     }
708    /// });
709    /// ```
710    pub fn add_timer(
711        &mut self,
712        interval: Duration,
713        duration: Option<Duration>,
714        callback: impl Fn(&mut EventContext, TimerAction) + 'static,
715    ) -> Timer {
716        let id = Timer(self.timers.len());
717        self.timers.push(TimerState {
718            entity: Entity::root(),
719            id,
720            time: Instant::now(),
721            interval,
722            duration,
723            start_time: Instant::now(),
724            callback: Rc::new(callback),
725            ticking: false,
726            stopping: false,
727        });
728
729        id
730    }
731
732    /// Starts a timer with the provided timer id.
733    ///
734    /// Events sent within the timer callback provided in `add_timer()` will target the current view.
735    pub fn start_timer(&mut self, timer: Timer) {
736        let current = self.current;
737        if !self.timer_is_running(timer) {
738            let timer_state = self.timers[timer.0].clone();
739            // Copy timer state from pending to playing
740            self.running_timers.push(timer_state);
741        }
742
743        self.modify_timer(timer, |timer_state| {
744            let now = Instant::now();
745            timer_state.start_time = now;
746            timer_state.time = now;
747            timer_state.entity = current;
748            timer_state.ticking = false;
749            timer_state.stopping = false;
750        });
751    }
752
753    /// Modifies the state of an existing timer with the provided `Timer` id.
754    pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
755        while let Some(next_timer_state) = self.running_timers.peek() {
756            if next_timer_state.id == timer {
757                let mut timer_state = self.running_timers.pop().unwrap();
758
759                (timer_function)(&mut timer_state);
760
761                self.running_timers.push(timer_state);
762
763                return;
764            }
765        }
766
767        for pending_timer in self.timers.iter_mut() {
768            if pending_timer.id == timer {
769                (timer_function)(pending_timer);
770            }
771        }
772    }
773
774    /// Returns true if the timer with the provided timer id is currently running.
775    pub fn timer_is_running(&mut self, timer: Timer) -> bool {
776        for timer_state in self.running_timers.iter() {
777            if timer_state.id == timer {
778                return true;
779            }
780        }
781
782        false
783    }
784
785    /// Stops the timer with the given timer id.
786    ///
787    /// 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()`.
788    pub fn stop_timer(&mut self, timer: Timer) {
789        let mut running_timers = self.running_timers.clone();
790
791        for timer_state in running_timers.iter() {
792            if timer_state.id == timer {
793                (timer_state.callback)(
794                    &mut EventContext::new_with_current(self, timer_state.entity),
795                    TimerAction::Stop,
796                );
797            }
798        }
799
800        self.running_timers =
801            running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
802    }
803
804    // Tick all timers.
805    pub(crate) fn tick_timers(&mut self) {
806        let now = Instant::now();
807        while let Some(next_timer_state) = self.running_timers.peek() {
808            if next_timer_state.time <= now {
809                let mut timer_state = self.running_timers.pop().unwrap();
810
811                if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
812                    if !timer_state.ticking {
813                        (timer_state.callback)(
814                            &mut EventContext::new_with_current(self, timer_state.entity),
815                            TimerAction::Start,
816                        );
817                        timer_state.ticking = true;
818                    } else {
819                        (timer_state.callback)(
820                            &mut EventContext::new_with_current(self, timer_state.entity),
821                            TimerAction::Tick(now - timer_state.time),
822                        );
823                    }
824                    timer_state.time = now + timer_state.interval - (now - timer_state.time);
825                    self.running_timers.push(timer_state);
826                } else {
827                    (timer_state.callback)(
828                        &mut EventContext::new_with_current(self, timer_state.entity),
829                        TimerAction::Stop,
830                    );
831                }
832            } else {
833                break;
834            }
835        }
836    }
837
838    /// Loads an image from memory and associates it with the provided path.
839    pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
840        let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
841            *image_id
842        } else {
843            let id = self.resource_manager.image_id_manager.create();
844            self.resource_manager.image_ids.insert(path.to_owned(), id);
845            id
846        };
847
848        if let Some(image) =
849            skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
850        {
851            match self.resource_manager.images.entry(id) {
852                Entry::Occupied(mut occ) => {
853                    occ.get_mut().image = ImageOrSvg::Image(image);
854                    occ.get_mut().dirty = true;
855                    occ.get_mut().retention_policy = policy;
856                }
857                Entry::Vacant(vac) => {
858                    vac.insert(StoredImage {
859                        image: ImageOrSvg::Image(image),
860                        retention_policy: policy,
861                        used: true,
862                        dirty: false,
863                        observers: HashSet::new(),
864                    });
865                }
866            }
867            self.style.needs_relayout();
868        }
869    }
870
871    pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
872        let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
873            return *image_id;
874        } else {
875            let id = self.resource_manager.image_id_manager.create();
876            self.resource_manager.image_ids.insert(path.to_owned(), id);
877            id
878        };
879
880        if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
881        {
882            match self.resource_manager.images.entry(id) {
883                Entry::Occupied(mut occ) => {
884                    occ.get_mut().image = ImageOrSvg::Svg(svg);
885                    occ.get_mut().dirty = true;
886                    occ.get_mut().retention_policy = policy;
887                }
888                Entry::Vacant(vac) => {
889                    vac.insert(StoredImage {
890                        image: ImageOrSvg::Svg(svg),
891                        retention_policy: policy,
892                        used: true,
893                        dirty: false,
894                        observers: HashSet::new(),
895                    });
896                }
897            }
898            self.style.needs_relayout();
899        }
900
901        id
902    }
903
904    pub fn spawn<F>(&self, target: F)
905    where
906        F: 'static + Send + FnOnce(&mut ContextProxy),
907    {
908        let mut cxp = ContextProxy {
909            current: self.current,
910            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
911        };
912
913        std::thread::spawn(move || target(&mut cxp));
914    }
915
916    pub fn get_proxy(&self) -> ContextProxy {
917        ContextProxy {
918            current: self.current,
919            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
920        }
921    }
922
923    /// Finds the entity that identifier identifies
924    pub(crate) fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
925        self.entity_identifiers.get(identity).cloned()
926    }
927
928    pub fn set_ime_state(&mut self, new_state: ImeState) {
929        self.ime_state = new_state;
930    }
931}
932
933pub(crate) enum InternalEvent {
934    Redraw,
935    LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
936}
937
938pub struct LocalizationContext<'a> {
939    pub(crate) current: Entity,
940    pub(crate) resource_manager: &'a ResourceManager,
941    pub(crate) models: &'a Models,
942    pub(crate) views: &'a Views,
943    pub(crate) tree: &'a Tree<Entity>,
944}
945
946impl<'a> LocalizationContext<'a> {
947    pub(crate) fn from_context(cx: &'a Context) -> Self {
948        Self {
949            current: cx.current,
950            resource_manager: &cx.resource_manager,
951            models: &cx.models,
952            views: &cx.views,
953            tree: &cx.tree,
954        }
955    }
956
957    pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
958        Self {
959            current: cx.current,
960            resource_manager: cx.resource_manager,
961            models: cx.models,
962            views: cx.views,
963            tree: cx.tree,
964        }
965    }
966
967    pub(crate) fn environment(&self) -> &Environment {
968        self.data::<Environment>()
969    }
970}
971
972/// A trait for any Context-like object that lets you access stored model data.
973///
974/// This lets resource reads be generic over any of these types.
975pub trait DataContext {
976    /// Get model/view data from the context. Returns `None` if the data does not exist.
977    fn try_data<T: 'static>(&self) -> Option<&T>;
978
979    /// Get model/view data from the context. Panics if the data does not exist.
980    fn data<T: 'static>(&self) -> &T {
981        self.try_data::<T>().expect("data not found in context")
982    }
983
984    /// Convert the current context into a [LocalizationContext].
985    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
986        None
987    }
988}
989
990/// A trait for any Context-like object that lets you emit events.
991pub trait EmitContext {
992    /// Send an event containing the provided message up the tree from the current entity.
993    ///
994    /// # Example
995    /// ```rust
996    /// # use vizia_core::prelude::*;
997    /// # use instant::{Instant, Duration};
998    /// # let cx = &mut Context::default();
999    /// # enum AppEvent {Increment}
1000    /// cx.emit(AppEvent::Increment);
1001    /// ```
1002    fn emit<M: Any + Send>(&mut self, message: M);
1003
1004    /// Send an event containing the provided message directly to a specified entity from the current entity.
1005    ///
1006    /// # Example
1007    /// ```rust
1008    /// # use vizia_core::prelude::*;
1009    /// # use instant::{Instant, Duration};
1010    /// # let cx = &mut Context::default();
1011    /// # enum AppEvent {Increment}
1012    /// cx.emit_to(Entity::root(), AppEvent::Increment);
1013    /// ```
1014    fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
1015
1016    /// Send a custom event with custom origin and propagation information.
1017    ///
1018    /// # Example
1019    /// ```rust
1020    /// # use vizia_core::prelude::*;
1021    /// # use instant::{Instant, Duration};
1022    /// # let cx = &mut Context::default();
1023    /// # enum AppEvent {Increment}
1024    /// cx.emit_custom(
1025    ///     Event::new(AppEvent::Increment)
1026    ///         .origin(cx.current())
1027    ///         .target(Entity::root())
1028    ///         .propagate(Propagation::Subtree)
1029    /// );
1030    /// ```
1031    fn emit_custom(&mut self, event: Event);
1032
1033    /// Send an event containing the provided message up the tree at a particular time instant.
1034    ///
1035    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1036    ///
1037    /// # Example
1038    /// Emit an event after a delay of 2 seconds:
1039    /// ```rust
1040    /// # use vizia_core::prelude::*;
1041    /// # use instant::{Instant, Duration};
1042    /// # let cx = &mut Context::default();
1043    /// # enum AppEvent {Increment}
1044    /// cx.schedule_emit(AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1045    /// ```
1046    fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1047
1048    /// Send an event containing the provided message directly to a specified view at a particular time instant.
1049    ///
1050    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1051    ///
1052    /// # Example
1053    /// Emit an event to the root view (window) after a delay of 2 seconds:
1054    /// ```rust
1055    /// # use vizia_core::prelude::*;
1056    /// # use instant::{Instant, Duration};
1057    /// # let cx = &mut Context::default();
1058    /// # enum AppEvent {Increment}
1059    /// cx.schedule_emit_to(Entity::root(), AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1060    /// ```
1061    fn schedule_emit_to<M: Any + Send>(
1062        &mut self,
1063        target: Entity,
1064        message: M,
1065        at: Instant,
1066    ) -> TimedEventHandle;
1067
1068    /// Send a custom event with custom origin and propagation information at a particular time instant.
1069    ///
1070    /// Returns a `TimedEventHandle` which can be used to cancel the scheduled event.
1071    ///
1072    /// # Example
1073    /// Emit a custom event after a delay of 2 seconds:
1074    /// ```rust
1075    /// # use vizia_core::prelude::*;
1076    /// # use instant::{Instant, Duration};
1077    /// # let cx = &mut Context::default();
1078    /// # enum AppEvent {Increment}
1079    /// cx.schedule_emit_custom(    
1080    ///     Event::new(AppEvent::Increment)
1081    ///         .target(Entity::root())
1082    ///         .origin(cx.current())
1083    ///         .propagate(Propagation::Subtree),
1084    ///     Instant::now() + Duration::from_secs(2)
1085    /// );
1086    /// ```
1087    fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1088
1089    /// Cancel a scheduled event before it is sent.
1090    ///
1091    /// # Example
1092    /// ```rust
1093    /// # use vizia_core::prelude::*;
1094    /// # use instant::{Instant, Duration};
1095    /// # let cx = &mut Context::default();
1096    /// # enum AppEvent {Increment}
1097    /// let timed_event = cx.schedule_emit_to(Entity::root(), AppEvent::Increment, Instant::now() + Duration::from_secs(2));
1098    /// cx.cancel_scheduled(timed_event);
1099    /// ```
1100    fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1101}
1102
1103impl DataContext for Context {
1104    fn try_data<T: 'static>(&self) -> Option<&T> {
1105        // return data for the static model.
1106        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1107            return Some(t);
1108        }
1109
1110        for entity in self.current.parent_iter(&self.tree) {
1111            // Return any model data.
1112            if let Some(models) = self.models.get(&entity) {
1113                if let Some(model) = models.get(&TypeId::of::<T>()) {
1114                    return model.downcast_ref::<T>();
1115                }
1116            }
1117
1118            // Return any view data.
1119            if let Some(view_handler) = self.views.get(&entity) {
1120                if let Some(data) = view_handler.downcast_ref::<T>() {
1121                    return Some(data);
1122                }
1123            }
1124        }
1125
1126        None
1127    }
1128
1129    fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1130        Some(LocalizationContext::from_context(self))
1131    }
1132}
1133
1134impl DataContext for LocalizationContext<'_> {
1135    fn try_data<T: 'static>(&self) -> Option<&T> {
1136        // return data for the static model.
1137        if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1138            return Some(t);
1139        }
1140
1141        for entity in self.current.parent_iter(self.tree) {
1142            // Return any model data.
1143            if let Some(models) = self.models.get(&entity) {
1144                if let Some(model) = models.get(&TypeId::of::<T>()) {
1145                    return model.downcast_ref::<T>();
1146                }
1147            }
1148
1149            // Return any view data.
1150            if let Some(view_handler) = self.views.get(&entity) {
1151                if let Some(data) = view_handler.downcast_ref::<T>() {
1152                    return Some(data);
1153                }
1154            }
1155        }
1156
1157        None
1158    }
1159}
1160
1161impl EmitContext for Context {
1162    fn emit<M: Any + Send>(&mut self, message: M) {
1163        self.event_queue.push_back(
1164            Event::new(message)
1165                .target(self.current)
1166                .origin(self.current)
1167                .propagate(Propagation::Up),
1168        );
1169    }
1170
1171    fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
1172        self.event_queue.push_back(
1173            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1174        );
1175    }
1176
1177    fn emit_custom(&mut self, event: Event) {
1178        self.event_queue.push_back(event);
1179    }
1180
1181    fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1182        self.schedule_emit_custom(
1183            Event::new(message)
1184                .target(self.current)
1185                .origin(self.current)
1186                .propagate(Propagation::Up),
1187            at,
1188        )
1189    }
1190
1191    fn schedule_emit_to<M: Any + Send>(
1192        &mut self,
1193        target: Entity,
1194        message: M,
1195        at: Instant,
1196    ) -> TimedEventHandle {
1197        self.schedule_emit_custom(
1198            Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1199            at,
1200        )
1201    }
1202
1203    fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1204        let handle = TimedEventHandle(self.next_event_id);
1205        self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1206        self.next_event_id += 1;
1207        handle
1208    }
1209
1210    fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1211        self.event_schedule =
1212            self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1213    }
1214}