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