vizia_core/context/
proxy.rs1use std::any::Any;
2use std::fmt::Formatter;
3use std::sync::Mutex;
4
5use super::InternalEvent;
6
7use crate::events::ProxyEvent;
8use crate::prelude::*;
9
10pub struct ContextProxy {
15 pub current: Entity,
17 pub event_proxy: Option<Box<dyn EventProxy>>,
19}
20
21#[derive(Debug)]
23pub enum ProxyEmitError {
24 Unsupported,
26 EventLoopClosed,
28}
29
30impl std::fmt::Display for ProxyEmitError {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 match self {
33 ProxyEmitError::Unsupported => {
34 f.write_str("The current runtime does not support proxying events")
35 }
36 ProxyEmitError::EventLoopClosed => {
37 f.write_str("Sending an event to an event loop which has been closed")
38 }
39 }
40 }
41}
42
43impl std::error::Error for ProxyEmitError {}
44
45impl ContextProxy {
46 pub fn emit<M: Any + Send>(&mut self, message: M) -> Result<(), ProxyEmitError> {
47 if let Some(proxy) = &self.event_proxy {
48 let event = ProxyEvent::new(message)
49 .target(self.current)
50 .origin(self.current)
51 .propagate(Propagation::Up);
52
53 proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
54 } else {
55 Err(ProxyEmitError::Unsupported)
56 }
57 }
58
59 pub fn emit_to<M: Any + Send>(
60 &mut self,
61 target: Entity,
62 message: M,
63 ) -> Result<(), ProxyEmitError> {
64 if let Some(proxy) = &self.event_proxy {
65 let event = ProxyEvent::new(message)
66 .target(target)
67 .origin(self.current)
68 .propagate(Propagation::Direct);
69
70 proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
71 } else {
72 Err(ProxyEmitError::Unsupported)
73 }
74 }
75
76 pub fn redraw(&mut self) -> Result<(), ProxyEmitError> {
77 self.emit(InternalEvent::Redraw)
78 }
79
80 pub fn load_image_encoded(
81 &mut self,
82 path: String,
83 data: &[u8],
84 policy: ImageRetentionPolicy,
85 ) -> Result<bool, ProxyEmitError> {
86 if let Some(image) = skia_safe::Image::from_encoded(skia_safe::Data::new_copy(data)) {
87 self.emit(InternalEvent::LoadImage { path, image: Mutex::new(Some(image)), policy })?;
88 return Ok(true);
89 }
90
91 Ok(false)
92 }
93
94 pub fn load_svg(
95 &mut self,
96 path: String,
97 data: &[u8],
98 policy: ImageRetentionPolicy,
99 ) -> Result<(), ProxyEmitError> {
100 self.emit(InternalEvent::LoadSvg { path, data: data.to_vec(), policy })
101 }
102
103 pub fn load_font(&mut self, path: String, data: &[u8]) -> Result<(), ProxyEmitError> {
104 self.emit(InternalEvent::LoadFont { path, data: data.to_vec() })
105 }
106
107 pub fn load_translation(
108 &mut self,
109 lang: LanguageIdentifier,
110 path: String,
111 ftl: String,
112 ) -> Result<(), ProxyEmitError> {
113 self.emit(InternalEvent::LoadTranslation { lang, path, ftl })
114 }
115
116 pub fn update_resource_status(
117 &mut self,
118 path: String,
119 status: crate::resource::LoadingStatus,
120 ) -> Result<(), ProxyEmitError> {
121 self.emit(InternalEvent::UpdateResourceStatus { path, status })
122 }
123
124 pub fn spawn<F>(&self, target: F)
125 where
126 F: 'static + Send + FnOnce(&mut ContextProxy),
127 {
128 let mut cxp = self.clone();
129 std::thread::spawn(move || target(&mut cxp));
130 }
131}
132
133impl Clone for ContextProxy {
134 fn clone(&self) -> Self {
135 Self {
136 current: self.current,
137 event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
138 }
139 }
140}
141
142pub trait EventProxy: Send {
143 #[allow(clippy::result_unit_err)]
144 fn send(&self, event: ProxyEvent) -> Result<(), ()>;
145 fn make_clone(&self) -> Box<dyn EventProxy>;
146}