1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-30 21:30:03 -04:00

Make App 'static

This commit is contained in:
Emil Ernerfeldt
2026-01-05 18:35:10 +01:00
parent faccc12c09
commit 3ffbed8d61
7 changed files with 31 additions and 35 deletions

View File

@@ -43,8 +43,7 @@ type DynError = Box<dyn std::error::Error + Send + Sync>;
/// This is how your app is created. /// This is how your app is created.
/// ///
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc. /// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
pub type AppCreator<'app> = pub type AppCreator = Box<dyn FnOnce(&CreationContext<'_>) -> Result<Box<dyn App>, DynError>>;
Box<dyn 'app + FnOnce(&CreationContext<'_>) -> Result<Box<dyn 'app + App>, DynError>>;
/// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. /// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app.
pub struct CreationContext<'s> { pub struct CreationContext<'s> {
@@ -131,7 +130,7 @@ impl CreationContext<'_> {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/// Implement this trait to write apps that can be compiled for both web/wasm and desktop/native using [`eframe`](https://github.com/emilk/egui/tree/main/crates/eframe). /// Implement this trait to write apps that can be compiled for both web/wasm and desktop/native using [`eframe`](https://github.com/emilk/egui/tree/main/crates/eframe).
pub trait App { pub trait App: std::any::Any {
/// Called once before each call to [`Self::ui`], /// Called once before each call to [`Self::ui`],
/// and additionally also called when the UI is hidden, but [`egui::Context::request_repaint`] was called. /// and additionally also called when the UI is hidden, but [`egui::Context::request_repaint`] was called.
/// ///

View File

@@ -256,7 +256,7 @@ pub mod icon_data;
pub fn run_native( pub fn run_native(
app_name: &str, app_name: &str,
mut native_options: NativeOptions, mut native_options: NativeOptions,
app_creator: AppCreator<'_>, app_creator: AppCreator,
) -> Result { ) -> Result {
let renderer = init_native(app_name, &mut native_options); let renderer = init_native(app_name, &mut native_options);
@@ -325,7 +325,7 @@ pub fn run_native(
pub fn create_native<'a>( pub fn create_native<'a>(
app_name: &str, app_name: &str,
mut native_options: NativeOptions, mut native_options: NativeOptions,
app_creator: AppCreator<'a>, app_creator: AppCreator,
event_loop: &winit::event_loop::EventLoop<UserEvent>, event_loop: &winit::event_loop::EventLoop<UserEvent>,
) -> EframeWinitApplication<'a> { ) -> EframeWinitApplication<'a> {
let renderer = init_native(app_name, &mut native_options); let renderer = init_native(app_name, &mut native_options);

View File

@@ -45,24 +45,24 @@ use super::{
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types: // Types:
pub struct GlowWinitApp<'app> { pub struct GlowWinitApp {
repaint_proxy: Arc<egui::mutex::Mutex<EventLoopProxy<UserEvent>>>, repaint_proxy: Arc<egui::mutex::Mutex<EventLoopProxy<UserEvent>>>,
app_name: String, app_name: String,
native_options: NativeOptions, native_options: NativeOptions,
running: Option<GlowWinitRunning<'app>>, running: Option<GlowWinitRunning>,
// Note that since this `AppCreator` is FnOnce we are currently unable to support // Note that since this `AppCreator` is FnOnce we are currently unable to support
// re-initializing the `GlowWinitRunning` state on Android if the application // re-initializing the `GlowWinitRunning` state on Android if the application
// suspends and resumes. // suspends and resumes.
app_creator: Option<AppCreator<'app>>, app_creator: Option<AppCreator>,
} }
/// State that is initialized when the application is first starts running via /// State that is initialized when the application is first starts running via
/// a Resumed event. On Android this ensures that any graphics state is only /// a Resumed event. On Android this ensures that any graphics state is only
/// initialized once the application has an associated `SurfaceView`. /// initialized once the application has an associated `SurfaceView`.
struct GlowWinitRunning<'app> { struct GlowWinitRunning {
integration: EpiIntegration, integration: EpiIntegration,
app: Box<dyn 'app + App>, app: Box<dyn App>,
// These needs to be shared with the immediate viewport renderer, hence the Rc/Arc/RefCells: // These needs to be shared with the immediate viewport renderer, hence the Rc/Arc/RefCells:
glutin: Rc<RefCell<GlutinWindowContext>>, glutin: Rc<RefCell<GlutinWindowContext>>,
@@ -123,12 +123,12 @@ struct Viewport {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
impl<'app> GlowWinitApp<'app> { impl GlowWinitApp {
pub fn new( pub fn new(
event_loop: &EventLoop<UserEvent>, event_loop: &EventLoop<UserEvent>,
app_name: &str, app_name: &str,
native_options: NativeOptions, native_options: NativeOptions,
app_creator: AppCreator<'app>, app_creator: AppCreator,
) -> Self { ) -> Self {
profiling::function_scope!(); profiling::function_scope!();
Self { Self {
@@ -191,10 +191,7 @@ impl<'app> GlowWinitApp<'app> {
Ok((glutin_window_context, painter)) Ok((glutin_window_context, painter))
} }
fn init_run_state( fn init_run_state(&mut self, event_loop: &ActiveEventLoop) -> Result<&mut GlowWinitRunning> {
&mut self,
event_loop: &ActiveEventLoop,
) -> Result<&mut GlowWinitRunning<'app>> {
profiling::function_scope!(); profiling::function_scope!();
let storage = if let Some(file) = &self.native_options.persistence_path { let storage = if let Some(file) = &self.native_options.persistence_path {
@@ -290,7 +287,7 @@ impl<'app> GlowWinitApp<'app> {
let app_creator = std::mem::take(&mut self.app_creator) let app_creator = std::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken"); .expect("Single-use AppCreator has unexpectedly already been taken");
let app: Box<dyn 'app + App> = { let app: Box<dyn App> = {
// Use latest raw_window_handle for eframe compatibility // Use latest raw_window_handle for eframe compatibility
use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
@@ -344,7 +341,7 @@ impl<'app> GlowWinitApp<'app> {
} }
} }
impl WinitApp for GlowWinitApp<'_> { impl WinitApp for GlowWinitApp {
fn egui_ctx(&self) -> Option<&egui::Context> { fn egui_ctx(&self) -> Option<&egui::Context> {
self.running.as_ref().map(|r| &r.integration.egui_ctx) self.running.as_ref().map(|r| &r.integration.egui_ctx)
} }
@@ -496,7 +493,7 @@ impl WinitApp for GlowWinitApp<'_> {
} }
} }
impl GlowWinitRunning<'_> { impl GlowWinitRunning {
fn run_ui_and_paint( fn run_ui_and_paint(
&mut self, &mut self,
event_loop: &ActiveEventLoop, event_loop: &ActiveEventLoop,

View File

@@ -347,7 +347,7 @@ fn run_and_exit(event_loop: EventLoop<UserEvent>, winit_app: impl WinitApp) -> R
pub fn run_glow( pub fn run_glow(
app_name: &str, app_name: &str,
mut native_options: epi::NativeOptions, mut native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'_>, app_creator: epi::AppCreator,
) -> Result { ) -> Result {
use super::glow_integration::GlowWinitApp; use super::glow_integration::GlowWinitApp;
@@ -368,7 +368,7 @@ pub fn run_glow(
pub fn create_glow<'a>( pub fn create_glow<'a>(
app_name: &str, app_name: &str,
native_options: epi::NativeOptions, native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'a>, app_creator: epi::AppCreator,
event_loop: &EventLoop<UserEvent>, event_loop: &EventLoop<UserEvent>,
) -> impl ApplicationHandler<UserEvent> + 'a { ) -> impl ApplicationHandler<UserEvent> + 'a {
use super::glow_integration::GlowWinitApp; use super::glow_integration::GlowWinitApp;
@@ -383,7 +383,7 @@ pub fn create_glow<'a>(
pub fn run_wgpu( pub fn run_wgpu(
app_name: &str, app_name: &str,
mut native_options: epi::NativeOptions, mut native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'_>, app_creator: epi::AppCreator,
) -> Result { ) -> Result {
use super::wgpu_integration::WgpuWinitApp; use super::wgpu_integration::WgpuWinitApp;
@@ -404,7 +404,7 @@ pub fn run_wgpu(
pub fn create_wgpu<'a>( pub fn create_wgpu<'a>(
app_name: &str, app_name: &str,
native_options: epi::NativeOptions, native_options: epi::NativeOptions,
app_creator: epi::AppCreator<'a>, app_creator: epi::AppCreator,
event_loop: &EventLoop<UserEvent>, event_loop: &EventLoop<UserEvent>,
) -> impl ApplicationHandler<UserEvent> + 'a { ) -> impl ApplicationHandler<UserEvent> + 'a {
use super::wgpu_integration::WgpuWinitApp; use super::wgpu_integration::WgpuWinitApp;

View File

@@ -35,26 +35,26 @@ use super::{epi_integration, event_loop_context, winit_integration, winit_integr
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types: // Types:
pub struct WgpuWinitApp<'app> { pub struct WgpuWinitApp {
repaint_proxy: Arc<Mutex<EventLoopProxy<UserEvent>>>, repaint_proxy: Arc<Mutex<EventLoopProxy<UserEvent>>>,
app_name: String, app_name: String,
native_options: NativeOptions, native_options: NativeOptions,
/// Set at initialization, then taken and set to `None` in `init_run_state`. /// Set at initialization, then taken and set to `None` in `init_run_state`.
app_creator: Option<AppCreator<'app>>, app_creator: Option<AppCreator>,
/// Set when we are actually up and running. /// Set when we are actually up and running.
running: Option<WgpuWinitRunning<'app>>, running: Option<WgpuWinitRunning>,
} }
/// State that is initialized when the application is first starts running via /// State that is initialized when the application is first starts running via
/// a Resumed event. On Android this ensures that any graphics state is only /// a Resumed event. On Android this ensures that any graphics state is only
/// initialized once the application has an associated `SurfaceView`. /// initialized once the application has an associated `SurfaceView`.
struct WgpuWinitRunning<'app> { struct WgpuWinitRunning {
integration: EpiIntegration, integration: EpiIntegration,
/// The users application. /// The users application.
app: Box<dyn 'app + App>, app: Box<dyn App>,
/// Wrapped in an `Rc<RefCell<…>>` so it can be re-entrantly shared via a weak-pointer. /// Wrapped in an `Rc<RefCell<…>>` so it can be re-entrantly shared via a weak-pointer.
shared: Rc<RefCell<SharedState>>, shared: Rc<RefCell<SharedState>>,
@@ -97,12 +97,12 @@ pub struct Viewport {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
impl<'app> WgpuWinitApp<'app> { impl WgpuWinitApp {
pub fn new( pub fn new(
event_loop: &EventLoop<UserEvent>, event_loop: &EventLoop<UserEvent>,
app_name: &str, app_name: &str,
native_options: NativeOptions, native_options: NativeOptions,
app_creator: AppCreator<'app>, app_creator: AppCreator,
) -> Self { ) -> Self {
profiling::function_scope!(); profiling::function_scope!();
@@ -182,7 +182,7 @@ impl<'app> WgpuWinitApp<'app> {
storage: Option<Box<dyn Storage>>, storage: Option<Box<dyn Storage>>,
window: Window, window: Window,
builder: ViewportBuilder, builder: ViewportBuilder,
) -> crate::Result<&mut WgpuWinitRunning<'app>> { ) -> crate::Result<&mut WgpuWinitRunning> {
profiling::function_scope!(); profiling::function_scope!();
let mut painter = pollster::block_on(egui_wgpu::winit::Painter::new( let mut painter = pollster::block_on(egui_wgpu::winit::Painter::new(
egui_ctx.clone(), egui_ctx.clone(),
@@ -341,7 +341,7 @@ impl<'app> WgpuWinitApp<'app> {
} }
} }
impl WinitApp for WgpuWinitApp<'_> { impl WinitApp for WgpuWinitApp {
fn egui_ctx(&self) -> Option<&egui::Context> { fn egui_ctx(&self) -> Option<&egui::Context> {
self.running.as_ref().map(|r| &r.integration.egui_ctx) self.running.as_ref().map(|r| &r.integration.egui_ctx)
} }
@@ -510,7 +510,7 @@ impl WinitApp for WgpuWinitApp<'_> {
} }
} }
impl WgpuWinitRunning<'_> { impl WgpuWinitRunning {
/// Saves the application state /// Saves the application state
fn save(&mut self) { fn save(&mut self) {
let shared = self.shared.borrow(); let shared = self.shared.borrow();

View File

@@ -43,7 +43,7 @@ impl AppRunner {
pub async fn new( pub async fn new(
canvas: web_sys::HtmlCanvasElement, canvas: web_sys::HtmlCanvasElement,
web_options: crate::WebOptions, web_options: crate::WebOptions,
app_creator: epi::AppCreator<'static>, app_creator: epi::AppCreator,
text_agent: TextAgent, text_agent: TextAgent,
) -> Result<Self, String> { ) -> Result<Self, String> {
let egui_ctx = egui::Context::default(); let egui_ctx = egui::Context::default();

View File

@@ -58,7 +58,7 @@ impl WebRunner {
&self, &self,
canvas: web_sys::HtmlCanvasElement, canvas: web_sys::HtmlCanvasElement,
web_options: crate::WebOptions, web_options: crate::WebOptions,
app_creator: epi::AppCreator<'static>, app_creator: epi::AppCreator,
) -> Result<(), JsValue> { ) -> Result<(), JsValue> {
self.destroy(); self.destroy();