use std::collections::HashMap; use std::path::PathBuf; use std::time::Instant; use canary::{PanelId, ScriptAbiImpl, ScriptInstance, WasmtimeRuntime, WasmtimeScript}; use glium::backend::glutin::DisplayCreationError; use glium::{glutin, Surface}; use glutin::event::{Event, WindowEvent}; use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}; use glutin::window::WindowId; use crate::gl::Graphics; use crate::ipc::{IpcMessage, IpcMessageSender}; pub enum WindowMessage { OpenWindow { id: usize, script: PathBuf }, CloseWindow { id: usize }, Quit, } pub type WindowMessageSender = EventLoopProxy; pub struct Window { pub graphics: Graphics, pub script: WasmtimeScript, pub panel: PanelId, pub last_update: Instant, } impl Window { pub fn new( script: WasmtimeScript, panel: PanelId, event_loop: &EventLoopWindowTarget, ) -> Result { let wb = glutin::window::WindowBuilder::new(); let cb = glutin::ContextBuilder::new(); let display = glium::Display::new(wb, cb, &event_loop)?; let graphics = Graphics::new(display); let last_update = Instant::now(); Ok(Self { graphics, script, panel, last_update, }) } pub fn get_id(&self) -> WindowId { self.graphics.display.gl_window().window().id() } pub fn request_redraw(&mut self) { self.graphics.display.gl_window().window().request_redraw(); } pub fn update(&mut self) { let now = Instant::now(); let dt = now.duration_since(self.last_update).as_secs_f32(); self.script.update(self.panel, dt); } pub fn draw(&mut self) { self.script.draw(self.panel, |commands| { self.graphics.draw(commands); }); } } pub struct WindowStore { pub ipc_sender: IpcMessageSender, pub ipc_to_window: HashMap, pub windows: HashMap, pub runtime: WasmtimeRuntime, } impl WindowStore { pub fn new(ipc_sender: IpcMessageSender) -> Self { Self { ipc_sender, ipc_to_window: Default::default(), windows: Default::default(), runtime: WasmtimeRuntime::new().unwrap(), } } pub fn run(mut self, event_loop: EventLoop) -> ! { event_loop.run(move |event, event_loop, control_flow| match event { Event::WindowEvent { window_id, event } => { if let Some(window) = self.windows.get_mut(&window_id) { match event { WindowEvent::Resized(_) => window.request_redraw(), _ => {} } } } Event::RedrawRequested(id) => { if let Some(window) = self.windows.get_mut(&id) { window.draw(); } } Event::MainEventsCleared => { for (_id, window) in self.windows.iter_mut() { window.update(); window.request_redraw(); } } Event::UserEvent(event) => match event { WindowMessage::OpenWindow { id, script } => { println!("Opening window {} with script {:?}", id, script); let abi = Default::default(); let module = std::fs::read(script).unwrap(); let mut script = self.runtime.load_module(abi, &module).unwrap(); let panel = script.bind_panel(vec![]); let window = Window::new(script, panel, &event_loop).unwrap(); let window_id = window.get_id(); self.windows.insert(window_id, window); self.ipc_to_window.insert(id, window_id); } WindowMessage::CloseWindow { id } => { if let Some(window_id) = self.ipc_to_window.remove(&id) { self.windows.remove(&window_id); } } WindowMessage::Quit => *control_flow = ControlFlow::Exit, }, _ => {} }); } }