easy_imgui_window/
window.rs

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
20// Only used with the main-window feature
21#[allow(unused_imports)]
22use winit::dpi::{LogicalPosition, PhysicalPosition, Pixel};
23
24/// This struct maintains basic window info to be kept across events.
25#[derive(Debug, Clone)]
26pub struct MainWindowStatus {
27    last_frame: Instant,
28    current_cursor: Option<CursorIcon>,
29}
30
31impl Default for MainWindowStatus {
32    fn default() -> MainWindowStatus {
33        let now = Instant::now();
34        MainWindowStatus {
35            last_frame: now,
36            current_cursor: Some(CursorIcon::Default),
37        }
38    }
39}
40
41/// This struct handles the main loop going to idle when there is no user input for a while.
42pub struct MainWindowIdler {
43    idle_time: Duration,
44    idle_frame_count: u32,
45    last_input_time: Instant,
46    last_input_frame: u32,
47}
48
49impl Default for MainWindowIdler {
50    fn default() -> MainWindowIdler {
51        let now = Instant::now();
52        MainWindowIdler {
53            idle_time: Duration::from_secs(1),
54            idle_frame_count: 60,
55            last_input_time: now,
56            last_input_frame: 0,
57        }
58    }
59}
60
61impl MainWindowIdler {
62    /// Sets the maximum time that the window will be rendered without user input.
63    pub fn set_idle_time(&mut self, time: Duration) {
64        self.idle_time = time;
65    }
66    /// Sets the maximum number of frames time that the window will be rendered without user input.
67    pub fn set_idle_frame_count(&mut self, frame_count: u32) {
68        self.idle_frame_count = frame_count;
69    }
70    /// Call this when the window is renderer.
71    pub fn incr_frame(&mut self) {
72        // An u32 incrementing 60 values/second would overflow after about 2 years, better safe
73        // than sorry.
74        self.last_input_frame = self.last_input_frame.saturating_add(1);
75    }
76    /// Check whether the window should go to idle or keep on rendering.
77    pub fn has_to_render(&self) -> bool {
78        self.last_input_frame < self.idle_frame_count
79            || Instant::now().duration_since(self.last_input_time) < self.idle_time
80    }
81    /// Notify this struct that user input happened.
82    pub fn ping_user_input(&mut self) {
83        self.last_input_time = Instant::now();
84        self.last_input_frame = 0;
85    }
86}
87
88/// This traits grants access to a Window.
89///
90/// Usually you will have a [`MainWindow`], but if you create the `Window` with an external
91/// crate, maybe you don't own it.
92pub trait MainWindowRef {
93    /// Gets the [`Window`].
94    fn window(&self) -> &Window;
95    /// This runs just before rendering.
96    ///
97    /// The intended use is to make the GL context current, if needed.
98    /// Clearing the background is usually done in [`easy_imgui::UiBuilder::pre_render`], or by the renderer if it has a background color.
99    fn pre_render(&mut self) {}
100    /// This runs just after rendering.
101    ///
102    /// The intended use is to present the screen buffer.
103    fn post_render(&mut self) {}
104    /// Notifies of a user interaction, for idling purposes.
105    fn ping_user_input(&mut self) {}
106    /// There are no more messages, going to idle.
107    fn about_to_wait(&mut self, _pinged: bool) {}
108    /// Transform the given `pos` by using the current scale factor.
109    fn transform_position(&self, pos: Vector2) -> Vector2 {
110        pos / self.scale_factor()
111    }
112    /// Gets the scale factor of the window, (HiDPI).
113    fn scale_factor(&self) -> f32 {
114        self.window().scale_factor() as f32
115    }
116    /// Changes the scale factor.
117    ///
118    /// Normally there is nothing to be done here, unless you are doing something fancy with HiDPI.
119    ///
120    /// It returns the real applied scale factor, as it would returned by
121    /// `self.scale_factor()` after this change has been applied.
122    fn set_scale_factor(&self, scale: f32) -> f32 {
123        scale
124    }
125    /// The window has been resized.
126    ///
127    /// Takes the new physical size. It should return the new logical size.
128    fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
129        let scale = self.scale_factor();
130        size.to_logical(scale as f64)
131    }
132    /// Changes the mouse cursor.
133    fn set_cursor(&mut self, cursor: Option<CursorIcon>) {
134        let w = self.window();
135        match cursor {
136            None => w.set_cursor_visible(false),
137            Some(c) => {
138                w.set_cursor(c);
139                w.set_cursor_visible(true);
140            }
141        }
142    }
143}
144
145fn transform_position_with_optional_matrix(
146    w: &impl MainWindowRef,
147    pos: Vector2,
148    mx: &Option<Matrix3<f32>>,
149) -> Vector2 {
150    use cgmath::{EuclideanSpace as _, Transform};
151    match mx {
152        Some(mx) => mx.transform_point(cgmath::Point2::from_vec(pos)).to_vec(),
153        None => pos / w.scale_factor(),
154    }
155}
156
157bitflags::bitflags! {
158    /// These flags can be used to customize the [`window_event`] function.
159    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
160    pub struct EventFlags: u32 {
161        /// Do not render the UI
162        const DoNotRender = 1;
163        /// Do not change the size or scale of the UI
164        const DoNotResize = 4;
165        /// Do not send mouse positions
166        const DoNotMouse = 8;
167    }
168}
169
170/// Helper struct to call [`window_event`] without owning the Window.
171pub struct MainWindowPieces<'a> {
172    window: &'a Window,
173    surface: &'a Surface<WindowSurface>,
174    gl_context: &'a PossiblyCurrentContext,
175    matrix: Option<Matrix3<f32>>,
176}
177
178impl<'a> MainWindowPieces<'a> {
179    /// Creates a value from the pieces.
180    pub fn new(
181        window: &'a Window,
182        surface: &'a Surface<WindowSurface>,
183        gl_context: &'a PossiblyCurrentContext,
184    ) -> Self {
185        MainWindowPieces {
186            window,
187            surface,
188            gl_context,
189            matrix: None,
190        }
191    }
192    /// Sets the matrix that transforms the input mouse coordinates into UI space.
193    ///
194    /// If none, it uses the default transformation.
195    pub fn set_matrix(&mut self, matrix: Option<Matrix3<f32>>) {
196        self.matrix = matrix;
197    }
198}
199
200/// Default implementation if you have all the pieces.
201impl MainWindowRef for MainWindowPieces<'_> {
202    fn window(&self) -> &Window {
203        self.window
204    }
205    fn pre_render(&mut self) {
206        let _ = self
207            .gl_context
208            .make_current(self.surface)
209            .inspect_err(|e| log::error!("{e}"));
210    }
211    fn post_render(&mut self) {
212        self.window.pre_present_notify();
213        let _ = self
214            .surface
215            .swap_buffers(self.gl_context)
216            .inspect_err(|e| log::error!("{e}"));
217    }
218    fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
219        let width = NonZeroU32::new(size.width.max(1)).unwrap();
220        let height = NonZeroU32::new(size.height.max(1)).unwrap();
221        self.surface.resize(self.gl_context, width, height);
222        let scale = self.scale_factor();
223        size.to_logical(scale as f64)
224    }
225    fn transform_position(&self, pos: Vector2) -> Vector2 {
226        transform_position_with_optional_matrix(self, pos, &self.matrix)
227    }
228}
229
230/// Simple implementation if you only have a window, no pre/post render, no resize.
231impl MainWindowRef for &Window {
232    fn window(&self) -> &Window {
233        self
234    }
235}
236
237/// NewType to disable the HiDPI scaling.
238pub struct NoScale<'a>(pub &'a Window);
239
240impl MainWindowRef for NoScale<'_> {
241    fn window(&self) -> &Window {
242        self.0
243    }
244    fn scale_factor(&self) -> f32 {
245        1.0
246    }
247    fn set_scale_factor(&self, _scale: f32) -> f32 {
248        1.0
249    }
250}
251
252/// The result of processing an event in the ImGui loop.
253#[derive(Debug, Default, Clone)]
254pub struct EventResult {
255    /// The user requested to close the window. You can break the loop or ignore it, at will.
256    pub window_closed: bool,
257    /// ImGui requests handling the mouse, your application should ignore mouse events.
258    pub want_capture_mouse: bool,
259    /// ImGui requests handling the keyboard, your application should ignore keyboard events.
260    pub want_capture_keyboard: bool,
261    /// ImGui requests handling text input, your application should ignore text events.
262    pub want_text_input: bool,
263}
264
265/// Corresponds to winit's `ApplicationHandler::new_events`.
266pub fn new_events(renderer: &mut Renderer, status: &mut MainWindowStatus) {
267    let now = Instant::now();
268    unsafe {
269        renderer
270            .imgui()
271            .io_mut()
272            .inner()
273            .set_delta_time(now.duration_since(status.last_frame));
274    }
275    status.last_frame = now;
276}
277
278/// Corresponds to winit's `ApplicationHandler::about_to_wait`.
279pub fn about_to_wait(main_window: &mut impl MainWindowRef, renderer: &mut Renderer) {
280    let imgui = unsafe { renderer.imgui().set_current() };
281    let io = imgui.io();
282    if io.WantSetMousePos {
283        let pos = io.MousePos;
284        let pos = winit::dpi::LogicalPosition { x: pos.x, y: pos.y };
285        let _ = main_window.window().set_cursor_position(pos);
286    }
287    // If the mouse is down, redraw all the time, maybe the user is dragging.
288    let mouse = unsafe { ImGui_IsAnyMouseDown() };
289    main_window.about_to_wait(mouse);
290}
291
292/// Corresponds to winit's `ApplicationHandler::window_event`.
293pub fn window_event(
294    main_window: &mut impl MainWindowRef,
295    renderer: &mut Renderer,
296    status: &mut MainWindowStatus,
297    app: &mut impl imgui::UiBuilder,
298    event: &winit::event::WindowEvent,
299    flags: EventFlags,
300) -> EventResult {
301    use winit::event::WindowEvent::*;
302    let mut window_closed = false;
303    match event {
304        CloseRequested => {
305            window_closed = true;
306        }
307        RedrawRequested => unsafe {
308            let imgui = renderer.imgui().set_current();
309            let io = imgui.io();
310            let config_flags = imgui::ConfigFlags::from_bits_truncate(io.ConfigFlags);
311            if !config_flags.contains(imgui::ConfigFlags::NoMouseCursorChange) {
312                let cursor = if io.MouseDrawCursor {
313                    None
314                } else {
315                    let cursor = imgui::MouseCursor::from_bits(ImGui_GetMouseCursor())
316                        .unwrap_or(imgui::MouseCursor::Arrow);
317                    from_imgui_cursor(cursor)
318                };
319                if cursor != status.current_cursor {
320                    main_window.set_cursor(cursor);
321                    status.current_cursor = cursor;
322                }
323            }
324            if !flags.contains(EventFlags::DoNotRender) {
325                main_window.pre_render();
326                renderer.do_frame(app);
327                main_window.post_render();
328            }
329        },
330        Resized(size) => {
331            // Do not skip this line or the gl surface may be wrong in Wayland
332            // GL surface in physical pixels, imgui in logical
333            let size = main_window.resize(*size);
334            if !flags.contains(EventFlags::DoNotResize) {
335                main_window.ping_user_input();
336                // GL surface in physical pixels, imgui in logical
337                let size = Vector2::from(mint::Vector2::from(size));
338                unsafe {
339                    renderer.imgui().io_mut().inner().DisplaySize = imgui::v2_to_im(size);
340                }
341            }
342        }
343        ScaleFactorChanged { scale_factor, .. } => {
344            if !flags.contains(EventFlags::DoNotResize) {
345                main_window.ping_user_input();
346                let scale_factor = main_window.set_scale_factor(*scale_factor as f32);
347                unsafe {
348                    let io = renderer.imgui().io_mut().inner();
349                    // Keep the mouse in the same relative position: maybe it is wrong, but it is
350                    // the best guess we can do.
351                    let old_scale_factor = io.DisplayFramebufferScale.x;
352                    if io.MousePos.x.is_finite() && io.MousePos.y.is_finite() {
353                        io.MousePos.x *= scale_factor / old_scale_factor;
354                        io.MousePos.y *= scale_factor / old_scale_factor;
355                    }
356                }
357                let size = renderer.size();
358                renderer.set_size(size, scale_factor);
359            }
360        }
361        ModifiersChanged(mods) => {
362            main_window.ping_user_input();
363            unsafe {
364                let io = renderer.imgui().io_mut().inner();
365                io.AddKeyEvent(imgui::Key::ModCtrl.bits(), mods.state().control_key());
366                io.AddKeyEvent(imgui::Key::ModShift.bits(), mods.state().shift_key());
367                io.AddKeyEvent(imgui::Key::ModAlt.bits(), mods.state().alt_key());
368                io.AddKeyEvent(imgui::Key::ModSuper.bits(), mods.state().super_key());
369            }
370        }
371        KeyboardInput {
372            event:
373                winit::event::KeyEvent {
374                    physical_key,
375                    text,
376                    state,
377                    ..
378                },
379            is_synthetic: false,
380            ..
381        } => {
382            main_window.ping_user_input();
383            let pressed = *state == winit::event::ElementState::Pressed;
384            if let Some(key) = to_imgui_key(*physical_key) {
385                unsafe {
386                    let io = renderer.imgui().io_mut().inner();
387                    io.AddKeyEvent(key.bits(), pressed);
388
389                    use winit::keyboard::KeyCode::*;
390                    if let PhysicalKey::Code(keycode) = physical_key {
391                        let kmod = match keycode {
392                            ControlLeft | ControlRight => Some(imgui::Key::ModCtrl),
393                            ShiftLeft | ShiftRight => Some(imgui::Key::ModShift),
394                            AltLeft | AltRight => Some(imgui::Key::ModAlt),
395                            SuperLeft | SuperRight => Some(imgui::Key::ModSuper),
396                            _ => None,
397                        };
398                        if let Some(kmod) = kmod {
399                            io.AddKeyEvent(kmod.bits(), pressed);
400                        }
401                    }
402                }
403            }
404            if pressed && let Some(text) = text {
405                unsafe {
406                    let io = renderer.imgui().io_mut().inner();
407                    for c in text.chars() {
408                        io.AddInputCharacter(c as u32);
409                    }
410                }
411            }
412        }
413        Ime(Commit(text)) => {
414            main_window.ping_user_input();
415            unsafe {
416                let io = renderer.imgui().io_mut().inner();
417                for c in text.chars() {
418                    io.AddInputCharacter(c as u32);
419                }
420            }
421        }
422        CursorMoved { position, .. } => {
423            main_window.ping_user_input();
424            unsafe {
425                let io = renderer.imgui().io_mut().inner();
426                let position = main_window
427                    .transform_position(Vector2::new(position.x as f32, position.y as f32));
428                io.AddMousePosEvent(position.x, position.y);
429            }
430        }
431        MouseWheel {
432            delta,
433            phase: winit::event::TouchPhase::Moved,
434            ..
435        } => {
436            main_window.ping_user_input();
437            let mut imgui = unsafe { renderer.imgui().set_current() };
438            unsafe {
439                let io = imgui.io_mut().inner();
440                let (h, v) = match delta {
441                    winit::event::MouseScrollDelta::LineDelta(h, v) => (*h, *v),
442                    winit::event::MouseScrollDelta::PixelDelta(d) => {
443                        let scale = io.DisplayFramebufferScale.x;
444                        let f_scale = ImGui_GetFontSize();
445                        let scale = scale * f_scale;
446                        (d.x as f32 / scale, d.y as f32 / scale)
447                    }
448                };
449                io.AddMouseWheelEvent(h, v);
450            }
451        }
452        MouseInput { state, button, .. } => {
453            main_window.ping_user_input();
454            unsafe {
455                let io = renderer.imgui().io_mut().inner();
456                if let Some(btn) = to_imgui_button(*button) {
457                    let pressed = *state == winit::event::ElementState::Pressed;
458                    io.AddMouseButtonEvent(btn.bits(), pressed);
459                }
460            }
461        }
462        CursorLeft { .. } => {
463            main_window.ping_user_input();
464            unsafe {
465                let io = renderer.imgui().io_mut().inner();
466                io.AddMousePosEvent(f32::MAX, f32::MAX);
467            }
468        }
469        Focused(focused) => {
470            main_window.ping_user_input();
471            unsafe {
472                let io = renderer.imgui().io_mut().inner();
473                io.AddFocusEvent(*focused);
474            }
475        }
476        _ => {}
477    }
478    let imgui = renderer.imgui();
479    EventResult {
480        window_closed,
481        want_capture_mouse: imgui.io().want_capture_mouse(),
482        want_capture_keyboard: imgui.io().want_capture_keyboard(),
483        want_text_input: imgui.io().want_text_input(),
484    }
485}
486
487#[cfg(feature = "clipboard")]
488/// Easy wrapper for the clipboard functions.
489///
490/// This module depends on the `clipboard` feature. Usually this is set up automatically just by
491/// enabling the faature.
492pub mod clipboard {
493    use easy_imgui::{self as imgui};
494    use std::ffi::{CStr, CString, c_char, c_void};
495
496    /// Sets up the ImGui clipboard using the `arboard` crate.
497    pub fn setup(imgui: &mut imgui::Context) {
498        if let Ok(ctx) = arboard::Clipboard::new() {
499            let clip = MyClipboard {
500                ctx,
501                text: CString::default(),
502            };
503            unsafe {
504                let pio = imgui.platform_io_mut();
505                pio.Platform_ClipboardUserData = Box::into_raw(Box::new(clip)) as *mut c_void;
506                pio.Platform_SetClipboardTextFn = Some(set_clipboard_text);
507                pio.Platform_GetClipboardTextFn = Some(get_clipboard_text);
508            }
509        }
510    }
511    unsafe extern "C" fn set_clipboard_text(
512        imgui: *mut easy_imgui_sys::ImGuiContext,
513        text: *const c_char,
514    ) {
515        unsafe {
516            let user = (*imgui).PlatformIO.Platform_ClipboardUserData;
517            let clip = &mut *(user as *mut MyClipboard);
518            if text.is_null() {
519                let _ = clip.ctx.clear();
520            } else {
521                let cstr = CStr::from_ptr(text);
522                let str = String::from_utf8_lossy(cstr.to_bytes()).to_string();
523                let _ = clip.ctx.set_text(str);
524            }
525        }
526    }
527
528    // The returned pointer should be valid for a while...
529    unsafe extern "C" fn get_clipboard_text(
530        imgui: *mut easy_imgui_sys::ImGuiContext,
531    ) -> *const c_char {
532        unsafe {
533            let user = (*imgui).PlatformIO.Platform_ClipboardUserData;
534            let clip = &mut *(user as *mut MyClipboard);
535            let Ok(text) = clip.ctx.get_text() else {
536                return std::ptr::null();
537            };
538            let Ok(text) = CString::new(text) else {
539                return std::ptr::null();
540            };
541            clip.text = text;
542            clip.text.as_ptr()
543        }
544    }
545
546    struct MyClipboard {
547        ctx: arboard::Clipboard,
548        text: CString,
549    }
550}
551
552#[cfg(feature = "main-window")]
553mod main_window {
554    use super::*;
555    use std::future::Future;
556    mod fut;
557    use anyhow::{Result, anyhow};
558    use easy_imgui_renderer::glow;
559    pub use fut::{FutureBackCaller, FutureHandle, FutureHandleGuard};
560    use glutin::{
561        config::{Config, ConfigTemplateBuilder},
562        context::{ContextApi, ContextAttributesBuilder},
563        display::GetGlDisplay,
564        surface::SurfaceAttributesBuilder,
565    };
566    use glutin_winit::DisplayBuilder;
567    use raw_window_handle::HasWindowHandle;
568    use winit::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
569    use winit::window::WindowAttributes;
570
571    /// This type represents a `winit` window and an OpenGL context.
572    pub struct MainWindow {
573        gl_context: PossiblyCurrentContext,
574        // The surface must be dropped before the window.
575        surface: Surface<WindowSurface>,
576        window: Window,
577        matrix: Option<Matrix3<f32>>,
578        idler: MainWindowIdler,
579    }
580
581    /// This is a [`MainWindow`] plus a [`Renderer`]. It is the ultimate `easy-imgui` object.
582    /// Instead of a literal `MainWindow` you can use any type that implements [`MainWindowRef`].
583    pub struct MainWindowWithRenderer {
584        main_window: MainWindow,
585        renderer: Renderer,
586        status: MainWindowStatus,
587    }
588
589    impl MainWindow {
590        /// Creates a `MainWindow` with default values.
591        pub fn new(event_loop: &ActiveEventLoop, wattr: WindowAttributes) -> Result<MainWindow> {
592            // For standard UI, we need as few fancy things as available
593            let score = |c: &Config| (c.num_samples(), c.depth_size(), c.stencil_size());
594            Self::with_gl_chooser(event_loop, wattr, |cfg1, cfg2| {
595                if score(&cfg2) < score(&cfg1) {
596                    cfg2
597                } else {
598                    cfg1
599                }
600            })
601        }
602        /// Creates a `MainWindow` with your own OpenGL context chooser.
603        ///
604        /// If you don't have specific OpenGL needs, prefer using [`MainWindow::new`]. If you do,
605        /// consider using a _FramebufferObject_ and do an offscreen rendering instead.
606        pub fn with_gl_chooser(
607            event_loop: &ActiveEventLoop,
608            wattr: WindowAttributes,
609            f_choose_cfg: impl FnMut(Config, Config) -> Config,
610        ) -> Result<MainWindow> {
611            let template = ConfigTemplateBuilder::new()
612                .prefer_hardware_accelerated(Some(true))
613                .with_depth_size(0)
614                .with_stencil_size(0);
615
616            let display_builder = DisplayBuilder::new().with_window_attributes(Some(wattr));
617            let (window, gl_config) = display_builder
618                .build(event_loop, template, |configs| {
619                    configs.reduce(f_choose_cfg).unwrap()
620                })
621                .map_err(|e| anyhow!("{:#?}", e))?;
622            let window = window.unwrap();
623            window.set_ime_allowed(true);
624            let raw_window_handle = Some(window.window_handle().unwrap().as_raw());
625            let gl_display = gl_config.display();
626            let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);
627            let fallback_context_attributes = ContextAttributesBuilder::new()
628                .with_context_api(ContextApi::Gles(None))
629                .build(raw_window_handle);
630
631            let mut not_current_gl_context = Some(unsafe {
632                gl_display
633                    .create_context(&gl_config, &context_attributes)
634                    .or_else(|_| {
635                        gl_display.create_context(&gl_config, &fallback_context_attributes)
636                    })?
637            });
638
639            let size = window.inner_size();
640
641            let (width, height): (u32, u32) = size.into();
642            let raw_window_handle = window.window_handle().unwrap().as_raw();
643            let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
644                raw_window_handle,
645                NonZeroU32::new(width).unwrap(),
646                NonZeroU32::new(height).unwrap(),
647            );
648
649            let surface = unsafe {
650                gl_config
651                    .display()
652                    .create_window_surface(&gl_config, &attrs)?
653            };
654            let gl_context = not_current_gl_context
655                .take()
656                .unwrap()
657                .make_current(&surface)?;
658
659            // Enable v-sync to avoid consuming too much CPU
660            let _ = surface.set_swap_interval(
661                &gl_context,
662                glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap()),
663            );
664
665            Ok(MainWindow {
666                gl_context,
667                window,
668                surface,
669                matrix: None,
670                idler: MainWindowIdler::default(),
671            })
672        }
673        /// Sets a custom matrix that converts physical mouse coordinates into logical ones.
674        pub fn set_matrix(&mut self, matrix: Option<Matrix3<f32>>) {
675            self.matrix = matrix;
676        }
677
678        /// Splits this window into its parts.
679        ///
680        /// # Safety
681        /// Do not drop the `window` without dropping the `surface` first.
682        pub unsafe fn into_pieces(
683            self,
684        ) -> (PossiblyCurrentContext, Surface<WindowSurface>, Window) {
685            (self.gl_context, self.surface, self.window)
686        }
687        /// Returns the `glutin` context.
688        pub fn glutin_context(&self) -> &PossiblyCurrentContext {
689            &self.gl_context
690        }
691        /// Creates a new `glow` OpenGL context for this window and the selected configuration.
692        pub fn create_gl_context(&self) -> glow::Context {
693            let dsp = self.gl_context.display();
694            unsafe { glow::Context::from_loader_function_cstr(|s| dsp.get_proc_address(s)) }
695        }
696        /// Gets a reference to the `winit` window.
697        pub fn window(&self) -> &Window {
698            &self.window
699        }
700        /// Returns the `glutin` surface.
701        pub fn surface(&self) -> &Surface<WindowSurface> {
702            &self.surface
703        }
704        /// Converts the given physical size to a logical size, using the window scale factor.
705        pub fn to_logical_size<X: Pixel, Y: Pixel>(&self, size: PhysicalSize<X>) -> LogicalSize<Y> {
706            let scale = self.window.scale_factor();
707            size.to_logical(scale)
708        }
709        /// Converts the given logical size to a physical size, using the window scale factor.
710        pub fn to_physical_size<X: Pixel, Y: Pixel>(
711            &self,
712            size: LogicalSize<X>,
713        ) -> PhysicalSize<Y> {
714            let scale = self.window.scale_factor();
715            size.to_physical(scale)
716        }
717        /// Converts the given physical position to a logical position, using the window scale factor.
718        pub fn to_logical_pos<X: Pixel, Y: Pixel>(
719            &self,
720            pos: PhysicalPosition<X>,
721        ) -> LogicalPosition<Y> {
722            let scale = self.window.scale_factor();
723            pos.to_logical(scale)
724        }
725        /// Converts the given logical position to a physical position, using the window scale factor.
726        pub fn to_physical_pos<X: Pixel, Y: Pixel>(
727            &self,
728            pos: LogicalPosition<X>,
729        ) -> PhysicalPosition<Y> {
730            let scale = self.window.scale_factor();
731            pos.to_physical(scale)
732        }
733    }
734
735    impl MainWindowWithRenderer {
736        /// Creates a new [`Renderer`] and attaches it to the given window.
737        pub fn new(main_window: MainWindow) -> Self {
738            Self::with_builder(main_window, &imgui::ContextBuilder::new())
739        }
740        /// Creates a new [`Renderer`] and attaches it to the given window.
741        ///
742        /// The `builder` argument can be used to modify the inner ImGui context.
743        pub fn with_builder(main_window: MainWindow, builder: &imgui::ContextBuilder) -> Self {
744            let gl = main_window.create_gl_context();
745            let renderer = Renderer::with_builder(std::rc::Rc::new(gl), builder).unwrap();
746            Self::new_with_renderer(main_window, renderer)
747        }
748        /// Sets the time after which the UI will stop rendering, if there is no user input.
749        pub fn set_idle_time(&mut self, time: Duration) {
750            self.main_window.idler.set_idle_time(time);
751        }
752        /// Sets the frame count after which the UI will stop rendering, if there is no user input.
753        ///
754        /// Note that by default V-Sync is enabled, and that will affect the frame rate.
755        pub fn set_idle_frame_count(&mut self, frame_count: u32) {
756            self.main_window.idler.set_idle_frame_count(frame_count);
757        }
758        /// Forces a rebuild of the UI.
759        ///
760        /// By default the window will stop rendering the UI after a while without user input. Use this
761        /// function to force a redraw because of some external factor.
762        pub fn ping_user_input(&mut self) {
763            self.main_window.idler.ping_user_input();
764        }
765        /// Gets a reference to the inner renderer.
766        pub fn renderer(&mut self) -> &mut Renderer {
767            &mut self.renderer
768        }
769        /// Gets a reference to the ImGui context by the renderer.
770        ///
771        /// Just like `self.renderer().imgui()`
772        pub fn imgui(&mut self) -> &mut imgui::Context {
773            self.renderer.imgui()
774        }
775        /// Gets a reference to the inner window.
776        pub fn main_window(&mut self) -> &mut MainWindow {
777            &mut self.main_window
778        }
779        /// Attaches the given window and renderer together.
780        pub fn new_with_renderer(main_window: MainWindow, mut renderer: Renderer) -> Self {
781            let w = main_window.window();
782            let size = w.inner_size();
783            let scale = w.scale_factor();
784            let size = size.to_logical::<f32>(scale);
785            renderer.set_size(Vector2::from(mint::Vector2::from(size)), scale as f32);
786
787            #[cfg(feature = "clipboard")]
788            clipboard::setup(renderer.imgui());
789
790            MainWindowWithRenderer {
791                main_window,
792                renderer,
793                status: MainWindowStatus::default(),
794            }
795        }
796        /// The main event function. Corresponds to winit's `ApplicationHandler::window_event`.
797        ///
798        /// It returns [`EventResult`]. You can use it to break the main loop, or ignore it, as you see fit.
799        /// It also informs of whether ImGui want the monopoly of the user input.
800        pub fn window_event(
801            &mut self,
802            app: &mut impl imgui::UiBuilder,
803            event: &winit::event::WindowEvent,
804            flags: EventFlags,
805        ) -> EventResult {
806            window_event(
807                &mut self.main_window,
808                &mut self.renderer,
809                &mut self.status,
810                app,
811                event,
812                flags,
813            )
814        }
815
816        /// Corresponds to winit's `ApplicationHandler::new_events`.
817        pub fn new_events(&mut self) {
818            new_events(&mut self.renderer, &mut self.status);
819        }
820        /// Corresponds to winit's `ApplicationHandler::about_to_wait`.
821        pub fn about_to_wait(&mut self) {
822            about_to_wait(&mut self.main_window, &mut self.renderer);
823        }
824    }
825
826    /// Main implementation of the `MainWindowRef` trait for an owned `MainWindow`.
827    impl MainWindowRef for MainWindow {
828        fn window(&self) -> &Window {
829            &self.window
830        }
831        fn pre_render(&mut self) {
832            self.idler.incr_frame();
833            let _ = self
834                .gl_context
835                .make_current(&self.surface)
836                .inspect_err(|e| log::error!("{e}"));
837        }
838        fn post_render(&mut self) {
839            self.window.pre_present_notify();
840            let _ = self
841                .surface
842                .swap_buffers(&self.gl_context)
843                .inspect_err(|e| log::error!("{e}"));
844        }
845        fn resize(&mut self, size: PhysicalSize<u32>) -> LogicalSize<f32> {
846            let width = NonZeroU32::new(size.width.max(1)).unwrap();
847            let height = NonZeroU32::new(size.height.max(1)).unwrap();
848            self.surface.resize(&self.gl_context, width, height);
849            self.to_logical_size::<_, f32>(size)
850        }
851        fn ping_user_input(&mut self) {
852            self.idler.ping_user_input();
853        }
854        fn about_to_wait(&mut self, pinged: bool) {
855            if pinged || self.idler.has_to_render() {
856                // No need to call set_control_flow(): doing a redraw will force extra Poll.
857                // Not doing it will default to Wait.
858                self.window.request_redraw();
859            }
860        }
861        fn transform_position(&self, pos: Vector2) -> Vector2 {
862            transform_position_with_optional_matrix(self, pos, &self.matrix)
863        }
864    }
865
866    /// This type is an aggregate of values retured by [`AppHandler`].
867    ///
868    /// With this you don't need to have a buch of `use` that you probably
869    /// don't care about.
870    ///
871    /// Since this is not `Send` it is always used from the main loop, and it can be
872    /// used to send non `Send` callbacks to the idle loop.
873    #[non_exhaustive]
874    pub struct Args<'a, A: Application> {
875        /// The main window.
876        pub window: &'a mut MainWindowWithRenderer,
877        /// The event loop.
878        pub event_loop: &'a ActiveEventLoop,
879        /// A proxy to send messages to the main loop.
880        pub event_proxy: &'a EventLoopProxy<AppEvent<A>>,
881        /// The custom application data.
882        pub data: &'a mut A::Data,
883    }
884
885    /// This type is a wrapper for `EventLoopProxy` that is not `Send`.
886    ///
887    /// Since it can only be used from the main loop, it can send events that are not `Send`.
888    pub struct LocalProxy<A: Application> {
889        event_proxy: EventLoopProxy<AppEvent<A>>,
890        // !Send + !Sync
891        pd: std::marker::PhantomData<*const ()>,
892    }
893
894    impl<A: Application> Clone for LocalProxy<A> {
895        fn clone(&self) -> Self {
896            LocalProxy {
897                event_proxy: self.event_proxy.clone(),
898                pd: std::marker::PhantomData,
899            }
900        }
901    }
902
903    macro_rules! local_proxy_impl {
904        () => {
905            /// Registers a future to be run during the idle step of the main loop.
906            pub fn spawn_idle<T: 'static, F: Future<Output = T> + 'static>(
907                &self,
908                f: F,
909            ) -> crate::FutureHandle<T> {
910                unsafe { fut::spawn_idle(&self.event_proxy, f) }
911            }
912            /// Registers a callback to be called during the idle step of the main loop.
913            pub fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + 'static>(
914                &self,
915                f: F,
916            ) -> Result<(), winit::event_loop::EventLoopClosed<()>> {
917                // Self is !Send+!Sync, so this must be in the main loop,
918                // and the idle callback will be run in the same loop.
919                let f = send_wrapper::SendWrapper::new(f);
920                // If it fails, drop the message instead of returing it, because the
921                // message is Send but the f inside is not.
922                self.event_proxy
923                    .run_idle(move |app, args| (f.take())(app, args))
924                    .map_err(|_| winit::event_loop::EventLoopClosed(()))
925            }
926            /// Creates a `FutureBackCaller` for this application.
927            pub fn future_back(&self) -> crate::FutureBackCaller<A> {
928                fut::future_back_caller_new()
929            }
930        };
931    }
932
933    impl<A: Application> Args<'_, A> {
934        /// Creates a `LocalProxy` that is `Clone` but not `Send`.
935        pub fn local_proxy(&self) -> LocalProxy<A> {
936            LocalProxy {
937                event_proxy: self.event_proxy.clone(),
938                pd: std::marker::PhantomData,
939            }
940        }
941        /// Helper function to call `ping_user_input` in the main window.
942        pub fn ping_user_input(&mut self) {
943            self.window.ping_user_input();
944        }
945        local_proxy_impl! {}
946    }
947
948    impl<A: Application> LocalProxy<A> {
949        /// Gets the inner real proxy, that is `Send`.
950        pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
951            &self.event_proxy
952        }
953        local_proxy_impl! {}
954    }
955
956    /// Trait that connects a `UiBuilder` with an `AppHandler`.
957    ///
958    /// Implement this to manage the main loop of your application.
959    pub trait Application: imgui::UiBuilder + Sized + 'static {
960        /// The custom event for the `EventLoop`, usually `()`.
961        type UserEvent: Send + 'static;
962        /// The custom data for your `AppHandler`.
963        type Data;
964
965        /// The `EventFlags` for this application. Usually the default is ok.
966        const EVENT_FLAGS: EventFlags = EventFlags::empty();
967
968        /// The main window has been created, please create the application.
969        fn new(args: Args<'_, Self>) -> Self;
970
971        /// A new window event has been received.
972        ///
973        /// When this is called the event has already been fed to the ImGui
974        /// context. The output is in `res`.
975        /// The default impl will end the application when the window is closed.
976        fn window_event(
977            &mut self,
978            args: Args<'_, Self>,
979            _event: winit::event::WindowEvent,
980            res: EventResult,
981        ) {
982            if res.window_closed {
983                args.event_loop.exit();
984            }
985        }
986
987        /// Advanced handling for window events.
988        ///
989        /// The default impl will pass the event to ImGui and then call `window_event`.
990        fn window_event_full(&mut self, args: Args<'_, Self>, event: winit::event::WindowEvent) {
991            let res = args.window.window_event(self, &event, Self::EVENT_FLAGS);
992            self.window_event(args, event, res);
993        }
994
995        /// A device event has been received.
996        ///
997        /// This event is not handled in any way, just passed laong.
998        fn device_event(
999            &mut self,
1000            _args: Args<'_, Self>,
1001            _device_id: winit::event::DeviceId,
1002            _event: winit::event::DeviceEvent,
1003        ) {
1004        }
1005
1006        /// A custom event has been received.
1007        fn user_event(&mut self, _args: Args<'_, Self>, _event: Self::UserEvent) {}
1008
1009        /// Corresponds to `winit` `suspended`` function.
1010        fn suspended(&mut self, _args: Args<'_, Self>) {}
1011
1012        /// Corresponds to `winit` `resumed` function.
1013        fn resumed(&mut self, _args: Args<'_, Self>) {}
1014    }
1015
1016    /// The main event type to be used with `winit::EventLoop`.
1017    ///
1018    /// It is generic on the `Application` type.
1019    #[non_exhaustive]
1020    pub enum AppEvent<A: Application> {
1021        /// Calls `ping_user_input` on the main window.
1022        PingUserInput,
1023        /// Runs the given callback in the main loop idle step, with the regular arguments.
1024        #[allow(clippy::type_complexity)]
1025        RunIdle(Box<dyn FnOnce(&mut A, Args<'_, A>) + Send + Sync>),
1026        /// Runs the given callback in the main loop idle step, without arguments.
1027        RunIdleSimple(Box<dyn FnOnce() + Send + Sync>),
1028        /// Sends the custom user event.
1029        User(A::UserEvent),
1030    }
1031
1032    impl<A: Application> std::fmt::Debug for AppEvent<A> {
1033        fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1034            write!(fmt, "<AppEvent>")
1035        }
1036    }
1037
1038    /// Helper trait to extend `winit::EventLoopProxy` with useful functions.
1039    pub trait EventLoopExt<A: Application> {
1040        /// Sends a `AppEvent::User` event.
1041        fn send_user(
1042            &self,
1043            u: A::UserEvent,
1044        ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
1045        /// Sends a `AppEvent::PingUserInput` event.
1046        fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
1047        /// Sends a `AppEvent::RunIdle` event.
1048        fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
1049            &self,
1050            f: F,
1051        ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>>;
1052    }
1053
1054    impl<A: Application> EventLoopExt<A> for EventLoopProxy<AppEvent<A>> {
1055        fn send_user(
1056            &self,
1057            u: A::UserEvent,
1058        ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
1059            self.send_event(AppEvent::User(u))
1060        }
1061        fn ping_user_input(&self) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
1062            self.send_event(AppEvent::PingUserInput)
1063        }
1064        fn run_idle<F: FnOnce(&mut A, Args<'_, A>) + Send + Sync + 'static>(
1065            &self,
1066            f: F,
1067        ) -> Result<(), winit::event_loop::EventLoopClosed<AppEvent<A>>> {
1068            self.send_event(AppEvent::RunIdle(Box::new(f)))
1069        }
1070    }
1071
1072    /// Default implementation for `winit::application::ApplicationHandler`.
1073    ///
1074    /// The new `winit` requires an implementation of that trait to be able to use
1075    /// an `EventLoop`, and everything, including the main window, will be done from
1076    /// that.
1077    /// This type implements this trait and does some basic tasks:
1078    ///  * Creates the `MainWindowWithRenderer` object.
1079    ///  * Forwards the events to your application object.
1080    ///
1081    /// For that it requires that your application object implements `UiBuilder` and
1082    /// `Application`.
1083    ///
1084    /// If you have special needs you can skip this and write your own implementation
1085    /// of `winit::application::ApplicationHandler`.
1086    pub struct AppHandler<A: Application> {
1087        builder: imgui::ContextBuilder,
1088        wattrs: WindowAttributes,
1089        event_proxy: EventLoopProxy<AppEvent<A>>,
1090        window: Option<MainWindowWithRenderer>,
1091        app: Option<A>,
1092        app_data: A::Data,
1093    }
1094
1095    impl<A: Application> AppHandler<A> {
1096        /// Creates a new `AppHandler`.
1097        ///
1098        /// It creates an empty handler. It automatically creates an `EventLoopProxy`.
1099        pub fn new(event_loop: &EventLoop<AppEvent<A>>, app_data: A::Data) -> Self {
1100            AppHandler {
1101                builder: imgui::ContextBuilder::new(),
1102                wattrs: Window::default_attributes(),
1103                event_proxy: event_loop.create_proxy(),
1104                window: None,
1105                app: None,
1106                app_data,
1107            }
1108        }
1109        /// Returns the `ContextBuilder` of this application.
1110        ///
1111        /// With this you can change the ImGui options before the context is created.
1112        pub fn imgui_builder(&mut self) -> &mut imgui::ContextBuilder {
1113            &mut self.builder
1114        }
1115        /// Sets the window attributes that will be used to create the main window.
1116        pub fn set_attributes(&mut self, wattrs: WindowAttributes) {
1117            self.wattrs = wattrs;
1118        }
1119        /// Gets the current window attributes.
1120        ///
1121        /// It returns a mutable reference, so you can modify it in-place, which is
1122        /// sometimes more convenient.
1123        pub fn attributes(&mut self) -> &mut WindowAttributes {
1124            &mut self.wattrs
1125        }
1126        /// Gets the custom data.
1127        pub fn data(&self) -> &A::Data {
1128            &self.app_data
1129        }
1130        /// Gets a mutable reference to the custom data.
1131        pub fn data_mut(&mut self) -> &mut A::Data {
1132            &mut self.app_data
1133        }
1134        /// Gets the inner app object.
1135        pub fn app(&self) -> Option<&A> {
1136            self.app.as_ref()
1137        }
1138        /// Gets a mutable reference to the inner app object.
1139        pub fn app_mut(&mut self) -> Option<&mut A> {
1140            self.app.as_mut()
1141        }
1142        /// Extracts the inner values.
1143        ///
1144        /// You may need this after the main loop has finished to get
1145        /// the result of your program execution.
1146        pub fn into_inner(self) -> (Option<A>, A::Data) {
1147            (self.app, self.app_data)
1148        }
1149
1150        /// Gets the inner `EventLoopProxy`.
1151        pub fn event_proxy(&self) -> &EventLoopProxy<AppEvent<A>> {
1152            &self.event_proxy
1153        }
1154    }
1155
1156    impl<A> winit::application::ApplicationHandler<AppEvent<A>> for AppHandler<A>
1157    where
1158        A: Application,
1159    {
1160        fn suspended(&mut self, event_loop: &ActiveEventLoop) {
1161            let Some(window) = self.window.as_mut() else {
1162                return;
1163            };
1164            if let Some(app) = &mut self.app {
1165                let args = Args {
1166                    window,
1167                    event_loop,
1168                    event_proxy: &self.event_proxy,
1169                    data: &mut self.app_data,
1170                };
1171                app.suspended(args);
1172            }
1173            self.window = None;
1174        }
1175        fn resumed(&mut self, event_loop: &ActiveEventLoop) {
1176            let main_window = MainWindow::new(event_loop, self.wattrs.clone()).unwrap();
1177            let mut window = MainWindowWithRenderer::with_builder(main_window, &self.builder);
1178
1179            let args = Args {
1180                window: &mut window,
1181                event_loop,
1182                event_proxy: &self.event_proxy,
1183                data: &mut self.app_data,
1184            };
1185            match &mut self.app {
1186                None => self.app = Some(A::new(args)),
1187                Some(app) => app.resumed(args),
1188            }
1189            self.window = Some(window);
1190        }
1191        fn window_event(
1192            &mut self,
1193            event_loop: &ActiveEventLoop,
1194            window_id: winit::window::WindowId,
1195            event: winit::event::WindowEvent,
1196        ) {
1197            let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1198                return;
1199            };
1200            let w = window.main_window();
1201            if w.window().id() != window_id {
1202                return;
1203            }
1204
1205            let args = Args {
1206                window,
1207                event_loop,
1208                event_proxy: &self.event_proxy,
1209                data: &mut self.app_data,
1210            };
1211            app.window_event_full(args, event);
1212        }
1213        fn device_event(
1214            &mut self,
1215            event_loop: &ActiveEventLoop,
1216            device_id: winit::event::DeviceId,
1217            event: winit::event::DeviceEvent,
1218        ) {
1219            let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1220                return;
1221            };
1222            let args = Args {
1223                window,
1224                event_loop,
1225                event_proxy: &self.event_proxy,
1226                data: &mut self.app_data,
1227            };
1228            app.device_event(args, device_id, event);
1229        }
1230        fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppEvent<A>) {
1231            let (Some(window), Some(app)) = (self.window.as_mut(), self.app.as_mut()) else {
1232                return;
1233            };
1234            let args = Args {
1235                window,
1236                event_loop,
1237                event_proxy: &self.event_proxy,
1238                data: &mut self.app_data,
1239            };
1240
1241            match event {
1242                AppEvent::PingUserInput => window.ping_user_input(),
1243                AppEvent::RunIdle(f) => f(app, args),
1244                AppEvent::RunIdleSimple(f) => fut::future_back_caller_prepare((app, args), f),
1245                AppEvent::User(uevent) => app.user_event(args, uevent),
1246            }
1247        }
1248        fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
1249            let Some(window) = self.window.as_mut() else {
1250                return;
1251            };
1252            window.new_events();
1253        }
1254        fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
1255            let Some(window) = self.window.as_mut() else {
1256                return;
1257            };
1258            window.about_to_wait();
1259        }
1260    }
1261}
1262
1263#[cfg(feature = "main-window")]
1264pub use main_window::*;