summaryrefslogblamecommitdiff
path: root/src/window_manager.rs
blob: 9322adb795d5a4cbbe416e5f5eb56afe504e2895 (plain) (tree)
1
2
3
4
5
6
7
8
9
             
                              


                                                                              
                                       
                                 
 
                    
                          
              
                                         
                                               

         






                                                             

                                                                         

                                                 
                                                                            
                               
                                                                        
                         

                                                                   
                                         






                                                                                                       


                                                                            
 
                                     
                                                                                                                     










                                                                                                                         
                                 


                                                                                                 
                                 




                                                                                                              
                             
                                                                                                                                             
                                                                                                            
                                                                                                            
                                                                                        
                                                                                             
                                                                                       















                                                                      


                         
                                                              
                                             
                                                             
                                              
                                                    

                                                       
                     
                                                                   



                                                                            
 





                                                                                                 


             
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<WindowId, Window>,
    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<dyn WindowController>) {
        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 => (),

                _ => (),
            }
        })
    }
}