use std::{sync::Arc, time::Instant}; use winit::{ event_loop::EventLoopWindowTarget, window::{Window, WindowId}, }; use egui::ViewportId; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; use super::epi_integration::EpiIntegration; /// Create an egui context, restoring it from storage if possible. pub fn create_egui_context(storage: Option<&dyn crate::Storage>) -> egui::Context { crate::profile_function!(); pub const IS_DESKTOP: bool = cfg!(any( target_os = "freebsd", target_os = "linux", target_os = "macos", target_os = "openbsd", target_os = "windows", )); let egui_ctx = egui::Context::default(); egui_ctx.set_embed_viewports(!IS_DESKTOP); let memory = crate::native::epi_integration::load_egui_memory(storage).unwrap_or_default(); egui_ctx.memory_mut(|mem| *mem = memory); egui_ctx } /// The custom even `eframe` uses with the [`winit`] event loop. #[derive(Debug)] pub enum UserEvent { /// A repaint is requested. RequestRepaint { /// What to repaint. viewport_id: ViewportId, /// When to repaint. when: Instant, /// What the frame number was when the repaint was _requested_. frame_nr: u64, }, /// A request related to [`accesskit`](https://accesskit.dev/). #[cfg(feature = "accesskit")] AccessKitActionRequest(accesskit_winit::ActionRequestEvent), } #[cfg(feature = "accesskit")] impl From for UserEvent { fn from(inner: accesskit_winit::ActionRequestEvent) -> Self { Self::AccessKitActionRequest(inner) } } pub trait WinitApp { /// The current frame number, as reported by egui. fn frame_nr(&self, viewport_id: ViewportId) -> u64; fn is_focused(&self, window_id: WindowId) -> bool; fn integration(&self) -> Option<&EpiIntegration>; fn window(&self, window_id: WindowId) -> Option>; fn window_id_from_viewport_id(&self, id: ViewportId) -> Option; fn save_and_destroy(&mut self); fn run_ui_and_paint( &mut self, event_loop: &EventLoopWindowTarget, window_id: WindowId, ) -> EventResult; fn on_event( &mut self, event_loop: &EventLoopWindowTarget, event: &winit::event::Event, ) -> crate::Result; } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum EventResult { Wait, /// Causes a synchronous repaint inside the event handler. This should only /// be used in special situations if the window must be repainted while /// handling a specific event. This occurs on Windows when handling resizes. /// /// `RepaintNow` creates a new frame synchronously, and should therefore /// only be used for extremely urgent repaints. RepaintNow(WindowId), /// Queues a repaint for once the event loop handles its next redraw. Exists /// so that multiple input events can be handled in one frame. Does not /// cause any delay like `RepaintNow`. RepaintNext(WindowId), RepaintAt(WindowId, Instant), Exit, } pub fn system_theme(window: &Window, options: &crate::NativeOptions) -> Option { if options.follow_system_theme { window .theme() .map(super::epi_integration::theme_from_winit_theme) } else { None } } /// Short and fast description of an event. /// Useful for logging and profiling. pub fn short_event_description(event: &winit::event::Event) -> &'static str { match event { winit::event::Event::UserEvent(user_event) => match user_event { UserEvent::RequestRepaint { .. } => "UserEvent::RequestRepaint", #[cfg(feature = "accesskit")] UserEvent::AccessKitActionRequest(_) => "UserEvent::AccessKitActionRequest", }, _ => egui_winit::short_generic_event_description(event), } }