137 lines
4.3 KiB
Rust
Executable file
137 lines
4.3 KiB
Rust
Executable file
/*
|
|
* Copyright (C) 2022 Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
|
*
|
|
* 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<WindowId, Window>,
|
|
events: HashMap<ApplicationEvent, Vec<Box<dyn FnMut(&mut Context)>>>,
|
|
ctx: Rc<RefCell<Context>>,
|
|
}
|
|
|
|
impl Application {
|
|
pub fn new() -> Self {
|
|
Default::default()
|
|
}
|
|
|
|
pub fn apply_plugin<P>(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<const N: usize>(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())),
|
|
}
|
|
}
|
|
}
|