use std::any::Any;
use std::fmt::Formatter;
use std::sync::Mutex;
use super::InternalEvent;
use crate::prelude::*;
pub struct ContextProxy {
pub current: Entity,
pub event_proxy: Option<Box<dyn EventProxy>>,
}
#[derive(Debug)]
pub enum ProxyEmitError {
Unsupported,
EventLoopClosed,
}
impl std::fmt::Display for ProxyEmitError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProxyEmitError::Unsupported => {
f.write_str("The current runtime does not support proxying events")
}
ProxyEmitError::EventLoopClosed => {
f.write_str("Sending an event to an event loop which has been closed")
}
}
}
}
impl std::error::Error for ProxyEmitError {}
impl ContextProxy {
pub fn emit<M: Any + Send>(&mut self, message: M) -> Result<(), ProxyEmitError> {
if let Some(proxy) = &self.event_proxy {
let event = Event::new(message)
.target(self.current)
.origin(self.current)
.propagate(Propagation::Up);
proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
} else {
Err(ProxyEmitError::Unsupported)
}
}
pub fn emit_to<M: Any + Send>(
&mut self,
target: Entity,
message: M,
) -> Result<(), ProxyEmitError> {
if let Some(proxy) = &self.event_proxy {
let event = Event::new(message)
.target(target)
.origin(self.current)
.propagate(Propagation::Direct);
proxy.send(event).map_err(|_| ProxyEmitError::EventLoopClosed)
} else {
Err(ProxyEmitError::Unsupported)
}
}
pub fn redraw(&mut self) -> Result<(), ProxyEmitError> {
self.emit(InternalEvent::Redraw)
}
pub fn load_image(
&mut self,
path: String,
data: &[u8],
policy: ImageRetentionPolicy,
) -> Result<(), ProxyEmitError> {
if let Some(image) = skia_safe::Image::from_encoded(skia_safe::Data::new_copy(data)) {
self.emit(InternalEvent::LoadImage { path, image: Mutex::new(Some(image)), policy })?
}
Ok(())
}
pub fn spawn<F>(&self, target: F)
where
F: 'static + Send + FnOnce(&mut ContextProxy),
{
let mut cxp = self.clone();
std::thread::spawn(move || target(&mut cxp));
}
}
impl Clone for ContextProxy {
fn clone(&self) -> Self {
Self {
current: self.current,
event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
}
}
}
pub trait EventProxy: Send {
#[allow(clippy::result_unit_err)]
fn send(&self, event: Event) -> Result<(), ()>;
fn make_clone(&self) -> Box<dyn EventProxy>;
}