use std::collections::HashMap;
use winit::{application::ApplicationHandler, window::WindowAttributes};
use crate::{
event::WindowEvent,
util::{CVec, from_ptr, into_ptr},
};
#[repr(transparent)]
pub struct EventLoop(pub *mut winit::event_loop::EventLoop);
#[unsafe(no_mangle)]
pub extern "C" fn event_loop_new() -> EventLoop {
let raw = winit::event_loop::EventLoop::builder().build().unwrap();
EventLoop(into_ptr(raw))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn event_loop_drop(event_loop: EventLoop) {
let EventLoop(ptr) = event_loop;
unsafe { from_ptr(ptr) };
}
#[derive(Debug)]
#[repr(transparent)]
pub struct WindowId(usize);
#[derive(Debug)]
struct App {
init: extern "C" fn() -> InitActions,
on_window_event: extern "C" fn(WindowId, WindowEvent) -> EventActions,
windows: HashMap<winit::window::WindowId, Box<dyn winit::window::Window>>,
}
#[derive(Debug)]
#[repr(C)]
pub struct InitActions {
pub fst: InitAction,
pub rest: CVec<InitAction>,
}
#[derive(Debug)]
#[repr(u8)]
pub enum InitAction {
CreateWindow,
}
pub type EventActions = CVec<EventAction>;
#[derive(Debug)]
#[repr(u8)]
pub enum EventAction {
CreateWindow,
CloseWindow(WindowId),
Exit,
}
#[unsafe(no_mangle)]
pub extern "C" fn run_app(
event_loop: EventLoop,
init: extern "C" fn() -> InitActions,
on_window_event: extern "C" fn(WindowId, WindowEvent) -> EventActions,
) {
let EventLoop(ptr) = event_loop;
let event_loop: winit::event_loop::EventLoop = unsafe { from_ptr(ptr) };
let app = App {
init,
on_window_event,
windows: Default::default(),
};
event_loop.run_app(app).expect("TODO");
}
impl ApplicationHandler for App {
fn can_create_surfaces(&mut self, event_loop: &dyn winit::event_loop::ActiveEventLoop) {
let InitActions { fst, rest } = (self.init)();
for action in [fst].into_iter().chain(rest.into_vec().into_iter()) {
match action {
InitAction::CreateWindow => {
let window = event_loop
.create_window(WindowAttributes::default())
.unwrap();
let id = window.id();
self.windows.insert(id, window);
}
}
}
}
fn window_event(
&mut self,
event_loop: &dyn winit::event_loop::ActiveEventLoop,
window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
let window_id = WindowId::from(window_id);
let event = WindowEvent::from(event);
let actions = (self.on_window_event)(window_id, event);
for action in actions.into_vec() {
match action {
EventAction::CreateWindow => {
let window = event_loop
.create_window(WindowAttributes::default())
.unwrap();
let id = window.id();
self.windows.insert(id, window);
}
EventAction::CloseWindow(WindowId(id)) => {
let id = winit::window::WindowId::from_raw(id);
let _window = self.windows.remove(&id);
}
EventAction::Exit => event_loop.exit(),
}
}
}
}
impl From<winit::window::WindowId> for WindowId {
fn from(value: winit::window::WindowId) -> Self {
Self(value.into_raw())
}
}