diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2023-10-10 14:56:04 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2023-10-10 14:56:04 +1300 |
commit | a6e97019bd53e4478c846f8f636c18ecb53bece2 (patch) | |
tree | 69dada994e34cdfb4ddcef5a29c753f449407ec7 /src/window_manager.rs | |
download | phosphor-a6e97019bd53e4478c846f8f636c18ecb53bece2.zip |
First commit, before upgrading winit to version 28.1
Diffstat (limited to 'src/window_manager.rs')
-rw-r--r-- | src/window_manager.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/window_manager.rs b/src/window_manager.rs new file mode 100644 index 0000000..144f1c3 --- /dev/null +++ b/src/window_manager.rs @@ -0,0 +1,156 @@ +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<P: ProgramController> { + limiter: Option<FrameRateLimiter>, + frame_timer: FrameTimer, + event_loop: EventLoop<()>, + windows: HashMap<WindowId, Window>, + program: P, +} + +impl WindowManager<DefaultProgramController> { + pub fn without_program() -> Self { + Self::with_program(DefaultProgramController {}) + } +} + +impl<P: 'static + ProgramController> WindowManager<P> { + 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<dyn WindowController>) { + 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<dyn WindowController>| { + 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<DefaultProgramController> { + fn default() -> Self { + Self::without_program() + } +} |