summaryrefslogtreecommitdiff
path: root/src/window_manager.rs
blob: 9322adb795d5a4cbbe416e5f5eb56afe504e2895 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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 => (),

                _ => (),
            }
        })
    }
}