/* * Copyright (C) 2022 Umut İnan Erdoğan * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; use winit::event::{Event, WindowEvent as WinitWindowEvent}; use winit::event_loop::EventLoop; use winit::window::WindowId; use crate::context::Context; use crate::event::{ application::Event as ApplicationEvent, window::Event as WindowEvent, }; use crate::plugin::Plugin; use crate::window::{Window, WindowBuilder}; macro_rules! emit_app_event { ($app:expr, $event:expr) => { if let Some(handlers) = $app.events.get_mut(&$event) { handlers.iter_mut().for_each(|handler| handler(&mut $app.ctx.borrow_mut())); } }; } pub struct Application { winit_event_loop: EventLoop<()>, windows: HashMap, events: HashMap>>, ctx: Rc>, } impl Application { pub fn new() -> Self { Default::default() } pub fn apply_plugin

(self, plugin: P) -> Self where P: Plugin { plugin.apply(self) } pub fn add_window(mut self, builder: WindowBuilder) -> Self { let window = builder .build(self.ctx.clone(), &self.winit_event_loop) .unwrap(); self.windows.insert(window.id(), window); self } pub fn add_windows(mut self, builders: [WindowBuilder; N] ) -> Self { self.windows.extend(builders.map(|builder| { let window = builder .build(self.ctx.clone(), &self.winit_event_loop) .unwrap(); (window.id(), window) })); self } pub fn on_event(mut self, event: ApplicationEvent, handler: fn(&mut Context), ) -> Self { if let Some(handlers) = self.events.get_mut(&event) { handlers.push(Box::new(handler)); } else { self.events.insert(event, vec![Box::new(handler)]); } self } /// This method enters the event loop. You probably don't want to call this /// directly, the `launch` macro will call this in the generated main /// function. pub fn launch(mut self, rt: tokio::runtime::Runtime) { self.ctx.borrow_mut().set_rt(rt); self.winit_event_loop.run(move |event, target, control_flow| { *control_flow = self.ctx.borrow().control_flow(); while let Some(builder) = self.ctx.borrow_mut().pop_window_builder() { let window = builder.build(self.ctx.clone(), target).unwrap(); self.windows.insert(window.id(), window); } match event { Event::WindowEvent { window_id, event: WinitWindowEvent::CloseRequested, } => { self.windows.get_mut(&window_id).unwrap() .emit_event(WindowEvent::Closed); self.windows.remove(&window_id); if self.windows.is_empty() { emit_app_event!(self, ApplicationEvent::AllWindowsClosed); } } Event::WindowEvent { window_id, event: WinitWindowEvent::Resized(size) } => self.windows.get_mut(&window_id).unwrap().resized(size), Event::MainEventsCleared => { // determine if state changed and request redraw if needed // rinse and repeat for every window } Event::RedrawRequested(window_id) => self.windows.get_mut(&window_id).unwrap().render(), _ => () } }) } } impl Default for Application { fn default() -> Self { Self { winit_event_loop: EventLoop::new(), windows: Default::default(), events: Default::default(), ctx: Rc::new(RefCell::new(Context::new())), } } }