A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/winit_app.rs')
-rw-r--r--src/winit_app.rs167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/winit_app.rs b/src/winit_app.rs
new file mode 100644
index 0000000..07f1fab
--- /dev/null
+++ b/src/winit_app.rs
@@ -0,0 +1,167 @@
+/// Common boilerplate for setting up a winit application.
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+use winit::application::ApplicationHandler;
+use winit::event::{Event, WindowEvent};
+use winit::event_loop::{ActiveEventLoop, EventLoop};
+use winit::window::{Window, WindowAttributes, WindowId};
+
+/// Run a Winit application.
+#[allow(unused_mut)]
+pub(crate) fn run_app(
+ event_loop: EventLoop<()>,
+ mut app: impl ApplicationHandler<()> + 'static,
+) {
+ #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
+ event_loop.run_app(&mut app).unwrap();
+
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ winit::platform::web::EventLoopExtWebSys::spawn_app(event_loop, app);
+}
+
+/// Create a window from a set of window attributes.
+#[allow(dead_code)]
+pub(crate) fn make_window(
+ elwt: &ActiveEventLoop,
+ f: impl FnOnce(WindowAttributes) -> WindowAttributes,
+) -> Rc<Window> {
+ let attributes = f(WindowAttributes::default());
+ #[cfg(target_arch = "wasm32")]
+ let attributes =
+ winit::platform::web::WindowAttributesExtWebSys::with_append(
+ attributes, true,
+ );
+ let window = elwt.create_window(attributes);
+ Rc::new(window.unwrap())
+}
+
+/// Easily constructable winit application.
+pub(crate) struct WinitApp<T, S, Init, InitSurface, Handler> {
+ /// Closure to initialize `state`.
+ init: Init,
+
+ /// Closure to initialize `surface_state`.
+ init_surface: InitSurface,
+
+ /// Closure to run on window events.
+ event: Handler,
+
+ /// Contained state.
+ state: Option<T>,
+
+ /// Contained surface state.
+ surface_state: Option<S>,
+}
+
+/// Builder that makes it so we don't have to name `T`.
+pub(crate) struct WinitAppBuilder<T, S, Init, InitSurface> {
+ /// Closure to initialize `state`.
+ init: Init,
+
+ /// Closure to initialize `surface_state`.
+ init_surface: InitSurface,
+
+ /// Eat the type parameter.
+ _marker: PhantomData<(Option<T>, Option<S>)>,
+}
+
+impl<T, S, Init, InitSurface> WinitAppBuilder<T, S, Init, InitSurface>
+where
+ Init: FnMut(&ActiveEventLoop) -> T,
+ InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
+{
+ /// Create with an "init" closure.
+ pub(crate) fn with_init(
+ init: Init,
+ init_surface: InitSurface,
+ ) -> Self {
+ Self {
+ init,
+ init_surface,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Build a new application.
+ pub(crate) fn with_event_handler<F>(
+ self,
+ handler: F,
+ ) -> WinitApp<T, S, Init, InitSurface, F>
+ where
+ F: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
+ {
+ WinitApp::new(self.init, self.init_surface, handler)
+ }
+}
+
+impl<T, S, Init, InitSurface, Handler>
+ WinitApp<T, S, Init, InitSurface, Handler>
+where
+ Init: FnMut(&ActiveEventLoop) -> T,
+ InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
+ Handler: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
+{
+ /// Create a new application.
+ pub(crate) fn new(
+ init: Init,
+ init_surface: InitSurface,
+ event: Handler,
+ ) -> Self {
+ Self {
+ init,
+ init_surface,
+ event,
+ state: None,
+ surface_state: None,
+ }
+ }
+}
+
+impl<T, S, Init, InitSurface, Handler> ApplicationHandler
+ for WinitApp<T, S, Init, InitSurface, Handler>
+where
+ Init: FnMut(&ActiveEventLoop) -> T,
+ InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
+ Handler: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
+{
+ fn resumed(&mut self, el: &ActiveEventLoop) {
+ debug_assert!(self.state.is_none());
+ let mut state = (self.init)(el);
+ self.surface_state = Some((self.init_surface)(el, &mut state));
+ self.state = Some(state);
+ }
+
+ fn suspended(&mut self, _event_loop: &ActiveEventLoop) {
+ let surface_state = self.surface_state.take();
+ debug_assert!(surface_state.is_some());
+ drop(surface_state);
+ }
+
+ fn window_event(
+ &mut self,
+ event_loop: &ActiveEventLoop,
+ window_id: WindowId,
+ event: WindowEvent,
+ ) {
+ let state = self.state.as_mut().unwrap();
+ let surface_state = self.surface_state.as_mut();
+ (self.event)(
+ state,
+ surface_state,
+ Event::WindowEvent { window_id, event },
+ event_loop,
+ );
+ }
+
+ fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
+ if let Some(state) = self.state.as_mut() {
+ (self.event)(
+ state,
+ self.surface_state.as_mut(),
+ Event::AboutToWait,
+ event_loop,
+ );
+ }
+ }
+}