From cce89f2d8342da0d1873aabe8d58da322d01d62f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 11:02:24 +0100 Subject: [PATCH 01/11] Change how eframe apps are created --- eframe/examples/custom_3d.rs | 36 ++++++++++++++-------- eframe/src/lib.rs | 34 ++++++++++++++++----- egui-winit/src/epi.rs | 58 +++++++++++------------------------- egui/src/lib.rs | 4 +-- egui_glow/src/epi_backend.rs | 46 ++++++++++++++++++++++------ epi/src/lib.rs | 47 +++++++++++++---------------- 6 files changed, 126 insertions(+), 99 deletions(-) diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index 548918f744e..a0c5c3160b9 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -13,17 +13,26 @@ use eframe::{egui, epi}; use parking_lot::Mutex; use std::sync::Arc; -#[derive(Default)] struct MyApp { - rotating_triangle: Arc>>, + rotating_triangle: Arc>, angle: f32, } -impl epi::App for MyApp { - fn name(&self) -> &str { - "Custom 3D painting inside an egui window" +impl MyApp { + fn new( + _ctx: &egui::Context, + _frame: &epi::Frame, + _storage: Option<&dyn epi::Storage>, + gl: &std::rc::Rc, + ) -> Box { + Box::new(MyApp { + rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(gl))), + angle: 0.0, + }) } +} +impl epi::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Here is some 3D stuff:"); @@ -44,6 +53,10 @@ impl epi::App for MyApp { self.custom_painting(ui); }); } + + fn on_exit(&mut self, gl: &glow::Context) { + self.rotating_triangle.lock().destroy(gl) + } } impl MyApp { @@ -53,16 +66,15 @@ impl MyApp { self.angle += response.drag_delta().x * 0.01; + // Clone locals so we can move them into the paint callback: let angle = self.angle; let rotating_triangle = self.rotating_triangle.clone(); - let callback = egui::epaint::PaintCallback { + let callback = egui::PaintCallback { rect, callback: std::sync::Arc::new(move |render_ctx| { if let Some(painter) = render_ctx.downcast_ref::() { - let mut rotating_triangle = rotating_triangle.lock(); - let rotating_triangle = rotating_triangle - .get_or_insert_with(|| RotatingTriangle::new(painter.gl())); + let rotating_triangle = rotating_triangle.lock(); rotating_triangle.paint(painter.gl(), angle); } else { eprintln!("Can't do custom painting because we are not using a glow context"); @@ -163,9 +175,7 @@ impl RotatingTriangle { } } - // TODO: figure out how to call this in a nice way - #[allow(unused)] - fn destroy(self, gl: &glow::Context) { + fn destroy(&self, gl: &glow::Context) { use glow::HasContext as _; unsafe { gl.delete_program(self.program); @@ -189,5 +199,5 @@ impl RotatingTriangle { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("Custom 3D painting in eframe", options, MyApp::new); } diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index fcb55cecb7f..d1ac2a3dbc7 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -117,6 +117,11 @@ pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bin // ---------------------------------------------------------------------------- // When compiling natively +/// This is how you start a native (desktop) app. +/// +/// The first argument is name of your app, used for the title bar of the native window +/// and the save location of persistence (see [`epi::App::save`]). +/// /// Call from `fn main` like this: /// ``` no_run /// use eframe::{epi, egui}; @@ -124,11 +129,22 @@ pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bin /// #[derive(Default)] /// struct MyEguiApp {} /// -/// impl epi::App for MyEguiApp { -/// fn name(&self) -> &str { -/// "My egui App" -/// } +/// impl MyEguiApp { +/// fn new( +/// _ctx: &egui::Context, +/// _frame: &epi::Frame, +/// _storage: Option<&dyn epi::Storage>, +/// _gl: &std::rc::Rc +/// ) -> Box { +/// // Customize egui here with ctx.set_fonts and ctx.set_visuals. +/// // Restore app state using the storage (requires the "persistence" feature). +/// // Use the glow::Context to create graphics shaders and buffers that you can use +/// // for e.g. egui::PaintCallback +/// Box::new(MyEguiApp::default()) +/// } +/// } /// +/// impl epi::App for MyEguiApp { /// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { /// egui::CentralPanel::default().show(ctx, |ui| { /// ui.heading("Hello World!"); @@ -139,10 +155,14 @@ pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bin /// fn main() { /// let app = MyEguiApp::default(); /// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native(Box::new(app), native_options); +/// eframe::run_native("MyApp", native_options, MyEguiApp::new); /// } /// ``` #[cfg(not(target_arch = "wasm32"))] -pub fn run_native(app: Box, native_options: epi::NativeOptions) -> ! { - egui_glow::run(app, &native_options) +pub fn run_native( + app_name: &str, + native_options: epi::NativeOptions, + app_creator: epi::AppCreator, +) -> ! { + egui_glow::run(app_name, &native_options, app_creator) } diff --git a/egui-winit/src/epi.rs b/egui-winit/src/epi.rs index e09af05ef89..f7772f0f7a5 100644 --- a/egui-winit/src/epi.rs +++ b/egui-winit/src/epi.rs @@ -216,14 +216,13 @@ impl Persistence { /// Everything needed to make a winit-based integration for [`epi`]. pub struct EpiIntegration { - frame: epi::Frame, - persistence: crate::epi::Persistence, + pub frame: epi::Frame, + pub persistence: crate::epi::Persistence, pub egui_ctx: egui::Context, pending_full_output: egui::FullOutput, egui_winit: crate::State, - pub app: Box, /// When set, it is time to quit - quit: bool, + pub quit: bool, can_drag_window: bool, } @@ -234,7 +233,6 @@ impl EpiIntegration { window: &winit::window::Window, gl: &std::rc::Rc, persistence: crate::epi::Persistence, - app: Box, ) -> Self { let egui_ctx = egui::Context::default(); @@ -259,41 +257,21 @@ impl EpiIntegration { egui_ctx.set_visuals(egui::Visuals::light()); } - let mut slf = Self { + Self { frame, persistence, egui_ctx, egui_winit: crate::State::new(max_texture_side, window), pending_full_output: Default::default(), - app, quit: false, can_drag_window: false, - }; - - slf.setup(window, gl); - if slf.app.warm_up_enabled() { - slf.warm_up(window); - } - - slf - } - - fn setup(&mut self, window: &winit::window::Window, gl: &std::rc::Rc) { - self.app - .setup(&self.egui_ctx, &self.frame, self.persistence.storage(), gl); - let app_output = self.frame.take_app_output(); - - if app_output.quit { - self.quit = self.app.on_exit_event(); } - - crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); } - fn warm_up(&mut self, window: &winit::window::Window) { + pub fn warm_up(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) { let saved_memory: egui::Memory = self.egui_ctx.memory().clone(); self.egui_ctx.memory().set_everything_is_visible(true); - let full_output = self.update(window); + let full_output = self.update(app, window); self.pending_full_output.append(full_output); // Handle it next frame *self.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge. self.egui_ctx.clear_animations(); @@ -304,11 +282,11 @@ impl EpiIntegration { self.quit } - pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) { + pub fn on_event(&mut self, app: &mut dyn epi::App, event: &winit::event::WindowEvent<'_>) { use winit::event::{ElementState, MouseButton, WindowEvent}; match event { - WindowEvent::CloseRequested => self.quit = self.app.on_exit_event(), + WindowEvent::CloseRequested => self.quit = app.on_exit_event(), WindowEvent::Destroyed => self.quit = true, WindowEvent::MouseInput { button: MouseButton::Left, @@ -321,12 +299,16 @@ impl EpiIntegration { self.egui_winit.on_event(&self.egui_ctx, event); } - pub fn update(&mut self, window: &winit::window::Window) -> egui::FullOutput { + pub fn update( + &mut self, + app: &mut dyn epi::App, + window: &winit::window::Window, + ) -> egui::FullOutput { let frame_start = instant::Instant::now(); let raw_input = self.egui_winit.take_egui_input(window); let full_output = self.egui_ctx.run(raw_input, |egui_ctx| { - self.app.update(egui_ctx, &self.frame); + app.update(egui_ctx, &self.frame); }); self.pending_full_output.append(full_output); let full_output = std::mem::take(&mut self.pending_full_output); @@ -336,7 +318,7 @@ impl EpiIntegration { app_output.drag_window &= self.can_drag_window; // Necessary on Windows; see https://github.com/emilk/egui/pull/1108 self.can_drag_window = false; if app_output.quit { - self.quit = self.app.on_exit_event(); + self.quit = app.on_exit_event(); } crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); } @@ -356,15 +338,9 @@ impl EpiIntegration { .handle_platform_output(window, &self.egui_ctx, platform_output); } - pub fn maybe_autosave(&mut self, window: &winit::window::Window) { - self.persistence - .maybe_autosave(&mut *self.app, &self.egui_ctx, window); - } - - pub fn on_exit(&mut self, window: &winit::window::Window) { - self.app.on_exit(); + pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) { self.persistence - .save(&mut *self.app, &self.egui_ctx, window); + .maybe_autosave(&mut *app, &self.egui_ctx, window); } } diff --git a/egui/src/lib.rs b/egui/src/lib.rs index 07e283e42ca..e3a604150d4 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -386,8 +386,8 @@ pub use epaint::{ color, mutex, text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak}, textures::TexturesDelta, - AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, Rgba, Rounding, Shape, - Stroke, TextureHandle, TextureId, + AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, PaintCallback, Rgba, + Rounding, Shape, Stroke, TextureHandle, TextureId, }; pub mod text { diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index bef12fad20d..642cc0c7959 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -39,24 +39,24 @@ pub use epi::NativeOptions; /// Run an egui app #[allow(unsafe_code)] -pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { - let persistence = egui_winit::epi::Persistence::from_app_name(app.name()); +pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi::AppCreator) -> ! { + let persistence = egui_winit::epi::Persistence::from_app_name(app_name); let window_settings = persistence.load_window_settings(); let window_builder = - egui_winit::epi::window_builder(native_options, &window_settings).with_title(app.name()); + egui_winit::epi::window_builder(native_options, &window_settings).with_title(app_name); let event_loop = winit::event_loop::EventLoop::with_user_event(); let (gl_window, gl) = create_display(window_builder, &event_loop); let gl = std::rc::Rc::new(gl); let mut painter = crate::Painter::new(gl.clone(), None, "") .unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error)); + let mut integration = egui_winit::epi::EpiIntegration::new( "egui_glow", painter.max_texture_side(), gl_window.window(), &gl, persistence, - app, ); { @@ -66,6 +66,31 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { }); } + let mut app = app_creator( + &integration.egui_ctx, + &integration.frame, + integration.persistence.storage(), + &gl, + ); + + { + // things that happened during app creation: + let app_output = integration.frame.take_app_output(); + if app_output.quit { + integration.quit = app.on_exit_event(); + } + egui_winit::epi::handle_app_output( + gl_window.window(), + integration.egui_ctx.pixels_per_point(), + app_output, + ); + } + + if app.warm_up_enabled() { + integration.warm_up(app.as_mut(), gl_window.window()); +>>>>>>> d870c2f1 (Change how eframe apps are created) + } + let mut is_focused = true; event_loop.run(move |event, _, control_flow| { @@ -84,7 +109,7 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { needs_repaint, textures_delta, shapes, - } = integration.update(gl_window.window()); + } = integration.update(app.as_mut(), gl_window.window()); integration.handle_platform_output(gl_window.window(), platform_output); @@ -92,7 +117,7 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { // paint: { - let color = integration.app.clear_color(); + let color = app.clear_color(); unsafe { use glow::HasContext as _; gl.disable(glow::SCISSOR_TEST); @@ -120,7 +145,7 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { }; } - integration.maybe_autosave(gl_window.window()); + integration.maybe_autosave(app.as_mut(), gl_window.window()); }; match event { @@ -139,7 +164,7 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { gl_window.resize(physical_size); } - integration.on_event(&event); + integration.on_event(app.as_mut(), &event); if integration.should_quit() { *control_flow = winit::event_loop::ControlFlow::Exit; } @@ -147,7 +172,10 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { gl_window.window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead } winit::event::Event::LoopDestroyed => { - integration.on_exit(gl_window.window()); + integration + .persistence + .save(&mut *app, &integration.egui_ctx, gl_window.window()); + app.on_exit(&gl); painter.destroy(); } winit::event::Event::UserEvent(RequestRepaintEvent) => { diff --git a/epi/src/lib.rs b/epi/src/lib.rs index c618c0d8e87..c4efcdc2bab 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -98,6 +98,20 @@ pub use glow; // Re-export for user convenience use std::sync::{Arc, Mutex}; +/// The is is how your app is created. +/// +/// You need to define a function with this signature. +/// +/// You can use this to customize the look of egui, e.g to call [`egui::Context::set_fonts`], +/// [`egui::Context::set_visuals`] etc. +/// +/// You can use the storage to restore app state state (requires the "persistence" feature). +/// +/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that +/// you might want to use later from a [`egui::PaintCallback`]. +pub type AppCreator = + fn(&egui::Context, &Frame, Option<&dyn Storage>, &std::rc::Rc) -> Box; + // ---------------------------------------------------------------------------- /// Implement this trait to write apps that can be compiled both natively using the [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) crate, @@ -113,35 +127,17 @@ pub trait App { /// or call [`Frame::request_repaint`] at any time (e.g. from another thread). fn update(&mut self, ctx: &egui::Context, frame: &Frame); - /// Called exactly once at startup, before any call to [`Self::update`]. - /// - /// Allows you to do setup code, e.g to call [`egui::Context::set_fonts`], - /// [`egui::Context::set_visuals`] etc. - /// - /// Also allows you to restore state, if there is a storage (requires the "persistence" feature). - /// - /// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that - /// you might want to use later from a [`egui::PaintCallback`]. - fn setup( - &mut self, - _ctx: &egui::Context, - _frame: &Frame, - _storage: Option<&dyn Storage>, - _gl: &std::rc::Rc, - ) { - } - /// Called on shutdown, and perhaps at regular intervals. Allows you to save state. /// /// Only called when the "persistence" feature is enabled. /// - /// On web the states is stored to "Local Storage". + /// On web the state is stored to "Local Storage". /// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is: /// * Linux: `/home/UserName/.local/share/APPNAME` /// * macOS: `/Users/UserName/Library/Application Support/APPNAME` /// * Windows: `C:\Users\UserName\AppData\Roaming\APPNAME` /// - /// where `APPNAME` is what is returned by [`Self::name()`]. + /// where `APPNAME` is what is given to `eframe::run_native`. fn save(&mut self, _storage: &mut dyn Storage) {} /// Called before an exit that can be aborted. @@ -156,17 +152,14 @@ pub trait App { true } - /// Called once on shutdown (before or after [`Self::save`]). If you need to abort an exit use - /// [`Self::on_exit_event`] - fn on_exit(&mut self) {} + /// Called once on shutdown, after [`Self::save`]. + /// + /// If you need to abort an exit use [`Self::on_exit_event`]. + fn on_exit(&mut self, _gl: &glow::Context) {} // --------- // Settings: - /// The name of your App, used for the title bar of native windows - /// and the save location of persistence (see [`Self::save`]). - fn name(&self) -> &str; - /// Time between automatic calls to [`Self::save`] fn auto_save_interval(&self) -> std::time::Duration { std::time::Duration::from_secs(30) From c4c3967f733d26f47b86455d5175b6b719095291 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 13:35:08 +0100 Subject: [PATCH 02/11] Convert egui_web and all apps to the new format --- eframe/examples/confirm_exit.rs | 8 +- eframe/examples/custom_font.rs | 81 +++++++++---------- eframe/examples/download_image.rs | 10 +-- eframe/examples/file_dialog.rs | 10 +-- eframe/examples/hello_world.rs | 8 +- eframe/examples/image.rs | 8 +- eframe/examples/svg.rs | 8 +- eframe/src/lib.rs | 7 +- egui-winit/src/epi.rs | 1 - egui_demo_app/src/lib.rs | 3 +- egui_demo_app/src/main.rs | 3 +- egui_demo_lib/src/apps/color_test.rs | 4 - egui_demo_lib/src/apps/demo/app.rs | 27 +------ egui_demo_lib/src/apps/fractal_clock.rs | 4 - egui_demo_lib/src/apps/http_app.rs | 4 - .../src/easy_mark/easy_mark_editor.rs | 4 - egui_demo_lib/src/wrap_app.rs | 48 ++++++----- egui_glow/src/epi_backend.rs | 2 - egui_web/src/backend.rs | 13 ++- 19 files changed, 104 insertions(+), 149 deletions(-) diff --git a/eframe/examples/confirm_exit.rs b/eframe/examples/confirm_exit.rs index f1e8a359dcb..9c25ee286f6 100644 --- a/eframe/examples/confirm_exit.rs +++ b/eframe/examples/confirm_exit.rs @@ -9,10 +9,6 @@ struct MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "Confirm exit" - } - fn on_exit_event(&mut self) -> bool { self.is_exiting = true; self.can_exit @@ -45,5 +41,7 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("Confirm exit", options, |_, _, _, _| { + Box::new(MyApp::default()) + }); } diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index 0192d32ca1f..766354607b6 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -1,57 +1,54 @@ use eframe::{egui, epi}; -struct MyApp { - text: String, +fn setup_custom_fonts(ctx: &egui::Context) { + // Start with the default fonts (we will be adding to them rather than replacing them). + let mut fonts = egui::FontDefinitions::default(); + + // Install my own font (maybe supporting non-latin characters). + // .ttf and .otf files supported. + fonts.font_data.insert( + "my_font".to_owned(), + egui::FontData::from_static(include_bytes!("../../epaint/fonts/Hack-Regular.ttf")), + ); + + // Put my font first (highest priority) for proportional text: + fonts + .families + .entry(egui::FontFamily::Proportional) + .or_default() + .insert(0, "my_font".to_owned()); + + // Put my font as last fallback for monospace: + fonts + .families + .entry(egui::FontFamily::Monospace) + .or_default() + .push("my_font".to_owned()); + + // Tell egui to use these fonts: + ctx.set_fonts(fonts); } -impl Default for MyApp { - fn default() -> Self { - Self { - text: "Edit this text field if you want".to_owned(), - } - } +struct MyApp { + text: String, } -impl epi::App for MyApp { - fn name(&self) -> &str { - "egui example: custom font" - } - - fn setup( - &mut self, +impl MyApp { + fn new( ctx: &egui::Context, _frame: &epi::Frame, _storage: Option<&dyn epi::Storage>, _gl: &std::rc::Rc, - ) { - // Start with the default fonts (we will be adding to them rather than replacing them). - let mut fonts = egui::FontDefinitions::default(); - - // Install my own font (maybe supporting non-latin characters). - // .ttf and .otf files supported. - fonts.font_data.insert( - "my_font".to_owned(), - egui::FontData::from_static(include_bytes!("../../epaint/fonts/Hack-Regular.ttf")), - ); - - // Put my font first (highest priority) for proportional text: - fonts - .families - .entry(egui::FontFamily::Proportional) - .or_default() - .insert(0, "my_font".to_owned()); - - // Put my font as last fallback for monospace: - fonts - .families - .entry(egui::FontFamily::Monospace) - .or_default() - .push("my_font".to_owned()); + ) -> Box { + setup_custom_fonts(ctx); - // Tell egui to use these fonts: - ctx.set_fonts(fonts); + Box::new(MyApp { + text: "Edit this text field if you want".to_owned(), + }) } +} +impl epi::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("egui using custom fonts"); @@ -62,5 +59,5 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("egui example: custom font", options, MyApp::new); } diff --git a/eframe/examples/download_image.rs b/eframe/examples/download_image.rs index ba754b75aa7..82716f46604 100644 --- a/eframe/examples/download_image.rs +++ b/eframe/examples/download_image.rs @@ -6,7 +6,11 @@ use poll_promise::Promise; fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native( + "Download and show an image with eframe/egui", + options, + |_, _, _, _| Box::new(MyApp::default()), + ); } #[derive(Default)] @@ -16,10 +20,6 @@ struct MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "Download and show an image with eframe/egui" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { let promise = self.promise.get_or_insert_with(|| { // Begin download. diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs index f4b2f5a91de..2360e1fae2b 100644 --- a/eframe/examples/file_dialog.rs +++ b/eframe/examples/file_dialog.rs @@ -9,10 +9,6 @@ struct MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "Native file dialogs and drag-and-drop files" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.label("Drag-and-drop files onto the window!"); @@ -99,5 +95,9 @@ fn main() { drag_and_drop_support: true, ..Default::default() }; - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native( + "Native file dialogs and drag-and-drop files", + options, + |_, _, _, _| Box::new(MyApp::default()), + ); } diff --git a/eframe/examples/hello_world.rs b/eframe/examples/hello_world.rs index 77f1479b716..3aaf6bc00ab 100644 --- a/eframe/examples/hello_world.rs +++ b/eframe/examples/hello_world.rs @@ -17,10 +17,6 @@ impl Default for MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "My egui App" - } - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("My egui Application"); @@ -42,5 +38,7 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("My egui App", options, |_, _, _, _| { + Box::new(MyApp::default()) + }); } diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 97575c23581..93f38149851 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -20,10 +20,6 @@ impl Default for MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "Show an image with eframe/egui" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("This is an image:"); @@ -40,5 +36,7 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("Show an image with eframe/egui", options, |_, _, _, _| { + Box::new(MyApp::default()) + }); } diff --git a/eframe/examples/svg.rs b/eframe/examples/svg.rs index b7d362f925f..44ea22fb74a 100644 --- a/eframe/examples/svg.rs +++ b/eframe/examples/svg.rs @@ -23,10 +23,6 @@ impl Default for MyApp { } impl epi::App for MyApp { - fn name(&self) -> &str { - "svg example" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("SVG example"); @@ -45,5 +41,7 @@ fn main() { initial_window_size: Some(egui::vec2(1000.0, 700.0)), ..Default::default() }; - eframe::run_native(Box::new(MyApp::default()), options); + eframe::run_native("svg example", options, |_, _, _, _| { + Box::new(MyApp::default()) + }); } diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index d1ac2a3dbc7..3c2741c7919 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -109,8 +109,11 @@ pub use egui_web::wasm_bindgen; /// } /// ``` #[cfg(target_arch = "wasm32")] -pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bindgen::JsValue> { - egui_web::start(canvas_id, app)?; +pub fn start_web( + canvas_id: &str, + app_creator: epi::AppCreator, +) -> Result<(), wasm_bindgen::JsValue> { + egui_web::start(canvas_id, app_creator)?; Ok(()) } diff --git a/egui-winit/src/epi.rs b/egui-winit/src/epi.rs index f7772f0f7a5..2c57c6b32af 100644 --- a/egui-winit/src/epi.rs +++ b/egui-winit/src/epi.rs @@ -231,7 +231,6 @@ impl EpiIntegration { integration_name: &'static str, max_texture_side: usize, window: &winit::window::Window, - gl: &std::rc::Rc, persistence: crate::epi::Persistence, ) -> Self { let egui_ctx = egui::Context::default(); diff --git a/egui_demo_app/src/lib.rs b/egui_demo_app/src/lib.rs index 487933f2745..234425da92e 100644 --- a/egui_demo_app/src/lib.rs +++ b/egui_demo_app/src/lib.rs @@ -19,6 +19,5 @@ pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> { // Redirect tracing to console.log and friends: tracing_wasm::set_as_global_default(); - let app = egui_demo_lib::WrapApp::default(); - eframe::start_web(canvas_id, Box::new(app)) + eframe::start_web(canvas_id, egui_demo_lib::WrapApp::new) } diff --git a/egui_demo_app/src/main.rs b/egui_demo_app/src/main.rs index 1ad429b9b4c..03efc928906 100644 --- a/egui_demo_app/src/main.rs +++ b/egui_demo_app/src/main.rs @@ -10,12 +10,11 @@ fn main() { // Log to stdout (if you run with `RUST_LOG=debug`). tracing_subscriber::fmt::init(); - let app = egui_demo_lib::WrapApp::default(); let options = eframe::NativeOptions { // Let's show off that we support transparent windows transparent: true, drag_and_drop_support: true, ..Default::default() }; - eframe::run_native(Box::new(app), options); + eframe::run_native("egui demo app", options, egui_demo_lib::WrapApp::new); } diff --git a/egui_demo_lib/src/apps/color_test.rs b/egui_demo_lib/src/apps/color_test.rs index ca25fd17722..cf002269fb7 100644 --- a/egui_demo_lib/src/apps/color_test.rs +++ b/egui_demo_lib/src/apps/color_test.rs @@ -30,10 +30,6 @@ impl Default for ColorTest { } impl epi::App for ColorTest { - fn name(&self) -> &str { - "🎨 Color test" - } - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { if frame.is_web() { diff --git a/egui_demo_lib/src/apps/demo/app.rs b/egui_demo_lib/src/apps/demo/app.rs index 5544a51ad39..2e87aae6a09 100644 --- a/egui_demo_lib/src/apps/demo/app.rs +++ b/egui_demo_lib/src/apps/demo/app.rs @@ -1,7 +1,4 @@ -/// Demonstrates how to make an app using egui. -/// -/// Implements `epi::App` so it can be used with -/// [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium), [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) and [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web). +/// Demonstrates how to make an eframe app using egui. #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] @@ -10,28 +7,6 @@ pub struct DemoApp { } impl epi::App for DemoApp { - fn name(&self) -> &str { - "✨ Demos" - } - - fn setup( - &mut self, - _ctx: &egui::Context, - _frame: &epi::Frame, - _storage: Option<&dyn epi::Storage>, - _gl: &std::rc::Rc, - ) { - #[cfg(feature = "persistence")] - if let Some(storage) = _storage { - *self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); - } - } - - #[cfg(feature = "persistence")] - fn save(&mut self, storage: &mut dyn epi::Storage) { - epi::set_value(storage, epi::APP_KEY, self); - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { self.demo_windows.ui(ctx); } diff --git a/egui_demo_lib/src/apps/fractal_clock.rs b/egui_demo_lib/src/apps/fractal_clock.rs index 943a0139604..51a03f4c938 100644 --- a/egui_demo_lib/src/apps/fractal_clock.rs +++ b/egui_demo_lib/src/apps/fractal_clock.rs @@ -33,10 +33,6 @@ impl Default for FractalClock { } impl epi::App for FractalClock { - fn name(&self) -> &str { - "🕑 Fractal Clock" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default() .frame(Frame::dark_canvas(&ctx.style())) diff --git a/egui_demo_lib/src/apps/http_app.rs b/egui_demo_lib/src/apps/http_app.rs index 63ae9f01309..a2c9097c777 100644 --- a/egui_demo_lib/src/apps/http_app.rs +++ b/egui_demo_lib/src/apps/http_app.rs @@ -54,10 +54,6 @@ impl Default for HttpApp { } impl epi::App for HttpApp { - fn name(&self) -> &str { - "⬇ HTTP" - } - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| { let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); diff --git a/egui_demo_lib/src/easy_mark/easy_mark_editor.rs b/egui_demo_lib/src/easy_mark/easy_mark_editor.rs index dc066e383ca..30350e8428a 100644 --- a/egui_demo_lib/src/easy_mark/easy_mark_editor.rs +++ b/egui_demo_lib/src/easy_mark/easy_mark_editor.rs @@ -30,10 +30,6 @@ impl Default for EasyMarkEditor { } impl epi::App for EasyMarkEditor { - fn name(&self) -> &str { - "🖹 EasyMark editor" - } - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| { let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); diff --git a/egui_demo_lib/src/wrap_app.rs b/egui_demo_lib/src/wrap_app.rs index 0a1195978e9..f8d8fa03b91 100644 --- a/egui_demo_lib/src/wrap_app.rs +++ b/egui_demo_lib/src/wrap_app.rs @@ -12,14 +12,26 @@ pub struct Apps { } impl Apps { - fn iter_mut(&mut self) -> impl Iterator { + fn iter_mut(&mut self) -> impl Iterator { vec![ - ("demo", &mut self.demo as &mut dyn epi::App), - ("easymark", &mut self.easy_mark_editor as &mut dyn epi::App), + ("✨ Demos", "demo", &mut self.demo as &mut dyn epi::App), + ( + "🖹 EasyMark editor", + "easymark", + &mut self.easy_mark_editor as &mut dyn epi::App, + ), #[cfg(feature = "http")] - ("http", &mut self.http as &mut dyn epi::App), - ("clock", &mut self.clock as &mut dyn epi::App), - ("colors", &mut self.color_test as &mut dyn epi::App), + ("⬇ HTTP", "http", &mut self.http as &mut dyn epi::App), + ( + "🕑 Fractal Clock", + "clock", + &mut self.clock as &mut dyn epi::App, + ), + ( + "🎨 Color test", + "colors", + &mut self.color_test as &mut dyn epi::App, + ), ] .into_iter() } @@ -37,24 +49,24 @@ pub struct WrapApp { dropped_files: Vec, } -impl epi::App for WrapApp { - fn name(&self) -> &str { - "egui demo apps" - } - - fn setup( - &mut self, +impl WrapApp { + pub fn new( _ctx: &egui::Context, _frame: &epi::Frame, _storage: Option<&dyn epi::Storage>, _gl: &std::rc::Rc, - ) { + ) -> Box { #[cfg(feature = "persistence")] if let Some(storage) = _storage { - *self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); + let app: Self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); + return Box::new(app); } + + Box::new(WrapApp::default()) } +} +impl epi::App for WrapApp { #[cfg(feature = "persistence")] fn save(&mut self, storage: &mut dyn epi::Storage) { epi::set_value(storage, epi::APP_KEY, self); @@ -111,7 +123,7 @@ impl epi::App for WrapApp { let mut found_anchor = false; - for (anchor, app) in self.apps.iter_mut() { + for (_name, anchor, app) in self.apps.iter_mut() { if anchor == self.selected_anchor || ctx.memory().everything_is_visible() { app.update(ctx, frame); found_anchor = true; @@ -138,9 +150,9 @@ impl WrapApp { ui.checkbox(&mut self.backend_panel.open, "💻 Backend"); ui.separator(); - for (anchor, app) in self.apps.iter_mut() { + for (name, anchor, _app) in self.apps.iter_mut() { if ui - .selectable_label(self.selected_anchor == anchor, app.name()) + .selectable_label(self.selected_anchor == anchor, name) .clicked() { self.selected_anchor = anchor.to_owned(); diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 642cc0c7959..3ebaedb86cc 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -55,7 +55,6 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi "egui_glow", painter.max_texture_side(), gl_window.window(), - &gl, persistence, ); @@ -88,7 +87,6 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi if app.warm_up_enabled() { integration.warm_up(app.as_mut(), gl_window.window()); ->>>>>>> d870c2f1 (Change how eframe apps are created) } let mut is_focused = true; diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index b85d1a08d80..df14491dea3 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -139,7 +139,7 @@ pub struct AppRunner { } impl AppRunner { - pub fn new(canvas_id: &str, app: Box) -> Result { + pub fn new(canvas_id: &str, app_creator: epi::AppCreator) -> Result { let painter = WrappedGlowPainter::new(canvas_id).map_err(JsValue::from)?; let prefer_dark_mode = crate::prefer_dark_mode(); @@ -177,6 +177,8 @@ impl AppRunner { let storage = LocalStorage::default(); + let app = app_creator(&egui_ctx, &frame, Some(&storage), painter.painter.gl()); + let mut runner = Self { frame, egui_ctx, @@ -194,11 +196,6 @@ impl AppRunner { runner.input.raw.max_texture_side = Some(runner.painter.max_texture_side()); - let gl = runner.painter.painter.gl(); - runner - .app - .setup(&runner.egui_ctx, &runner.frame, Some(&runner.storage), gl); - Ok(runner) } @@ -327,8 +324,8 @@ impl AppRunner { /// Install event listeners to register different input events /// and start running the given app. -pub fn start(canvas_id: &str, app: Box) -> Result { - let mut runner = AppRunner::new(canvas_id, app)?; +pub fn start(canvas_id: &str, app_creator: epi::AppCreator) -> Result { + let mut runner = AppRunner::new(canvas_id, app_creator)?; runner.warm_up()?; start_runner(runner) } From c05a6038a858bc41b9803c70cb4d73256ba2978e Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 16:42:04 +0100 Subject: [PATCH 03/11] Add epi::CreationContext to reduce parameter count --- eframe/examples/confirm_exit.rs | 4 +-- eframe/examples/custom_3d.rs | 40 ++++++++++------------- eframe/examples/custom_font.rs | 18 ++++------- eframe/examples/download_image.rs | 2 +- eframe/examples/file_dialog.rs | 2 +- eframe/examples/hello_world.rs | 4 +-- eframe/examples/image.rs | 2 +- eframe/examples/svg.rs | 4 +-- eframe/src/lib.rs | 54 +++++++++++++------------------ egui_demo_app/src/main.rs | 4 ++- egui_demo_lib/src/wrap_app.rs | 15 +++------ egui_glow/src/epi_backend.rs | 13 ++++---- egui_web/src/backend.rs | 7 +++- epi/src/lib.rs | 23 +++++++++++-- 14 files changed, 93 insertions(+), 99 deletions(-) diff --git a/eframe/examples/confirm_exit.rs b/eframe/examples/confirm_exit.rs index 9c25ee286f6..805cab33996 100644 --- a/eframe/examples/confirm_exit.rs +++ b/eframe/examples/confirm_exit.rs @@ -41,7 +41,5 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native("Confirm exit", options, |_, _, _, _| { - Box::new(MyApp::default()) - }); + eframe::run_native("Confirm exit", options, |_cc| Box::new(MyApp::default())); } diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index a0c5c3160b9..a13812067b8 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -13,29 +13,36 @@ use eframe::{egui, epi}; use parking_lot::Mutex; use std::sync::Arc; +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native("Custom 3D painting in eframe", options, |cc| { + Box::new(MyApp::new(cc)) + }); +} + struct MyApp { rotating_triangle: Arc>, angle: f32, } impl MyApp { - fn new( - _ctx: &egui::Context, - _frame: &epi::Frame, - _storage: Option<&dyn epi::Storage>, - gl: &std::rc::Rc, - ) -> Box { - Box::new(MyApp { - rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(gl))), + fn new(cc: epi::CreationContext<'_>) -> Self { + Self { + rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))), angle: 0.0, - }) + } } } impl epi::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { - ui.heading("Here is some 3D stuff:"); + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.label("The triangle is being painted using "); + ui.hyperlink_to("glow", "https://github.com/grovesNL/glow"); + ui.label(" (OpenGL)."); + }); egui::ScrollArea::both().show(ui, |ui| { egui::Frame::dark_canvas(ui.style()).show(ui, |ui| { @@ -44,14 +51,6 @@ impl epi::App for MyApp { ui.label("Drag to rotate!"); }); }); - - let mut frame = egui::Frame::window(&*ctx.style()); - frame.fill = frame.fill.linear_multiply(0.5); // transparent - egui::Window::new("3D stuff in a window") - .frame(frame) - .show(ctx, |ui| { - self.custom_painting(ui); - }); } fn on_exit(&mut self, gl: &glow::Context) { @@ -196,8 +195,3 @@ impl RotatingTriangle { } } } - -fn main() { - let options = eframe::NativeOptions::default(); - eframe::run_native("Custom 3D painting in eframe", options, MyApp::new); -} diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index 766354607b6..a52c3edc4c0 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -34,17 +34,11 @@ struct MyApp { } impl MyApp { - fn new( - ctx: &egui::Context, - _frame: &epi::Frame, - _storage: Option<&dyn epi::Storage>, - _gl: &std::rc::Rc, - ) -> Box { - setup_custom_fonts(ctx); - - Box::new(MyApp { + fn new(cc: epi::CreationContext<'_>) -> Self { + setup_custom_fonts(&cc.egui_ctx); + Self { text: "Edit this text field if you want".to_owned(), - }) + } } } @@ -59,5 +53,7 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native("egui example: custom font", options, MyApp::new); + eframe::run_native("egui example: custom font", options, |cc| { + Box::new(MyApp::new(cc)) + }); } diff --git a/eframe/examples/download_image.rs b/eframe/examples/download_image.rs index 82716f46604..43c92692183 100644 --- a/eframe/examples/download_image.rs +++ b/eframe/examples/download_image.rs @@ -9,7 +9,7 @@ fn main() { eframe::run_native( "Download and show an image with eframe/egui", options, - |_, _, _, _| Box::new(MyApp::default()), + |_cc| Box::new(MyApp::default()), ); } diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs index 2360e1fae2b..b078347cb79 100644 --- a/eframe/examples/file_dialog.rs +++ b/eframe/examples/file_dialog.rs @@ -98,6 +98,6 @@ fn main() { eframe::run_native( "Native file dialogs and drag-and-drop files", options, - |_, _, _, _| Box::new(MyApp::default()), + |_cc| Box::new(MyApp::default()), ); } diff --git a/eframe/examples/hello_world.rs b/eframe/examples/hello_world.rs index 3aaf6bc00ab..8bdceed1cde 100644 --- a/eframe/examples/hello_world.rs +++ b/eframe/examples/hello_world.rs @@ -38,7 +38,5 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native("My egui App", options, |_, _, _, _| { - Box::new(MyApp::default()) - }); + eframe::run_native("My egui App", options, |_cc| Box::new(MyApp::default())); } diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 93f38149851..211b68dcdcd 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -36,7 +36,7 @@ impl epi::App for MyApp { fn main() { let options = eframe::NativeOptions::default(); - eframe::run_native("Show an image with eframe/egui", options, |_, _, _, _| { + eframe::run_native("Show an image with eframe/egui", options, |_cc| { Box::new(MyApp::default()) }); } diff --git a/eframe/examples/svg.rs b/eframe/examples/svg.rs index 44ea22fb74a..e804671bbde 100644 --- a/eframe/examples/svg.rs +++ b/eframe/examples/svg.rs @@ -41,7 +41,5 @@ fn main() { initial_window_size: Some(egui::vec2(1000.0, 700.0)), ..Default::default() }; - eframe::run_native("svg example", options, |_, _, _, _| { - Box::new(MyApp::default()) - }); + eframe::run_native("svg example", options, |_cc| Box::new(MyApp::default())); } diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index 3c2741c7919..e6779f1d85e 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -21,22 +21,28 @@ //! #[derive(Default)] //! struct MyEguiApp {} //! -//! impl epi::App for MyEguiApp { -//! fn name(&self) -> &str { -//! "My egui App" -//! } +//! impl MyEguiApp { +//! fn new(cc: epi::CreationContext<'_>) -> Self { +//! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. +//! // Restore app state using cc.storage (requires the "persistence" feature). +//! // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use +//! // for e.g. egui::PaintCallback. +//! Self::default() +//! } +//! } //! +//! impl epi::App for MyEguiApp { //! fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { //! egui::CentralPanel::default().show(ctx, |ui| { //! ui.heading("Hello World!"); //! }); //! } -//!} +//! } //! //! fn main() { //! let app = MyEguiApp::default(); //! let native_options = eframe::NativeOptions::default(); -//! eframe::run_native(Box::new(app), native_options); +//! eframe::run_native("My egui App", native_options, |cc| Box::new(MyEguiApp::new(cc))); //! } //! ``` //! @@ -50,7 +56,7 @@ //! #[wasm_bindgen] //! pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> { //! let app = MyEguiApp::default(); -//! eframe::start_web(canvas_id, Box::new(app)) +//! eframe::start_web(canvas_id, |cc| Box::new(MyApp::new(cc))) //! } //! ``` @@ -83,16 +89,6 @@ pub use egui_web::wasm_bindgen; /// fill the whole width of the browser. /// This can be changed by overriding [`epi::Frame::max_size_points`]. /// -/// ### Usage, native: -/// ``` no_run -/// fn main() { -/// let app = MyEguiApp::default(); -/// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native(Box::new(app), native_options); -/// } -/// ``` -/// -/// ### Web /// ``` no_run /// #[cfg(target_arch = "wasm32")] /// use wasm_bindgen::prelude::*; @@ -104,8 +100,7 @@ pub use egui_web::wasm_bindgen; /// #[cfg(target_arch = "wasm32")] /// #[wasm_bindgen] /// pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> { -/// let app = MyEguiApp::default(); -/// eframe::start_web(canvas_id, Box::new(app)) +/// eframe::start_web(canvas_id, |cc| Box::new(MyEguiApp::new(cc))) /// } /// ``` #[cfg(target_arch = "wasm32")] @@ -133,17 +128,12 @@ pub fn start_web( /// struct MyEguiApp {} /// /// impl MyEguiApp { -/// fn new( -/// _ctx: &egui::Context, -/// _frame: &epi::Frame, -/// _storage: Option<&dyn epi::Storage>, -/// _gl: &std::rc::Rc -/// ) -> Box { -/// // Customize egui here with ctx.set_fonts and ctx.set_visuals. -/// // Restore app state using the storage (requires the "persistence" feature). -/// // Use the glow::Context to create graphics shaders and buffers that you can use -/// // for e.g. egui::PaintCallback -/// Box::new(MyEguiApp::default()) +/// fn new(cc: epi::CreationContext<'_>) -> Self { +/// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. +/// // Restore app state using cc.storage (requires the "persistence" feature). +/// // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use +/// // for e.g. egui::PaintCallback. +/// Self::default() /// } /// } /// @@ -153,12 +143,12 @@ pub fn start_web( /// ui.heading("Hello World!"); /// }); /// } -///} +/// } /// /// fn main() { /// let app = MyEguiApp::default(); /// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native("MyApp", native_options, MyEguiApp::new); +/// eframe::run_native("MyApp", native_options, |cc| Box::new(MyEguiApp::new(cc))); /// } /// ``` #[cfg(not(target_arch = "wasm32"))] diff --git a/egui_demo_app/src/main.rs b/egui_demo_app/src/main.rs index 03efc928906..30425599b38 100644 --- a/egui_demo_app/src/main.rs +++ b/egui_demo_app/src/main.rs @@ -16,5 +16,7 @@ fn main() { drag_and_drop_support: true, ..Default::default() }; - eframe::run_native("egui demo app", options, egui_demo_lib::WrapApp::new); + eframe::run_native("egui demo app", options, |cc| { + Box::new(egui_demo_lib::WrapApp::new(cc)) + }); } diff --git a/egui_demo_lib/src/wrap_app.rs b/egui_demo_lib/src/wrap_app.rs index f8d8fa03b91..a9df554251c 100644 --- a/egui_demo_lib/src/wrap_app.rs +++ b/egui_demo_lib/src/wrap_app.rs @@ -50,19 +50,12 @@ pub struct WrapApp { } impl WrapApp { - pub fn new( - _ctx: &egui::Context, - _frame: &epi::Frame, - _storage: Option<&dyn epi::Storage>, - _gl: &std::rc::Rc, - ) -> Box { + pub fn new(cc: epi::CreationContext<'_>) -> Self { #[cfg(feature = "persistence")] - if let Some(storage) = _storage { - let app: Self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); - return Box::new(app); + if let Some(storage) = cc.storage { + return epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); } - - Box::new(WrapApp::default()) + Self::default() } } diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 3ebaedb86cc..84ee3a512b5 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -65,12 +65,13 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi }); } - let mut app = app_creator( - &integration.egui_ctx, - &integration.frame, - integration.persistence.storage(), - &gl, - ); + let mut app = app_creator(epi::CreationContext { + egui_ctx: integration.egui_ctx.clone(), + integration_info: integration.frame.info(), + #[cfg(feature = "persistence")] + storage: integration.persistence.storage(), + gl: gl.clone(), + }); { // things that happened during app creation: diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index df14491dea3..9c3151cf61f 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -177,7 +177,12 @@ impl AppRunner { let storage = LocalStorage::default(); - let app = app_creator(&egui_ctx, &frame, Some(&storage), painter.painter.gl()); + let app = app_creator(epi::CreationContext { + egui_ctx: egui_ctx.clone(), + integration_info: frame.info(), + storage: Some(&storage), + gl: painter.painter.gl().clone(), + }); let mut runner = Self { frame, diff --git a/epi/src/lib.rs b/epi/src/lib.rs index c4efcdc2bab..473ad12834b 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -109,8 +109,27 @@ use std::sync::{Arc, Mutex}; /// /// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that /// you might want to use later from a [`egui::PaintCallback`]. -pub type AppCreator = - fn(&egui::Context, &Frame, Option<&dyn Storage>, &std::rc::Rc) -> Box; +pub type AppCreator = fn(CreationContext<'_>) -> Box; + +/// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. +pub struct CreationContext<'s> { + /// The egui Context. + /// + /// You can use this to customize the look of egui, e.g to call [`egui::Context::set_fonts`], + /// [`egui::Context::set_visuals`] etc. + pub egui_ctx: egui::Context, + + /// Information about the surrounding environment. + pub integration_info: IntegrationInfo, + + /// You can use the storage to restore app state state (requires the "persistence" feature). + #[cfg(feature = "persistence")] + pub storage: Option<&'s dyn Storage>, + + /// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that + /// you might want to use later from a [`egui::PaintCallback`]. + pub gl: std::rc::Rc, +} // ---------------------------------------------------------------------------- From 58821e7262470be3d648a16dcc3e36daf55c2f47 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 16:43:20 +0100 Subject: [PATCH 04/11] Pass CreationContext by reference --- eframe/examples/custom_3d.rs | 2 +- eframe/examples/custom_font.rs | 2 +- eframe/src/lib.rs | 4 ++-- egui_demo_lib/src/wrap_app.rs | 2 +- egui_glow/src/epi_backend.rs | 2 +- egui_web/src/backend.rs | 2 +- epi/src/lib.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index a13812067b8..8190c75144c 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -26,7 +26,7 @@ struct MyApp { } impl MyApp { - fn new(cc: epi::CreationContext<'_>) -> Self { + fn new(cc: &epi::CreationContext<'_>) -> Self { Self { rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))), angle: 0.0, diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index a52c3edc4c0..2722ce38b7f 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -34,7 +34,7 @@ struct MyApp { } impl MyApp { - fn new(cc: epi::CreationContext<'_>) -> Self { + fn new(cc: &epi::CreationContext<'_>) -> Self { setup_custom_fonts(&cc.egui_ctx); Self { text: "Edit this text field if you want".to_owned(), diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index e6779f1d85e..c9d1d59c1c8 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -22,7 +22,7 @@ //! struct MyEguiApp {} //! //! impl MyEguiApp { -//! fn new(cc: epi::CreationContext<'_>) -> Self { +//! fn new(cc: &epi::CreationContext<'_>) -> Self { //! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. //! // Restore app state using cc.storage (requires the "persistence" feature). //! // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use @@ -128,7 +128,7 @@ pub fn start_web( /// struct MyEguiApp {} /// /// impl MyEguiApp { -/// fn new(cc: epi::CreationContext<'_>) -> Self { +/// fn new(cc: &epi::CreationContext<'_>) -> Self { /// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. /// // Restore app state using cc.storage (requires the "persistence" feature). /// // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use diff --git a/egui_demo_lib/src/wrap_app.rs b/egui_demo_lib/src/wrap_app.rs index a9df554251c..11ab7d7a829 100644 --- a/egui_demo_lib/src/wrap_app.rs +++ b/egui_demo_lib/src/wrap_app.rs @@ -50,7 +50,7 @@ pub struct WrapApp { } impl WrapApp { - pub fn new(cc: epi::CreationContext<'_>) -> Self { + pub fn new(cc: &epi::CreationContext<'_>) -> Self { #[cfg(feature = "persistence")] if let Some(storage) = cc.storage { return epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 84ee3a512b5..48b06c92130 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -65,7 +65,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi }); } - let mut app = app_creator(epi::CreationContext { + let mut app = app_creator(&epi::CreationContext { egui_ctx: integration.egui_ctx.clone(), integration_info: integration.frame.info(), #[cfg(feature = "persistence")] diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index 9c3151cf61f..6242435024c 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -177,7 +177,7 @@ impl AppRunner { let storage = LocalStorage::default(); - let app = app_creator(epi::CreationContext { + let app = app_creator(&epi::CreationContext { egui_ctx: egui_ctx.clone(), integration_info: frame.info(), storage: Some(&storage), diff --git a/epi/src/lib.rs b/epi/src/lib.rs index 473ad12834b..61ba3e3fa4e 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -109,7 +109,7 @@ use std::sync::{Arc, Mutex}; /// /// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that /// you might want to use later from a [`egui::PaintCallback`]. -pub type AppCreator = fn(CreationContext<'_>) -> Box; +pub type AppCreator = fn(&CreationContext<'_>) -> Box; /// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. pub struct CreationContext<'s> { From a12975103a0d8bed3c466cee7170cac976133a69 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 16:47:25 +0100 Subject: [PATCH 05/11] Move main functions to the top --- eframe/examples/confirm_exit.rs | 10 ++-- eframe/examples/custom_font.rs | 16 +++--- eframe/examples/file_dialog.rs | 24 ++++----- eframe/examples/hello_world.rs | 10 ++-- eframe/examples/image.rs | 14 +++--- eframe/examples/svg.rs | 16 +++--- eframe/src/lib.rs | 23 ++++----- egui_glium/examples/native_texture.rs | 70 +++++++++++++------------- egui_glium/examples/pure_glium.rs | 36 +++++++------- egui_glow/examples/pure_glow.rs | 72 +++++++++++++-------------- 10 files changed, 145 insertions(+), 146 deletions(-) diff --git a/eframe/examples/confirm_exit.rs b/eframe/examples/confirm_exit.rs index 805cab33996..4a8049ceb46 100644 --- a/eframe/examples/confirm_exit.rs +++ b/eframe/examples/confirm_exit.rs @@ -2,6 +2,11 @@ use eframe::{egui, epi}; +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native("Confirm exit", options, |_cc| Box::new(MyApp::default())); +} + #[derive(Default)] struct MyApp { can_exit: bool, @@ -38,8 +43,3 @@ impl epi::App for MyApp { } } } - -fn main() { - let options = eframe::NativeOptions::default(); - eframe::run_native("Confirm exit", options, |_cc| Box::new(MyApp::default())); -} diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index 2722ce38b7f..df0adb939b7 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -1,5 +1,14 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + use eframe::{egui, epi}; +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native("egui example: custom font", options, |cc| { + Box::new(MyApp::new(cc)) + }); +} + fn setup_custom_fonts(ctx: &egui::Context) { // Start with the default fonts (we will be adding to them rather than replacing them). let mut fonts = egui::FontDefinitions::default(); @@ -50,10 +59,3 @@ impl epi::App for MyApp { }); } } - -fn main() { - let options = eframe::NativeOptions::default(); - eframe::run_native("egui example: custom font", options, |cc| { - Box::new(MyApp::new(cc)) - }); -} diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs index b078347cb79..4a62d1169a2 100644 --- a/eframe/examples/file_dialog.rs +++ b/eframe/examples/file_dialog.rs @@ -2,6 +2,18 @@ use eframe::{egui, epi}; +fn main() { + let options = eframe::NativeOptions { + drag_and_drop_support: true, + ..Default::default() + }; + eframe::run_native( + "Native file dialogs and drag-and-drop files", + options, + |_cc| Box::new(MyApp::default()), + ); +} + #[derive(Default)] struct MyApp { dropped_files: Vec, @@ -89,15 +101,3 @@ impl MyApp { } } } - -fn main() { - let options = eframe::NativeOptions { - drag_and_drop_support: true, - ..Default::default() - }; - eframe::run_native( - "Native file dialogs and drag-and-drop files", - options, - |_cc| Box::new(MyApp::default()), - ); -} diff --git a/eframe/examples/hello_world.rs b/eframe/examples/hello_world.rs index 8bdceed1cde..8989016193a 100644 --- a/eframe/examples/hello_world.rs +++ b/eframe/examples/hello_world.rs @@ -2,6 +2,11 @@ use eframe::{egui, epi}; +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native("My egui App", options, |_cc| Box::new(MyApp::default())); +} + struct MyApp { name: String, age: u32, @@ -35,8 +40,3 @@ impl epi::App for MyApp { frame.set_window_size(ctx.used_size()); } } - -fn main() { - let options = eframe::NativeOptions::default(); - eframe::run_native("My egui App", options, |_cc| Box::new(MyApp::default())); -} diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 211b68dcdcd..03b11568e24 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -3,6 +3,13 @@ use eframe::{egui, epi}; use egui_extras::RetainedImage; +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native("Show an image with eframe/egui", options, |_cc| { + Box::new(MyApp::default()) + }); +} + struct MyApp { image: RetainedImage, } @@ -33,10 +40,3 @@ impl epi::App for MyApp { }); } } - -fn main() { - let options = eframe::NativeOptions::default(); - eframe::run_native("Show an image with eframe/egui", options, |_cc| { - Box::new(MyApp::default()) - }); -} diff --git a/eframe/examples/svg.rs b/eframe/examples/svg.rs index e804671bbde..3dd0c8ba775 100644 --- a/eframe/examples/svg.rs +++ b/eframe/examples/svg.rs @@ -6,6 +6,14 @@ use eframe::{egui, epi}; +fn main() { + let options = eframe::NativeOptions { + initial_window_size: Some(egui::vec2(1000.0, 700.0)), + ..Default::default() + }; + eframe::run_native("svg example", options, |_cc| Box::new(MyApp::default())); +} + struct MyApp { svg_image: egui_extras::RetainedImage, } @@ -35,11 +43,3 @@ impl epi::App for MyApp { }); } } - -fn main() { - let options = eframe::NativeOptions { - initial_window_size: Some(egui::vec2(1000.0, 700.0)), - ..Default::default() - }; - eframe::run_native("svg example", options, |_cc| Box::new(MyApp::default())); -} diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index c9d1d59c1c8..cd641e62020 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -18,6 +18,11 @@ //! ``` no_run //! use eframe::{epi, egui}; //! +//! fn main() { +//! let native_options = eframe::NativeOptions::default(); +//! eframe::run_native("My egui App", native_options, |cc| Box::new(MyEguiApp::new(cc))); +//! } +//! //! #[derive(Default)] //! struct MyEguiApp {} //! @@ -38,12 +43,6 @@ //! }); //! } //! } -//! -//! fn main() { -//! let app = MyEguiApp::default(); -//! let native_options = eframe::NativeOptions::default(); -//! eframe::run_native("My egui App", native_options, |cc| Box::new(MyEguiApp::new(cc))); -//! } //! ``` //! //! ## Usage, web: @@ -55,7 +54,6 @@ //! #[cfg(target_arch = "wasm32")] //! #[wasm_bindgen] //! pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> { -//! let app = MyEguiApp::default(); //! eframe::start_web(canvas_id, |cc| Box::new(MyApp::new(cc))) //! } //! ``` @@ -124,6 +122,11 @@ pub fn start_web( /// ``` no_run /// use eframe::{epi, egui}; /// +/// fn main() { +/// let native_options = eframe::NativeOptions::default(); +/// eframe::run_native("MyApp", native_options, |cc| Box::new(MyEguiApp::new(cc))); +/// } +/// /// #[derive(Default)] /// struct MyEguiApp {} /// @@ -144,12 +147,6 @@ pub fn start_web( /// }); /// } /// } -/// -/// fn main() { -/// let app = MyEguiApp::default(); -/// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native("MyApp", native_options, |cc| Box::new(MyEguiApp::new(cc))); -/// } /// ``` #[cfg(not(target_arch = "wasm32"))] pub fn run_native( diff --git a/egui_glium/examples/native_texture.rs b/egui_glium/examples/native_texture.rs index a5197ccf117..8d65c52819d 100644 --- a/egui_glium/examples/native_texture.rs +++ b/egui_glium/examples/native_texture.rs @@ -4,41 +4,6 @@ use glium::glutin; -fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { - let window_builder = glutin::window::WindowBuilder::new() - .with_resizable(true) - .with_inner_size(glutin::dpi::LogicalSize { - width: 800.0, - height: 600.0, - }) - .with_title("egui_glium example"); - - let context_builder = glutin::ContextBuilder::new() - .with_depth_buffer(0) - .with_srgb(true) - .with_stencil_buffer(0) - .with_vsync(true); - - glium::Display::new(window_builder, context_builder, event_loop).unwrap() -} - -fn load_glium_image(png_data: &[u8]) -> glium::texture::RawImage2d { - // Load image using the image crate: - let image = image::load_from_memory(png_data).unwrap().to_rgba8(); - let image_dimensions = image.dimensions(); - - // Premultiply alpha: - let pixels: Vec<_> = image - .into_vec() - .chunks_exact(4) - .map(|p| egui::Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3])) - .flat_map(|color| color.to_array()) - .collect(); - - // Convert to glium image: - glium::texture::RawImage2d::from_raw_rgba(pixels, image_dimensions) -} - fn main() { let event_loop = glutin::event_loop::EventLoop::with_user_event(); let display = create_display(&event_loop); @@ -127,3 +92,38 @@ fn main() { } }); } + +fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { + let window_builder = glutin::window::WindowBuilder::new() + .with_resizable(true) + .with_inner_size(glutin::dpi::LogicalSize { + width: 800.0, + height: 600.0, + }) + .with_title("egui_glium example"); + + let context_builder = glutin::ContextBuilder::new() + .with_depth_buffer(0) + .with_srgb(true) + .with_stencil_buffer(0) + .with_vsync(true); + + glium::Display::new(window_builder, context_builder, event_loop).unwrap() +} + +fn load_glium_image(png_data: &[u8]) -> glium::texture::RawImage2d { + // Load image using the image crate: + let image = image::load_from_memory(png_data).unwrap().to_rgba8(); + let image_dimensions = image.dimensions(); + + // Premultiply alpha: + let pixels: Vec<_> = image + .into_vec() + .chunks_exact(4) + .map(|p| egui::Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3])) + .flat_map(|color| color.to_array()) + .collect(); + + // Convert to glium image: + glium::texture::RawImage2d::from_raw_rgba(pixels, image_dimensions) +} diff --git a/egui_glium/examples/pure_glium.rs b/egui_glium/examples/pure_glium.rs index 52808d7b70c..4fe900f712d 100644 --- a/egui_glium/examples/pure_glium.rs +++ b/egui_glium/examples/pure_glium.rs @@ -4,24 +4,6 @@ use glium::glutin; -fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { - let window_builder = glutin::window::WindowBuilder::new() - .with_resizable(true) - .with_inner_size(glutin::dpi::LogicalSize { - width: 800.0, - height: 600.0, - }) - .with_title("egui_glium example"); - - let context_builder = glutin::ContextBuilder::new() - .with_depth_buffer(0) - .with_srgb(true) - .with_stencil_buffer(0) - .with_vsync(true); - - glium::Display::new(window_builder, context_builder, event_loop).unwrap() -} - fn main() { let event_loop = glutin::event_loop::EventLoop::with_user_event(); let display = create_display(&event_loop); @@ -89,3 +71,21 @@ fn main() { } }); } + +fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { + let window_builder = glutin::window::WindowBuilder::new() + .with_resizable(true) + .with_inner_size(glutin::dpi::LogicalSize { + width: 800.0, + height: 600.0, + }) + .with_title("egui_glium example"); + + let context_builder = glutin::ContextBuilder::new() + .with_depth_buffer(0) + .with_srgb(true) + .with_stencil_buffer(0) + .with_vsync(true); + + glium::Display::new(window_builder, context_builder, event_loop).unwrap() +} diff --git a/egui_glow/examples/pure_glow.rs b/egui_glow/examples/pure_glow.rs index 870f412153a..4b832878c54 100644 --- a/egui_glow/examples/pure_glow.rs +++ b/egui_glow/examples/pure_glow.rs @@ -2,42 +2,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -fn create_display( - event_loop: &glutin::event_loop::EventLoop<()>, -) -> ( - glutin::WindowedContext, - glow::Context, -) { - let window_builder = glutin::window::WindowBuilder::new() - .with_resizable(true) - .with_inner_size(glutin::dpi::LogicalSize { - width: 800.0, - height: 600.0, - }) - .with_title("egui_glow example"); - - let gl_window = unsafe { - glutin::ContextBuilder::new() - .with_depth_buffer(0) - .with_srgb(true) - .with_stencil_buffer(0) - .with_vsync(true) - .build_windowed(window_builder, event_loop) - .unwrap() - .make_current() - .unwrap() - }; - - let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) }; - - unsafe { - use glow::HasContext as _; - gl.enable(glow::FRAMEBUFFER_SRGB); - } - - (gl_window, gl) -} - fn main() { let mut clear_color = [0.1, 0.1, 0.1]; @@ -116,3 +80,39 @@ fn main() { } }); } + +fn create_display( + event_loop: &glutin::event_loop::EventLoop<()>, +) -> ( + glutin::WindowedContext, + glow::Context, +) { + let window_builder = glutin::window::WindowBuilder::new() + .with_resizable(true) + .with_inner_size(glutin::dpi::LogicalSize { + width: 800.0, + height: 600.0, + }) + .with_title("egui_glow example"); + + let gl_window = unsafe { + glutin::ContextBuilder::new() + .with_depth_buffer(0) + .with_srgb(true) + .with_stencil_buffer(0) + .with_vsync(true) + .build_windowed(window_builder, event_loop) + .unwrap() + .make_current() + .unwrap() + }; + + let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) }; + + unsafe { + use glow::HasContext as _; + gl.enable(glow::FRAMEBUFFER_SRGB); + } + + (gl_window, gl) +} From e87d90a2d541236929fd1ce2da8fe9a7df6f36bf Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 16:56:11 +0100 Subject: [PATCH 06/11] Tidy up --- eframe/examples/custom_3d.rs | 4 ++-- egui_demo_lib/src/apps/demo/app.rs | 1 - egui_glow/src/epi_backend.rs | 13 ------------- epi/src/lib.rs | 12 ++---------- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index 8190c75144c..35efc852c3a 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -21,6 +21,7 @@ fn main() { } struct MyApp { + /// Behind an `Arc>` so we can pass it to [`egui::PaintCallback`] and paint later. rotating_triangle: Arc>, angle: f32, } @@ -73,8 +74,7 @@ impl MyApp { rect, callback: std::sync::Arc::new(move |render_ctx| { if let Some(painter) = render_ctx.downcast_ref::() { - let rotating_triangle = rotating_triangle.lock(); - rotating_triangle.paint(painter.gl(), angle); + rotating_triangle.lock().paint(painter.gl(), angle); } else { eprintln!("Can't do custom painting because we are not using a glow context"); } diff --git a/egui_demo_lib/src/apps/demo/app.rs b/egui_demo_lib/src/apps/demo/app.rs index 2e87aae6a09..c01aa8b9cfb 100644 --- a/egui_demo_lib/src/apps/demo/app.rs +++ b/egui_demo_lib/src/apps/demo/app.rs @@ -1,4 +1,3 @@ -/// Demonstrates how to make an eframe app using egui. #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 48b06c92130..5382f80ff15 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -73,19 +73,6 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi gl: gl.clone(), }); - { - // things that happened during app creation: - let app_output = integration.frame.take_app_output(); - if app_output.quit { - integration.quit = app.on_exit_event(); - } - egui_winit::epi::handle_app_output( - gl_window.window(), - integration.egui_ctx.pixels_per_point(), - app_output, - ); - } - if app.warm_up_enabled() { integration.warm_up(app.as_mut(), gl_window.window()); } diff --git a/epi/src/lib.rs b/epi/src/lib.rs index 61ba3e3fa4e..3d9b650f322 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -100,15 +100,7 @@ use std::sync::{Arc, Mutex}; /// The is is how your app is created. /// -/// You need to define a function with this signature. -/// -/// You can use this to customize the look of egui, e.g to call [`egui::Context::set_fonts`], -/// [`egui::Context::set_visuals`] etc. -/// -/// You can use the storage to restore app state state (requires the "persistence" feature). -/// -/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that -/// you might want to use later from a [`egui::PaintCallback`]. +/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc. pub type AppCreator = fn(&CreationContext<'_>) -> Box; /// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. @@ -122,7 +114,7 @@ pub struct CreationContext<'s> { /// Information about the surrounding environment. pub integration_info: IntegrationInfo, - /// You can use the storage to restore app state state (requires the "persistence" feature). + /// You can use the storage to restore app state(requires the "persistence" feature). #[cfg(feature = "persistence")] pub storage: Option<&'s dyn Storage>, From 180ce6d2ab6e99576549a226124dc3a4eb121e23 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 16:59:59 +0100 Subject: [PATCH 07/11] Fix web build --- egui_demo_app/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/egui_demo_app/src/lib.rs b/egui_demo_app/src/lib.rs index 234425da92e..033aaa15515 100644 --- a/egui_demo_app/src/lib.rs +++ b/egui_demo_app/src/lib.rs @@ -19,5 +19,5 @@ pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> { // Redirect tracing to console.log and friends: tracing_wasm::set_as_global_default(); - eframe::start_web(canvas_id, egui_demo_lib::WrapApp::new) + eframe::start_web(canvas_id, |cc| Box::new(egui_demo_lib::WrapApp::new(cc))) } From b24f650f5f1da4f241fb9596ec95c21add8800c4 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 17:19:51 +0100 Subject: [PATCH 08/11] More fixes --- egui_demo_lib/src/wrap_app.rs | 4 ++-- egui_glium/src/lib.rs | 1 - egui_glow/src/epi_backend.rs | 1 - epi/src/lib.rs | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/egui_demo_lib/src/wrap_app.rs b/egui_demo_lib/src/wrap_app.rs index 11ab7d7a829..d8d701d3f82 100644 --- a/egui_demo_lib/src/wrap_app.rs +++ b/egui_demo_lib/src/wrap_app.rs @@ -50,9 +50,9 @@ pub struct WrapApp { } impl WrapApp { - pub fn new(cc: &epi::CreationContext<'_>) -> Self { + pub fn new(_cc: &epi::CreationContext<'_>) -> Self { #[cfg(feature = "persistence")] - if let Some(storage) = cc.storage { + if let Some(storage) = _cc.storage { return epi::get_value(storage, epi::APP_KEY).unwrap_or_default(); } Self::default() diff --git a/egui_glium/src/lib.rs b/egui_glium/src/lib.rs index 9e6760e5392..1ecfda86a1f 100644 --- a/egui_glium/src/lib.rs +++ b/egui_glium/src/lib.rs @@ -2,7 +2,6 @@ //! //! The main type you want to use is [`EguiGlium`]. //! -//! This library is an [`epi`] backend. //! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead. // Forbid warnings in release builds: diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 5382f80ff15..32705bf25aa 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -68,7 +68,6 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi let mut app = app_creator(&epi::CreationContext { egui_ctx: integration.egui_ctx.clone(), integration_info: integration.frame.info(), - #[cfg(feature = "persistence")] storage: integration.persistence.storage(), gl: gl.clone(), }); diff --git a/epi/src/lib.rs b/epi/src/lib.rs index 3d9b650f322..aa21a0f273a 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -115,7 +115,6 @@ pub struct CreationContext<'s> { pub integration_info: IntegrationInfo, /// You can use the storage to restore app state(requires the "persistence" feature). - #[cfg(feature = "persistence")] pub storage: Option<&'s dyn Storage>, /// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that From 1f0e84a90986a5061a67727766767a68e1f81f3f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 14 Mar 2022 17:27:12 +0100 Subject: [PATCH 09/11] eframe: re-export epi::* so users don't need to care about what epi is --- eframe/examples/confirm_exit.rs | 6 +++--- eframe/examples/custom_3d.rs | 8 ++++---- eframe/examples/custom_font.rs | 8 ++++---- eframe/examples/download_image.rs | 6 +++--- eframe/examples/file_dialog.rs | 6 +++--- eframe/examples/hello_world.rs | 6 +++--- eframe/examples/image.rs | 6 +++--- eframe/examples/svg.rs | 6 +++--- eframe/src/lib.rs | 32 +++++++++++++------------------ 9 files changed, 39 insertions(+), 45 deletions(-) diff --git a/eframe/examples/confirm_exit.rs b/eframe/examples/confirm_exit.rs index 4a8049ceb46..1e9035fa4fa 100644 --- a/eframe/examples/confirm_exit.rs +++ b/eframe/examples/confirm_exit.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; fn main() { let options = eframe::NativeOptions::default(); @@ -13,13 +13,13 @@ struct MyApp { is_exiting: bool, } -impl epi::App for MyApp { +impl eframe::App for MyApp { fn on_exit_event(&mut self) -> bool { self.is_exiting = true; self.can_exit } - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { + fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Try to close the window"); }); diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index 35efc852c3a..8b14f130dc3 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -8,7 +8,7 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; use parking_lot::Mutex; use std::sync::Arc; @@ -27,7 +27,7 @@ struct MyApp { } impl MyApp { - fn new(cc: &epi::CreationContext<'_>) -> Self { + fn new(cc: &eframe::CreationContext<'_>) -> Self { Self { rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))), angle: 0.0, @@ -35,8 +35,8 @@ impl MyApp { } } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.horizontal(|ui| { ui.spacing_mut().item_spacing.x = 0.0; diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index df0adb939b7..dc74fe0d0b4 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; fn main() { let options = eframe::NativeOptions::default(); @@ -43,7 +43,7 @@ struct MyApp { } impl MyApp { - fn new(cc: &epi::CreationContext<'_>) -> Self { + fn new(cc: &eframe::CreationContext<'_>) -> Self { setup_custom_fonts(&cc.egui_ctx); Self { text: "Edit this text field if you want".to_owned(), @@ -51,8 +51,8 @@ impl MyApp { } } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("egui using custom fonts"); ui.text_edit_multiline(&mut self.text); diff --git a/eframe/examples/download_image.rs b/eframe/examples/download_image.rs index 43c92692183..f7958762434 100644 --- a/eframe/examples/download_image.rs +++ b/eframe/examples/download_image.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; use egui_extras::RetainedImage; use poll_promise::Promise; @@ -19,8 +19,8 @@ struct MyApp { promise: Option>>, } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { let promise = self.promise.get_or_insert_with(|| { // Begin download. // We download the image using `ehttp`, a library that works both in WASM and on native. diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs index 4a62d1169a2..66d0f3fc62f 100644 --- a/eframe/examples/file_dialog.rs +++ b/eframe/examples/file_dialog.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; fn main() { let options = eframe::NativeOptions { @@ -20,8 +20,8 @@ struct MyApp { picked_path: Option, } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.label("Drag-and-drop files onto the window!"); diff --git a/eframe/examples/hello_world.rs b/eframe/examples/hello_world.rs index 8989016193a..d5a9576f09b 100644 --- a/eframe/examples/hello_world.rs +++ b/eframe/examples/hello_world.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; fn main() { let options = eframe::NativeOptions::default(); @@ -21,8 +21,8 @@ impl Default for MyApp { } } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("My egui Application"); ui.horizontal(|ui| { diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 03b11568e24..c91622f3964 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; use egui_extras::RetainedImage; fn main() { @@ -26,8 +26,8 @@ impl Default for MyApp { } } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("This is an image:"); self.image.show(ui); diff --git a/eframe/examples/svg.rs b/eframe/examples/svg.rs index 3dd0c8ba775..a4e71bf74b3 100644 --- a/eframe/examples/svg.rs +++ b/eframe/examples/svg.rs @@ -4,7 +4,7 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release -use eframe::{egui, epi}; +use eframe::egui; fn main() { let options = eframe::NativeOptions { @@ -30,8 +30,8 @@ impl Default for MyApp { } } -impl epi::App for MyApp { - fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("SVG example"); ui.label("The SVG is rasterized and displayed as a texture."); diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index cd641e62020..ffa4f568ee2 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -16,7 +16,7 @@ //! //! ## Usage, native: //! ``` no_run -//! use eframe::{epi, egui}; +//! use eframe::egui; //! //! fn main() { //! let native_options = eframe::NativeOptions::default(); @@ -27,7 +27,7 @@ //! struct MyEguiApp {} //! //! impl MyEguiApp { -//! fn new(cc: &epi::CreationContext<'_>) -> Self { +//! fn new(cc: &eframe::CreationContext<'_>) -> Self { //! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. //! // Restore app state using cc.storage (requires the "persistence" feature). //! // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use @@ -36,8 +36,8 @@ //! } //! } //! -//! impl epi::App for MyEguiApp { -//! fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { +//! impl eframe::App for MyEguiApp { +//! fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) { //! egui::CentralPanel::default().show(ctx, |ui| { //! ui.heading("Hello World!"); //! }); @@ -69,10 +69,11 @@ )] #![allow(clippy::needless_doctest_main)] +// Re-export all useful libraries: pub use {egui, egui::emath, egui::epaint, epi}; -#[cfg(not(target_arch = "wasm32"))] -pub use epi::NativeOptions; +// Re-export everything in `epi` so `eframe` users don't have to care about what `epi` is: +pub use epi::*; // ---------------------------------------------------------------------------- // When compiling for web @@ -102,10 +103,7 @@ pub use egui_web::wasm_bindgen; /// } /// ``` #[cfg(target_arch = "wasm32")] -pub fn start_web( - canvas_id: &str, - app_creator: epi::AppCreator, -) -> Result<(), wasm_bindgen::JsValue> { +pub fn start_web(canvas_id: &str, app_creator: AppCreator) -> Result<(), wasm_bindgen::JsValue> { egui_web::start(canvas_id, app_creator)?; Ok(()) } @@ -120,7 +118,7 @@ pub fn start_web( /// /// Call from `fn main` like this: /// ``` no_run -/// use eframe::{epi, egui}; +/// use eframe::egui; /// /// fn main() { /// let native_options = eframe::NativeOptions::default(); @@ -131,7 +129,7 @@ pub fn start_web( /// struct MyEguiApp {} /// /// impl MyEguiApp { -/// fn new(cc: &epi::CreationContext<'_>) -> Self { +/// fn new(cc: &eframe::CreationContext<'_>) -> Self { /// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals. /// // Restore app state using cc.storage (requires the "persistence" feature). /// // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use @@ -140,8 +138,8 @@ pub fn start_web( /// } /// } /// -/// impl epi::App for MyEguiApp { -/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { +/// impl eframe::App for MyEguiApp { +/// fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) { /// egui::CentralPanel::default().show(ctx, |ui| { /// ui.heading("Hello World!"); /// }); @@ -149,10 +147,6 @@ pub fn start_web( /// } /// ``` #[cfg(not(target_arch = "wasm32"))] -pub fn run_native( - app_name: &str, - native_options: epi::NativeOptions, - app_creator: epi::AppCreator, -) -> ! { +pub fn run_native(app_name: &str, native_options: NativeOptions, app_creator: AppCreator) -> ! { egui_glow::run(app_name, &native_options, app_creator) } From d03e60d808952df21f23f4db23dfc425d55c952d Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 16 Mar 2022 08:56:30 +0100 Subject: [PATCH 10/11] make quit non-pub again --- egui-winit/src/epi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/egui-winit/src/epi.rs b/egui-winit/src/epi.rs index 2c57c6b32af..2674db33dba 100644 --- a/egui-winit/src/epi.rs +++ b/egui-winit/src/epi.rs @@ -222,7 +222,7 @@ pub struct EpiIntegration { pending_full_output: egui::FullOutput, egui_winit: crate::State, /// When set, it is time to quit - pub quit: bool, + quit: bool, can_drag_window: bool, } From 157cdf6cb168aa369eb8862a9be64f311f5bf553 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 16 Mar 2022 09:01:48 +0100 Subject: [PATCH 11/11] Fix docstring for Ap::update --- epi/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/epi/src/lib.rs b/epi/src/lib.rs index aa21a0f273a..ddc1add0762 100644 --- a/epi/src/lib.rs +++ b/epi/src/lib.rs @@ -133,8 +133,7 @@ pub trait App { /// /// The [`egui::Context`] and [`Frame`] can be cloned and saved if you like. /// - /// To force a repaint, call either [`egui::Context::request_repaint`] during the call to `update`, - /// or call [`Frame::request_repaint`] at any time (e.g. from another thread). + /// To force a repaint, call [`egui::Context::request_repaint`] at any time (e.g. from another thread). fn update(&mut self, ctx: &egui::Context, frame: &Frame); /// Called on shutdown, and perhaps at regular intervals. Allows you to save state.