thin_engine/
application.rs

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            // todo position
74            .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            // todo transparent
81            .with_decorations(window.is_decorated())
82            .with_theme(window.theme())
83            // todo resize increments
84            // todo parrent window
85        ));
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}