use crate::*; use std::collections::HashMap; use std::time::Duration; use winit::{event::*, event_loop::{EventLoop, ControlFlow}, window::WindowId}; pub struct WindowManager { event_loop: EventLoop<()>, windows: HashMap, min_frame_duration: Duration, } impl WindowManager { pub fn new() -> Self { Self { event_loop: EventLoop::new(), windows: HashMap::new(), min_frame_duration: Duration::ZERO, } } pub fn with_frame_limit(mut self, limit: u64) -> Self { self.min_frame_duration = match limit { 0 => Duration::ZERO, _ => Duration::from_nanos(1_000_000_000 / limit), }; return self; } /// Add a window to the window manager before the event loop begins. pub fn add_window(&mut self, controller: Box) { let window = Window::new(&self.event_loop, controller); self.windows.insert(window.id(), window); } /// Start the event loop, passing program control to the window manager. pub fn run(mut self) -> ! { self.event_loop.run(move |event, _window_target, control_flow| { match event { // Called when the event loop is first initialized. Event::NewEvents(StartCause::Init) => (), Event::NewEvents(..) => { control_flow.set_wait_timeout(self.min_frame_duration); } // Called when an application suspends on a mobile platform. Event::Suspended => (), // Called when an application resumes, or after initialization on non-mobile platforms. Event::Resumed => (), Event::WindowEvent { window_id, event } => { if let Some(window) = self.windows.get_mut(&window_id) { use WindowEvent::*; match event { Resized(dim) => window.resize_buffer_and_surface(Dimensions::new(dim.width, dim.height)), Moved(position) => window.controller.on_move(Point::new(position.x, position.y)), Focused(is_focused) => window.controller.on_focus_change(is_focused), CursorEntered { .. } => window.controller.on_cursor_enter(), CursorLeft { .. } => window.controller.on_cursor_exit(), CursorMoved { position: p, .. } => { window.move_cursor(Point::new(p.x as i32, p.y as i32)) } MouseWheel {delta, ..} => match delta { MouseScrollDelta::LineDelta(x, y) => { let (x, y) = (x as f64, y as f64); if x != 0.0 {window.controller.on_line_scroll_horizontal(x)} if y != 0.0 {window.controller.on_line_scroll_vertical(y)} } MouseScrollDelta::PixelDelta(point) => { let (x, y) = (point.x, point.y); if x != 0.0 {window.controller.on_pixel_scroll_horizontal(x)} if y != 0.0 {window.controller.on_pixel_scroll_vertical(y)} } } MouseInput { state, button, .. } => match button { MouseButton::Left => window.controller.on_left_mouse_button(state.into()), MouseButton::Middle => window.controller.on_middle_mouse_button(state.into()), MouseButton::Right => window.controller.on_right_mouse_button(state.into()), MouseButton::Other(_) => (), } KeyboardInput { input, .. } => if let Ok(input) = input.try_into() { window.controller.on_keyboard_input(input)}, ModifiersChanged(state) => window.controller.on_keyboard_modifier_change(state), ReceivedCharacter(character) => window.controller.on_character_input(character), HoveredFile(path) => window.controller.on_file_hover(&path), HoveredFileCancelled => window.controller.on_file_hover_cancel(), DroppedFile(path) => window.controller.on_file_drop(&path), CloseRequested => { window.controller.on_close_request(); *control_flow = ControlFlow::Exit; }, Destroyed => window.controller.on_close(), Ime(_) => (), AxisMotion { .. } => (), Touch(_) => (), TouchpadRotate { .. } => (), TouchpadPressure { .. } => (), TouchpadMagnify { .. } => (), SmartMagnify { .. } => (), ScaleFactorChanged { .. } => (), ThemeChanged(_) => (), Occluded(_) => (), } } } // Called before any render events are called. Event::MainEventsCleared => { for window in self.windows.values_mut() { window.controller.on_process(); window.update_title(); window.update_window_size(); window.update_cursor_icon(); window.update_cursor_visible(); window.handle_render_request(); } } // Called if a window has requested to be rendered. Event::RedrawRequested(window_id) => { if let Some(window) = self.windows.get_mut(&window_id) { window.render(); } } // Called after all rendering has completed, or if there were no render requests. Event::RedrawEventsCleared => (), // Called before the program closes. Event::LoopDestroyed => (), _ => (), } }) } }