epi: merge App::load into App::setup, and provide Frame argument
This gives users more control over the order of load/setup. It also allows users to load textures in setup.
This commit is contained in:
parent
31769d400f
commit
44b573f6a6
7 changed files with 105 additions and 53 deletions
|
@ -3,6 +3,8 @@ All notable changes to the `eframe` crate.
|
|||
|
||||
|
||||
## Unreleased
|
||||
* `App::setup` now takes a `Frame` and `Storage` by argument.
|
||||
* `App::load` has been removed. Implement `App::setup` instead.
|
||||
|
||||
|
||||
## 0.12.0 - 2021-05-10
|
||||
|
|
|
@ -15,9 +15,16 @@ impl epi::App for DemoApp {
|
|||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn load(&mut self, storage: &dyn epi::Storage) {
|
||||
fn setup(
|
||||
&mut self,
|
||||
_ctx: &egui::CtxRef,
|
||||
_frame: &mut epi::Frame<'_>,
|
||||
storage: Option<&dyn epi::Storage>,
|
||||
) {
|
||||
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) {
|
||||
|
|
|
@ -40,10 +40,17 @@ impl epi::App for WrapApp {
|
|||
"egui demo apps"
|
||||
}
|
||||
|
||||
fn setup(
|
||||
&mut self,
|
||||
ctx: &egui::CtxRef,
|
||||
frame: &mut epi::Frame<'_>,
|
||||
storage: Option<&dyn epi::Storage>,
|
||||
) {
|
||||
#[cfg(feature = "persistence")]
|
||||
fn load(&mut self, storage: &dyn epi::Storage) {
|
||||
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) {
|
||||
|
|
|
@ -35,16 +35,16 @@ All notable changes to the `egui_glium` integration will be noted in this file.
|
|||
|
||||
|
||||
## 0.7.0 - 2021-01-04
|
||||
### Changed
|
||||
### Changed 🔧
|
||||
* `http` `persistence` and `time` are now optional (and opt-in) features.
|
||||
|
||||
|
||||
## 0.6.0 - 2020-12-26
|
||||
### Added
|
||||
### Added ⭐
|
||||
* `egui_glium` will auto-save your app state every 30 seconds.
|
||||
* `egui_glium` can now set windows as fixed size (e.g. the user can't resize the window). See `egui::App::is_resizable()`.
|
||||
|
||||
### Changed
|
||||
### Changed 🔧
|
||||
* `egui_glium` will now save you app state to [a better directory](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir).
|
||||
* `egui_glium::run`: the parameter `app` now has signature `Box<dyn App>` (you need to add `Box::new(app)` to your code).
|
||||
* Window title is now passed via the `trait` function `egui::App::name()`.
|
||||
|
@ -55,7 +55,7 @@ All notable changes to the `egui_glium` integration will be noted in this file.
|
|||
|
||||
|
||||
## 0.5.0 - 2020-12-13
|
||||
### Changed
|
||||
### Changed 🔧
|
||||
* FileStorage::from_path now takes `Into<Path>` instead of `String`
|
||||
|
||||
|
||||
|
|
|
@ -167,9 +167,8 @@ fn load_icon(icon_data: epi::IconData) -> Option<glutin::window::Icon> {
|
|||
pub fn run(mut app: Box<dyn epi::App>, nativve_options: epi::NativeOptions) -> ! {
|
||||
let mut storage = create_storage(app.name());
|
||||
|
||||
if let Some(storage) = &mut storage {
|
||||
app.load(storage.as_ref());
|
||||
}
|
||||
#[cfg(feature = "http")]
|
||||
let http = std::sync::Arc::new(crate::http::GliumHttp {});
|
||||
|
||||
let window_settings = deserialize_window_settings(&storage);
|
||||
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
||||
|
@ -183,7 +182,20 @@ pub fn run(mut app: Box<dyn epi::App>, nativve_options: epi::NativeOptions) -> !
|
|||
let mut egui = EguiGlium::new(&display);
|
||||
*egui.ctx().memory() = deserialize_memory(&storage).unwrap_or_default();
|
||||
|
||||
app.setup(&egui.ctx());
|
||||
{
|
||||
let (ctx, painter) = egui.ctx_and_painter_mut();
|
||||
let mut app_output = epi::backend::AppOutput::default();
|
||||
let mut frame = epi::backend::FrameBuilder {
|
||||
info: integration_info(&display, None),
|
||||
tex_allocator: painter,
|
||||
#[cfg(feature = "http")]
|
||||
http: http.clone(),
|
||||
output: &mut app_output,
|
||||
repaint_signal: repaint_signal.clone(),
|
||||
}
|
||||
.build();
|
||||
app.setup(&ctx, &mut frame, storage.as_deref());
|
||||
}
|
||||
|
||||
let mut previous_frame_time = None;
|
||||
|
||||
|
@ -192,9 +204,6 @@ pub fn run(mut app: Box<dyn epi::App>, nativve_options: epi::NativeOptions) -> !
|
|||
#[cfg(feature = "persistence")]
|
||||
let mut last_auto_save = Instant::now();
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
let http = std::sync::Arc::new(crate::http::GliumHttp {});
|
||||
|
||||
if app.warm_up_enabled() {
|
||||
let saved_memory = egui.ctx().memory().clone();
|
||||
egui.ctx().memory().set_everything_is_visible(true);
|
||||
|
|
|
@ -5,7 +5,7 @@ pub use egui::{pos2, Color32};
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub struct WebBackend {
|
||||
ctx: egui::CtxRef,
|
||||
egui_ctx: egui::CtxRef,
|
||||
painter: Box<dyn Painter>,
|
||||
previous_frame_time: Option<f32>,
|
||||
frame_start: Option<f64>,
|
||||
|
@ -25,7 +25,7 @@ impl WebBackend {
|
|||
};
|
||||
|
||||
Ok(Self {
|
||||
ctx,
|
||||
egui_ctx: ctx,
|
||||
painter,
|
||||
previous_frame_time: None,
|
||||
frame_start: None,
|
||||
|
@ -39,7 +39,7 @@ impl WebBackend {
|
|||
|
||||
pub fn begin_frame(&mut self, raw_input: egui::RawInput) {
|
||||
self.frame_start = Some(now_sec());
|
||||
self.ctx.begin_frame(raw_input)
|
||||
self.egui_ctx.begin_frame(raw_input)
|
||||
}
|
||||
|
||||
pub fn end_frame(&mut self) -> Result<(egui::Output, Vec<egui::ClippedMesh>), JsValue> {
|
||||
|
@ -48,8 +48,8 @@ impl WebBackend {
|
|||
.take()
|
||||
.expect("unmatched calls to begin_frame/end_frame");
|
||||
|
||||
let (output, shapes) = self.ctx.end_frame();
|
||||
let clipped_meshes = self.ctx.tessellate(shapes);
|
||||
let (output, shapes) = self.egui_ctx.end_frame();
|
||||
let clipped_meshes = self.egui_ctx.tessellate(shapes);
|
||||
|
||||
let now = now_sec();
|
||||
self.previous_frame_time = Some((now - frame_start) as f32);
|
||||
|
@ -62,10 +62,10 @@ impl WebBackend {
|
|||
clear_color: egui::Rgba,
|
||||
clipped_meshes: Vec<egui::ClippedMesh>,
|
||||
) -> Result<(), JsValue> {
|
||||
self.painter.upload_egui_texture(&self.ctx.texture());
|
||||
self.painter.upload_egui_texture(&self.egui_ctx.texture());
|
||||
self.painter.clear(clear_color);
|
||||
self.painter
|
||||
.paint_meshes(clipped_meshes, self.ctx.pixels_per_point())
|
||||
.paint_meshes(clipped_meshes, self.egui_ctx.pixels_per_point())
|
||||
}
|
||||
|
||||
pub fn painter_debug_info(&self) -> String {
|
||||
|
@ -145,12 +145,11 @@ pub struct AppRunner {
|
|||
}
|
||||
|
||||
impl AppRunner {
|
||||
pub fn new(web_backend: WebBackend, mut app: Box<dyn epi::App>) -> Result<Self, JsValue> {
|
||||
load_memory(&web_backend.ctx);
|
||||
pub fn new(web_backend: WebBackend, app: Box<dyn epi::App>) -> Result<Self, JsValue> {
|
||||
load_memory(&web_backend.egui_ctx);
|
||||
let storage = LocalStorage::default();
|
||||
app.load(&storage);
|
||||
app.setup(&web_backend.ctx);
|
||||
Ok(Self {
|
||||
let prefer_dark_mode = crate::prefer_dark_mode();
|
||||
let mut runner = Self {
|
||||
web_backend,
|
||||
input: Default::default(),
|
||||
app,
|
||||
|
@ -161,11 +160,31 @@ impl AppRunner {
|
|||
#[cfg(feature = "http")]
|
||||
http: Arc::new(http::WebHttp {}),
|
||||
last_text_cursor_pos: None,
|
||||
})
|
||||
};
|
||||
|
||||
{
|
||||
let mut app_output = epi::backend::AppOutput::default();
|
||||
let mut frame = epi::backend::FrameBuilder {
|
||||
info: runner.integration_info(),
|
||||
tex_allocator: runner.web_backend.painter.as_tex_allocator(),
|
||||
#[cfg(feature = "http")]
|
||||
http: runner.http.clone(),
|
||||
output: &mut app_output,
|
||||
repaint_signal: runner.needs_repaint.clone(),
|
||||
}
|
||||
.build();
|
||||
runner.app.setup(
|
||||
&runner.web_backend.egui_ctx,
|
||||
&mut frame,
|
||||
Some(&runner.storage),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(runner)
|
||||
}
|
||||
|
||||
pub fn egui_ctx(&self) -> &egui::CtxRef {
|
||||
&self.web_backend.ctx
|
||||
&self.web_backend.egui_ctx
|
||||
}
|
||||
|
||||
pub fn auto_save(&mut self) {
|
||||
|
@ -173,7 +192,7 @@ impl AppRunner {
|
|||
let time_since_last_save = now - self.last_save_time;
|
||||
|
||||
if time_since_last_save > self.app.auto_save_interval().as_secs_f64() {
|
||||
save_memory(&self.web_backend.ctx);
|
||||
save_memory(&self.web_backend.egui_ctx);
|
||||
self.app.save(&mut self.storage);
|
||||
self.last_save_time = now;
|
||||
}
|
||||
|
@ -185,37 +204,39 @@ impl AppRunner {
|
|||
|
||||
pub fn warm_up(&mut self) -> Result<(), JsValue> {
|
||||
if self.app.warm_up_enabled() {
|
||||
let saved_memory = self.web_backend.ctx.memory().clone();
|
||||
let saved_memory = self.web_backend.egui_ctx.memory().clone();
|
||||
self.web_backend
|
||||
.ctx
|
||||
.egui_ctx
|
||||
.memory()
|
||||
.set_everything_is_visible(true);
|
||||
self.logic()?;
|
||||
*self.web_backend.ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
|
||||
self.web_backend.ctx.clear_animations();
|
||||
*self.web_backend.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
|
||||
self.web_backend.egui_ctx.clear_animations();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn integration_info(&self) -> epi::IntegrationInfo {
|
||||
epi::IntegrationInfo {
|
||||
web_info: Some(epi::WebInfo {
|
||||
web_location_hash: location_hash().unwrap_or_default(),
|
||||
}),
|
||||
cpu_usage: self.web_backend.previous_frame_time,
|
||||
seconds_since_midnight: Some(seconds_since_midnight()),
|
||||
native_pixels_per_point: Some(native_pixels_per_point()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn logic(&mut self) -> Result<(egui::Output, Vec<egui::ClippedMesh>), JsValue> {
|
||||
resize_canvas_to_screen_size(self.web_backend.canvas_id(), self.app.max_size_points());
|
||||
let canvas_size = canvas_size_in_points(self.web_backend.canvas_id());
|
||||
let raw_input = self.input.new_frame(canvas_size);
|
||||
|
||||
let info = epi::IntegrationInfo {
|
||||
web_info: Some(epi::WebInfo {
|
||||
web_location_hash: location_hash().unwrap_or_default(),
|
||||
}),
|
||||
cpu_usage: self.web_backend.previous_frame_time,
|
||||
seconds_since_midnight: Some(seconds_since_midnight()),
|
||||
native_pixels_per_point: Some(native_pixels_per_point()),
|
||||
};
|
||||
|
||||
self.web_backend.begin_frame(raw_input);
|
||||
|
||||
let mut app_output = epi::backend::AppOutput::default();
|
||||
let mut frame = epi::backend::FrameBuilder {
|
||||
info,
|
||||
info: self.integration_info(),
|
||||
tex_allocator: self.web_backend.painter.as_tex_allocator(),
|
||||
#[cfg(feature = "http")]
|
||||
http: self.http.clone(),
|
||||
|
@ -224,10 +245,10 @@ impl AppRunner {
|
|||
}
|
||||
.build();
|
||||
|
||||
self.app.update(&self.web_backend.ctx, &mut frame);
|
||||
self.app.update(&self.web_backend.egui_ctx, &mut frame);
|
||||
let (egui_output, clipped_meshes) = self.web_backend.end_frame()?;
|
||||
|
||||
if self.web_backend.ctx.memory().options.screen_reader {
|
||||
if self.web_backend.egui_ctx.memory().options.screen_reader {
|
||||
self.screen_reader.speak(&egui_output.events_description());
|
||||
}
|
||||
handle_output(&egui_output, self);
|
||||
|
|
|
@ -95,9 +95,18 @@ pub trait App {
|
|||
fn update(&mut self, ctx: &egui::CtxRef, frame: &mut Frame<'_>);
|
||||
|
||||
/// Called once before the first frame.
|
||||
/// Allows you to do setup code and to call `ctx.set_fonts()`.
|
||||
/// Optional.
|
||||
fn setup(&mut self, _ctx: &egui::CtxRef) {}
|
||||
///
|
||||
/// Allows you to do setup code, e.g to call `[Context::set_fonts]`,
|
||||
/// `[Context::set_visuals]` etc.
|
||||
///
|
||||
/// Also allows you to restore state, if there is a storage.
|
||||
fn setup(
|
||||
&mut self,
|
||||
_ctx: &egui::CtxRef,
|
||||
_frame: &mut Frame<'_>,
|
||||
_storage: Option<&dyn Storage>,
|
||||
) {
|
||||
}
|
||||
|
||||
/// If `true` a warm-up call to [`Self::update`] will be issued where
|
||||
/// `ctx.memory().everything_is_visible()` will be set to `true`.
|
||||
|
@ -107,9 +116,6 @@ pub trait App {
|
|||
false
|
||||
}
|
||||
|
||||
/// Called once on start. Allows you to restore state.
|
||||
fn load(&mut self, _storage: &dyn Storage) {}
|
||||
|
||||
/// Called on shutdown, and perhaps at regular intervals. Allows you to save state.
|
||||
///
|
||||
/// On web the states is stored to "Local Storage".
|
||||
|
|
Loading…
Reference in a new issue