use crate::frame::context::{Context, Render, UpdateType};
use crate::frame::App;
use crate::map::Map;
use crate::ui::AppContext;
use crate::window::event::WindowEvent;
use crate::window::{UserEvent, WindowId, WindowType};
use crate::{Device, DeviceInput, Size, WindowAttribute};
use glyphon::{Cache, Resolution, Viewport};
use std::error::Error;
use std::sync::Arc;
pub trait EventLoopHandle {
fn event(&mut self, event: WindowEvent);
}
pub struct LoopWindow {
pub(crate) app_ctx: AppContext,
pub(crate) app: Box<dyn App>,
}
impl LoopWindow {
pub async fn create_window(mut app: Box<dyn App>, wt: Arc<WindowType>, attr: &WindowAttribute) -> LoopWindow {
let device = Self::rebuild_device(&wt, attr.inner_size).await.unwrap();
device.surface.configure(&device.device, &device.surface_config);
let viewport = Viewport::new(&device.device, &device.cache);
let context = Context {
font: attr.font.clone(),
viewport,
window: wt,
render: Render::new(&device),
updates: Map::new(),
user_update: (WindowId(crate::unique_id_u32()), UpdateType::None),
new_window: None,
};
let mut app_ctx = AppContext::new(device, context);
app_ctx.draw(&mut app);
LoopWindow {
app_ctx,
app,
}
}
pub(crate) async fn rebuild_device(window: &Arc<WindowType>, size: Size) -> Result<Device, Box<dyn Error>> {
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await?;
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor::default()).await?;
let cache = Cache::new(&device);
let surface = instance.create_surface(window.clone())?;
let cap = surface.get_capabilities(&adapter);
let surface_config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: cap.formats[0],
view_formats: vec![cap.formats[0].add_srgb_suffix()],
alpha_mode: wgpu::CompositeAlphaMode::Auto,
width: size.width,
height: size.height,
desired_maximum_frame_latency: 2,
present_mode: wgpu::PresentMode::AutoVsync,
};
let w = window.clone();
device.on_uncaptured_error(Box::new(move |err: wgpu::Error| {
w.request_update_event(UserEvent::ReInit);
println!("Error: {:#?}", err);
println!("{}", err.to_string());
}));
Ok(Device {
device,
queue,
cache,
surface,
texture_format: cap.formats[0],
surface_config,
device_input: DeviceInput::new(),
})
}
}
impl EventLoopHandle for LoopWindow {
fn event(&mut self, event: WindowEvent) {
match event {
WindowEvent::None => {}
WindowEvent::KeyPress(key) => self.app_ctx.update(UpdateType::KeyPress(key), &mut self.app),
WindowEvent::KeyRelease(key) => self.app_ctx.update(UpdateType::KeyRelease(key), &mut self.app),
WindowEvent::MouseMove(pos) => {
self.app_ctx.device.device_input.mouse.update(pos);
self.app_ctx.update(UpdateType::MouseMove, &mut self.app);
}
WindowEvent::MouseWheel(y) => {
self.app_ctx.device.device_input.mouse.delta = (0.0, y);
self.app_ctx.update(UpdateType::MouseWheel, &mut self.app);
self.app_ctx.device.device_input.mouse.delta = (0.0, 0.0);
}
WindowEvent::MousePress(pos) => {
self.app_ctx.device.device_input.mouse.lastest = pos;
self.app_ctx.device.device_input.mouse.mouse_press();
self.app_ctx.update(UpdateType::MousePress, &mut self.app);
}
WindowEvent::MouseRelease(pos) => {
self.app_ctx.device.device_input.mouse.lastest = pos;
self.app_ctx.device.device_input.mouse.mouse_release();
self.app_ctx.update(UpdateType::MouseRelease, &mut self.app);
self.app_ctx.device.device_input.mouse.a = 0.0;
}
WindowEvent::Redraw => {
self.app_ctx.context.viewport.update(&self.app_ctx.device.queue, Resolution {
width: self.app_ctx.device.surface_config.width,
height: self.app_ctx.device.surface_config.height,
});
self.app_ctx.redraw(&mut self.app)
}
WindowEvent::ReInit => self.app_ctx.update(UpdateType::ReInit, &mut self.app),
WindowEvent::Resize(size) => {
self.app_ctx.device.surface_config.width = size.width;
self.app_ctx.device.surface_config.height = size.height;
let device = &self.app_ctx.device.device;
let config = &self.app_ctx.device.surface_config;
self.app_ctx.device.surface.configure(device, config);
}
WindowEvent::ReqUpdate => self.app_ctx.update(self.app_ctx.context.user_update.1.clone(), &mut self.app),
WindowEvent::IME(data) => self.app_ctx.update(UpdateType::IME(data), &mut self.app),
WindowEvent::Clipboard(data) => self.app_ctx.update(UpdateType::Clipboard(data), &mut self.app),
WindowEvent::UserUpdate => self.app_ctx.user_update(&mut self.app),
_ => {}
}
}
}