1mod access;
4#[doc(hidden)]
5pub mod backend;
6mod draw;
7mod event;
8mod proxy;
9mod resource;
10
11use log::debug;
12use skia_safe::{
13 FontMgr, svg,
14 textlayout::{FontCollection, TypefaceFontProvider},
15};
16use std::cell::RefCell;
17use std::collections::{BinaryHeap, VecDeque};
18use std::rc::Rc;
19use std::sync::Mutex;
20use std::{
21 any::{Any, TypeId},
22 sync::Arc,
23};
24use vizia_id::IdManager;
25use vizia_window::WindowDescription;
26
27#[cfg(feature = "clipboard")]
28use copypasta::{ClipboardContext, ClipboardProvider, nop_clipboard::NopClipboardContext};
29use hashbrown::{HashMap, HashSet, hash_map::Entry};
30
31pub use access::*;
32pub use draw::*;
33pub use event::*;
34pub use proxy::*;
35pub use resource::*;
36
37use crate::{
38 events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler},
39 model::ModelData,
40};
41
42use crate::{binding::BindingHandler, resource::StoredImage};
43use crate::{cache::CachedData, resource::ImageOrSvg};
44
45use crate::prelude::*;
46use crate::resource::ResourceManager;
47use crate::text::TextContext;
48use vizia_input::{ImeState, MouseState};
49use vizia_storage::{ChildIterator, LayoutTreeIterator};
50
51static DEFAULT_LAYOUT: &str = include_str!("../../resources/themes/default_layout.css");
52static DEFAULT_THEME: &str = include_str!("../../resources/themes/default_theme.css");
53static MARKDOWN: &str = include_str!("../../resources/themes/markdown.css");
54static DEFAULT_TRANSLATION_EN_US: &str =
55 include_str!("../../resources/translations/en-US/core.ftl");
56
57type Views = HashMap<Entity, Box<dyn ViewHandler>>;
58type Models = HashMap<Entity, HashMap<TypeId, Box<dyn ModelData>>>;
59type Bindings = HashMap<Entity, Box<dyn BindingHandler>>;
60
61thread_local! {
62 pub(crate) static SIGNAL_REBUILDS: RefCell<HashSet<Entity>> = RefCell::new(HashSet::new());
65}
66
67#[derive(Default, Clone)]
68pub struct WindowState {
69 pub window_description: WindowDescription,
70 pub scale_factor: f32,
71 pub needs_relayout: bool,
72 pub needs_redraw: bool,
73 pub redraw_list: HashSet<Entity>,
74 pub dirty_rect: Option<BoundingBox>,
75 pub owner: Option<Entity>,
76 pub is_modal: bool,
77 pub should_close: bool,
78 pub content: Option<Arc<dyn Fn(&mut Context)>>,
79}
80
81pub struct Context {
83 pub(crate) entity_manager: IdManager<Entity>,
84 pub(crate) entity_identifiers: HashMap<String, Entity>,
85 pub tree: Tree<Entity>,
86 pub(crate) current: Entity,
87 pub(crate) views: Views,
88 pub(crate) models: Models,
89 pub(crate) bindings: Bindings,
90 pub(crate) event_queue: VecDeque<Event>,
91 pub(crate) event_schedule: BinaryHeap<TimedEvent>,
92 pub(crate) next_event_id: usize,
93 pub(crate) timers: Vec<TimerState>,
94 pub(crate) running_timers: BinaryHeap<TimerState>,
95 pub tree_updates: Vec<Option<accesskit::TreeUpdate>>,
96 pub(crate) listeners:
97 HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
98 pub(crate) global_listeners: Vec<Box<dyn Fn(&mut EventContext, &mut Event)>>,
99 pub(crate) style: Style,
100 pub(crate) cache: CachedData,
101 pub windows: HashMap<Entity, WindowState>,
102
103 pub mouse: MouseState<Entity>,
104 pub(crate) modifiers: Modifiers,
105
106 pub(crate) captured: Entity,
107 pub(crate) triggered: Entity,
108 pub(crate) hovered: Entity,
109 pub(crate) focused: Entity,
110 pub(crate) focus_stack: Vec<Entity>,
111 pub(crate) cursor_icon_locked: bool,
112
113 pub(crate) resource_manager: ResourceManager,
114
115 pub text_context: TextContext,
116
117 pub(crate) event_proxy: Option<Box<dyn EventProxy>>,
118
119 #[cfg(feature = "clipboard")]
120 pub(crate) clipboard: Box<dyn ClipboardProvider>,
121
122 pub(crate) click_time: Instant,
123 pub(crate) clicks: usize,
124 pub(crate) click_pos: (f32, f32),
125 pub(crate) click_button: MouseButton,
126
127 pub ignore_default_theme: bool,
128 built_in_translations_added: bool,
129 pub window_has_focus: bool,
130 pub ime_state: ImeState,
131
132 pub(crate) drop_data: Option<DropData>,
133}
134
135impl Default for Context {
136 fn default() -> Self {
137 Context::new()
138 }
139}
140
141impl Context {
142 pub fn new() -> Self {
144 let mut cache = CachedData::default();
145 cache.add(Entity::root());
146
147 let mut result = Self {
148 entity_manager: IdManager::new(),
149 entity_identifiers: HashMap::new(),
150 tree: Tree::new(),
151 current: Entity::root(),
152 views: HashMap::default(),
153 models: HashMap::default(),
154 bindings: HashMap::default(),
155 style: Style::default(),
156 cache,
157 windows: HashMap::new(),
158 event_queue: VecDeque::new(),
159 event_schedule: BinaryHeap::new(),
160 next_event_id: 0,
161 timers: Vec::new(),
162 running_timers: BinaryHeap::new(),
163 tree_updates: Vec::new(),
164 listeners: HashMap::default(),
165 global_listeners: Vec::new(),
166 mouse: MouseState::default(),
167 modifiers: Modifiers::empty(),
168 captured: Entity::null(),
169 triggered: Entity::null(),
170 hovered: Entity::root(),
171 focused: Entity::root(),
172 focus_stack: Vec::new(),
173 cursor_icon_locked: false,
174 resource_manager: ResourceManager::new(),
175 text_context: {
176 let mut font_collection = FontCollection::new();
177
178 let default_font_manager = FontMgr::default();
179
180 let asset_provider = TypefaceFontProvider::new();
181
182 font_collection.set_default_font_manager(default_font_manager.clone(), None);
183 let asset_font_manager: FontMgr = asset_provider.clone().into();
184 font_collection.set_asset_font_manager(asset_font_manager);
185
186 TextContext {
187 font_collection,
188 default_font_manager,
189 asset_provider,
190 text_bounds: Default::default(),
191 text_paragraphs: Default::default(),
192 }
193 },
194
195 event_proxy: None,
196
197 #[cfg(feature = "clipboard")]
198 clipboard: {
199 if let Ok(context) = ClipboardContext::new() {
200 Box::new(context)
201 } else {
202 Box::new(NopClipboardContext::new().unwrap())
203 }
204 },
205 click_time: Instant::now(),
206 clicks: 0,
207 click_pos: (0.0, 0.0),
208 click_button: MouseButton::Left,
209
210 ignore_default_theme: false,
211 built_in_translations_added: false,
212 window_has_focus: true,
213
214 ime_state: Default::default(),
215
216 drop_data: None,
217 };
218
219 result.tree.set_window(Entity::root(), true);
220
221 result.style.needs_restyle(Entity::root());
222 result.style.needs_relayout();
223 result.style.needs_retransform(Entity::root());
224 result.style.needs_reclip(Entity::root());
225 result.needs_redraw(Entity::root());
226
227 result.style.dpi_factor = 1.0;
229
230 Environment::new(&mut result).build(&mut result);
232
233 result.entity_manager.create();
234
235 result.style.role.insert(Entity::root(), Role::Window);
236
237 result
238 }
239
240 pub fn current(&self) -> Entity {
243 self.current
244 }
245
246 pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
248 let previous = self.current;
249 self.current = current;
250 let ret = f(self);
251 self.current = previous;
252 ret
253 }
254
255 pub fn environment(&self) -> &Environment {
257 self.data::<Environment>()
258 }
259
260 pub fn parent_window(&self) -> Entity {
262 self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
263 }
264
265 pub fn scale_factor(&self) -> f32 {
267 self.style.dpi_factor as f32
268 }
269
270 pub fn needs_redraw(&mut self, entity: Entity) {
272 if self.entity_manager.is_alive(entity) {
273 let window = if self.tree.is_window(entity) {
276 entity
277 } else {
278 self.tree.get_parent_window(entity).unwrap_or(Entity::root())
279 };
280 if let Some(window_state) = self.windows.get_mut(&window) {
281 window_state.redraw_list.insert(entity);
282 }
283 }
284 }
285
286 pub fn needs_restyle(&mut self, entity: Entity) {
288 if entity == Entity::null() || self.style.restyle.contains(&entity) {
289 return;
290 }
291 self.style.restyle.insert(entity);
292 let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
293 LayoutTreeIterator::subtree(&self.tree, parent)
294 } else {
295 LayoutTreeIterator::subtree(&self.tree, entity)
296 };
297
298 for descendant in iter {
299 self.style.restyle.insert(descendant);
300 }
301 }
303
304 pub fn needs_retransform(&mut self, entity: Entity) {
305 self.style.needs_retransform(entity);
306 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
307 for descendant in iter {
308 self.style.needs_retransform(descendant);
309 }
310 }
311
312 pub fn needs_reclip(&mut self, entity: Entity) {
313 self.style.needs_reclip(entity);
314 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
315 for descendant in iter {
316 self.style.needs_reclip(descendant);
317 }
318 }
319
320 pub fn needs_relayout(&mut self) {
322 self.style.needs_relayout();
323 }
324
325 pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
326 if system_flags.contains(SystemFlags::RELAYOUT) {
327 self.needs_relayout();
328 }
329
330 if system_flags.contains(SystemFlags::RESTYLE) {
331 self.needs_restyle(entity);
332 }
333
334 if system_flags.contains(SystemFlags::REDRAW) {
335 self.needs_redraw(entity);
336 }
337
338 if system_flags.contains(SystemFlags::REFLOW) {
339 self.style.needs_text_update(entity);
340 }
341
342 if system_flags.contains(SystemFlags::RETRANSFORM) {
343 self.needs_retransform(entity);
344 }
345
346 if system_flags.contains(SystemFlags::RECLIP) {
347 self.needs_reclip(entity);
348 }
349
350 if system_flags.contains(SystemFlags::REACCESS) {
351 self.style.needs_access_update(entity);
352 }
353 }
354
355 pub(crate) fn set_focus_pseudo_classes(
357 &mut self,
358 focused: Entity,
359 enabled: bool,
360 focus_visible: bool,
361 ) {
362 if enabled {
363 debug!(
364 "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
365 focused,
366 self.tree.get_parent(focused),
367 self.views
368 .get(&focused)
369 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
370 self.cache.get_posx(focused),
371 self.cache.get_posy(focused),
372 self.cache.get_width(focused),
373 self.cache.get_height(focused),
374 );
375 }
376
377 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
378 pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
379 if !enabled || focus_visible {
380 pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
381 self.style.needs_access_update(focused);
382 self.needs_restyle(focused);
383 }
384 }
385
386 let ancestors = focused.parent_iter(&self.tree).collect::<Vec<_>>();
387 for entity in ancestors {
388 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
389 pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
390 }
391 self.needs_restyle(entity);
392 }
393 }
394
395 pub fn focus_with_visibility(&mut self, focus_visible: bool) {
397 let old_focus = self.focused;
398 let new_focus = self.current;
399 self.set_focus_pseudo_classes(old_focus, false, focus_visible);
400 if self.current != self.focused {
401 self.emit_to(old_focus, WindowEvent::FocusOut);
402 self.emit_to(new_focus, WindowEvent::FocusIn);
403 self.focused = self.current;
404 }
405 self.set_focus_pseudo_classes(new_focus, true, focus_visible);
406
407 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
408 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
409
410 self.needs_restyle(self.focused);
411 self.needs_restyle(self.current);
412 self.style.needs_access_update(self.focused);
413 self.style.needs_access_update(self.current);
414 }
415
416 pub fn focus(&mut self) {
418 let focused = self.focused;
419 let old_focus_visible = self
420 .style
421 .pseudo_classes
422 .get_mut(focused)
423 .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
424 .is_some();
425 self.focus_with_visibility(old_focus_visible)
426 }
427
428 pub(crate) fn remove_children(&mut self, entity: Entity) {
430 let child_iter = ChildIterator::new(&self.tree, entity);
431 let children = child_iter.collect::<Vec<_>>();
432 for child in children.into_iter() {
433 self.remove(child);
434 }
435 }
436
437 pub fn remove(&mut self, entity: Entity) {
439 let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
440
441 if !delete_list.is_empty() {
442 self.style.needs_restyle(self.current);
443 self.style.needs_relayout();
444 self.needs_redraw(self.current);
445 }
446
447 for entity in delete_list.iter().rev() {
448 if let Some(mut view) = self.views.remove(entity) {
449 view.event(
450 &mut EventContext::new_with_current(self, *entity),
451 &mut Event::new(WindowEvent::Destroyed).direct(*entity),
452 );
453
454 self.views.insert(*entity, view);
455 }
456
457 if let Some(binding) = self.bindings.remove(entity) {
458 binding.remove(self);
459
460 self.bindings.insert(*entity, binding);
461 }
462
463 for image in self.resource_manager.images.values_mut() {
464 image.observers.remove(entity);
466 }
467
468 if let Some(identifier) = self.style.ids.get(*entity) {
469 self.entity_identifiers.remove(identifier);
470 }
471
472 if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
473 self.focus_stack.remove(index);
474 }
475
476 if self.focused == *entity {
477 if let Some(new_focus) = self.focus_stack.pop() {
478 self.with_current(new_focus, |cx| cx.focus());
479 } else {
480 self.with_current(Entity::root(), |cx| cx.focus());
481 }
482 }
483
484 if self.captured == *entity {
485 self.captured = Entity::null();
486 }
487
488 if let Some(parent) = self.tree.get_layout_parent(*entity) {
489 self.style.needs_access_update(parent);
490 }
491
492 let mut stopped_timers = Vec::new();
493
494 for timer in self.running_timers.iter() {
495 if timer.entity == *entity {
496 stopped_timers.push(timer.id);
497 }
498 }
499
500 for timer in stopped_timers {
501 self.stop_timer(timer);
502 }
503
504 let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
505
506 if !self.tree.is_window(*entity) {
507 if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
508 if let Some(dirty_rect) =
509 &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
510 {
511 *dirty_rect = dirty_rect.union(draw_bounds);
512 } else {
513 self.windows.get_mut(&window_entity).unwrap().dirty_rect =
514 Some(*draw_bounds);
515 }
516 }
517 }
518
519 self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
520
521 if self.windows.contains_key(entity) {
522 self.windows.remove(entity);
523 }
524
525 self.tree.remove(*entity).expect("");
526 self.cache.remove(*entity);
527 self.style.remove(*entity);
528 self.models.remove(entity);
529 self.views.remove(entity);
530 self.text_context.text_bounds.remove(*entity);
531 self.text_context.text_paragraphs.remove(*entity);
532 self.entity_manager.destroy(*entity);
533 }
534 }
535
536 pub fn toggle_class(&mut self, name: &str, applied: impl Res<bool>) {
538 let name = name.to_owned();
539 let entity = self.current();
540 let current = self.current();
541 self.with_current(current, |cx| {
542 applied.set_or_bind(cx, move |cx, applied| {
543 let applied = applied.get_value(cx);
544 if let Some(class_list) = cx.style.classes.get_mut(entity) {
545 if applied {
546 class_list.insert(name.clone());
547 } else {
548 class_list.remove(&name);
549 }
550 }
551
552 cx.needs_restyle(entity);
553 });
554 });
555 }
556
557 pub fn add_listener<F, W>(&mut self, listener: F)
563 where
564 W: View,
565 F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
566 {
567 self.listeners.insert(
568 self.current,
569 Box::new(move |event_handler, context, event| {
570 if let Some(widget) = event_handler.downcast_mut::<W>() {
571 (listener)(widget, context, event);
572 }
573 }),
574 );
575 }
576
577 pub fn add_global_listener<F>(&mut self, listener: F)
583 where
584 F: 'static + Fn(&mut EventContext, &mut Event),
585 {
586 self.global_listeners.push(Box::new(listener));
587 }
588
589 pub fn add_font_mem(&mut self, data: impl AsRef<[u8]>) {
591 self.text_context.asset_provider.register_typeface(
592 self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
593 None,
594 );
595 }
596
597 pub fn focused_element(&self) -> Option<&'static str> {
605 self.views.get(&self.focused).and_then(|view| view.element())
606 }
607
608 pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
609 self.resource_manager.styles.push(Box::new(style));
610
611 EventContext::new(self).reload_styles().expect("Failed to reload styles");
612
613 Ok(())
614 }
615
616 pub fn add_built_in_styles(&mut self) {
618 self.add_built_in_translations();
619
620 let mut user_styles = Vec::new();
621 if self.resource_manager.styles.len() >= 3 {
622 user_styles = self.resource_manager.styles.drain(3..).collect::<Vec<_>>();
623 }
624
625 self.resource_manager.styles.clear();
626
627 self.add_stylesheet(DEFAULT_LAYOUT).unwrap();
628 self.add_stylesheet(MARKDOWN).unwrap();
629
630 if !self.ignore_default_theme {
631 self.add_stylesheet(DEFAULT_THEME).unwrap();
632 let environment = self.data::<Environment>();
633 let theme_mode = environment.effective_theme();
634 let direction = environment.direction.get();
635 self.with_current(Entity::root(), |cx| {
636 let cx = &mut EventContext::new(cx);
637 cx.toggle_class("dark", theme_mode == ThemeMode::DarkMode);
638 cx.toggle_class("rtl", direction == Direction::RightToLeft);
639 })
640 } else {
641 self.add_stylesheet("").unwrap();
643 }
644
645 self.resource_manager.styles.extend(user_styles);
646
647 EventContext::new(self).reload_styles().unwrap();
648 }
649
650 pub fn add_built_in_translations(&mut self) {
652 if self.built_in_translations_added {
653 return;
654 }
655
656 self.add_translation("en-US".parse().unwrap(), DEFAULT_TRANSLATION_EN_US)
657 .expect("Failed to load built-in en-US translation resources");
658 self.built_in_translations_added = true;
659 }
660
661 pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
662 self.style.add_animation(animation)
663 }
664
665 pub fn set_image_loader<F: 'static + Fn(&mut ResourceContext, &str)>(&mut self, loader: F) {
666 self.resource_manager.image_loader = Some(Box::new(loader));
667 }
668
669 pub fn add_translation(
673 &mut self,
674 lang: LanguageIdentifier,
675 ftl: impl ToString,
676 ) -> Result<(), crate::resource::TranslationError> {
677 self.resource_manager.add_translation(lang, ftl.to_string())
678 }
679
680 pub fn add_timer(
711 &mut self,
712 interval: Duration,
713 duration: Option<Duration>,
714 callback: impl Fn(&mut EventContext, TimerAction) + 'static,
715 ) -> Timer {
716 let id = Timer(self.timers.len());
717 self.timers.push(TimerState {
718 entity: Entity::root(),
719 id,
720 time: Instant::now(),
721 interval,
722 duration,
723 start_time: Instant::now(),
724 callback: Rc::new(callback),
725 ticking: false,
726 stopping: false,
727 });
728
729 id
730 }
731
732 pub fn start_timer(&mut self, timer: Timer) {
736 let current = self.current;
737 if !self.timer_is_running(timer) {
738 let timer_state = self.timers[timer.0].clone();
739 self.running_timers.push(timer_state);
741 }
742
743 self.modify_timer(timer, |timer_state| {
744 let now = Instant::now();
745 timer_state.start_time = now;
746 timer_state.time = now;
747 timer_state.entity = current;
748 timer_state.ticking = false;
749 timer_state.stopping = false;
750 });
751 }
752
753 pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
755 while let Some(next_timer_state) = self.running_timers.peek() {
756 if next_timer_state.id == timer {
757 let mut timer_state = self.running_timers.pop().unwrap();
758
759 (timer_function)(&mut timer_state);
760
761 self.running_timers.push(timer_state);
762
763 return;
764 }
765 }
766
767 for pending_timer in self.timers.iter_mut() {
768 if pending_timer.id == timer {
769 (timer_function)(pending_timer);
770 }
771 }
772 }
773
774 pub fn timer_is_running(&mut self, timer: Timer) -> bool {
776 for timer_state in self.running_timers.iter() {
777 if timer_state.id == timer {
778 return true;
779 }
780 }
781
782 false
783 }
784
785 pub fn stop_timer(&mut self, timer: Timer) {
789 let mut running_timers = self.running_timers.clone();
790
791 for timer_state in running_timers.iter() {
792 if timer_state.id == timer {
793 (timer_state.callback)(
794 &mut EventContext::new_with_current(self, timer_state.entity),
795 TimerAction::Stop,
796 );
797 }
798 }
799
800 self.running_timers =
801 running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
802 }
803
804 pub(crate) fn tick_timers(&mut self) {
806 let now = Instant::now();
807 while let Some(next_timer_state) = self.running_timers.peek() {
808 if next_timer_state.time <= now {
809 let mut timer_state = self.running_timers.pop().unwrap();
810
811 if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
812 if !timer_state.ticking {
813 (timer_state.callback)(
814 &mut EventContext::new_with_current(self, timer_state.entity),
815 TimerAction::Start,
816 );
817 timer_state.ticking = true;
818 } else {
819 (timer_state.callback)(
820 &mut EventContext::new_with_current(self, timer_state.entity),
821 TimerAction::Tick(now - timer_state.time),
822 );
823 }
824 timer_state.time = now + timer_state.interval - (now - timer_state.time);
825 self.running_timers.push(timer_state);
826 } else {
827 (timer_state.callback)(
828 &mut EventContext::new_with_current(self, timer_state.entity),
829 TimerAction::Stop,
830 );
831 }
832 } else {
833 break;
834 }
835 }
836 }
837
838 pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
840 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
841 *image_id
842 } else {
843 let id = self.resource_manager.image_id_manager.create();
844 self.resource_manager.image_ids.insert(path.to_owned(), id);
845 id
846 };
847
848 if let Some(image) =
849 skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
850 {
851 match self.resource_manager.images.entry(id) {
852 Entry::Occupied(mut occ) => {
853 occ.get_mut().image = ImageOrSvg::Image(image);
854 occ.get_mut().dirty = true;
855 occ.get_mut().retention_policy = policy;
856 }
857 Entry::Vacant(vac) => {
858 vac.insert(StoredImage {
859 image: ImageOrSvg::Image(image),
860 retention_policy: policy,
861 used: true,
862 dirty: false,
863 observers: HashSet::new(),
864 });
865 }
866 }
867 self.style.needs_relayout();
868 }
869 }
870
871 pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
872 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
873 return *image_id;
874 } else {
875 let id = self.resource_manager.image_id_manager.create();
876 self.resource_manager.image_ids.insert(path.to_owned(), id);
877 id
878 };
879
880 if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
881 {
882 match self.resource_manager.images.entry(id) {
883 Entry::Occupied(mut occ) => {
884 occ.get_mut().image = ImageOrSvg::Svg(svg);
885 occ.get_mut().dirty = true;
886 occ.get_mut().retention_policy = policy;
887 }
888 Entry::Vacant(vac) => {
889 vac.insert(StoredImage {
890 image: ImageOrSvg::Svg(svg),
891 retention_policy: policy,
892 used: true,
893 dirty: false,
894 observers: HashSet::new(),
895 });
896 }
897 }
898 self.style.needs_relayout();
899 }
900
901 id
902 }
903
904 pub fn spawn<F>(&self, target: F)
905 where
906 F: 'static + Send + FnOnce(&mut ContextProxy),
907 {
908 let mut cxp = ContextProxy {
909 current: self.current,
910 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
911 };
912
913 std::thread::spawn(move || target(&mut cxp));
914 }
915
916 pub fn get_proxy(&self) -> ContextProxy {
917 ContextProxy {
918 current: self.current,
919 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
920 }
921 }
922
923 pub(crate) fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
925 self.entity_identifiers.get(identity).cloned()
926 }
927
928 pub fn set_ime_state(&mut self, new_state: ImeState) {
929 self.ime_state = new_state;
930 }
931}
932
933pub(crate) enum InternalEvent {
934 Redraw,
935 LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
936}
937
938pub struct LocalizationContext<'a> {
939 pub(crate) current: Entity,
940 pub(crate) resource_manager: &'a ResourceManager,
941 pub(crate) models: &'a Models,
942 pub(crate) views: &'a Views,
943 pub(crate) tree: &'a Tree<Entity>,
944}
945
946impl<'a> LocalizationContext<'a> {
947 pub(crate) fn from_context(cx: &'a Context) -> Self {
948 Self {
949 current: cx.current,
950 resource_manager: &cx.resource_manager,
951 models: &cx.models,
952 views: &cx.views,
953 tree: &cx.tree,
954 }
955 }
956
957 pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
958 Self {
959 current: cx.current,
960 resource_manager: cx.resource_manager,
961 models: cx.models,
962 views: cx.views,
963 tree: cx.tree,
964 }
965 }
966
967 pub(crate) fn environment(&self) -> &Environment {
968 self.data::<Environment>()
969 }
970}
971
972pub trait DataContext {
976 fn try_data<T: 'static>(&self) -> Option<&T>;
978
979 fn data<T: 'static>(&self) -> &T {
981 self.try_data::<T>().expect("data not found in context")
982 }
983
984 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
986 None
987 }
988}
989
990pub trait EmitContext {
992 fn emit<M: Any + Send>(&mut self, message: M);
1003
1004 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
1015
1016 fn emit_custom(&mut self, event: Event);
1032
1033 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1047
1048 fn schedule_emit_to<M: Any + Send>(
1062 &mut self,
1063 target: Entity,
1064 message: M,
1065 at: Instant,
1066 ) -> TimedEventHandle;
1067
1068 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1088
1089 fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1101}
1102
1103impl DataContext for Context {
1104 fn try_data<T: 'static>(&self) -> Option<&T> {
1105 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1107 return Some(t);
1108 }
1109
1110 for entity in self.current.parent_iter(&self.tree) {
1111 if let Some(models) = self.models.get(&entity) {
1113 if let Some(model) = models.get(&TypeId::of::<T>()) {
1114 return model.downcast_ref::<T>();
1115 }
1116 }
1117
1118 if let Some(view_handler) = self.views.get(&entity) {
1120 if let Some(data) = view_handler.downcast_ref::<T>() {
1121 return Some(data);
1122 }
1123 }
1124 }
1125
1126 None
1127 }
1128
1129 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1130 Some(LocalizationContext::from_context(self))
1131 }
1132}
1133
1134impl DataContext for LocalizationContext<'_> {
1135 fn try_data<T: 'static>(&self) -> Option<&T> {
1136 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1138 return Some(t);
1139 }
1140
1141 for entity in self.current.parent_iter(self.tree) {
1142 if let Some(models) = self.models.get(&entity) {
1144 if let Some(model) = models.get(&TypeId::of::<T>()) {
1145 return model.downcast_ref::<T>();
1146 }
1147 }
1148
1149 if let Some(view_handler) = self.views.get(&entity) {
1151 if let Some(data) = view_handler.downcast_ref::<T>() {
1152 return Some(data);
1153 }
1154 }
1155 }
1156
1157 None
1158 }
1159}
1160
1161impl EmitContext for Context {
1162 fn emit<M: Any + Send>(&mut self, message: M) {
1163 self.event_queue.push_back(
1164 Event::new(message)
1165 .target(self.current)
1166 .origin(self.current)
1167 .propagate(Propagation::Up),
1168 );
1169 }
1170
1171 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
1172 self.event_queue.push_back(
1173 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1174 );
1175 }
1176
1177 fn emit_custom(&mut self, event: Event) {
1178 self.event_queue.push_back(event);
1179 }
1180
1181 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1182 self.schedule_emit_custom(
1183 Event::new(message)
1184 .target(self.current)
1185 .origin(self.current)
1186 .propagate(Propagation::Up),
1187 at,
1188 )
1189 }
1190
1191 fn schedule_emit_to<M: Any + Send>(
1192 &mut self,
1193 target: Entity,
1194 message: M,
1195 at: Instant,
1196 ) -> TimedEventHandle {
1197 self.schedule_emit_custom(
1198 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1199 at,
1200 )
1201 }
1202
1203 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1204 let handle = TimedEventHandle(self.next_event_id);
1205 self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1206 self.next_event_id += 1;
1207 handle
1208 }
1209
1210 fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1211 self.event_schedule =
1212 self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1213 }
1214}