deft 0.15.0

Cross platform ui framework
use crate::app::{AppEvent, AppEventPayload};
use crate::base::{ResultWaiter, UnsafeFnMut, UnsafeFnOnce};
use std::cell::{Cell, RefCell};
use std::ptr::null_mut;
use std::sync::{Arc, Mutex};
use winit::event_loop::{ActiveEventLoop, EventLoopClosed, EventLoopProxy};

thread_local! {
    pub static ACTIVE_EVENT_LOOP: Cell<*const ActiveEventLoop> = Cell::new(null_mut());
    pub static STATIC_EVENT_LOOP_PROXY: RefCell<Option<AppEventProxy>> = RefCell::new(None);
}

#[derive(Clone)]
pub struct AppEventProxy {
    proxy: EventLoopProxy<AppEventPayload>,
}

impl AppEventProxy {
    pub fn new(proxy: EventLoopProxy<AppEventPayload>) -> AppEventProxy {
        Self { proxy }
    }

    pub fn send_event(
        &self,
        event: AppEvent,
    ) -> Result<ResultWaiter<()>, EventLoopClosed<AppEventPayload>> {
        let result_waiter = ResultWaiter::new();
        self.proxy.send_event(AppEventPayload {
            event,
            result_waiter: result_waiter.clone(),
        })?;
        Ok(result_waiter)
    }
}

pub struct EventLoopCallback {
    event_loop_proxy: AppEventProxy,
    callback: Option<UnsafeFnOnce>,
}

impl EventLoopCallback {
    pub fn call(mut self) {
        let callback = self.callback.take().unwrap();
        self.event_loop_proxy
            .send_event(AppEvent::Callback(Box::new(|| {
                callback.call();
            })))
            .unwrap();
    }
}

pub struct EventLoopFnMutCallback<P> {
    event_loop_proxy: AppEventProxy,
    callback: Arc<Mutex<UnsafeFnMut<P>>>,
}

impl<P> Clone for EventLoopFnMutCallback<P> {
    fn clone(&self) -> Self {
        Self {
            event_loop_proxy: self.event_loop_proxy.clone(),
            callback: self.callback.clone(),
        }
    }
}

impl<P: Send + Sync + 'static> EventLoopFnMutCallback<P> {
    pub fn call(&mut self, param: P) {
        let cb = self.callback.clone();
        let _ = self
            .event_loop_proxy
            .send_event(AppEvent::Callback(Box::new(move || {
                let mut cb = cb.lock().unwrap();
                (cb.callback)(param);
            })));
    }
}

pub fn create_event_loop_callback<F: FnOnce() + 'static>(callback: F) -> EventLoopCallback {
    let callback = unsafe { UnsafeFnOnce::new(callback) };
    let event_loop_proxy = create_event_loop_proxy();
    EventLoopCallback {
        event_loop_proxy,
        callback: Some(callback),
    }
}

pub fn create_event_loop_fn_mut<P: Send + Sync, F: FnMut(P) + 'static>(
    callback: F,
) -> EventLoopFnMutCallback<P> {
    let fn_mut = UnsafeFnMut {
        callback: Box::new(callback),
    };
    let event_loop_proxy = create_event_loop_proxy();
    EventLoopFnMutCallback {
        event_loop_proxy,
        callback: Arc::new(Mutex::new(fn_mut)),
    }
}

pub fn run_event_loop_task<F: FnOnce()>(event_loop: &ActiveEventLoop, callback: F) {
    ACTIVE_EVENT_LOOP.set(event_loop as *const ActiveEventLoop);
    callback();
    ACTIVE_EVENT_LOOP.set(null_mut());
}

pub fn run_with_event_loop<R, F: FnOnce(&ActiveEventLoop) -> R>(callback: F) -> R {
    let el = ACTIVE_EVENT_LOOP.get();
    unsafe {
        if el == null_mut() {
            panic!("ActiveEventLoop not found");
        }
        callback(&*el)
    }
}

pub fn init_event_loop_proxy(elp: AppEventProxy) {
    STATIC_EVENT_LOOP_PROXY.with_borrow_mut(move |m| {
        m.replace(elp);
    })
}

pub fn create_event_loop_proxy() -> AppEventProxy {
    STATIC_EVENT_LOOP_PROXY.with_borrow(|p| {
        p.as_ref()
            .expect("Failed to create event loop proxy")
            .clone()
    })
}