use crate::*; use nosferatu::*; use std::collections::HashMap; use winit::event::{Event, MouseButton, StartCause, WindowEvent, MouseScrollDelta}; use winit::event_loop::EventLoop; use winit::window::WindowId; /// Controls the entire program. pub struct WindowManager { limiter: Option, frame_timer: FrameTimer, event_loop: EventLoop<()>, windows: HashMap, program: P, } impl WindowManager { pub fn without_program() -> Self { Self::with_program(DefaultProgramController {}) } } impl WindowManager

{ pub fn with_program(program: P) -> Self { Self { limiter: None, frame_timer: FrameTimer::one_second(), event_loop: EventLoop::new(), windows: HashMap::new(), program, } } pub fn with_frame_limit(mut self, limit: usize) -> Self { self.limiter = Some(FrameRateLimiter::from_frame_rate(limit)); self } /// Used to create one or more windows before the event loop starts. pub fn create_window(&mut self, controller: Box) { let window = unsafe { Window::new(&self.event_loop, controller) }; self.windows.insert(window.id(), window); } /// Starts the event loop, causing program control to be passed permanently to the window manager. pub fn run(mut self) -> ! { self.event_loop.run(move |event, window_target, control_flow| { control_flow.set_poll(); match event { // Event loop has just initialised (is only ever emitted once) Event::NewEvents(StartCause::Init) => self.program.initialise(), Event::WindowEvent { window_id, event } => { if let Some(window) = self.windows.get_mut(&window_id) { use WindowEvent::*; match event { Resized(dim) => window.resize_buffer(Dimensions::new(dim.width, dim.height)), Moved(p) => window.controller.on_move(Point::new(p.x, p.y)), Focused(state) => window.controller.on_focus_change(state), CursorEntered { .. } => window.controller.on_mouse_enter(), CursorLeft { .. } => window.controller.on_mouse_exit(), CursorMoved { position, .. } => { let point = Point::new(position.x as i32, position.y as i32); window.move_mouse(point); } 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()), _ => (), } window.bump_mouse(); } KeyboardInput { input, .. } => window.controller.on_keyboard_input(input.into()), ModifiersChanged(state) => window.controller.on_keyboard_modifier_change(state), ReceivedCharacter(c) => window.controller.on_character_received(c), HoveredFile(path) => window.controller.on_file_hovered(path), DroppedFile(path) => window.controller.on_file_dropped(path), // Tell the window, and let it raise its own event to close itself // When all windows are closed: control_flow.set_exit_with_code(0); CloseRequested => todo!("window.controller.on_close_requested()"), _ => (), } } } // Called each loop before any rendering would begin. Event::MainEventsCleared => { self.frame_timer.tick(); // println!("{}", self.frame_timer.frame_rate()); self.program.on_process(&mut |controller: Box| { let window = unsafe { Window::new(window_target, controller) }; self.windows.insert(window.id(), window); }); for window in self.windows.values_mut() { window.controller.on_process(); let cursor_icon = window.controller.cursor_icon(); window.set_cursor_icon(cursor_icon); // let resizable = window.controller.resizable(); // window.set_resizable(resizable); // let cursor_visible = window.controller.cursor_visible(); // window.set_cursor_visible(cursor_visible); window.check_render_request(); let title = window.controller.title(); window.set_title(&title); let minimum_dimensions = window.controller.minimum_dimensions(); window.set_minimum_dimensions(minimum_dimensions); let maximum_dimensions = window.controller.maximum_dimensions(); window.set_maximum_dimensions(maximum_dimensions); } } // Called if a render was requested for a window Event::RedrawRequested(window_id) => { if let Some(window) = self.windows.get_mut(&window_id) { window.render(); } } // Called after rendering has completed Event::RedrawEventsCleared => { if let Some(limiter) = &mut self.limiter { limiter.tick(); } } _other => {} // todo!("{:?}", other), } }) } } impl Default for WindowManager { fn default() -> Self { Self::without_program() } }