1#![allow(clippy::type_complexity)]
2use winit::{
3 application::ApplicationHandler,
4 window::{Window, WindowId},
5 event_loop::{EventLoop, ActiveEventLoop},
6 event::*
7};
8use crate::{SimpleWindowBuilder, Display, Settings};
9use std::{hash::Hash, time::Instant};
10use winit_input_map::InputMap;
11pub struct ThinEngine<'a, H, D, S, U, E>
13where H: Hash + PartialEq + Eq + Clone + Copy,
14S: FnMut(&Display, &mut Window, &ActiveEventLoop),
15U: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
16D: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
17E: FnMut(Event<()>, &ActiveEventLoop, Option<&(Window, Display)>)
18{
19 state: Option<(Window, Display)>,
20 window_settings: Option<SimpleWindowBuilder>,
21 update: &'a mut U,
22 draw: &'a mut D,
23 setup: &'a mut S,
24 event_handler: &'a mut E,
25 input_map: InputMap<H>,
26 settings: Settings,
27 frame_start: Instant,
28}
29impl<H, D, S, U, E> ApplicationHandler for ThinEngine<'_, H, D, S, U, E>
30where H: Hash + PartialEq + Eq + Clone + Copy,
31S: FnMut(&Display, &mut Window, &ActiveEventLoop),
32U: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
33D: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
34E: FnMut(Event<()>, &ActiveEventLoop, Option<&(Window, Display)>)
35{
36 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
37 if self.state.is_some() { return }
38 let (mut window, display) = self.window_settings
39 .take().expect("No window settings are available")
40 .build(event_loop);
41 (self.setup)(&display, &mut window, event_loop);
42 self.state = Some((window, display));
43 }
44 fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) {
45 match event {
46 WindowEvent::Resized(size) => self.state.as_mut().unwrap().1.resize(size.into()),
47 WindowEvent::CloseRequested => event_loop.exit(),
48 WindowEvent::RedrawRequested => {
49 let Some((ref mut window, ref display)) = self.state else { return };
50 let input = &mut self.input_map;
51 let settings = &mut self.settings;
52 (self.draw)(input, display, settings, event_loop, window)
53 },
54 _ => self.input_map.update_with_window_event(&event)
55 }
56 (self.event_handler)(Event::WindowEvent { window_id, event }, event_loop, self.state.as_ref());
57 }
58 fn device_event(&mut self, event_loop: &ActiveEventLoop, device_id: DeviceId, event: DeviceEvent) {
59 self.input_map.update_with_device_event(device_id, &event);
60 (self.event_handler)(Event::DeviceEvent { device_id, event }, event_loop, self.state.as_ref());
61 }
62 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
63 if let Some(ref mut gilrs) = self.settings.gamepads { self.input_map.update_with_gilrs(gilrs) }
64
65 let update = self.settings.min_frame_duration
66 .map(|i| i <= self.frame_start.elapsed())
67 .unwrap_or(true);
68 if update {
69 let (window, display) = self.state.as_mut().unwrap();
70 (self.update)(&mut self.input_map, display, &mut self.settings, event_loop, window);
71 self.frame_start = Instant::now();
72 self.input_map.init();
73 }
74 (self.event_handler)(Event::AboutToWait, event_loop, self.state.as_ref());
75 }
76 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
77 let window = self.state.take().unwrap().0;
78
79 self.window_settings = Some(SimpleWindowBuilder::new()
80 .set_window_builder(Window::default_attributes()
81 .with_inner_size(window.inner_size())
82 .with_resizable(window.is_resizable())
84 .with_enabled_buttons(window.enabled_buttons())
85 .with_title(window.title())
86 .with_fullscreen(window.fullscreen())
87 .with_maximized(window.is_maximized())
88 .with_visible(window.is_visible().unwrap_or(true))
89 .with_decorations(window.is_decorated())
91 .with_theme(window.theme())
92 ));
95 (self.event_handler)(Event::Suspended, event_loop, self.state.as_ref());
96 }
97}
98pub struct ThinBuilder<'a, H: Hash + PartialEq + Eq + Clone + Copy> {
100 window_settings: SimpleWindowBuilder,
101 input_map: InputMap<H>,
102 settings: Settings,
103 update: Box<dyn FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a>,
104 setup: Box<dyn FnMut(&Display, &mut Window, &ActiveEventLoop) + 'a>,
105 draw: Box<dyn FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a>,
106 event_handler: Box<dyn FnMut(Event<()>, &ActiveEventLoop, Option<&(Window, Display)>) + 'a>
107}
108impl<'a, H: Hash + PartialEq + Eq + Clone + Copy> ThinBuilder<'a, H> {
109 pub fn new(input_map: InputMap<H>) -> ThinBuilder<'a, H> {
110 ThinBuilder {
111 input_map,
112 settings: Settings::default(),
113 update: Box::new(|_, _, _, _, _| {}),
114 setup: Box::new(|_, _, _| {}),
115 draw: Box::new(|_, _, _, _, _| {}),
116 event_handler: Box::new(|_, _, _| {}),
117 window_settings: SimpleWindowBuilder::new()
118 }
119 }
120 pub fn build(mut self, ev: EventLoop<()>) -> Result<(), winit::error::EventLoopError> {
122 let mut engine = ThinEngine {
123 state: None,
124 window_settings: Some(self.window_settings),
125 update: &mut self.update,
126 draw: &mut self.draw,
127 setup: &mut self.setup,
128 event_handler: &mut self.event_handler,
129 input_map: self.input_map,
130 settings: self.settings,
131 frame_start: Instant::now(),
132 };
133 ev.run_app(&mut engine)
134 }
135 pub fn with_draw(
137 mut self,
138 draw: impl FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a
139 ) -> Self {
140 self.draw = Box::new(draw);
141 self
142 }
143 pub fn with_setup(mut self, setup: impl FnMut(&Display, &mut Window, &ActiveEventLoop) + 'a) -> Self {
145 self.setup = Box::new(setup);
146 self
147 }
148 pub fn with_update(
150 mut self,
151 update: impl FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a
152 ) -> Self {
153 self.update = Box::new(update);
154 self
155 }
156 pub fn with_event_handler(
157 mut self,
158 event_handler: impl FnMut(Event<()>, &ActiveEventLoop, Option<&(Window, Display)>) + 'a
159 ) -> Self {
160 self.event_handler = Box::new(event_handler);
161 self
162 }
163 pub fn with_settings(mut self, settings: Settings) -> Self {
164 self.settings = settings;
165 self
166 }
167 pub fn with_window_settings(mut self, window_settings: SimpleWindowBuilder) -> Self {
168 self.window_settings = window_settings;
169 self
170 }
171}