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) drag_hovered: Entity,
110 pub(crate) focused: Entity,
111 pub(crate) focus_stack: Vec<Entity>,
112 pub(crate) cursor_icon_locked: bool,
113
114 pub(crate) resource_manager: ResourceManager,
115
116 pub text_context: TextContext,
117
118 pub(crate) event_proxy: Option<Box<dyn EventProxy>>,
119
120 #[cfg(feature = "clipboard")]
121 pub(crate) clipboard: Box<dyn ClipboardProvider>,
122
123 pub(crate) click_time: Instant,
124 pub(crate) clicks: usize,
125 pub(crate) click_pos: (f32, f32),
126 pub(crate) click_button: MouseButton,
127
128 pub ignore_default_theme: bool,
129 built_in_translations_added: bool,
130 pub window_has_focus: bool,
131 pub ime_state: ImeState,
132
133 pub(crate) drop_data: Option<DropData>,
134 pub(crate) active_drag_view: Option<Entity>,
135}
136
137impl Default for Context {
138 fn default() -> Self {
139 Context::new()
140 }
141}
142
143impl Context {
144 pub fn new() -> Self {
146 let mut cache = CachedData::default();
147 cache.add(Entity::root());
148
149 let mut result = Self {
150 entity_manager: IdManager::new(),
151 entity_identifiers: HashMap::new(),
152 tree: Tree::new(),
153 current: Entity::root(),
154 views: HashMap::default(),
155 models: HashMap::default(),
156 bindings: HashMap::default(),
157 style: Style::default(),
158 cache,
159 windows: HashMap::new(),
160 event_queue: VecDeque::new(),
161 event_schedule: BinaryHeap::new(),
162 next_event_id: 0,
163 timers: Vec::new(),
164 running_timers: BinaryHeap::new(),
165 tree_updates: Vec::new(),
166 listeners: HashMap::default(),
167 global_listeners: Vec::new(),
168 mouse: MouseState::default(),
169 modifiers: Modifiers::empty(),
170 captured: Entity::null(),
171 triggered: Entity::null(),
172 hovered: Entity::root(),
173 drag_hovered: Entity::null(),
174 focused: Entity::root(),
175 focus_stack: Vec::new(),
176 cursor_icon_locked: false,
177 resource_manager: ResourceManager::new(),
178 text_context: {
179 let mut font_collection = FontCollection::new();
180
181 let default_font_manager = FontMgr::default();
182
183 let asset_provider = TypefaceFontProvider::new();
184
185 font_collection.set_default_font_manager(default_font_manager.clone(), None);
186 let asset_font_manager: FontMgr = asset_provider.clone().into();
187 font_collection.set_asset_font_manager(asset_font_manager);
188
189 TextContext {
190 font_collection,
191 default_font_manager,
192 asset_provider,
193 text_bounds: Default::default(),
194 text_paragraphs: Default::default(),
195 }
196 },
197
198 event_proxy: None,
199
200 #[cfg(feature = "clipboard")]
201 clipboard: {
202 if let Ok(context) = ClipboardContext::new() {
203 Box::new(context)
204 } else {
205 Box::new(NopClipboardContext::new().unwrap())
206 }
207 },
208 click_time: Instant::now(),
209 clicks: 0,
210 click_pos: (0.0, 0.0),
211 click_button: MouseButton::Left,
212
213 ignore_default_theme: false,
214 built_in_translations_added: false,
215 window_has_focus: true,
216
217 ime_state: Default::default(),
218
219 drop_data: None,
220 active_drag_view: None,
221 };
222
223 result.tree.set_window(Entity::root(), true);
224
225 result.style.needs_restyle(Entity::root());
226 result.style.needs_relayout();
227 result.style.needs_retransform(Entity::root());
228 result.style.needs_reclip(Entity::root());
229 result.needs_redraw(Entity::root());
230
231 result.style.dpi_factor = 1.0;
233
234 Environment::new(&mut result).build(&mut result);
236
237 result.entity_manager.create();
238
239 result.style.role.insert(Entity::root(), Role::Window);
240
241 result
242 }
243
244 pub fn current(&self) -> Entity {
247 self.current
248 }
249
250 pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
252 let previous = self.current;
253 self.current = current;
254 let ret = f(self);
255 self.current = previous;
256 ret
257 }
258
259 pub fn environment(&self) -> &Environment {
261 self.data::<Environment>()
262 }
263
264 pub fn parent_window(&self) -> Entity {
266 self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
267 }
268
269 pub fn scale_factor(&self) -> f32 {
271 self.style.dpi_factor as f32
272 }
273
274 pub fn needs_redraw(&mut self, entity: Entity) {
276 if self.entity_manager.is_alive(entity) {
277 let window = if self.tree.is_window(entity) {
280 entity
281 } else {
282 self.tree.get_parent_window(entity).unwrap_or(Entity::root())
283 };
284 if let Some(window_state) = self.windows.get_mut(&window) {
285 window_state.redraw_list.insert(entity);
286 }
287 }
288 }
289
290 pub fn needs_restyle(&mut self, entity: Entity) {
292 if entity == Entity::null() || self.style.restyle.contains(&entity) {
293 return;
294 }
295 self.style.restyle.insert(entity);
296 let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
297 LayoutTreeIterator::subtree(&self.tree, parent)
298 } else {
299 LayoutTreeIterator::subtree(&self.tree, entity)
300 };
301
302 for descendant in iter {
303 self.style.restyle.insert(descendant);
304 }
305 }
307
308 pub fn needs_retransform(&mut self, entity: Entity) {
309 self.style.needs_retransform(entity);
310 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
311 for descendant in iter {
312 self.style.needs_retransform(descendant);
313 }
314 }
315
316 pub fn needs_reclip(&mut self, entity: Entity) {
317 self.style.needs_reclip(entity);
318 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
319 for descendant in iter {
320 self.style.needs_reclip(descendant);
321 }
322 }
323
324 pub fn needs_relayout(&mut self) {
326 self.style.needs_relayout();
327 }
328
329 pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
330 if system_flags.contains(SystemFlags::RELAYOUT) {
331 self.needs_relayout();
332 }
333
334 if system_flags.contains(SystemFlags::RESTYLE) {
335 self.needs_restyle(entity);
336 }
337
338 if system_flags.contains(SystemFlags::REDRAW) {
339 self.needs_redraw(entity);
340 }
341
342 if system_flags.contains(SystemFlags::REFLOW) {
343 self.style.needs_text_update(entity);
344 }
345
346 if system_flags.contains(SystemFlags::RETRANSFORM) {
347 self.needs_retransform(entity);
348 }
349
350 if system_flags.contains(SystemFlags::RECLIP) {
351 self.needs_reclip(entity);
352 }
353
354 if system_flags.contains(SystemFlags::REACCESS) {
355 self.style.needs_access_update(entity);
356 }
357 }
358
359 pub(crate) fn set_focus_pseudo_classes(
361 &mut self,
362 focused: Entity,
363 enabled: bool,
364 focus_visible: bool,
365 ) {
366 if enabled {
367 debug!(
368 "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
369 focused,
370 self.tree.get_parent(focused),
371 self.views
372 .get(&focused)
373 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
374 self.cache.get_posx(focused),
375 self.cache.get_posy(focused),
376 self.cache.get_width(focused),
377 self.cache.get_height(focused),
378 );
379 }
380
381 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
382 pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
383 if !enabled || focus_visible {
384 pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
385 self.style.needs_access_update(focused);
386 self.needs_restyle(focused);
387 }
388 }
389
390 let ancestors = focused.parent_iter(&self.tree).collect::<Vec<_>>();
391 for entity in ancestors {
392 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
393 pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
394 }
395 self.needs_restyle(entity);
396 }
397 }
398
399 pub fn focus_with_visibility(&mut self, focus_visible: bool) {
401 let old_focus = self.focused;
402 let new_focus = self.current;
403 self.set_focus_pseudo_classes(old_focus, false, focus_visible);
404 if self.current != self.focused {
405 self.emit_to(old_focus, WindowEvent::FocusOut);
406 self.emit_to(new_focus, WindowEvent::FocusIn);
407 self.focused = self.current;
408 }
409 self.set_focus_pseudo_classes(new_focus, true, focus_visible);
410
411 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
412 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
413
414 self.needs_restyle(self.focused);
415 self.needs_restyle(self.current);
416 self.style.needs_access_update(self.focused);
417 self.style.needs_access_update(self.current);
418 }
419
420 pub fn focus(&mut self) {
422 let focused = self.focused;
423 let old_focus_visible = self
424 .style
425 .pseudo_classes
426 .get_mut(focused)
427 .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
428 .is_some();
429 self.focus_with_visibility(old_focus_visible)
430 }
431
432 pub(crate) fn remove_children(&mut self, entity: Entity) {
434 let child_iter = ChildIterator::new(&self.tree, entity);
435 let children = child_iter.collect::<Vec<_>>();
436 for child in children.into_iter() {
437 self.remove(child);
438 }
439 }
440
441 pub fn remove(&mut self, entity: Entity) {
443 let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
444
445 if !delete_list.is_empty() {
446 self.style.needs_restyle(self.current);
447 self.style.needs_relayout();
448 self.needs_redraw(self.current);
449 }
450
451 for entity in delete_list.iter().rev() {
452 if let Some(mut view) = self.views.remove(entity) {
453 view.event(
454 &mut EventContext::new_with_current(self, *entity),
455 &mut Event::new(WindowEvent::Destroyed).direct(*entity),
456 );
457
458 self.views.insert(*entity, view);
459 }
460
461 if let Some(binding) = self.bindings.remove(entity) {
462 binding.remove(self);
463
464 self.bindings.insert(*entity, binding);
465 }
466
467 for image in self.resource_manager.images.values_mut() {
468 image.observers.remove(entity);
470 }
471
472 if let Some(identifier) = self.style.ids.get(*entity) {
473 self.entity_identifiers.remove(identifier);
474 }
475
476 if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
477 self.focus_stack.remove(index);
478 }
479
480 if self.focused == *entity {
481 if let Some(new_focus) = self.focus_stack.pop() {
482 self.with_current(new_focus, |cx| cx.focus());
483 } else {
484 self.with_current(Entity::root(), |cx| cx.focus());
485 }
486 }
487
488 if self.captured == *entity {
489 self.captured = Entity::null();
490 }
491
492 if let Some(parent) = self.tree.get_layout_parent(*entity) {
493 self.style.needs_access_update(parent);
494 }
495
496 let mut stopped_timers = Vec::new();
497
498 for timer in self.running_timers.iter() {
499 if timer.entity == *entity {
500 stopped_timers.push(timer.id);
501 }
502 }
503
504 for timer in stopped_timers {
505 self.stop_timer(timer);
506 }
507
508 let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
509
510 if !self.tree.is_window(*entity) {
511 if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
512 if let Some(dirty_rect) =
513 &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
514 {
515 *dirty_rect = dirty_rect.union(draw_bounds);
516 } else {
517 self.windows.get_mut(&window_entity).unwrap().dirty_rect =
518 Some(*draw_bounds);
519 }
520 }
521 }
522
523 self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
524
525 if self.windows.contains_key(entity) {
526 self.windows.remove(entity);
527 }
528
529 self.tree.remove(*entity).expect("");
530 self.cache.remove(*entity);
531 self.style.remove(*entity);
532 self.models.remove(entity);
533 self.views.remove(entity);
534 self.text_context.text_bounds.remove(*entity);
535 self.text_context.text_paragraphs.remove(*entity);
536 self.entity_manager.destroy(*entity);
537 }
538 }
539
540 pub fn toggle_class(&mut self, name: &str, applied: impl Res<bool>) {
542 let name = name.to_owned();
543 let entity = self.current();
544 let current = self.current();
545 self.with_current(current, |cx| {
546 applied.set_or_bind(cx, move |cx, applied| {
547 let applied = applied.get_value(cx);
548 if let Some(class_list) = cx.style.classes.get_mut(entity) {
549 if applied {
550 class_list.insert(name.clone());
551 } else {
552 class_list.remove(&name);
553 }
554 }
555
556 cx.needs_restyle(entity);
557 });
558 });
559 }
560
561 pub fn add_listener<F, W>(&mut self, listener: F)
567 where
568 W: View,
569 F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
570 {
571 self.listeners.insert(
572 self.current,
573 Box::new(move |event_handler, context, event| {
574 if let Some(widget) = event_handler.downcast_mut::<W>() {
575 (listener)(widget, context, event);
576 }
577 }),
578 );
579 }
580
581 pub fn add_global_listener<F>(&mut self, listener: F)
587 where
588 F: 'static + Fn(&mut EventContext, &mut Event),
589 {
590 self.global_listeners.push(Box::new(listener));
591 }
592
593 pub fn add_font_mem(&mut self, data: impl AsRef<[u8]>) {
595 self.text_context.asset_provider.register_typeface(
596 self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
597 None,
598 );
599 }
600
601 pub fn focused_element(&self) -> Option<&'static str> {
609 self.views.get(&self.focused).and_then(|view| view.element())
610 }
611
612 pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
613 self.resource_manager.styles.push(Box::new(style));
614
615 EventContext::new(self).reload_styles().expect("Failed to reload styles");
616
617 Ok(())
618 }
619
620 pub fn add_built_in_styles(&mut self) {
622 self.add_built_in_translations();
623
624 let mut user_styles = Vec::new();
625 if self.resource_manager.styles.len() >= 3 {
626 user_styles = self.resource_manager.styles.drain(3..).collect::<Vec<_>>();
627 }
628
629 self.resource_manager.styles.clear();
630
631 self.add_stylesheet(DEFAULT_LAYOUT).unwrap();
632 self.add_stylesheet(MARKDOWN).unwrap();
633
634 if !self.ignore_default_theme {
635 self.add_stylesheet(DEFAULT_THEME).unwrap();
636 let environment = self.data::<Environment>();
637 let theme_mode = environment.effective_theme();
638 let direction = environment.direction.get();
639 self.with_current(Entity::root(), |cx| {
640 let cx = &mut EventContext::new(cx);
641 cx.toggle_class("dark", theme_mode == ThemeMode::DarkMode);
642 cx.toggle_class("rtl", direction == Direction::RightToLeft);
643 })
644 } else {
645 self.add_stylesheet("").unwrap();
647 }
648
649 self.resource_manager.styles.extend(user_styles);
650
651 EventContext::new(self).reload_styles().unwrap();
652 }
653
654 pub fn add_built_in_translations(&mut self) {
656 if self.built_in_translations_added {
657 return;
658 }
659
660 self.add_translation("en-US".parse().unwrap(), DEFAULT_TRANSLATION_EN_US)
661 .expect("Failed to load built-in en-US translation resources");
662 self.built_in_translations_added = true;
663 }
664
665 pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
666 self.style.add_animation(animation)
667 }
668
669 pub fn set_image_loader<F: 'static + Fn(&mut ResourceContext, &str)>(&mut self, loader: F) {
670 self.resource_manager.image_loader = Some(Box::new(loader));
671 }
672
673 pub fn add_translation(
677 &mut self,
678 lang: LanguageIdentifier,
679 ftl: impl ToString,
680 ) -> Result<(), crate::resource::TranslationError> {
681 self.resource_manager.add_translation(lang, ftl.to_string())
682 }
683
684 pub fn add_timer(
715 &mut self,
716 interval: Duration,
717 duration: Option<Duration>,
718 callback: impl Fn(&mut EventContext, TimerAction) + 'static,
719 ) -> Timer {
720 let id = Timer(self.timers.len());
721 self.timers.push(TimerState {
722 entity: Entity::root(),
723 id,
724 time: Instant::now(),
725 interval,
726 duration,
727 start_time: Instant::now(),
728 callback: Rc::new(callback),
729 ticking: false,
730 stopping: false,
731 });
732
733 id
734 }
735
736 pub fn start_timer(&mut self, timer: Timer) {
740 let current = self.current;
741 if !self.timer_is_running(timer) {
742 let timer_state = self.timers[timer.0].clone();
743 self.running_timers.push(timer_state);
745 }
746
747 self.modify_timer(timer, |timer_state| {
748 let now = Instant::now();
749 timer_state.start_time = now;
750 timer_state.time = now;
751 timer_state.entity = current;
752 timer_state.ticking = false;
753 timer_state.stopping = false;
754 });
755 }
756
757 pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
759 while let Some(next_timer_state) = self.running_timers.peek() {
760 if next_timer_state.id == timer {
761 let mut timer_state = self.running_timers.pop().unwrap();
762
763 (timer_function)(&mut timer_state);
764
765 self.running_timers.push(timer_state);
766
767 return;
768 }
769 }
770
771 for pending_timer in self.timers.iter_mut() {
772 if pending_timer.id == timer {
773 (timer_function)(pending_timer);
774 }
775 }
776 }
777
778 pub fn timer_is_running(&mut self, timer: Timer) -> bool {
780 for timer_state in self.running_timers.iter() {
781 if timer_state.id == timer {
782 return true;
783 }
784 }
785
786 false
787 }
788
789 pub fn stop_timer(&mut self, timer: Timer) {
793 let mut running_timers = self.running_timers.clone();
794
795 for timer_state in running_timers.iter() {
796 if timer_state.id == timer {
797 (timer_state.callback)(
798 &mut EventContext::new_with_current(self, timer_state.entity),
799 TimerAction::Stop,
800 );
801 }
802 }
803
804 self.running_timers =
805 running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
806 }
807
808 pub(crate) fn tick_timers(&mut self) {
810 let now = Instant::now();
811 while let Some(next_timer_state) = self.running_timers.peek() {
812 if next_timer_state.time <= now {
813 let mut timer_state = self.running_timers.pop().unwrap();
814
815 if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
816 if !timer_state.ticking {
817 (timer_state.callback)(
818 &mut EventContext::new_with_current(self, timer_state.entity),
819 TimerAction::Start,
820 );
821 timer_state.ticking = true;
822 } else {
823 (timer_state.callback)(
824 &mut EventContext::new_with_current(self, timer_state.entity),
825 TimerAction::Tick(now - timer_state.time),
826 );
827 }
828 timer_state.time = now + timer_state.interval - (now - timer_state.time);
829 self.running_timers.push(timer_state);
830 } else {
831 (timer_state.callback)(
832 &mut EventContext::new_with_current(self, timer_state.entity),
833 TimerAction::Stop,
834 );
835 }
836 } else {
837 break;
838 }
839 }
840 }
841
842 pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
844 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
845 *image_id
846 } else {
847 let id = self.resource_manager.image_id_manager.create();
848 self.resource_manager.image_ids.insert(path.to_owned(), id);
849 id
850 };
851
852 if let Some(image) =
853 skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
854 {
855 match self.resource_manager.images.entry(id) {
856 Entry::Occupied(mut occ) => {
857 occ.get_mut().image = ImageOrSvg::Image(image);
858 occ.get_mut().dirty = true;
859 occ.get_mut().retention_policy = policy;
860 }
861 Entry::Vacant(vac) => {
862 vac.insert(StoredImage {
863 image: ImageOrSvg::Image(image),
864 retention_policy: policy,
865 used: true,
866 dirty: false,
867 observers: HashSet::new(),
868 });
869 }
870 }
871 self.style.needs_relayout();
872 }
873 }
874
875 pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
876 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
877 return *image_id;
878 } else {
879 let id = self.resource_manager.image_id_manager.create();
880 self.resource_manager.image_ids.insert(path.to_owned(), id);
881 id
882 };
883
884 if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
885 {
886 match self.resource_manager.images.entry(id) {
887 Entry::Occupied(mut occ) => {
888 occ.get_mut().image = ImageOrSvg::Svg(svg);
889 occ.get_mut().dirty = true;
890 occ.get_mut().retention_policy = policy;
891 }
892 Entry::Vacant(vac) => {
893 vac.insert(StoredImage {
894 image: ImageOrSvg::Svg(svg),
895 retention_policy: policy,
896 used: true,
897 dirty: false,
898 observers: HashSet::new(),
899 });
900 }
901 }
902 self.style.needs_relayout();
903 }
904
905 id
906 }
907
908 pub fn spawn<F>(&self, target: F)
909 where
910 F: 'static + Send + FnOnce(&mut ContextProxy),
911 {
912 let mut cxp = ContextProxy {
913 current: self.current,
914 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
915 };
916
917 std::thread::spawn(move || target(&mut cxp));
918 }
919
920 pub fn get_proxy(&self) -> ContextProxy {
921 ContextProxy {
922 current: self.current,
923 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
924 }
925 }
926
927 pub(crate) fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
929 self.entity_identifiers.get(identity).cloned()
930 }
931
932 pub fn set_ime_state(&mut self, new_state: ImeState) {
933 self.ime_state = new_state;
934 }
935}
936
937pub(crate) enum InternalEvent {
938 Redraw,
939 LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
940}
941
942pub struct LocalizationContext<'a> {
943 pub(crate) current: Entity,
944 pub(crate) resource_manager: &'a ResourceManager,
945 pub(crate) models: &'a Models,
946 pub(crate) views: &'a Views,
947 pub(crate) tree: &'a Tree<Entity>,
948}
949
950impl<'a> LocalizationContext<'a> {
951 pub(crate) fn from_context(cx: &'a Context) -> Self {
952 Self {
953 current: cx.current,
954 resource_manager: &cx.resource_manager,
955 models: &cx.models,
956 views: &cx.views,
957 tree: &cx.tree,
958 }
959 }
960
961 pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
962 Self {
963 current: cx.current,
964 resource_manager: cx.resource_manager,
965 models: cx.models,
966 views: cx.views,
967 tree: cx.tree,
968 }
969 }
970
971 pub(crate) fn environment(&self) -> &Environment {
972 self.data::<Environment>()
973 }
974}
975
976pub trait DataContext {
980 fn try_data<T: 'static>(&self) -> Option<&T>;
982
983 fn data<T: 'static>(&self) -> &T {
985 self.try_data::<T>().expect("data not found in context")
986 }
987
988 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
990 None
991 }
992}
993
994pub trait EmitContext {
996 fn emit<M: Any + Send>(&mut self, message: M);
1007
1008 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
1019
1020 fn emit_custom(&mut self, event: Event);
1036
1037 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1051
1052 fn schedule_emit_to<M: Any + Send>(
1066 &mut self,
1067 target: Entity,
1068 message: M,
1069 at: Instant,
1070 ) -> TimedEventHandle;
1071
1072 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1092
1093 fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1105}
1106
1107impl DataContext for Context {
1108 fn try_data<T: 'static>(&self) -> Option<&T> {
1109 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1111 return Some(t);
1112 }
1113
1114 for entity in self.current.parent_iter(&self.tree) {
1115 if let Some(models) = self.models.get(&entity) {
1117 if let Some(model) = models.get(&TypeId::of::<T>()) {
1118 return model.downcast_ref::<T>();
1119 }
1120 }
1121
1122 if let Some(view_handler) = self.views.get(&entity) {
1124 if let Some(data) = view_handler.downcast_ref::<T>() {
1125 return Some(data);
1126 }
1127 }
1128 }
1129
1130 None
1131 }
1132
1133 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1134 Some(LocalizationContext::from_context(self))
1135 }
1136}
1137
1138impl DataContext for LocalizationContext<'_> {
1139 fn try_data<T: 'static>(&self) -> Option<&T> {
1140 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1142 return Some(t);
1143 }
1144
1145 for entity in self.current.parent_iter(self.tree) {
1146 if let Some(models) = self.models.get(&entity) {
1148 if let Some(model) = models.get(&TypeId::of::<T>()) {
1149 return model.downcast_ref::<T>();
1150 }
1151 }
1152
1153 if let Some(view_handler) = self.views.get(&entity) {
1155 if let Some(data) = view_handler.downcast_ref::<T>() {
1156 return Some(data);
1157 }
1158 }
1159 }
1160
1161 None
1162 }
1163}
1164
1165impl EmitContext for Context {
1166 fn emit<M: Any + Send>(&mut self, message: M) {
1167 self.event_queue.push_back(
1168 Event::new(message)
1169 .target(self.current)
1170 .origin(self.current)
1171 .propagate(Propagation::Up),
1172 );
1173 }
1174
1175 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
1176 self.event_queue.push_back(
1177 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1178 );
1179 }
1180
1181 fn emit_custom(&mut self, event: Event) {
1182 self.event_queue.push_back(event);
1183 }
1184
1185 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1186 self.schedule_emit_custom(
1187 Event::new(message)
1188 .target(self.current)
1189 .origin(self.current)
1190 .propagate(Propagation::Up),
1191 at,
1192 )
1193 }
1194
1195 fn schedule_emit_to<M: Any + Send>(
1196 &mut self,
1197 target: Entity,
1198 message: M,
1199 at: Instant,
1200 ) -> TimedEventHandle {
1201 self.schedule_emit_custom(
1202 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1203 at,
1204 )
1205 }
1206
1207 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1208 let handle = TimedEventHandle(self.next_event_id);
1209 self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1210 self.next_event_id += 1;
1211 handle
1212 }
1213
1214 fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1215 self.event_schedule =
1216 self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1217 }
1218}