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