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>
12where H: Hash + PartialEq + Eq + Clone + Copy, S: FnMut(&Display, &mut Window),
13U: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
14D: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window)
15{
16 state: Option<(Window, Display)>,
17 window_settings: Option<SimpleWindowBuilder>,
18 update: &'a mut U,
19 draw: &'a mut D,
20 setup: &'a mut S,
21 input_map: InputMap<H>,
22 settings: Settings,
23 frame_start: Instant,
24}
25impl<'a, H, D, S, U> ApplicationHandler for ThinEngine<'a, H, D, S, U>
26where H: Hash + PartialEq + Eq + Clone + Copy, S: FnMut(&Display, &mut Window),
27U: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
28D: FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window),
29{
30 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
31 if self.state.is_some() { return }
32 let (mut window, display) = self.window_settings
33 .take().expect("No window settings are available")
34 .build(event_loop);
35 (self.setup)(&display, &mut window);
36 self.state = Some((window, display));
37 }
38 fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
39 match event {
40 WindowEvent::Resized(size) => self.state.as_mut().unwrap().1.resize(size.into()),
41 WindowEvent::CloseRequested => event_loop.exit(),
42 WindowEvent::RedrawRequested => {
43 let Some((ref mut window, ref display)) = self.state else { return };
44 let input = &mut self.input_map;
45 let settings = &mut self.settings;
46 (self.draw)(input, display, settings, event_loop, window)
47 },
48 _ => self.input_map.update_with_window_event(&event)
49 }
50 }
51 fn device_event(&mut self, _: &ActiveEventLoop, id: DeviceId, event: DeviceEvent) {
52 self.input_map.update_with_device_event(id, &event);
53 }
54 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
55 if let Some(ref mut gilrs) = self.settings.gamepads { self.input_map.update_with_gilrs(gilrs) }
56
57 let update = self.settings.min_frame_duration
58 .map(|i| i <= self.frame_start.elapsed())
59 .unwrap_or(true);
60 if update {
61 let (window, display) = self.state.as_mut().unwrap();
62 (self.update)(&mut self.input_map, display, &mut self.settings, event_loop, window);
63 self.frame_start = Instant::now();
64 self.input_map.init();
65 }
66 }
67 fn suspended(&mut self, _: &ActiveEventLoop) {
68 let window = self.state.take().unwrap().0;
69
70 self.window_settings = Some(SimpleWindowBuilder::new()
71 .set_window_builder(Window::default_attributes()
72 .with_inner_size(window.inner_size())
73 .with_resizable(window.is_resizable())
75 .with_enabled_buttons(window.enabled_buttons())
76 .with_title(window.title())
77 .with_fullscreen(window.fullscreen())
78 .with_maximized(window.is_maximized())
79 .with_visible(window.is_visible().unwrap_or(true))
80 .with_decorations(window.is_decorated())
82 .with_theme(window.theme())
83 ));
86 }
87}
88pub struct ThinBuilder<'a, H: Hash + PartialEq + Eq + Clone + Copy> {
89 window_settings: SimpleWindowBuilder,
90 input_map: InputMap<H>,
91 settings: Settings,
92 update: Box<dyn FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a>,
93 setup: Box<dyn FnMut(&Display, &mut Window) + 'a>,
94 draw: Box<dyn FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a>,
95}
96impl<'a, H: Hash + PartialEq + Eq + Clone + Copy> ThinBuilder<'a, H> {
97 pub fn new(input_map: InputMap<H>) -> ThinBuilder<'a, H> {
98 ThinBuilder {
99 input_map,
100 settings: Settings::default(),
101 update: Box::new(|_, _, _, _, _| {}),
102 setup: Box::new(|_, _| {}),
103 draw: Box::new(|_, _, _, _, _| {}),
104 window_settings: SimpleWindowBuilder::new()
105 }
106 }
107 pub fn build(mut self, ev: EventLoop<()>) -> Result<(), winit::error::EventLoopError> {
108 let mut engine = ThinEngine {
109 state: None,
110 window_settings: Some(self.window_settings),
111 update: &mut self.update,
112 draw: &mut self.draw,
113 setup: &mut self.setup,
114 input_map: self.input_map,
115 settings: self.settings,
116 frame_start: Instant::now(),
117 };
118 ev.run_app(&mut engine)
119 }
120 pub fn with_draw(
121 mut self,
122 draw: impl FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a
123 ) -> Self {
124 self.draw = Box::new(draw);
125 self
126 }
127 pub fn with_setup(mut self, setup: impl FnMut(&Display, &mut Window) + 'a) -> Self {
128 self.setup = Box::new(setup);
129 self
130 }
131 pub fn with_update(
132 mut self,
133 update: impl FnMut(&mut InputMap<H>, &Display, &mut Settings, &ActiveEventLoop, &mut Window) + 'a
134 ) -> Self {
135 self.update = Box::new(update);
136 self
137 }
138 pub fn with_settings(mut self, settings: Settings) -> Self {
139 self.settings = settings;
140 self
141 }
142 pub fn with_window_settings(mut self, window_settings: SimpleWindowBuilder) -> Self {
143 self.window_settings = window_settings;
144 self
145 }
146}