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 ScaleFactorChanged { scale_factor, .. } => {
286 if !flags.contains(EventFlags::DoNotResize) {
287 main_window.ping_user_input();
288 let scale_factor = main_window.set_scale_factor(*scale_factor as f32);
289 unsafe {
290 let io = renderer.imgui().io_mut().inner();
291 let old_scale_factor = io.DisplayFramebufferScale.x;
294 if io.MousePos.x.is_finite() && io.MousePos.y.is_finite() {
295 io.MousePos.x *= scale_factor / old_scale_factor;
296 io.MousePos.y *= scale_factor / old_scale_factor;
297 }
298 }
299 let size = renderer.size();
300 renderer.set_size(size, scale_factor);
301 }
302 }
303 ModifiersChanged(mods) => {
304 main_window.ping_user_input();
305 unsafe {
306 let io = renderer.imgui().io_mut().inner();
307 io.AddKeyEvent(imgui::Key::ModCtrl.bits(), mods.state().control_key());
308 io.AddKeyEvent(imgui::Key::ModShift.bits(), mods.state().shift_key());
309 io.AddKeyEvent(imgui::Key::ModAlt.bits(), mods.state().alt_key());
310 io.AddKeyEvent(imgui::Key::ModSuper.bits(), mods.state().super_key());
311 }
312 }
313 KeyboardInput {
314 event:
315 winit::event::KeyEvent {
316 physical_key,
317 text,
318 state,
319 ..
320 },
321 is_synthetic: false,
322 ..
323 } => {
324 main_window.ping_user_input();
325 let pressed = *state == winit::event::ElementState::Pressed;
326 if let Some(key) = to_imgui_key(*physical_key) {
327 unsafe {
328 let io = renderer.imgui().io_mut().inner();
329 io.AddKeyEvent(key.bits(), pressed);
330
331 use winit::keyboard::KeyCode::*;
332 if let PhysicalKey::Code(keycode) = physical_key {
333 let kmod = match keycode {
334 ControlLeft | ControlRight => Some(imgui::Key::ModCtrl),
335 ShiftLeft | ShiftRight => Some(imgui::Key::ModShift),
336 AltLeft | AltRight => Some(imgui::Key::ModAlt),
337 SuperLeft | SuperRight => Some(imgui::Key::ModSuper),
338 _ => None,
339 };
340 if let Some(kmod) = kmod {
341 io.AddKeyEvent(kmod.bits(), pressed);
342 }
343 }
344 }
345 }
346 if pressed && let Some(text) = text {
347 unsafe {
348 let io = renderer.imgui().io_mut().inner();
349 for c in text.chars() {
350 io.AddInputCharacter(c as u32);
351 }
352 }
353 }
354 }
355 Ime(Commit(text)) => {
356 main_window.ping_user_input();
357 unsafe {
358 let io = renderer.imgui().io_mut().inner();
359 for c in text.chars() {
360 io.AddInputCharacter(c as u32);
361 }
362 }
363 }
364 CursorMoved { position, .. } => {
365 main_window.ping_user_input();
366 unsafe {
367 let io = renderer.imgui().io_mut().inner();
368 let position = main_window
369 .transform_position(Vector2::new(position.x as f32, position.y as f32));
370 io.AddMousePosEvent(position.x, position.y);
371 }
372 }
373 MouseWheel {
374 delta,
375 phase: winit::event::TouchPhase::Moved,
376 ..
377 } => {
378 main_window.ping_user_input();
379 let mut imgui = unsafe { renderer.imgui().set_current() };
380 unsafe {
381 let io = imgui.io_mut().inner();
382 let (h, v) = match delta {
383 winit::event::MouseScrollDelta::LineDelta(h, v) => (*h, *v),
384 winit::event::MouseScrollDelta::PixelDelta(d) => {
385 let scale = io.DisplayFramebufferScale.x;
386 let f_scale = ImGui_GetFontSize();
387 let scale = scale * f_scale;
388 (d.x as f32 / scale, d.y as f32 / scale)
389 }
390 };
391 io.AddMouseWheelEvent(h, v);
392 }
393 }
394 MouseInput { state, button, .. } => {
395 main_window.ping_user_input();
396 unsafe {
397 let io = renderer.imgui().io_mut().inner();
398 if let Some(btn) = to_imgui_button(*button) {
399 let pressed = *state == winit::event::ElementState::Pressed;
400 io.AddMouseButtonEvent(btn.bits(), pressed);
401 }
402 }
403 }
404 CursorLeft { .. } => {
405 main_window.ping_user_input();
406 unsafe {
407 let io = renderer.imgui().io_mut().inner();
408 io.AddMousePosEvent(f32::MAX, f32::MAX);
409 }
410 }
411 Focused(focused) => {
412 main_window.ping_user_input();
413 unsafe {
414 let io = renderer.imgui().io_mut().inner();
415 io.AddFocusEvent(*focused);
416 }
417 }
418 _ => {}
419 }
420 let imgui = renderer.imgui();
421 EventResult::new(imgui, window_closed)
422}
423
424#[cfg(feature = "main-window")]
425mod main_window {
426 use super::*;
427 use std::future::Future;
428 mod fut;
429 use anyhow::{Result, anyhow};
430 use easy_imgui::Idler;
431 use easy_imgui_renderer::glow;
432 pub use fut::FutureBackCaller;
433 use glutin::{
434 config::{Config, ConfigTemplateBuilder},
435 context::{ContextApi, ContextAttributesBuilder},
436 display::GetGlDisplay,
437 surface::SurfaceAttributesBuilder,
438 };
439 use glutin_winit::DisplayBuilder;
440 use raw_window_handle::HasWindowHandle;
441 use winit::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
442 use winit::window::WindowAttributes;
443
444 pub struct MainWindow {
446 gl_context: PossiblyCurrentContext,
447 surface: Surface<WindowSurface>,
449 window: Window,
450 matrix: Option<Matrix3<f32>>,
451 idler: Idler,
452 }
453
454 pub struct MainWindowWithRenderer {
457 main_window: MainWindow,
458 renderer: Renderer,
459 status: MainWindowStatus,
460 }
461
462 impl MainWindow {
463 pub fn new(event_loop: &ActiveEventLoop, wattr: WindowAttributes) -> Result<MainWindow> {
465 let score = |c: &Config| (c.num_samples(), c.depth_size(), c.stencil_size());
467 Self::with_gl_chooser(event_loop, wattr, |cfg1, cfg2| {
468 if score(&cfg2) < score(&cfg1) {
469 cfg2
470 } else {
471 cfg1
472 }
473 })
474 }
475 pub fn with_gl_chooser(
480 event_loop: &ActiveEventLoop,
481 wattr: WindowAttributes,
482 f_choose_cfg: impl FnMut(Config, Config) -> Config,
483 ) -> Result<MainWindow> {
484 let template = ConfigTemplateBuilder::new()
485 .prefer_hardware_accelerated(Some(true))
486 .with_depth_size(0)
487 .with_stencil_size(0);
488
489 let display_builder = DisplayBuilder::new().with_window_attributes(Some(wattr));
490 let (window, gl_config) = display_builder
491 .build(event_loop, template, |configs| {
492 configs.reduce(f_choose_cfg).unwrap()
493 })
494 .map_err(|e| anyhow!("{:#?}", e))?;
495 let window = window.unwrap();
496 window.set_ime_allowed(true);
497 let raw_window_handle = Some(window.window_handle().unwrap().as_raw());
498 let gl_display = gl_config.display();
499 let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);
500 let fallback_context_attributes = ContextAttributesBuilder::new()
501 .with_context_api(ContextApi::Gles(None))
502 .build(raw_window_handle);
503
504 let mut not_current_gl_context = Some(unsafe {
505 gl_display
506 .create_context(&gl_config, &context_attributes)
507 .or_else(|_| {
508 gl_display.create_context(&gl_config, &fallback_context_attributes)
509 })?
510 });
511
512 let size = window.inner_size();
513
514 let (width, height): (u32, u32) = size.into();
515 let raw_window_handle = window.window_handle().unwrap().as_raw();
516 let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
517 raw_window_handle,
518 NonZeroU32::new(width).unwrap(),
519 NonZeroU32::new(height).unwrap(),
520 );
521
522 let surface = unsafe {
523 gl_config
524 .display()
525 .create_window_surface(&gl_config, &attrs)?
526 };
527 let gl_context = not_current_gl_context
528 .take()
529 .unwrap()
530 .make_current(&surface)?;
531
532 let _ = surface.set_swap_interval(
534 &gl_context,
535 glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap()),
536 );
537
538 Ok(MainWindow {
539 gl_context,
540 window,
541 surface,
542 matrix: None,
543 idler: Idler::default(),
544 })
545 }
546 pub fn set_matrix(&mut self, matrix: Option<Matrix3<f32>>) {
548 self.matrix = matrix;
549 }
550
551 pub unsafe fn into_pieces(
556 self,
557 ) -> (PossiblyCurrentContext, Surface<WindowSurface>, Window) {
558 (self.gl_context, self.surface, self.window)
559 }
560 pub fn glutin_context(&self) -> &PossiblyCurrentContext {
562 &self.gl_context
563 }
564 pub fn create_gl_context(&self) -> glow::Context {
566 let dsp = self.gl_context.display();
567 unsafe { glow::Context::from_loader_function_cstr(|s| dsp.get_proc_address(s)) }
568 }
569 pub fn window(&self) -> &Window {
571 &self.window
572 }
573 pub fn surface(&self) -> &Surface<WindowSurface> {
575 &self.surface
576 }
577 pub fn to_logical_size<X: Pixel, Y: Pixel>(&self, size: PhysicalSize<X>) -> LogicalSize<Y> {
579 let scale = self.window.scale_factor();
580 size.to_logical(scale)
581 }
582 pub fn to_physical_size<X: Pixel, Y: Pixel>(
584 &self,
585 size: LogicalSize<X>,
586 ) -> PhysicalSize<Y> {
587 let scale = self.window.scale_factor();
588 size.to_physical(scale)
589 }
590 pub fn to_logical_pos<X: Pixel, Y: Pixel>(
592 &self,
593 pos: PhysicalPosition<X>,
594 ) -> LogicalPosition<Y> {
595 let scale = self.window.scale_factor();
596 pos.to_logical(scale)
597 }
598 pub fn to_physical_pos<X: Pixel, Y: Pixel>(
600 &self,
601 pos: LogicalPosition<X>,
602 ) -> PhysicalPosition<Y> {
603 let scale = self.window.scale_factor();
604 pos.to_physical(scale)
605 }
606 }
607
608 impl MainWindowWithRenderer {
609 pub fn new(main_window: MainWindow) -> Self {
611 Self::with_builder(main_window, &imgui::ContextBuilder::new())
612 }
613 pub fn with_builder(main_window: MainWindow, builder: &imgui::ContextBuilder) -> Self {
617 let gl = main_window.create_gl_context();
618 let renderer = Renderer::with_builder(std::rc::Rc::new(gl), builder).unwrap();
619 Self::new_with_renderer(main_window, renderer)
620 }
621 pub fn set_idle_time(&mut self, time: Duration) {
623 self.main_window.idler.set_idle_time(time);
624 }
625 pub fn set_idle_frame_count(&mut self, frame_count: u32) {
629 self.main_window.idler.set_idle_frame_count(frame_count);
630 }
631 pub fn ping_user_input(&mut self) {
636 self.main_window.idler.ping_user_input();
637 }
638 pub fn renderer(&mut self) -> &mut Renderer {
640 &mut self.renderer
641 }
642 pub fn imgui(&mut self) -> &mut imgui::Context {
646 self.renderer.imgui()
647 }
648 pub fn main_window(&mut self) -> &mut MainWindow {
650 &mut self.main_window
651 }
652 pub fn new_with_renderer(main_window: MainWindow, mut renderer: Renderer) -> Self {
654 let w = main_window.window();
655 let size = w.inner_size();
656 let scale = w.scale_factor();
657 let size = size.to_logical::<f32>(scale);
658 renderer.set_size(Vector2::from(mint::Vector2::from(size)), scale as f32);
659
660 MainWindowWithRenderer {
661 main_window,
662 renderer,
663 status: MainWindowStatus::default(),
664 }
665 }
666 pub fn window_event(
671 &mut self,
672 app: &mut impl imgui::UiBuilder,
673 event: &winit::event::WindowEvent,
674 flags: EventFlags,
675 ) -> EventResult {
676 window_event(
677 &mut self.main_window,
678 &mut self.renderer,
679 &mut self.status,
680 app,
681 event,
682 flags,
683 )
684 }
685
686 pub fn new_events(&mut self) {
688 new_events(&mut self.renderer, &mut self.status);
689 }
690 pub fn about_to_wait(&mut self) {
692 about_to_wait(&mut self.main_window, &mut self.renderer);
693 }
694 }
695
696 impl MainWindowRef for MainWindow {
698 fn window(&self) -> &Window {
699 &self.window
700 }
701 fn pre_render(&mut self) {
702 self.idler.incr_frame();
703 let _ = self
704 .gl_context
705 .make_current(&self.surface)
706 .inspect_err(|e| log::error!("{e}"));
707 }
708 fn post_render(&mut self) {
709 self.window.pre_present_notify();
710 let _ = self
711 .surface
712 .swap_buffers(&self.gl_context)
713 .inspect_err(|e| log::error!("{e}"));
714 }
715 fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
716 let width = NonZeroU32::new(size.width.max(1)).unwrap();
717 let height = NonZeroU32::new(size.height.max(1)).unwrap();
718 self.surface.resize(&self.gl_context, width, height);
719 self.to_logical_size::<_, f32>(size)
720 }
721 fn ping_user_input(&mut self) {
722 self.idler.ping_user_input();
723 }
724 fn about_to_wait(&mut self, pinged: bool) {
725 if pinged || self.idler.has_to_render() {
726 self.window.request_redraw();
729 }
730 }
731 fn transform_position(&self, pos: Vector2) -> Vector2 {
732 transform_position_with_optional_matrix(self, pos, &self.matrix)
733 }
734 }
735
736 #[non_exhaustive]
744 pub struct Args<'a, A: Application> {
745 pub window: &'a mut MainWindowWithRenderer,
747 pub event_loop: &'a ActiveEventLoop,
749 pub event_proxy: &'a EventLoopProxy<AppEvent<A>>,
751 pub data: &'a mut A::Data,
753 }
754
755 pub struct LocalProxy<A: Application> {
759 event_proxy: EventLoopProxy<AppEvent<A>>,
760 pd: std::marker::PhantomData<*const ()>,
762 }
763
764 impl<A: Application> Clone for LocalProxy<A> {
765 fn clone(&self) -> Self {
766 LocalProxy {
767 event_proxy: self.event_proxy.clone(),
768 pd: std::marker::PhantomData,
769 }
770 }
771 }
772
773 macro_rules! local_proxy_impl {
774 () => {
775 pub fn spawn_idle<T: 'static, F: Future<Output = T> + 'static>(
777 &self,
778 f: F,
779 ) -> easy_imgui::future::FutureHandle<T> {
780 let idle_runner = fut::MyIdleRunner(self.event_proxy.clone());
781 unsafe { easy_imgui::future::spawn_idle(idle_runner, f) }
782 }
783 pub fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + 'static>(
785 &self,
786 f: F,
787 ) -> Result<(), winit::event_loop::EventLoopClosed<()>> {
788 let f = send_wrapper::SendWrapper::new(f);
791 self.event_proxy
794 .run_idle(move |app, args| (f.take())(app, args))
795 .map_err(|_| winit::event_loop::EventLoopClosed(()))
796 }
797 pub fn future_back(&self) -> FutureBackCaller<A> {
799 FutureBackCaller::new()
800 }
801 };
802 }
803
804 impl<A: Application> Args<'_, A> {
805 pub fn reborrow(&mut self) -> Args<'_, A> {
806 Args {
807 window: self.window,
808 event_loop: self.event_loop,
809 event_proxy: self.event_proxy,
810 data: self.data,
811 }
812 }
813 pub fn local_proxy(&self) -> LocalProxy<A> {
815 LocalProxy {
816 event_proxy: self.event_proxy.clone(),
817 pd: std::marker::PhantomData,
818 }
819 }
820 pub fn ping_user_input(&mut self) {
822 self.window.ping_user_input();
823 }
824 local_proxy_impl! {}
825 }
826
827 impl<A: Application> LocalProxy<A> {
828 pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
830 &self.event_proxy
831 }
832 local_proxy_impl! {}
833 }
834
835 pub trait Application: imgui::UiBuilder + Sized + 'static {
839 type UserEvent: Send + 'static;
841 type Data;
843
844 const EVENT_FLAGS: EventFlags = EventFlags::empty();
846
847 fn new(args: Args<'_, Self>) -> Self;
849
850 fn window_event(
856 &mut self,
857 args: Args<'_, Self>,
858 _event: winit::event::WindowEvent,
859 res: EventResult,
860 ) {
861 if res.window_closed {
862 args.event_loop.exit();
863 }
864 }
865
866 fn window_event_full(&mut self, args: Args<'_, Self>, event: winit::event::WindowEvent) {
870 let res = args.window.window_event(self, &event, Self::EVENT_FLAGS);
871 self.window_event(args, event, res);
872 }
873
874 fn device_event(
878 &mut self,
879 _args: Args<'_, Self>,
880 _device_id: winit::event::DeviceId,
881 _event: winit::event::DeviceEvent,
882 ) {
883 }
884
885 fn user_event(&mut self, _args: Args<'_, Self>, _event: Self::UserEvent) {}
887
888 fn suspended(&mut self, _args: Args<'_, Self>) {}
890
891 fn resumed(&mut self, _args: Args<'_, Self>) {}
893 }
894
895 #[non_exhaustive]
899 pub enum AppEvent<A: Application> {
900 PingUserInput,
902 #[allow(clippy::type_complexity)]
904 RunIdle(Box<dyn FnOnce(&mut A, Args<'_, A>) + Send + Sync>),
905 RunIdleSimple(Box<dyn FnOnce() + Send + Sync>),
907 User(A::UserEvent),
909 }
910
911 impl<A: Application> std::fmt::Debug for AppEvent<A> {
912 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
913 write!(fmt, "<AppEvent>")
914 }
915 }
916
917 pub trait EventLoopExt<A: Application> {
919 fn send_user(
921 &self,
922 u: A::UserEvent,
923 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
924 fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
926 fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
928 &self,
929 f: F,
930 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
931 }
932
933 impl<A: Application> EventLoopExt<A> for EventLoopProxy<AppEvent<A>> {
934 fn send_user(
935 &self,
936 u: A::UserEvent,
937 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
938 self.send_event(AppEvent::User(u))
939 }
940 fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
941 self.send_event(AppEvent::PingUserInput)
942 }
943 fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
944 &self,
945 f: F,
946 ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
947 self.send_event(AppEvent::RunIdle(Box::new(f)))
948 }
949 }
950
951 pub struct AppHandler<A: Application> {
966 builder: imgui::ContextBuilder,
967 wattrs: WindowAttributes,
968 event_proxy: EventLoopProxy<AppEvent<A>>,
969 window: Option<MainWindowWithRenderer>,
970 app: Option<A>,
971 app_data: A::Data,
972 }
973
974 impl<A: Application> AppHandler<A> {
975 pub fn new(event_loop: &EventLoop<AppEvent<A>>, app_data: A::Data) -> Self {
979 AppHandler {
980 builder: imgui::ContextBuilder::new(),
981 wattrs: Window::default_attributes(),
982 event_proxy: event_loop.create_proxy(),
983 window: None,
984 app: None,
985 app_data,
986 }
987 }
988 pub fn imgui_builder(&mut self) -> &mut imgui::ContextBuilder {
992 &mut self.builder
993 }
994 pub fn set_attributes(&mut self, wattrs: WindowAttributes) {
996 self.wattrs = wattrs;
997 }
998 pub fn attributes(&mut self) -> &mut WindowAttributes {
1003 &mut self.wattrs
1004 }
1005 pub fn data(&self) -> &A::Data {
1007 &self.app_data
1008 }
1009 pub fn data_mut(&mut self) -> &mut A::Data {
1011 &mut self.app_data
1012 }
1013 pub fn app(&self) -> Option<&A> {
1015 self.app.as_ref()
1016 }
1017 pub fn app_mut(&mut self) -> Option<&mut A> {
1019 self.app.as_mut()
1020 }
1021 pub fn into_inner(self) -> (Option<A>, A::Data) {
1026 (self.app, self.app_data)
1027 }
1028
1029 pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
1031 &self.event_proxy
1032 }
1033 }
1034
1035 impl<A> winit::application::ApplicationHandler<AppEvent<A>> for AppHandler<A>
1036 where
1037 A: Application,
1038 {
1039 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
1040 let Some(window) = self.window.as_mut() else {
1041 return;
1042 };
1043 if let Some(app) = &mut self.app {
1044 let args = Args {
1045 window,
1046 event_loop,
1047 event_proxy: &self.event_proxy,
1048 data: &mut self.app_data,
1049 };
1050 app.suspended(args);
1051 }
1052 self.window = None;
1053 }
1054 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
1055 let main_window = MainWindow::new(event_loop, self.wattrs.clone()).unwrap();
1056 let mut window = MainWindowWithRenderer::with_builder(main_window, &self.builder);
1057
1058 let args = Args {
1059 window: &mut window,
1060 event_loop,
1061 event_proxy: &self.event_proxy,
1062 data: &mut self.app_data,
1063 };
1064 match &mut self.app {
1065 None => self.app = Some(A::new(args)),
1066 Some(app) => app.resumed(args),
1067 }
1068 self.window = Some(window);
1069 }
1070 fn window_event(
1071 &mut self,
1072 event_loop: &ActiveEventLoop,
1073 window_id: winit::window::WindowId,
1074 event: winit::event::WindowEvent,
1075 ) {
1076 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1077 return;
1078 };
1079 let w = window.main_window();
1080 if w.window().id() != window_id {
1081 return;
1082 }
1083
1084 let args = Args {
1085 window,
1086 event_loop,
1087 event_proxy: &self.event_proxy,
1088 data: &mut self.app_data,
1089 };
1090 app.window_event_full(args, event);
1091 }
1092 fn device_event(
1093 &mut self,
1094 event_loop: &ActiveEventLoop,
1095 device_id: winit::event::DeviceId,
1096 event: winit::event::DeviceEvent,
1097 ) {
1098 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1099 return;
1100 };
1101 let args = Args {
1102 window,
1103 event_loop,
1104 event_proxy: &self.event_proxy,
1105 data: &mut self.app_data,
1106 };
1107 app.device_event(args, device_id, event);
1108 }
1109 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppEvent<A>) {
1110 let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1111 return;
1112 };
1113 let args = Args {
1114 window,
1115 event_loop,
1116 event_proxy: &self.event_proxy,
1117 data: &mut self.app_data,
1118 };
1119
1120 match event {
1121 AppEvent::PingUserInput => window.ping_user_input(),
1122 AppEvent::RunIdle(f) => f(app, args),
1123 AppEvent::RunIdleSimple(f) => fut::FutureBackCaller::prepare(app, args, f),
1124 AppEvent::User(uevent) => app.user_event(args, uevent),
1125 }
1126 }
1127 fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
1128 let Some(window) = self.window.as_mut() else {
1129 return;
1130 };
1131 window.new_events();
1132 }
1133 fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
1134 let Some(window) = self.window.as_mut() else {
1135 return;
1136 };
1137 window.about_to_wait();
1138 }
1139 }
1140}
1141
1142#[cfg(feature = "main-window")]
1143pub use main_window::*;