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 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 pub fn current(&self) -> Entity {
246 self.current
247 }
248
249 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 pub fn environment(&self) -> &Environment {
262 self.data::<Environment>().unwrap()
263 }
264
265 pub fn parent_window(&self) -> Entity {
267 self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
268 }
269
270 pub fn scale_factor(&self) -> f32 {
272 self.style.dpi_factor as f32
273 }
274
275 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 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 }
299
300 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 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 }
357 }
358
359 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 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 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 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 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 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 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 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 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.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 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 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 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 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 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 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 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 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 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 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 pub fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
863 self.entity_identifiers.get(identity).cloned()
864 }
865
866 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
936pub trait DataContext {
940 fn data<T: 'static>(&self) -> Option<&T>;
942
943 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
945 None
946 }
947}
948
949pub trait EmitContext {
951 fn emit<M: Any + Send>(&mut self, message: M);
962
963 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
974
975 fn emit_custom(&mut self, event: Event);
991
992 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1006
1007 fn schedule_emit_to<M: Any + Send>(
1021 &mut self,
1022 target: Entity,
1023 message: M,
1024 at: Instant,
1025 ) -> TimedEventHandle;
1026
1027 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1047
1048 fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1060}
1061
1062impl DataContext for Context {
1063 fn data<T: 'static>(&self) -> Option<&T> {
1064 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 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 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 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 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 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}