1mod 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 pub static MAP_MANAGER: RefCell<IdManager<MapId>> = RefCell::new(IdManager::new());
69 pub static MAPS: RefCell<HashMap<MapId, (Entity, Box<dyn Any>)>> = RefCell::new(HashMap::new());
71 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
89pub 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 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 result.style.dpi_factor = 1.0;
235
236 Environment::new(&mut result).build(&mut result);
238
239 result.entity_manager.create();
240
241 result.style.role.insert(Entity::root(), Role::Window);
242
243 result
244 }
245
246 pub fn current(&self) -> Entity {
249 self.current
250 }
251
252 pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
254 let previous = self.current;
255 self.current = current;
256 CURRENT.with_borrow_mut(|f| *f = current);
257 let ret = f(self);
258 CURRENT.with_borrow_mut(|f| *f = previous);
259 self.current = previous;
260 ret
261 }
262
263 pub fn environment(&self) -> &Environment {
265 self.data::<Environment>().unwrap()
266 }
267
268 pub fn parent_window(&self) -> Entity {
270 self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
271 }
272
273 pub fn scale_factor(&self) -> f32 {
275 self.style.dpi_factor as f32
276 }
277
278 pub fn needs_redraw(&mut self, entity: Entity) {
280 if self.entity_manager.is_alive(entity) {
281 let window = if self.tree.is_window(entity) {
284 entity
285 } else {
286 self.tree.get_parent_window(entity).unwrap_or(Entity::root())
287 };
288 if let Some(window_state) = self.windows.get_mut(&window) {
289 window_state.redraw_list.insert(entity);
290 }
291 }
292 }
293
294 pub fn needs_restyle(&mut self, entity: Entity) {
296 self.style.restyle.insert(entity).unwrap();
297 let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
298 LayoutTreeIterator::subtree(&self.tree, parent)
299 } else {
300 LayoutTreeIterator::subtree(&self.tree, entity)
301 };
302
303 for descendant in iter {
304 self.style.restyle.insert(descendant).unwrap();
305 }
306 }
308
309 pub fn needs_relayout(&mut self) {
311 self.style.needs_relayout();
312 }
313
314 pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
315 if system_flags.contains(SystemFlags::RESTYLE) {
316 self.needs_restyle(entity);
317 }
318
319 if system_flags.contains(SystemFlags::REDRAW) {
320 self.needs_redraw(entity);
321 }
322
323 if system_flags.contains(SystemFlags::REFLOW) {
324 self.style.needs_text_update(entity);
325 }
326 }
327
328 pub(crate) fn set_focus_pseudo_classes(
330 &mut self,
331 focused: Entity,
332 enabled: bool,
333 focus_visible: bool,
334 ) {
335 if enabled {
336 debug!(
337 "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
338 focused,
339 self.tree.get_parent(focused),
340 self.views
341 .get(&focused)
342 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
343 self.cache.get_posx(focused),
344 self.cache.get_posy(focused),
345 self.cache.get_width(focused),
346 self.cache.get_height(focused),
347 );
348 }
349
350 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
351 pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
352 if !enabled || focus_visible {
353 pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
354 self.style.needs_access_update(focused);
355 self.needs_restyle(focused);
356 }
357 }
358
359 for ancestor in focused.parent_iter(&self.tree) {
360 let entity = ancestor;
361 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
362 pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
363 }
364 }
366 }
367
368 pub fn focus_with_visibility(&mut self, focus_visible: bool) {
370 let old_focus = self.focused;
371 let new_focus = self.current;
372 self.set_focus_pseudo_classes(old_focus, false, focus_visible);
373 if self.current != self.focused {
374 self.emit_to(old_focus, WindowEvent::FocusOut);
375 self.emit_to(new_focus, WindowEvent::FocusIn);
376 self.focused = self.current;
377 }
378 self.set_focus_pseudo_classes(new_focus, true, focus_visible);
379
380 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
381 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
382
383 self.needs_restyle(self.focused);
384 self.needs_restyle(self.current);
385 self.style.needs_access_update(self.focused);
386 self.style.needs_access_update(self.current);
387 }
388
389 pub fn focus(&mut self) {
391 let focused = self.focused;
392 let old_focus_visible = self
393 .style
394 .pseudo_classes
395 .get_mut(focused)
396 .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
397 .is_some();
398 self.focus_with_visibility(old_focus_visible)
399 }
400
401 pub(crate) fn remove_children(&mut self, entity: Entity) {
403 let child_iter = ChildIterator::new(&self.tree, entity);
404 let children = child_iter.collect::<Vec<_>>();
405 for child in children.into_iter() {
406 self.remove(child);
407 }
408 }
409
410 pub fn remove(&mut self, entity: Entity) {
412 let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
413
414 if !delete_list.is_empty() {
415 self.style.needs_restyle(self.current);
416 self.style.needs_relayout();
417 self.needs_redraw(self.current);
418 }
419
420 for entity in delete_list.iter().rev() {
421 if let Some(mut view) = self.views.remove(entity) {
422 view.event(
423 &mut EventContext::new_with_current(self, *entity),
424 &mut Event::new(WindowEvent::Destroyed).direct(*entity),
425 );
426
427 self.views.insert(*entity, view);
428 }
429
430 if let Some(binding) = self.bindings.remove(entity) {
431 binding.remove(self);
432
433 self.bindings.insert(*entity, binding);
434 }
435
436 for image in self.resource_manager.images.values_mut() {
437 image.observers.remove(entity);
439 }
440
441 if let Some(identifier) = self.style.ids.get(*entity) {
442 self.entity_identifiers.remove(identifier);
443 }
444
445 if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
446 self.focus_stack.remove(index);
447 }
448
449 if self.focused == *entity {
450 if let Some(new_focus) = self.focus_stack.pop() {
451 self.with_current(new_focus, |cx| cx.focus());
452 } else {
453 self.with_current(Entity::root(), |cx| cx.focus());
454 }
455 }
456
457 if self.captured == *entity {
458 self.captured = Entity::null();
459 }
460
461 MAP_MANAGER.with_borrow_mut(|manager| {
464 MAPS.with_borrow_mut(|maps| {
465 maps.retain(|id, (e, _)| {
466 if e == entity {
467 manager.destroy(*id);
468 false
469 } else {
470 true
471 }
472 });
473 });
474 });
475
476 if let Some(parent) = self.tree.get_layout_parent(*entity) {
477 self.style.needs_access_update(parent);
478 }
479
480 let mut stopped_timers = Vec::new();
481
482 for timer in self.running_timers.iter() {
483 if timer.entity == *entity {
484 stopped_timers.push(timer.id);
485 }
486 }
487
488 for timer in stopped_timers {
489 self.stop_timer(timer);
490 }
491
492 let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
493
494 if !self.tree.is_window(*entity) {
495 if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
496 if let Some(dirty_rect) =
497 &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
498 {
499 *dirty_rect = dirty_rect.union(draw_bounds);
500 } else {
501 self.windows.get_mut(&window_entity).unwrap().dirty_rect =
502 Some(*draw_bounds);
503 }
504 }
505 }
506
507 self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
508
509 if self.windows.contains_key(entity) {
510 self.windows.remove(entity);
511 }
512
513 self.tree.remove(*entity).expect("");
514 self.cache.remove(*entity);
515 self.style.remove(*entity);
516 self.models.remove(entity);
517 self.stores.remove(entity);
518 self.views.remove(entity);
519 self.text_context.text_bounds.remove(*entity);
520 self.text_context.text_paragraphs.remove(*entity);
521 self.entity_manager.destroy(*entity);
522 }
523 }
524
525 pub fn add_listener<F, W>(&mut self, listener: F)
531 where
532 W: View,
533 F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
534 {
535 self.listeners.insert(
536 self.current,
537 Box::new(move |event_handler, context, event| {
538 if let Some(widget) = event_handler.downcast_mut::<W>() {
539 (listener)(widget, context, event);
540 }
541 }),
542 );
543 }
544
545 pub fn add_global_listener<F>(&mut self, listener: F)
551 where
552 F: 'static + Fn(&mut EventContext, &mut Event),
553 {
554 self.global_listeners.push(Box::new(listener));
555 }
556
557 pub fn set_language(&mut self, lang: LanguageIdentifier) {
559 let cx = &mut EventContext::new(self);
560 if let Some(mut models) = cx.models.remove(&Entity::root()) {
561 if let Some(model) = models.get_mut(&TypeId::of::<Environment>()) {
562 model.event(cx, &mut Event::new(EnvironmentEvent::SetLocale(lang)));
563 }
564
565 self.models.insert(Entity::root(), models);
566 }
567 }
568
569 pub fn add_font_mem(&mut self, data: impl AsRef<[u8]>) {
570 self.text_context.asset_provider.register_typeface(
572 self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
573 None,
574 );
575 }
576
577 pub fn set_default_font(&mut self, names: &[&str]) {
579 self.style.default_font = names
580 .iter()
581 .map(|x| FamilyOwned::Named(x.to_string()))
582 .chain(std::iter::once(FamilyOwned::Generic(GenericFontFamily::SansSerif)))
583 .collect();
584 }
585
586 pub(crate) fn add_theme(&mut self, theme: &str) {
588 self.resource_manager.themes.push(theme.to_owned());
589
590 EventContext::new(self).reload_styles().expect("Failed to reload styles");
591 }
592
593 pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
594 self.resource_manager.styles.push(Box::new(style));
595
596 EventContext::new(self).reload_styles().expect("Failed to reload styles");
597
598 Ok(())
599 }
600
601 pub fn remove_user_themes(&mut self) {
603 self.resource_manager.themes.clear();
604
605 self.add_theme(DEFAULT_LAYOUT);
606 self.add_theme(MARKDOWN);
607 if !self.ignore_default_theme {
608 let environment = self.data::<Environment>().expect("Failed to get environment");
609 match environment.theme.get_current_theme() {
610 ThemeMode::LightMode => self.add_theme(LIGHT_THEME),
611 ThemeMode::DarkMode => self.add_theme(DARK_THEME),
612 }
613 }
614 }
615
616 pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
617 self.style.add_animation(animation)
618 }
619
620 pub fn set_image_loader<F: 'static + Fn(&mut ResourceContext, &str)>(&mut self, loader: F) {
621 self.resource_manager.image_loader = Some(Box::new(loader));
622 }
623
624 pub fn add_translation(&mut self, lang: LanguageIdentifier, ftl: impl ToString) {
625 self.resource_manager.add_translation(lang, ftl.to_string());
626 }
627
628 pub fn add_timer(
659 &mut self,
660 interval: Duration,
661 duration: Option<Duration>,
662 callback: impl Fn(&mut EventContext, TimerAction) + 'static,
663 ) -> Timer {
664 let id = Timer(self.timers.len());
665 self.timers.push(TimerState {
666 entity: Entity::root(),
667 id,
668 time: Instant::now(),
669 interval,
670 duration,
671 start_time: Instant::now(),
672 callback: Rc::new(callback),
673 ticking: false,
674 stopping: false,
675 });
676
677 id
678 }
679
680 pub fn start_timer(&mut self, timer: Timer) {
684 let current = self.current;
685 if !self.timer_is_running(timer) {
686 let timer_state = self.timers[timer.0].clone();
687 self.running_timers.push(timer_state);
689 }
690
691 self.modify_timer(timer, |timer_state| {
692 let now = Instant::now();
693 timer_state.start_time = now;
694 timer_state.time = now;
695 timer_state.entity = current;
696 timer_state.ticking = false;
697 timer_state.stopping = false;
698 });
699 }
700
701 pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
703 while let Some(next_timer_state) = self.running_timers.peek() {
704 if next_timer_state.id == timer {
705 let mut timer_state = self.running_timers.pop().unwrap();
706
707 (timer_function)(&mut timer_state);
708
709 self.running_timers.push(timer_state);
710
711 return;
712 }
713 }
714
715 for pending_timer in self.timers.iter_mut() {
716 if pending_timer.id == timer {
717 (timer_function)(pending_timer);
718 }
719 }
720 }
721
722 pub fn timer_is_running(&mut self, timer: Timer) -> bool {
724 for timer_state in self.running_timers.iter() {
725 if timer_state.id == timer {
726 return true;
727 }
728 }
729
730 false
731 }
732
733 pub fn stop_timer(&mut self, timer: Timer) {
737 let mut running_timers = self.running_timers.clone();
738
739 for timer_state in running_timers.iter() {
740 if timer_state.id == timer {
741 (timer_state.callback)(
742 &mut EventContext::new_with_current(self, timer_state.entity),
743 TimerAction::Stop,
744 );
745 }
746 }
747
748 self.running_timers =
749 running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
750 }
751
752 pub(crate) fn tick_timers(&mut self) {
754 let now = Instant::now();
755 while let Some(next_timer_state) = self.running_timers.peek() {
756 if next_timer_state.time <= now {
757 let mut timer_state = self.running_timers.pop().unwrap();
758
759 if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
760 if !timer_state.ticking {
761 (timer_state.callback)(
762 &mut EventContext::new_with_current(self, timer_state.entity),
763 TimerAction::Start,
764 );
765 timer_state.ticking = true;
766 } else {
767 (timer_state.callback)(
768 &mut EventContext::new_with_current(self, timer_state.entity),
769 TimerAction::Tick(now - timer_state.time),
770 );
771 }
772 timer_state.time = now + timer_state.interval - (now - timer_state.time);
773 self.running_timers.push(timer_state);
774 } else {
775 (timer_state.callback)(
776 &mut EventContext::new_with_current(self, timer_state.entity),
777 TimerAction::Stop,
778 );
779 }
780 } else {
781 break;
782 }
783 }
784 }
785
786 pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
787 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
788 *image_id
789 } else {
790 let id = self.resource_manager.image_id_manager.create();
791 self.resource_manager.image_ids.insert(path.to_owned(), id);
792 id
793 };
794
795 if let Some(image) =
796 skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
797 {
798 match self.resource_manager.images.entry(id) {
799 Entry::Occupied(mut occ) => {
800 occ.get_mut().image = ImageOrSvg::Image(image);
801 occ.get_mut().dirty = true;
802 occ.get_mut().retention_policy = policy;
803 }
804 Entry::Vacant(vac) => {
805 vac.insert(StoredImage {
806 image: ImageOrSvg::Image(image),
807 retention_policy: policy,
808 used: true,
809 dirty: false,
810 observers: HashSet::new(),
811 });
812 }
813 }
814 self.style.needs_relayout();
815 }
816 }
817
818 pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
819 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
820 return *image_id;
821 } else {
822 let id = self.resource_manager.image_id_manager.create();
823 self.resource_manager.image_ids.insert(path.to_owned(), id);
824 id
825 };
826
827 if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
828 {
829 match self.resource_manager.images.entry(id) {
830 Entry::Occupied(mut occ) => {
831 occ.get_mut().image = ImageOrSvg::Svg(svg);
832 occ.get_mut().dirty = true;
833 occ.get_mut().retention_policy = policy;
834 }
835 Entry::Vacant(vac) => {
836 vac.insert(StoredImage {
837 image: ImageOrSvg::Svg(svg),
838 retention_policy: policy,
839 used: true,
840 dirty: false,
841 observers: HashSet::new(),
842 });
843 }
844 }
845 self.style.needs_relayout();
846 }
847
848 id
849 }
850
851 pub fn spawn<F>(&self, target: F)
852 where
853 F: 'static + Send + FnOnce(&mut ContextProxy),
854 {
855 let mut cxp = ContextProxy {
856 current: self.current,
857 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
858 };
859
860 std::thread::spawn(move || target(&mut cxp));
861 }
862
863 pub fn get_proxy(&self) -> ContextProxy {
864 ContextProxy {
865 current: self.current,
866 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
867 }
868 }
869
870 pub fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
872 self.entity_identifiers.get(identity).cloned()
873 }
874
875 pub fn toggle_class(&mut self, class_name: &str, applied: bool) {
885 let current = self.current();
886 if let Some(class_list) = self.style.classes.get_mut(current) {
887 if applied {
888 class_list.insert(class_name.to_string());
889 } else {
890 class_list.remove(class_name);
891 }
892 } else if applied {
893 let mut class_list = HashSet::new();
894 class_list.insert(class_name.to_string());
895 self.style.classes.insert(current, class_list);
896 }
897
898 self.style.needs_restyle(self.current);
899 }
900
901 pub fn set_ime_state(&mut self, new_state: ImeState) {
902 self.ime_state = new_state;
903 }
904}
905
906pub(crate) enum InternalEvent {
907 Redraw,
908 LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
909}
910
911pub struct LocalizationContext<'a> {
912 pub(crate) current: Entity,
913 pub(crate) resource_manager: &'a ResourceManager,
914 pub(crate) models: &'a Models,
915 pub(crate) views: &'a Views,
916 pub(crate) tree: &'a Tree<Entity>,
917}
918
919impl<'a> LocalizationContext<'a> {
920 pub(crate) fn from_context(cx: &'a Context) -> Self {
921 Self {
922 current: cx.current,
923 resource_manager: &cx.resource_manager,
924 models: &cx.models,
925 views: &cx.views,
926 tree: &cx.tree,
927 }
928 }
929
930 pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
931 Self {
932 current: cx.current,
933 resource_manager: cx.resource_manager,
934 models: cx.models,
935 views: cx.views,
936 tree: cx.tree,
937 }
938 }
939
940 pub(crate) fn environment(&self) -> &Environment {
941 self.data::<Environment>().unwrap()
942 }
943}
944
945pub trait DataContext {
949 fn data<T: 'static>(&self) -> Option<&T>;
951
952 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
954 None
955 }
956}
957
958pub trait EmitContext {
960 fn emit<M: Any + Send>(&mut self, message: M);
971
972 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
983
984 fn emit_custom(&mut self, event: Event);
1000
1001 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1015
1016 fn schedule_emit_to<M: Any + Send>(
1030 &mut self,
1031 target: Entity,
1032 message: M,
1033 at: Instant,
1034 ) -> TimedEventHandle;
1035
1036 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1056
1057 fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1069}
1070
1071impl DataContext for Context {
1072 fn data<T: 'static>(&self) -> Option<&T> {
1073 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1075 return Some(t);
1076 }
1077
1078 for entity in self.current.parent_iter(&self.tree) {
1079 if let Some(models) = self.models.get(&entity) {
1081 if let Some(model) = models.get(&TypeId::of::<T>()) {
1082 return model.downcast_ref::<T>();
1083 }
1084 }
1085
1086 if let Some(view_handler) = self.views.get(&entity) {
1088 if let Some(data) = view_handler.downcast_ref::<T>() {
1089 return Some(data);
1090 }
1091 }
1092 }
1093
1094 None
1095 }
1096
1097 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1098 Some(LocalizationContext::from_context(self))
1099 }
1100}
1101
1102impl DataContext for LocalizationContext<'_> {
1103 fn data<T: 'static>(&self) -> Option<&T> {
1104 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1106 return Some(t);
1107 }
1108
1109 for entity in self.current.parent_iter(self.tree) {
1110 if let Some(models) = self.models.get(&entity) {
1112 if let Some(model) = models.get(&TypeId::of::<T>()) {
1113 return model.downcast_ref::<T>();
1114 }
1115 }
1116
1117 if let Some(view_handler) = self.views.get(&entity) {
1119 if let Some(data) = view_handler.downcast_ref::<T>() {
1120 return Some(data);
1121 }
1122 }
1123 }
1124
1125 None
1126 }
1127}
1128
1129impl EmitContext for Context {
1130 fn emit<M: Any + Send>(&mut self, message: M) {
1131 self.event_queue.push_back(
1132 Event::new(message)
1133 .target(self.current)
1134 .origin(self.current)
1135 .propagate(Propagation::Up),
1136 );
1137 }
1138
1139 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
1140 self.event_queue.push_back(
1141 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1142 );
1143 }
1144
1145 fn emit_custom(&mut self, event: Event) {
1146 self.event_queue.push_back(event);
1147 }
1148
1149 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1150 self.schedule_emit_custom(
1151 Event::new(message)
1152 .target(self.current)
1153 .origin(self.current)
1154 .propagate(Propagation::Up),
1155 at,
1156 )
1157 }
1158
1159 fn schedule_emit_to<M: Any + Send>(
1160 &mut self,
1161 target: Entity,
1162 message: M,
1163 at: Instant,
1164 ) -> TimedEventHandle {
1165 self.schedule_emit_custom(
1166 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1167 at,
1168 )
1169 }
1170
1171 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1172 let handle = TimedEventHandle(self.next_event_id);
1173 self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1174 self.next_event_id += 1;
1175 handle
1176 }
1177
1178 fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1179 self.event_schedule =
1180 self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1181 }
1182}