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 binding::{Store, StoreId},
39 events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler},
40 model::ModelData,
41};
42
43use crate::{
44 binding::{BindingHandler, MapId},
45 resource::StoredImage,
46};
47use crate::{cache::CachedData, resource::ImageOrSvg};
48
49use crate::prelude::*;
50use crate::resource::ResourceManager;
51use crate::text::TextContext;
52use vizia_input::{ImeState, MouseState};
53use vizia_storage::{ChildIterator, LayoutTreeIterator};
54
55static DEFAULT_LAYOUT: &str = include_str!("../../resources/themes/default_layout.css");
56static DARK_THEME: &str = include_str!("../../resources/themes/dark_theme.css");
57static LIGHT_THEME: &str = include_str!("../../resources/themes/light_theme.css");
58static MARKDOWN: &str = include_str!("../../resources/themes/markdown.css");
59
60type Views = HashMap<Entity, Box<dyn ViewHandler>>;
61type Models = HashMap<Entity, HashMap<TypeId, Box<dyn ModelData>>>;
62type Stores = HashMap<Entity, HashMap<StoreId, Box<dyn Store>>>;
63type Bindings = HashMap<Entity, Box<dyn BindingHandler>>;
64
65thread_local! {
66 pub static MAP_MANAGER: RefCell<IdManager<MapId>> = RefCell::new(IdManager::new());
68 pub static MAPS: RefCell<HashMap<MapId, (Entity, Box<dyn Any>)>> = RefCell::new(HashMap::new());
70 pub static CURRENT: RefCell<Entity> = RefCell::new(Entity::root());
72}
73
74#[derive(Default, Clone)]
75pub struct WindowState {
76 pub window_description: WindowDescription,
77 pub scale_factor: f32,
78 pub needs_relayout: bool,
79 pub needs_redraw: bool,
80 pub redraw_list: HashSet<Entity>,
81 pub dirty_rect: Option<BoundingBox>,
82 pub owner: Option<Entity>,
83 pub is_modal: bool,
84 pub should_close: bool,
85 pub content: Option<Arc<dyn Fn(&mut Context)>>,
86}
87
88pub struct Context {
90 pub(crate) entity_manager: IdManager<Entity>,
91 pub(crate) entity_identifiers: HashMap<String, Entity>,
92 pub tree: Tree<Entity>,
93 pub(crate) current: Entity,
94 pub(crate) views: Views,
95 pub(crate) models: Models,
96 pub(crate) stores: Stores,
97 pub(crate) bindings: Bindings,
98 pub(crate) event_queue: VecDeque<Event>,
99 pub(crate) event_schedule: BinaryHeap<TimedEvent>,
100 pub(crate) next_event_id: usize,
101 pub(crate) timers: Vec<TimerState>,
102 pub(crate) running_timers: BinaryHeap<TimerState>,
103 pub tree_updates: Vec<Option<accesskit::TreeUpdate>>,
104 pub(crate) listeners:
105 HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
106 pub(crate) global_listeners: Vec<Box<dyn Fn(&mut EventContext, &mut Event)>>,
107 pub(crate) style: Style,
108 pub(crate) cache: CachedData,
109 pub windows: HashMap<Entity, WindowState>,
110
111 pub mouse: MouseState<Entity>,
112 pub(crate) modifiers: Modifiers,
113
114 pub(crate) captured: Entity,
115 pub(crate) triggered: Entity,
116 pub(crate) hovered: Entity,
117 pub(crate) focused: Entity,
118 pub(crate) focus_stack: Vec<Entity>,
119 pub(crate) cursor_icon_locked: bool,
120
121 pub(crate) resource_manager: ResourceManager,
122
123 pub text_context: TextContext,
124
125 pub(crate) event_proxy: Option<Box<dyn EventProxy>>,
126
127 #[cfg(feature = "clipboard")]
128 pub(crate) clipboard: Box<dyn ClipboardProvider>,
129
130 pub(crate) click_time: Instant,
131 pub(crate) clicks: usize,
132 pub(crate) click_pos: (f32, f32),
133 pub(crate) click_button: MouseButton,
134
135 pub ignore_default_theme: bool,
136 pub window_has_focus: bool,
137 pub ime_state: ImeState,
138
139 pub(crate) drop_data: Option<DropData>,
140}
141
142impl Default for Context {
143 fn default() -> Self {
144 Context::new()
145 }
146}
147
148impl Context {
149 pub fn new() -> Self {
151 let mut cache = CachedData::default();
152 cache.add(Entity::root());
153
154 let mut result = Self {
155 entity_manager: IdManager::new(),
156 entity_identifiers: HashMap::new(),
157 tree: Tree::new(),
158 current: Entity::root(),
159 views: HashMap::default(),
160 models: HashMap::default(),
161 stores: HashMap::default(),
162 bindings: HashMap::default(),
163 style: Style::default(),
164 cache,
165 windows: HashMap::new(),
166 event_queue: VecDeque::new(),
167 event_schedule: BinaryHeap::new(),
168 next_event_id: 0,
169 timers: Vec::new(),
170 running_timers: BinaryHeap::new(),
171 tree_updates: Vec::new(),
172 listeners: HashMap::default(),
173 global_listeners: Vec::new(),
174 mouse: MouseState::default(),
175 modifiers: Modifiers::empty(),
176 captured: Entity::null(),
177 triggered: Entity::null(),
178 hovered: Entity::root(),
179 focused: Entity::root(),
180 focus_stack: Vec::new(),
181 cursor_icon_locked: false,
182 resource_manager: ResourceManager::new(),
183 text_context: {
184 let mut font_collection = FontCollection::new();
185
186 let default_font_manager = FontMgr::default();
187
188 let asset_provider = TypefaceFontProvider::new();
189
190 font_collection.set_default_font_manager(default_font_manager.clone(), None);
191 let asset_font_manager: FontMgr = asset_provider.clone().into();
192 font_collection.set_asset_font_manager(asset_font_manager);
193
194 TextContext {
195 font_collection,
196 default_font_manager,
197 asset_provider,
198 text_bounds: Default::default(),
199 text_paragraphs: Default::default(),
200 }
201 },
202
203 event_proxy: None,
204
205 #[cfg(feature = "clipboard")]
206 clipboard: {
207 if let Ok(context) = ClipboardContext::new() {
208 Box::new(context)
209 } else {
210 Box::new(NopClipboardContext::new().unwrap())
211 }
212 },
213 click_time: Instant::now(),
214 clicks: 0,
215 click_pos: (0.0, 0.0),
216 click_button: MouseButton::Left,
217
218 ignore_default_theme: false,
219 window_has_focus: true,
220
221 ime_state: Default::default(),
222
223 drop_data: None,
224 };
225
226 result.tree.set_window(Entity::root(), true);
227
228 result.style.needs_restyle(Entity::root());
229 result.style.needs_relayout();
230 result.style.needs_retransform(Entity::root());
231 result.style.needs_reclip(Entity::root());
232 result.needs_redraw(Entity::root());
233
234 result.style.dpi_factor = 1.0;
236
237 Environment::new(&mut result).build(&mut result);
239
240 result.entity_manager.create();
241
242 result.style.role.insert(Entity::root(), Role::Window);
243
244 result
245 }
246
247 pub fn current(&self) -> Entity {
250 self.current
251 }
252
253 pub fn with_current<T>(&mut self, current: Entity, f: impl FnOnce(&mut Context) -> T) -> T {
255 let previous = self.current;
256 self.current = current;
257 CURRENT.with_borrow_mut(|f| *f = current);
258 let ret = f(self);
259 CURRENT.with_borrow_mut(|f| *f = previous);
260 self.current = previous;
261 ret
262 }
263
264 pub fn environment(&self) -> &Environment {
266 self.data::<Environment>().unwrap()
267 }
268
269 pub fn parent_window(&self) -> Entity {
271 self.tree.get_parent_window(self.current).unwrap_or(Entity::root())
272 }
273
274 pub fn scale_factor(&self) -> f32 {
276 self.style.dpi_factor as f32
277 }
278
279 pub fn needs_redraw(&mut self, entity: Entity) {
281 if self.entity_manager.is_alive(entity) {
282 let window = if self.tree.is_window(entity) {
285 entity
286 } else {
287 self.tree.get_parent_window(entity).unwrap_or(Entity::root())
288 };
289 if let Some(window_state) = self.windows.get_mut(&window) {
290 window_state.redraw_list.insert(entity);
291 }
292 }
293 }
294
295 pub fn needs_restyle(&mut self, entity: Entity) {
297 if entity == Entity::null() || self.style.restyle.contains(&entity) {
298 return;
299 }
300 self.style.restyle.insert(entity);
301 let iter = if let Some(parent) = self.tree.get_layout_parent(entity) {
302 LayoutTreeIterator::subtree(&self.tree, parent)
303 } else {
304 LayoutTreeIterator::subtree(&self.tree, entity)
305 };
306
307 for descendant in iter {
308 self.style.restyle.insert(descendant);
309 }
310 }
312
313 pub fn needs_retransform(&mut self, entity: Entity) {
314 self.style.needs_retransform(entity);
315 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
316 for descendant in iter {
317 self.style.needs_retransform(descendant);
318 }
319 }
320
321 pub fn needs_reclip(&mut self, entity: Entity) {
322 self.style.needs_reclip(entity);
323 let iter = LayoutTreeIterator::subtree(&self.tree, entity);
324 for descendant in iter {
325 self.style.needs_reclip(descendant);
326 }
327 }
328
329 pub fn needs_relayout(&mut self) {
331 self.style.needs_relayout();
332 }
333
334 pub(crate) fn set_system_flags(&mut self, entity: Entity, system_flags: SystemFlags) {
335 if system_flags.contains(SystemFlags::RESTYLE) {
336 self.needs_restyle(entity);
337 }
338
339 if system_flags.contains(SystemFlags::REDRAW) {
340 self.needs_redraw(entity);
341 }
342
343 if system_flags.contains(SystemFlags::REFLOW) {
344 self.style.needs_text_update(entity);
345 }
346
347 if system_flags.contains(SystemFlags::RETRANSFORM) {
348 self.needs_retransform(entity);
349 }
350
351 if system_flags.contains(SystemFlags::RECLIP) {
352 self.needs_reclip(entity);
353 }
354 }
355
356 pub(crate) fn set_focus_pseudo_classes(
358 &mut self,
359 focused: Entity,
360 enabled: bool,
361 focus_visible: bool,
362 ) {
363 if enabled {
364 debug!(
365 "Focus changed to {:?} parent: {:?}, view: {}, posx: {}, posy: {} width: {} height: {}",
366 focused,
367 self.tree.get_parent(focused),
368 self.views
369 .get(&focused)
370 .map_or("<None>", |view| view.element().unwrap_or("<Unnamed>")),
371 self.cache.get_posx(focused),
372 self.cache.get_posy(focused),
373 self.cache.get_width(focused),
374 self.cache.get_height(focused),
375 );
376 }
377
378 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
379 pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
380 if !enabled || focus_visible {
381 pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
382 self.style.needs_access_update(focused);
383 self.needs_restyle(focused);
384 }
385 }
386
387 for ancestor in focused.parent_iter(&self.tree) {
388 let entity = ancestor;
389 if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
390 pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
391 }
392 }
394 }
395
396 pub fn focus_with_visibility(&mut self, focus_visible: bool) {
398 let old_focus = self.focused;
399 let new_focus = self.current;
400 self.set_focus_pseudo_classes(old_focus, false, focus_visible);
401 if self.current != self.focused {
402 self.emit_to(old_focus, WindowEvent::FocusOut);
403 self.emit_to(new_focus, WindowEvent::FocusIn);
404 self.focused = self.current;
405 }
406 self.set_focus_pseudo_classes(new_focus, true, focus_visible);
407
408 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(old_focus));
409 self.emit_custom(Event::new(WindowEvent::FocusVisibility(focus_visible)).target(new_focus));
410
411 self.needs_restyle(self.focused);
412 self.needs_restyle(self.current);
413 self.style.needs_access_update(self.focused);
414 self.style.needs_access_update(self.current);
415 }
416
417 pub fn focus(&mut self) {
419 let focused = self.focused;
420 let old_focus_visible = self
421 .style
422 .pseudo_classes
423 .get_mut(focused)
424 .filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
425 .is_some();
426 self.focus_with_visibility(old_focus_visible)
427 }
428
429 pub(crate) fn remove_children(&mut self, entity: Entity) {
431 let child_iter = ChildIterator::new(&self.tree, entity);
432 let children = child_iter.collect::<Vec<_>>();
433 for child in children.into_iter() {
434 self.remove(child);
435 }
436 }
437
438 pub fn remove(&mut self, entity: Entity) {
440 let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
441
442 if !delete_list.is_empty() {
443 self.style.needs_restyle(self.current);
444 self.style.needs_relayout();
445 self.needs_redraw(self.current);
446 }
447
448 for entity in delete_list.iter().rev() {
449 if let Some(mut view) = self.views.remove(entity) {
450 view.event(
451 &mut EventContext::new_with_current(self, *entity),
452 &mut Event::new(WindowEvent::Destroyed).direct(*entity),
453 );
454
455 self.views.insert(*entity, view);
456 }
457
458 if let Some(binding) = self.bindings.remove(entity) {
459 binding.remove(self);
460
461 self.bindings.insert(*entity, binding);
462 }
463
464 for image in self.resource_manager.images.values_mut() {
465 image.observers.remove(entity);
467 }
468
469 if let Some(identifier) = self.style.ids.get(*entity) {
470 self.entity_identifiers.remove(identifier);
471 }
472
473 if let Some(index) = self.focus_stack.iter().position(|r| r == entity) {
474 self.focus_stack.remove(index);
475 }
476
477 if self.focused == *entity {
478 if let Some(new_focus) = self.focus_stack.pop() {
479 self.with_current(new_focus, |cx| cx.focus());
480 } else {
481 self.with_current(Entity::root(), |cx| cx.focus());
482 }
483 }
484
485 if self.captured == *entity {
486 self.captured = Entity::null();
487 }
488
489 MAP_MANAGER.with_borrow_mut(|manager| {
492 MAPS.with_borrow_mut(|maps| {
493 maps.retain(|id, (e, _)| {
494 if e == entity {
495 manager.destroy(*id);
496 false
497 } else {
498 true
499 }
500 });
501 });
502 });
503
504 if let Some(parent) = self.tree.get_layout_parent(*entity) {
505 self.style.needs_access_update(parent);
506 }
507
508 let mut stopped_timers = Vec::new();
509
510 for timer in self.running_timers.iter() {
511 if timer.entity == *entity {
512 stopped_timers.push(timer.id);
513 }
514 }
515
516 for timer in stopped_timers {
517 self.stop_timer(timer);
518 }
519
520 let window_entity = self.tree.get_parent_window(*entity).unwrap_or(Entity::root());
521
522 if !self.tree.is_window(*entity) {
523 if let Some(draw_bounds) = self.cache.draw_bounds.get(*entity) {
524 if let Some(dirty_rect) =
525 &mut self.windows.get_mut(&window_entity).unwrap().dirty_rect
526 {
527 *dirty_rect = dirty_rect.union(draw_bounds);
528 } else {
529 self.windows.get_mut(&window_entity).unwrap().dirty_rect =
530 Some(*draw_bounds);
531 }
532 }
533 }
534
535 self.windows.get_mut(&window_entity).unwrap().redraw_list.remove(entity);
536
537 if self.windows.contains_key(entity) {
538 self.windows.remove(entity);
539 }
540
541 self.tree.remove(*entity).expect("");
542 self.cache.remove(*entity);
543 self.style.remove(*entity);
544 self.models.remove(entity);
545 self.stores.remove(entity);
546 self.views.remove(entity);
547 self.text_context.text_bounds.remove(*entity);
548 self.text_context.text_paragraphs.remove(*entity);
549 self.entity_manager.destroy(*entity);
550 }
551 }
552
553 pub fn add_listener<F, W>(&mut self, listener: F)
559 where
560 W: View,
561 F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
562 {
563 self.listeners.insert(
564 self.current,
565 Box::new(move |event_handler, context, event| {
566 if let Some(widget) = event_handler.downcast_mut::<W>() {
567 (listener)(widget, context, event);
568 }
569 }),
570 );
571 }
572
573 pub fn add_global_listener<F>(&mut self, listener: F)
579 where
580 F: 'static + Fn(&mut EventContext, &mut Event),
581 {
582 self.global_listeners.push(Box::new(listener));
583 }
584
585 pub fn set_language(&mut self, lang: LanguageIdentifier) {
587 let cx = &mut EventContext::new(self);
588 if let Some(mut models) = cx.models.remove(&Entity::root()) {
589 if let Some(model) = models.get_mut(&TypeId::of::<Environment>()) {
590 model.event(cx, &mut Event::new(EnvironmentEvent::SetLocale(lang)));
591 }
592
593 self.models.insert(Entity::root(), models);
594 }
595 }
596
597 pub fn add_font_mem(&mut self, data: impl AsRef<[u8]>) {
598 self.text_context.asset_provider.register_typeface(
600 self.text_context.default_font_manager.new_from_data(data.as_ref(), None).unwrap(),
601 None,
602 );
603 }
604
605 pub fn set_default_font(&mut self, names: &[&str]) {
607 self.style.default_font = names
608 .iter()
609 .map(|x| FamilyOwned::Named(x.to_string()))
610 .chain(std::iter::once(FamilyOwned::Generic(GenericFontFamily::SansSerif)))
611 .collect();
612 }
613
614 pub(crate) fn add_theme(&mut self, theme: &str) {
616 self.resource_manager.themes.push(theme.to_owned());
617
618 EventContext::new(self).reload_styles().expect("Failed to reload styles");
619 }
620
621 pub fn add_stylesheet(&mut self, style: impl IntoCssStr) -> Result<(), std::io::Error> {
622 self.resource_manager.styles.push(Box::new(style));
623
624 EventContext::new(self).reload_styles().expect("Failed to reload styles");
625
626 Ok(())
627 }
628
629 pub fn remove_user_themes(&mut self) {
631 self.resource_manager.themes.clear();
632
633 self.add_theme(DEFAULT_LAYOUT);
634 self.add_theme(MARKDOWN);
635 if !self.ignore_default_theme {
636 let environment = self.data::<Environment>().expect("Failed to get environment");
637 match environment.theme.get_current_theme() {
638 ThemeMode::LightMode => self.add_theme(LIGHT_THEME),
639 ThemeMode::DarkMode => self.add_theme(DARK_THEME),
640 }
641 }
642 }
643
644 pub fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
645 self.style.add_animation(animation)
646 }
647
648 pub fn set_image_loader<F: 'static + Fn(&mut ResourceContext, &str)>(&mut self, loader: F) {
649 self.resource_manager.image_loader = Some(Box::new(loader));
650 }
651
652 pub fn add_translation(&mut self, lang: LanguageIdentifier, ftl: impl ToString) {
653 self.resource_manager.add_translation(lang, ftl.to_string());
654 }
655
656 pub fn add_timer(
687 &mut self,
688 interval: Duration,
689 duration: Option<Duration>,
690 callback: impl Fn(&mut EventContext, TimerAction) + 'static,
691 ) -> Timer {
692 let id = Timer(self.timers.len());
693 self.timers.push(TimerState {
694 entity: Entity::root(),
695 id,
696 time: Instant::now(),
697 interval,
698 duration,
699 start_time: Instant::now(),
700 callback: Rc::new(callback),
701 ticking: false,
702 stopping: false,
703 });
704
705 id
706 }
707
708 pub fn start_timer(&mut self, timer: Timer) {
712 let current = self.current;
713 if !self.timer_is_running(timer) {
714 let timer_state = self.timers[timer.0].clone();
715 self.running_timers.push(timer_state);
717 }
718
719 self.modify_timer(timer, |timer_state| {
720 let now = Instant::now();
721 timer_state.start_time = now;
722 timer_state.time = now;
723 timer_state.entity = current;
724 timer_state.ticking = false;
725 timer_state.stopping = false;
726 });
727 }
728
729 pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
731 while let Some(next_timer_state) = self.running_timers.peek() {
732 if next_timer_state.id == timer {
733 let mut timer_state = self.running_timers.pop().unwrap();
734
735 (timer_function)(&mut timer_state);
736
737 self.running_timers.push(timer_state);
738
739 return;
740 }
741 }
742
743 for pending_timer in self.timers.iter_mut() {
744 if pending_timer.id == timer {
745 (timer_function)(pending_timer);
746 }
747 }
748 }
749
750 pub fn timer_is_running(&mut self, timer: Timer) -> bool {
752 for timer_state in self.running_timers.iter() {
753 if timer_state.id == timer {
754 return true;
755 }
756 }
757
758 false
759 }
760
761 pub fn stop_timer(&mut self, timer: Timer) {
765 let mut running_timers = self.running_timers.clone();
766
767 for timer_state in running_timers.iter() {
768 if timer_state.id == timer {
769 (timer_state.callback)(
770 &mut EventContext::new_with_current(self, timer_state.entity),
771 TimerAction::Stop,
772 );
773 }
774 }
775
776 self.running_timers =
777 running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
778 }
779
780 pub(crate) fn tick_timers(&mut self) {
782 let now = Instant::now();
783 while let Some(next_timer_state) = self.running_timers.peek() {
784 if next_timer_state.time <= now {
785 let mut timer_state = self.running_timers.pop().unwrap();
786
787 if timer_state.end_time().unwrap_or_else(|| now + Duration::from_secs(1)) >= now {
788 if !timer_state.ticking {
789 (timer_state.callback)(
790 &mut EventContext::new_with_current(self, timer_state.entity),
791 TimerAction::Start,
792 );
793 timer_state.ticking = true;
794 } else {
795 (timer_state.callback)(
796 &mut EventContext::new_with_current(self, timer_state.entity),
797 TimerAction::Tick(now - timer_state.time),
798 );
799 }
800 timer_state.time = now + timer_state.interval - (now - timer_state.time);
801 self.running_timers.push(timer_state);
802 } else {
803 (timer_state.callback)(
804 &mut EventContext::new_with_current(self, timer_state.entity),
805 TimerAction::Stop,
806 );
807 }
808 } else {
809 break;
810 }
811 }
812 }
813
814 pub fn load_image(&mut self, path: &str, data: &'static [u8], policy: ImageRetentionPolicy) {
815 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
816 *image_id
817 } else {
818 let id = self.resource_manager.image_id_manager.create();
819 self.resource_manager.image_ids.insert(path.to_owned(), id);
820 id
821 };
822
823 if let Some(image) =
824 skia_safe::Image::from_encoded(unsafe { skia_safe::Data::new_bytes(data) })
825 {
826 match self.resource_manager.images.entry(id) {
827 Entry::Occupied(mut occ) => {
828 occ.get_mut().image = ImageOrSvg::Image(image);
829 occ.get_mut().dirty = true;
830 occ.get_mut().retention_policy = policy;
831 }
832 Entry::Vacant(vac) => {
833 vac.insert(StoredImage {
834 image: ImageOrSvg::Image(image),
835 retention_policy: policy,
836 used: true,
837 dirty: false,
838 observers: HashSet::new(),
839 });
840 }
841 }
842 self.style.needs_relayout();
843 }
844 }
845
846 pub fn load_svg(&mut self, path: &str, data: &[u8], policy: ImageRetentionPolicy) -> ImageId {
847 let id = if let Some(image_id) = self.resource_manager.image_ids.get(path) {
848 return *image_id;
849 } else {
850 let id = self.resource_manager.image_id_manager.create();
851 self.resource_manager.image_ids.insert(path.to_owned(), id);
852 id
853 };
854
855 if let Ok(svg) = svg::Dom::from_bytes(data, self.text_context.default_font_manager.clone())
856 {
857 match self.resource_manager.images.entry(id) {
858 Entry::Occupied(mut occ) => {
859 occ.get_mut().image = ImageOrSvg::Svg(svg);
860 occ.get_mut().dirty = true;
861 occ.get_mut().retention_policy = policy;
862 }
863 Entry::Vacant(vac) => {
864 vac.insert(StoredImage {
865 image: ImageOrSvg::Svg(svg),
866 retention_policy: policy,
867 used: true,
868 dirty: false,
869 observers: HashSet::new(),
870 });
871 }
872 }
873 self.style.needs_relayout();
874 }
875
876 id
877 }
878
879 pub fn spawn<F>(&self, target: F)
880 where
881 F: 'static + Send + FnOnce(&mut ContextProxy),
882 {
883 let mut cxp = ContextProxy {
884 current: self.current,
885 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
886 };
887
888 std::thread::spawn(move || target(&mut cxp));
889 }
890
891 pub fn get_proxy(&self) -> ContextProxy {
892 ContextProxy {
893 current: self.current,
894 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
895 }
896 }
897
898 pub fn resolve_entity_identifier(&self, identity: &str) -> Option<Entity> {
900 self.entity_identifiers.get(identity).cloned()
901 }
902
903 pub fn toggle_class(&mut self, class_name: &str, applied: bool) {
913 let current = self.current();
914 if let Some(class_list) = self.style.classes.get_mut(current) {
915 if applied {
916 class_list.insert(class_name.to_string());
917 } else {
918 class_list.remove(class_name);
919 }
920 } else if applied {
921 let mut class_list = HashSet::new();
922 class_list.insert(class_name.to_string());
923 self.style.classes.insert(current, class_list);
924 }
925
926 self.style.needs_restyle(self.current);
927 }
928
929 pub fn set_ime_state(&mut self, new_state: ImeState) {
930 self.ime_state = new_state;
931 }
932}
933
934pub(crate) enum InternalEvent {
935 Redraw,
936 LoadImage { path: String, image: Mutex<Option<skia_safe::Image>>, policy: ImageRetentionPolicy },
937}
938
939pub struct LocalizationContext<'a> {
940 pub(crate) current: Entity,
941 pub(crate) resource_manager: &'a ResourceManager,
942 pub(crate) models: &'a Models,
943 pub(crate) views: &'a Views,
944 pub(crate) tree: &'a Tree<Entity>,
945}
946
947impl<'a> LocalizationContext<'a> {
948 pub(crate) fn from_context(cx: &'a Context) -> Self {
949 Self {
950 current: cx.current,
951 resource_manager: &cx.resource_manager,
952 models: &cx.models,
953 views: &cx.views,
954 tree: &cx.tree,
955 }
956 }
957
958 pub(crate) fn from_event_context(cx: &'a EventContext) -> Self {
959 Self {
960 current: cx.current,
961 resource_manager: cx.resource_manager,
962 models: cx.models,
963 views: cx.views,
964 tree: cx.tree,
965 }
966 }
967
968 pub(crate) fn environment(&self) -> &Environment {
969 self.data::<Environment>().unwrap()
970 }
971}
972
973pub trait DataContext {
977 fn data<T: 'static>(&self) -> Option<&T>;
979
980 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
982 None
983 }
984}
985
986pub trait EmitContext {
988 fn emit<M: Any + Send>(&mut self, message: M);
999
1000 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M);
1011
1012 fn emit_custom(&mut self, event: Event);
1028
1029 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle;
1043
1044 fn schedule_emit_to<M: Any + Send>(
1058 &mut self,
1059 target: Entity,
1060 message: M,
1061 at: Instant,
1062 ) -> TimedEventHandle;
1063
1064 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle;
1084
1085 fn cancel_scheduled(&mut self, handle: TimedEventHandle);
1097}
1098
1099impl DataContext for Context {
1100 fn data<T: 'static>(&self) -> Option<&T> {
1101 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1103 return Some(t);
1104 }
1105
1106 for entity in self.current.parent_iter(&self.tree) {
1107 if let Some(models) = self.models.get(&entity) {
1109 if let Some(model) = models.get(&TypeId::of::<T>()) {
1110 return model.downcast_ref::<T>();
1111 }
1112 }
1113
1114 if let Some(view_handler) = self.views.get(&entity) {
1116 if let Some(data) = view_handler.downcast_ref::<T>() {
1117 return Some(data);
1118 }
1119 }
1120 }
1121
1122 None
1123 }
1124
1125 fn localization_context(&self) -> Option<LocalizationContext<'_>> {
1126 Some(LocalizationContext::from_context(self))
1127 }
1128}
1129
1130impl DataContext for LocalizationContext<'_> {
1131 fn data<T: 'static>(&self) -> Option<&T> {
1132 if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
1134 return Some(t);
1135 }
1136
1137 for entity in self.current.parent_iter(self.tree) {
1138 if let Some(models) = self.models.get(&entity) {
1140 if let Some(model) = models.get(&TypeId::of::<T>()) {
1141 return model.downcast_ref::<T>();
1142 }
1143 }
1144
1145 if let Some(view_handler) = self.views.get(&entity) {
1147 if let Some(data) = view_handler.downcast_ref::<T>() {
1148 return Some(data);
1149 }
1150 }
1151 }
1152
1153 None
1154 }
1155}
1156
1157impl EmitContext for Context {
1158 fn emit<M: Any + Send>(&mut self, message: M) {
1159 self.event_queue.push_back(
1160 Event::new(message)
1161 .target(self.current)
1162 .origin(self.current)
1163 .propagate(Propagation::Up),
1164 );
1165 }
1166
1167 fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
1168 self.event_queue.push_back(
1169 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1170 );
1171 }
1172
1173 fn emit_custom(&mut self, event: Event) {
1174 self.event_queue.push_back(event);
1175 }
1176
1177 fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
1178 self.schedule_emit_custom(
1179 Event::new(message)
1180 .target(self.current)
1181 .origin(self.current)
1182 .propagate(Propagation::Up),
1183 at,
1184 )
1185 }
1186
1187 fn schedule_emit_to<M: Any + Send>(
1188 &mut self,
1189 target: Entity,
1190 message: M,
1191 at: Instant,
1192 ) -> TimedEventHandle {
1193 self.schedule_emit_custom(
1194 Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
1195 at,
1196 )
1197 }
1198
1199 fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
1200 let handle = TimedEventHandle(self.next_event_id);
1201 self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
1202 self.next_event_id += 1;
1203 handle
1204 }
1205
1206 fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
1207 self.event_schedule =
1208 self.event_schedule.drain().filter(|item| item.ident != handle).collect();
1209 }
1210}