1use crate::conv::{from_imgui_cursor, to_imgui_button, to_imgui_key};
2use cgmath::Matrix3;
3use easy_imgui::{self as imgui, Vector2, cgmath, mint};
4use easy_imgui_renderer::Renderer;
5use easy_imgui_sys::*;
6use glutin::{
7 context::PossiblyCurrentContext,
8 prelude::*,
9 surface::{Surface, WindowSurface},
10};
11use std::num::NonZeroU32;
12use std::time::{Duration, Instant};
13use winit::{
14 dpi::{LogicalSize, PhysicalSize},
15 event::Ime::Commit,
16 keyboard::PhysicalKey,
17 window::{CursorIcon, Window},
18};
19
20pub use easy_imgui::EventResult;
21
22#[allow(unused_imports)]
24use winit::dpi::{LogicalPosition, PhysicalPosition, Pixel};
25
26#[derive(Debug, Clone)]
28pub struct MainWindowStatus {
29 last_frame: Instant,
30 current_cursor: Option<CursorIcon>,
31}
32
33impl Default for MainWindowStatus {
34 fn default() -> MainWindowStatus {
35 let now = Instant::now();
36 MainWindowStatus {
37 last_frame: now,
38 current_cursor: Some(CursorIcon::Default),
39 }
40 }
41}
42
43pub trait MainWindowRef {
48 fn window(&self) -> &Window;
50 fn pre_render(&mut self) {}
55 fn post_render(&mut self) {}
59 fn ping_user_input(&mut self) {}
61 fn about_to_wait(&mut self, _pinged: bool) {}
63 fn transform_position(&self, pos: Vector2) -> Vector2 {
65 pos / self.scale_factor()
66 }
67 fn scale_factor(&self) -> f32 {
69 self.window().scale_factor() as f32
70 }
71 fn set_scale_factor(&self, scale: f32) -> f32 {
78 scale
79 }
80 fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
84 let scale = self.scale_factor();
85 size.to_logical(scale as f64)
86 }
87 fn set_cursor(&mut self, cursor: Option<CursorIcon>) {
89 let w = self.window();
90 match cursor {
91 None => w.set_cursor_visible(false),
92 Some(c) => {
93 w.set_cursor(c);
94 w.set_cursor_visible(true);
95 }
96 }
97 }
98}
99
100fn transform_position_with_optional_matrix(
101 w: &impl MainWindowRef,
102 pos: Vector2,
103 mx: &Option<Matrix3<f32>>,
104) -> Vector2 {
105 use cgmath::{EuclideanSpace as _, Transform};
106 match mx {
107 Some(mx) => mx.transform_point(cgmath::Point2::from_vec(pos)).to_vec(),
108 None => pos / w.scale_factor(),
109 }
110}
111
112bitflags::bitflags! {
113 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
115 pub struct EventFlags: u32 {
116 const DoNotRender = 1;
118 const DoNotResize = 4;
120 const DoNotMouse = 8;
122 }
123}
124
125pub struct MainWindowPieces<'a> {
127 window: &'a Window,
128 surface: &'a Surface<WindowSurface>,
129 gl_context: &'a PossiblyCurrentContext,
130 matrix: Option<Matrix3<f32>>,
131}
132
133impl<'a> MainWindowPieces<'a> {
134 pub fn new(
136 window: &'a Window,
137 surface: &'a Surface<WindowSurface>,
138 gl_context: &'a PossiblyCurrentContext,
139 ) -> Self {
140 MainWindowPieces {
141 window,
142 surface,
143 gl_context,
144 matrix: None,
145 }
146 }
147 pub fn set_matrix(&mut self, matrix: Option<Matrix3<f32>>) {
151 self.matrix = matrix;
152 }
153}
154
155impl MainWindowRef for MainWindowPieces<'_> {
157 fn window(&self) -> &Window {
158 self.window
159 }
160 fn pre_render(&mut self) {
161 let _ = self
162 .gl_context
163 .make_current(self.surface)
164 .inspect_err(|e| log::error!("{e}"));
165 }
166 fn post_render(&mut self) {
167 self.window.pre_present_notify();
168 let _ = self
169 .surface
170 .swap_buffers(self.gl_context)
171 .inspect_err(|e| log::error!("{e}"));
172 }
173 fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
174 let width = NonZeroU32::new(size.width.max(1)).unwrap();
175 let height = NonZeroU32::new(size.height.max(1)).unwrap();
176 self.surface.resize(self.gl_context, width, height);
177 let scale = self.scale_factor();
178 size.to_logical(scale as f64)
179 }
180 fn transform_position(&self, pos: Vector2) -> Vector2 {
181 transform_position_with_optional_matrix(self, pos, &self.matrix)
182 }
183}
184
185impl MainWindowRef for &Window {
187 fn window(&self) -> &Window {
188 self
189 }
190}
191
192pub struct NoScale<'a>(pub &'a Window);
194
195impl MainWindowRef for NoScale<'_> {
196 fn window(&self) -> &Window {
197 self.0
198 }
199 fn scale_factor(&self) -> f32 {
200 1.0
201 }
202 fn set_scale_factor(&self, _scale: f32) -> f32 {
203 1.0
204 }
205}
206
207pub fn new_events(renderer: &mut Renderer, status: &mut MainWindowStatus) {
209 let now = Instant::now();
210 unsafe {
211 renderer
212 .imgui()
213 .io_mut()
214 .inner()
215 .set_delta_time(now.duration_since(status.last_frame));
216 }
217 status.last_frame = now;
218}
219
220pub fn about_to_wait(main_window: &mut impl MainWindowRef, renderer: &mut Renderer) {
222 let imgui = unsafe { renderer.imgui().set_current() };
223 let io = imgui.io();
224 if io.WantSetMousePos {
225 let pos = io.MousePos;
226 let pos = winit::dpi::LogicalPosition { x: pos.x, y: pos.y };
227 let _ = main_window.window().set_cursor_position(pos);
228 }
229 let mouse = unsafe { ImGui_IsAnyMouseDown() };
231 main_window.about_to_wait(mouse);
232}
233
234pub fn window_event(
236 main_window: &mut impl MainWindowRef,
237 renderer: &mut Renderer,
238 status: &mut MainWindowStatus,
239 app: &mut impl imgui::UiBuilder,
240 event: &winit::event::WindowEvent,
241 flags: EventFlags,
242) -> EventResult {
243 use winit::event::WindowEvent::*;
244 let mut window_closed = false;
245 match event {
246 CloseRequested => {
247 window_closed = true;
248 }
249 RedrawRequested => unsafe {
250 let imgui = renderer.imgui().set_current();
251 let io = imgui.io();
252 let config_flags = imgui::ConfigFlags::from_bits_truncate(io.ConfigFlags);
253 if !config_flags.contains(imgui::ConfigFlags::NoMouseCursorChange) {
254 let cursor = if io.MouseDrawCursor {
255 None
256 } else {
257 let cursor = imgui::MouseCursor::from_bits(ImGui_GetMouseCursor())
258 .unwrap_or(imgui::MouseCursor::Arrow);
259 from_imgui_cursor(cursor)
260 };
261 if cursor != status.current_cursor {
262 main_window.set_cursor(cursor);
263 status.current_cursor = cursor;
264 }
265 }
266 if !flags.contains(EventFlags::DoNotRender) {
267 main_window.pre_render();
268 renderer.do_frame(app);
269 main_window.post_render();
270 }
271 },
272 Resized(size) => {
273 let size = main_window.resize(*size);
276 if !flags.contains(EventFlags::DoNotResize) {
277 main_window.ping_user_input();
278 let size = Vector2::from(mint::Vector2::from(size));
280 unsafe {
281 renderer.imgui().io_mut().inner().DisplaySize = imgui::v2_to_im(size);
282 }
283 }
284 }
285 #[allow(clippy::collapsible_match)]
286 ScaleFactorChanged { scale_factor, .. } => {
287 if !flags.contains(EventFlags::DoNotResize) {
288 main_window.ping_user_input();
289 let scale_factor = main_window.set_scale_factor(*scale_factor as f32);
290 unsafe {
291 let io = renderer.imgui().io_mut().inner();
292 let old_scale_factor = io.DisplayFramebufferScale.x;
295 if io.MousePos.x.is_finite() && io.MousePos.y.is_finite() {
296 io.MousePos.x *= scale_factor / old_scale_factor;
297 io.MousePos.y *= scale_factor / old_scale_factor;
298 }
299 }
300 let size = renderer.size();
301 renderer.set_size(size, scale_factor);
302 }
303 }
304 ModifiersChanged(mods) => {
305 main_window.ping_user_input();
306 unsafe {
307 let io = renderer.imgui().io_mut().inner();
308 io.AddKeyEvent(imgui::Key::ModCtrl.bits(), mods.state().control_key());
309 io.AddKeyEvent(imgui::Key::ModShift.bits(), mods.state().shift_key());
310 io.AddKeyEvent(imgui::Key::ModAlt.bits(), mods.state().alt_key());
311 io.AddKeyEvent(imgui::Key::ModSuper.bits(), mods.state().super_key());
312 }
313 }
314 KeyboardInput {
315 event:
316 winit::event::KeyEvent {
317 physical_key,
318 text,
319 state,
320 ..
321 },
322 is_synthetic: false,
323 ..
324 } => {
325 main_window.ping_user_input();
326 let pressed = *state == winit::event::ElementState::Pressed;
327 if let Some(key) = to_imgui_key(*physical_key) {
328 unsafe {
329 let io = renderer.imgui().io_mut().inner();
330 io.AddKeyEvent(key.bits(), pressed);
331
332 use winit::keyboard::KeyCode::*;
333 if let PhysicalKey::Code(keycode) = physical_key {
334 let kmod = match keycode {
335 ControlLeft | ControlRight => Some(imgui::Key::ModCtrl),
336 ShiftLeft | ShiftRight => Some(imgui::Key::ModShift),
337 AltLeft | AltRight => Some(imgui::Key::ModAlt),
338 SuperLeft | SuperRight => Some(imgui::Key::ModSuper),
339 _ => None,
340 };
341 if let Some(kmod) = kmod {
342 io.AddKeyEvent(kmod.bits(), pressed);
343 }
344 }
345 }
346 }
347 if pressed && let Some(text) = text {
348 unsafe {
349 let io = renderer.imgui().io_mut().inner();
350 for c in text.chars() {
351 io.AddInputCharacter(c as u32);
352 }
353 }
354 }
355 }
356 Ime(Commit(text)) => {
357 main_window.ping_user_input();
358 unsafe {
359 let io = renderer.imgui().io_mut().inner();
360 for c in text.chars() {
361 io.AddInputCharacter(c as u32);
362 }
363 }
364 }
365 CursorMoved { position, .. } => {
366 main_window.ping_user_input();
367 unsafe {
368 let io = renderer.imgui().io_mut().inner();
369 let position = main_window
370 .transform_position(Vector2::new(position.x as f32, position.y as f32));
371 io.AddMousePosEvent(position.x, position.y);
372 }
373 }
374 MouseWheel {
375 delta,
376 phase: winit::event::TouchPhase::Moved,
377 ..
378 } => {
379 main_window.ping_user_input();
380 let mut imgui = unsafe { renderer.imgui().set_current() };
381 unsafe {
382 let io = imgui.io_mut().inner();
383 let (h, v) = match delta {
384 winit::event::MouseScrollDelta::LineDelta(h, v) => (*h, *v),
385 winit::event::MouseScrollDelta::PixelDelta(d) => {
386 let scale = io.DisplayFramebufferScale.x;
387 let f_scale = ImGui_GetFontSize();
388 let scale = scale * f_scale;
389 (d.x as f32 / scale, d.y as f32 / scale)
390 }
391 };
392 io.AddMouseWheelEvent(h, v);
393 }
394 }
395 MouseInput { state, button, .. } => {
396 main_window.ping_user_input();
397 unsafe {
398 let io = renderer.imgui().io_mut().inner();
399 if let Some(btn) = to_imgui_button(*button) {
400 let pressed = *state == winit::event::ElementState::Pressed;
401 io.AddMouseButtonEvent(btn.bits(), pressed);
402 }
403 }
404 }
405 CursorLeft { .. } => {
406 main_window.ping_user_input();
407 unsafe {
408 let io = renderer.imgui().io_mut().inner();
409 io.AddMousePosEvent(f32::MAX, f32::MAX);
410 }
411 }
412 Focused(focused) => {
413 main_window.ping_user_input();
414 unsafe {
415 let io = renderer.imgui().io_mut().inner();
416 io.AddFocusEvent(*focused);
417 }
418 }
419 _ => {}
420 }
421 let imgui = renderer.imgui();
422 EventResult::new(imgui, window_closed)
423}
424
425#[cfg(feature = "main-window")]
426mod main_window {
427 use super::*;
428 use std::future::Future;
429 mod fut;
430 use anyhow::{Result, anyhow};
431 use easy_imgui::Idler;
432 use easy_imgui_renderer::glow;
433 pub use fut::FutureBackCaller;
434 use glutin::{
435 config::{Config, ConfigTemplateBuilder},
436 context::{ContextApi, ContextAttributesBuilder},
437 display::GetGlDisplay,
438 surface::SurfaceAttributesBuilder,
439 };
440 use glutin_winit::DisplayBuilder;
441 use raw_window_handle::HasWindowHandle;
442 use winit::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
443 use winit::window::WindowAttributes;
444
445 pub struct MainWindow {
447 gl_context: PossiblyCurrentContext,
448 surface: Surface<WindowSurface>,
450 window: Window,
451 matrix: Option<Matrix3<f32>>,
452 idler: Idler,
453 }
454
455 pub struct MainWindowWithRenderer {
458 main_window: MainWindow,
459 renderer: Renderer,
460 status: MainWindowStatus,
461 }
462
463 impl MainWindow {
464 pub fn new(event_loop: &ActiveEventLoop, wattr: WindowAttributes) -> Result<MainWindow> {
466 let score = |c: &Config| (c.num_samples(), c.depth_size(), c.stencil_size());
468 Self::with_gl_chooser(event_loop, wattr, |cfg1, cfg2| {
469 if score(&cfg2) < score(&cfg1) {
470 cfg2
471 } else {
472 cfg1
473 }
474 })
475 }
476 pub fn with_gl_chooser(
481 event_loop: &ActiveEventLoop,
482 wattr: WindowAttributes,
483 f_choose_cfg: impl FnMut(Config, Config) -> Config,
484 ) -> Result<MainWindow> {
485 let template = ConfigTemplateBuilder::new()
486 .prefer_hardware_accelerated(Some(true))
487 .with_depth_size(0)
488 .with_stencil_size(0);
489
490 let display_builder = DisplayBuilder::new().with_window_attributes(Some(wattr));
491 let (window, gl_config) = display_builder
492 .build(event_loop, template, |configs| {
493 configs.reduce(f_choose_cfg).unwrap()
494 })
495 .map_err(|e| anyhow!("{:#?}", e))?;
496 let window = window.unwrap();
497 window.set_ime_allowed(true);
498 let raw_window_handle = Some(window.window_handle().unwrap().as_raw());
499 let gl_display = gl_config.display();
500 let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);
501 let fallback_context_attributes = ContextAttributesBuilder::new()
502 .with_context_api(ContextApi::Gles(None))
503 .build(raw_window_handle);
504
505 let mut not_current_gl_context = Some(unsafe {
506 gl_display
507 .create_context(&gl_config, &context_attributes)
508 .or_else(|_| {
509 gl_display.create_context(&gl_config, &fallback_context_attributes)
510 })?
511 });
512
513 let size = window.inner_size();
514
515 let (width, height): (u32, u32) = size.into();
516 let raw_window_handle = window.window_handle().unwrap().as_raw();
517 let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
518 raw_window_handle,
519 NonZeroU32::new(width).unwrap(),
520 NonZeroU32::new(height).unwrap(),
521 );
522
523 let surface = unsafe {
524 gl_config
525 .display()
526 .create_window_surface(&gl_config, &attrs)?
527 };
528 let gl_context = not_current_gl_context
529 .take()
530 .unwrap()
531 .make_current(&surface)?;
532
533 let _ = surface.set_swap_interval(
535 &gl_context,
536 glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap()),
537 );
538
539 Ok(MainWindow {
540 gl_context,
541 window,
542 surface,
543 matrix: None,
544 idler: Idler::default(),
545 })
546 }
547 pub fn set_matrix(&mut self, matrix: Option<Matrix3<f32>>) {
549 self.matrix = matrix;
550 }
551
552 pub unsafe fn into_pieces(
557 self,
558 ) -> (PossiblyCurrentContext, Surface<WindowSurface>, Window) {
559 (self.gl_context, self.surface, self.window)
560 }
561 pub fn glutin_context(&self) -> &PossiblyCurrentContext {
563 &self.gl_context
564 }
565 pub fn create_gl_context(&self) -> glow::Context {
567 let dsp = self.gl_context.display();
568 unsafe { glow::Context::from_loader_function_cstr(|s| dsp.get_proc_address(s)) }
569 }
570 pub fn window(&self) -> &Window {
572 &self.window
573 }
574 pub fn surface(&self) -> &Surface<WindowSurface> {
576 &self.surface
577 }
578 pub fn to_logical_size<X: Pixel, Y: Pixel>(&self, size: PhysicalSize<X>) -> LogicalSize<Y> {
580 let scale = self.window.scale_factor();
581 size.to_logical(scale)
582 }
583 pub fn to_physical_size<X: Pixel, Y: Pixel>(
585 &self,
586 size: LogicalSize<X>,
587 ) -> PhysicalSize<Y> {
588 let scale = self.window.scale_factor();
589 size.to_physical(scale)
590 }
591 pub fn to_logical_pos<X: Pixel, Y: Pixel>(
593 &self,
594 pos: PhysicalPosition<X>,
595 ) -> LogicalPosition<Y> {
596 let scale = self.window.scale_factor();
597 pos.to_logical(scale)
598 }
599 pub fn to_physical_pos<X: Pixel, Y: Pixel>(
601 &self,
602 pos: LogicalPosition<X>,
603 ) -> PhysicalPosition<Y> {
604 let scale = self.window.scale_factor();
605 pos.to_physical(scale)
606 }
607 }
608
609 impl MainWindowWithRenderer {
610 pub fn new(main_window: MainWindow) -> Self {
612 Self::with_builder(main_window, &imgui::ContextBuilder::new())
613 }
614 pub fn with_builder(main_window: MainWindow, builder: &imgui::ContextBuilder) -> Self {
618 let gl = main_window.create_gl_context();
619 let renderer = Renderer::with_builder(std::rc::Rc::new(gl), builder).unwrap();
620 Self::new_with_renderer(main_window, renderer)
621 }
622 pub fn set_idle_time(&mut self, time: Duration) {
624 self.main_window.idler.set_idle_time(time);
625 }
626 pub fn set_idle_frame_count(&mut self, frame_count: u32) {
630 self.main_window.idler.set_idle_frame_count(frame_count);
631 }
632 pub fn ping_user_input(&mut self) {
637 self.main_window.idler.ping_user_input();
638 }
639 pub fn renderer(&mut self) -> &mut Renderer {
641 &mut self.renderer
642 }
643 pub fn imgui(&mut self) -> &mut imgui::Context {
647 self.renderer.imgui()
648 }
649 pub fn main_window(&mut self) -> &mut MainWindow {
651 &mut self.main_window
652 }
653 pub fn new_with_renderer(main_window: MainWindow, mut renderer: Renderer) -> Self {
655 let w = main_window.window();
656 let size = w.inner_size();
657 let scale = w.scale_factor();
658 let size = size.to_logical::<f32>(scale);
659 renderer.set_size(Vector2::from(mint::Vector2::from(size)), scale as f32);
660
661 MainWindowWithRenderer {
662 main_window,
663 renderer,
664 status: MainWindowStatus::default(),
665 }
666 }
667 pub fn window_event(
672 &mut self,
673 app: &mut impl imgui::UiBuilder,
674 event: &winit::event::WindowEvent,
675 flags: EventFlags,
676 ) -> EventResult {
677 window_event(
678 &mut self.main_window,
679 &mut self.renderer,
680 &mut self.status,
681 app,
682 event,
683 flags,
684 )
685 }
686
687 pub fn new_events(&mut self) {
689 new_events(&mut self.renderer, &mut self.status);
690 }
691 pub fn about_to_wait(&mut self) {
693 about_to_wait(&mut self.main_window, &mut self.renderer);
694 }
695 }
696
697 impl MainWindowRef for MainWindow {
699 fn window(&self) -> &Window {
700 &self.window
701 }
702 fn pre_render(&mut self) {
703 self.idler.incr_frame();
704 let _ = self
705 .gl_context
706 .make_current(&self.surface)
707 .inspect_err(|e| log::error!("{e}"));
708 }
709 fn post_render(&mut self) {
710 self.window.pre_present_notify();
711 let _ = self
712 .surface
713 .swap_buffers(&self.gl_context)
714 .inspect_err(|e| log::error!("{e}"));
715 }
716 fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
717 let width = NonZeroU32::new(size.width.max(1)).unwrap();
718 let height = NonZeroU32::new(size.height.max(1)).unwrap();
719 self.surface.resize(&self.gl_context, width, height);
720 self.to_logical_size::<_, f32>(size)
721 }
722 fn ping_user_input(&mut self) {
723 self.idler.ping_user_input();
724 }
725 fn about_to_wait(&mut self, pinged: bool) {
726 if pinged || self.idler.has_to_render() {
727 self.window.request_redraw();
730 }
731 }
732 fn transform_position(&self, pos: Vector2) -> Vector2 {
733 transform_position_with_optional_matrix(self, pos, &self.matrix)
734 }
735 }
736
737 #[non_exhaustive]
745 pub struct Args<'a, A: Application> {
746 pub window: &'a mut MainWindowWithRenderer,
748 pub event_loop: &'a ActiveEventLoop,
750 pub event_proxy: &'a EventLoopProxy<AppEvent<A>>,
752 pub data: &'a mut A::Data,
754 }
755
756 pub struct LocalProxy<A: Application> {
760 event_proxy: EventLoopProxy<AppEvent<A>>,
761 pd: std::marker::PhantomData<*const ()>,
763 }
764
765 impl<A: Application> Clone for LocalProxy<A> {
766 fn clone(&self) -> Self {
767 LocalProxy {
768 event_proxy: self.event_proxy.clone(),
769 pd: std::marker::PhantomData,
770 }
771 }
772 }
773
774 macro_rules! local_proxy_impl {
775 () => {
776 pub fn spawn_idle<T: 'static, F: Future<Output = T> + 'static>(
778 &self,
779 f: F,
780 ) -> easy_imgui::future::FutureHandle<T> {
781 let idle_runner = fut::MyIdleRunner(self.event_proxy.clone());
782 unsafe { easy_imgui::future::spawn_idle(idle_runner, f) }
783 }
784 pub fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + 'static>(
786 &self,
787 f: F,
788 ) -> Result<(), winit::event_loop::EventLoopClosed<()>> {
789 let f = send_wrapper::SendWrapper::new(f);
792 self.event_proxy
795 .run_idle(move |app, args| (f.take())(app, args))
796 .map_err(|_| winit::event_loop::EventLoopClosed(()))
797 }
798 pub fn future_back(&self) -> FutureBackCaller<A> {
800 FutureBackCaller::new()
801 }
802 };
803 }
804
805 impl<A: Application> Args<'_, A> {
806 pub fn reborrow(&mut self) -> Args<'_, A> {
807 Args {
808 window: self.window,
809 event_loop: self.event_loop,
810 event_proxy: self.event_proxy,
811 data: self.data,
812 }
813 }
814 pub fn local_proxy(&self) -> LocalProxy<A> {
816 LocalProxy {
817 event_proxy: self.event_proxy.clone(),
818 pd: std::marker::PhantomData,
819 }
820 }
821 pub fn ping_user_input(&mut self) {
823 self.window.ping_user_input();
824 }
825 local_proxy_impl! {}
826 }
827
828 impl<A: Application> LocalProxy<A> {
829 pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
831 &self.event_proxy
832 }
833 local_proxy_impl! {}
834 }
835
836 pub trait Application: imgui::UiBuilder + Sized + 'static {
840 type UserEvent: Send + 'static;
842 type Data;
844
845 const EVENT_FLAGS: EventFlags = EventFlags::empty();
847
848 fn new(args: Args<'_, Self>) -> Self;
850
851 fn window_event(
857 &mut self,
858 args: Args<'_, Self>,
859 _event: winit::event::WindowEvent,
860 res: EventResult,
861 ) {
862 if res.window_closed {
863 args.event_loop.exit();
864 }
865 }
866
867 fn window_event_full(&mut self, args: Args<'_, Self>, event: winit::event::WindowEvent) {
871 let res = args.window.window_event(self, &event, Self::EVENT_FLAGS);
872 self.window_event(args, event, res);
873 }
874
875 fn device_event(
879 &mut self,
880 _args: Args<'_, Self>,
881 _device_id: winit::event::DeviceId,
882 _event: winit::event::DeviceEvent,
883 ) {
884 }
885
886 fn user_event(&mut self, _args: Args<'_, Self>, _event: Self::UserEvent) {}
888
889 fn suspended(&mut self, _args: Args<'_, Self>) {}
891
892 fn resumed(&mut self, _args: Args<'_, Self>) {}
894 }
895
896 #[non_exhaustive]
900 pub enum AppEvent<A: Application> {
901 PingUserInput,
903 #[allow(clippy::type_complexity)]
905 RunIdle(Box<dyn FnOnce(&mut A, Args<'_, A>) + Send + Sync>),
906 RunIdleSimple(Box<dyn FnOnce() + Send + Sync>),
908 User(A::UserEvent),
910 }
911
912 impl<A: Application> std::fmt::Debug for AppEvent<A> {
913 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
914 write!(fmt, "<AppEvent>")
915 }
916 }
917
918 pub trait EventLoopExt<A: Application> {
920 fn send_user(
922 &self,
923 u: A::UserEvent,
924 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
925 fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
927 fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
929 &self,
930 f: F,
931 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
932 }
933
934 impl<A: Application> EventLoopExt<A> for EventLoopProxy<AppEvent<A>> {
935 fn send_user(
936 &self,
937 u: A::UserEvent,
938 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
939 self.send_event(AppEvent::User(u))
940 }
941 fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
942 self.send_event(AppEvent::PingUserInput)
943 }
944 fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
945 &self,
946 f: F,
947 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
948 self.send_event(AppEvent::RunIdle(Box::new(f)))
949 }
950 }
951
952 pub struct AppHandler<A: Application> {
967 builder: imgui::ContextBuilder,
968 wattrs: WindowAttributes,
969 event_proxy: EventLoopProxy<AppEvent<A>>,
970 window: Option<MainWindowWithRenderer>,
971 app: Option<A>,
972 app_data: A::Data,
973 }
974
975 impl<A: Application> AppHandler<A> {
976 pub fn new(event_loop: &EventLoop<AppEvent<A>>, app_data: A::Data) -> Self {
980 AppHandler {
981 builder: imgui::ContextBuilder::new(),
982 wattrs: Window::default_attributes(),
983 event_proxy: event_loop.create_proxy(),
984 window: None,
985 app: None,
986 app_data,
987 }
988 }
989 pub fn imgui_builder(&mut self) -> &mut imgui::ContextBuilder {
993 &mut self.builder
994 }
995 pub fn set_attributes(&mut self, wattrs: WindowAttributes) {
997 self.wattrs = wattrs;
998 }
999 pub fn attributes(&mut self) -> &mut WindowAttributes {
1004 &mut self.wattrs
1005 }
1006 pub fn data(&self) -> &A::Data {
1008 &self.app_data
1009 }
1010 pub fn data_mut(&mut self) -> &mut A::Data {
1012 &mut self.app_data
1013 }
1014 pub fn app(&self) -> Option<&A> {
1016 self.app.as_ref()
1017 }
1018 pub fn app_mut(&mut self) -> Option<&mut A> {
1020 self.app.as_mut()
1021 }
1022 pub fn into_inner(self) -> (Option<A>, A::Data) {
1027 (self.app, self.app_data)
1028 }
1029
1030 pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
1032 &self.event_proxy
1033 }
1034 }
1035
1036 impl<A> winit::application::ApplicationHandler<AppEvent<A>> for AppHandler<A>
1037 where
1038 A: Application,
1039 {
1040 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
1041 let Some(window) = self.window.as_mut() else {
1042 return;
1043 };
1044 if let Some(app) = &mut self.app {
1045 let args = Args {
1046 window,
1047 event_loop,
1048 event_proxy: &self.event_proxy,
1049 data: &mut self.app_data,
1050 };
1051 app.suspended(args);
1052 }
1053 self.window = None;
1054 }
1055 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
1056 let main_window = MainWindow::new(event_loop, self.wattrs.clone()).unwrap();
1057 let mut window = MainWindowWithRenderer::with_builder(main_window, &self.builder);
1058
1059 let args = Args {
1060 window: &mut window,
1061 event_loop,
1062 event_proxy: &self.event_proxy,
1063 data: &mut self.app_data,
1064 };
1065 match &mut self.app {
1066 None => self.app = Some(A::new(args)),
1067 Some(app) => app.resumed(args),
1068 }
1069 self.window = Some(window);
1070 }
1071 fn window_event(
1072 &mut self,
1073 event_loop: &ActiveEventLoop,
1074 window_id: winit::window::WindowId,
1075 event: winit::event::WindowEvent,
1076 ) {
1077 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1078 return;
1079 };
1080 let w = window.main_window();
1081 if w.window().id() != window_id {
1082 return;
1083 }
1084
1085 let args = Args {
1086 window,
1087 event_loop,
1088 event_proxy: &self.event_proxy,
1089 data: &mut self.app_data,
1090 };
1091 app.window_event_full(args, event);
1092 }
1093 fn device_event(
1094 &mut self,
1095 event_loop: &ActiveEventLoop,
1096 device_id: winit::event::DeviceId,
1097 event: winit::event::DeviceEvent,
1098 ) {
1099 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1100 return;
1101 };
1102 let args = Args {
1103 window,
1104 event_loop,
1105 event_proxy: &self.event_proxy,
1106 data: &mut self.app_data,
1107 };
1108 app.device_event(args, device_id, event);
1109 }
1110 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppEvent<A>) {
1111 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1112 return;
1113 };
1114 let args = Args {
1115 window,
1116 event_loop,
1117 event_proxy: &self.event_proxy,
1118 data: &mut self.app_data,
1119 };
1120
1121 match event {
1122 AppEvent::PingUserInput => window.ping_user_input(),
1123 AppEvent::RunIdle(f) => f(app, args),
1124 AppEvent::RunIdleSimple(f) => fut::FutureBackCaller::prepare(app, args, f),
1125 AppEvent::User(uevent) => app.user_event(args, uevent),
1126 }
1127 }
1128 fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
1129 let Some(window) = self.window.as_mut() else {
1130 return;
1131 };
1132 window.new_events();
1133 }
1134 fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
1135 let Some(window) = self.window.as_mut() else {
1136 return;
1137 };
1138 window.about_to_wait();
1139 }
1140 }
1141}
1142
1143#[cfg(feature = "main-window")]
1144pub use main_window::*;