Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage and frame refactor #1418

Merged
merged 6 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions eframe/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ NOTE: [`egui_web`](../egui_web/CHANGELOG.md), [`egui-winit`](../egui-winit/CHANG
* Change default for `NativeOptions::drag_and_drop_support` to `true` ([#1329](https://github.com/emilk/egui/pull/1329)).
* Remove the `egui_glium` feature. `eframe` will now always use `egui_glow` as the native backend ([#1357](https://github.com/emilk/egui/pull/1357)).
* Removed `Frame::request_repaint` - just call `egui::Context::request_repaint` for the same effect ([#1366](https://github.com/emilk/egui/pull/1366)).
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
* Add new `NativeOptions`: `vsync`, `multisampling`, `depth_buffer`, `stencil_buffer`.
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
* Added new `NativeOptions`: `vsync`, `multisampling`, `depth_buffer`, `stencil_buffer`.
* Changed app creation/setup ([#1363](https://github.com/emilk/egui/pull/1363)):
* Removed `App::setup` and `App::name`.
* Provide `CreationContext` when creating app with egui context, storage, integration info and glow context.
* Change interface of `run_native` and `start_web`.
* Added `Frame::storage()` and `Frame::storage_mut()` ([#1418](https://github.com/emilk/egui/pull/1418)).
* You can now load/save state in `App::update`
* Changed `App::update` to take `&mut Frame` instead of `&Frame`.
* `Frame` is no longer `Clone` or `Sync`.


## 0.17.0 - 2022-02-22
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/confirm_exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl eframe::App for MyApp {
self.can_exit
}

fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Try to close the window");
});
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/custom_3d_glow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/custom_3d_three-d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::widgets::global_dark_light_mode_buttons(ui);

Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/custom_font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("egui using custom fonts");
ui.text_edit_multiline(&mut self.text);
Expand Down
4 changes: 2 additions & 2 deletions eframe/examples/custom_window_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl eframe::App for MyApp {
egui::Rgba::TRANSPARENT // Make sure we don't paint anything behind the rounded corners
}

fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
custon_window_frame(ctx, frame, "egui with custom frame", |ui| {
ui.label("This is just the contents of the window");
ui.horizontal(|ui| {
Expand All @@ -41,7 +41,7 @@ impl eframe::App for MyApp {

fn custon_window_frame(
ctx: &egui::Context,
frame: &eframe::Frame,
frame: &mut eframe::Frame,
title: &str,
add_contents: impl FnOnce(&mut egui::Ui),
) {
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/download_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut 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.
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/file_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("Drag-and-drop files onto the window!");

Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Default for MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl Default for MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("This is an image:");
self.image.show(ui);
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Default for MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("SVG example");
ui.label("The SVG is rasterized and displayed as a texture.");
Expand Down
4 changes: 2 additions & 2 deletions eframe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
//! }
//!
//! impl eframe::App for MyEguiApp {
//! fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
//! fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
//! egui::CentralPanel::default().show(ctx, |ui| {
//! ui.heading("Hello World!");
//! });
Expand Down Expand Up @@ -126,7 +126,7 @@ pub fn start_web(canvas_id: &str, app_creator: AppCreator) -> Result<(), wasm_bi
/// }
///
/// impl eframe::App for MyEguiApp {
/// fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
/// fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// ui.heading("Hello World!");
/// });
Expand Down
160 changes: 62 additions & 98 deletions egui-winit/src/epi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,104 +124,20 @@ pub fn handle_app_output(
// ----------------------------------------------------------------------------

/// For loading/saving app state and/or egui memory to disk.
pub struct Persistence {
storage: Option<Box<dyn epi::Storage>>,
last_auto_save: instant::Instant,
}

#[allow(clippy::unused_self)]
impl Persistence {
#[cfg(feature = "persistence")]
const EGUI_MEMORY_KEY: &'static str = "egui";
#[cfg(feature = "persistence")]
const WINDOW_KEY: &'static str = "window";

pub fn from_app_name(app_name: &str) -> Self {
fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
#[cfg(feature = "persistence")]
if let Some(storage) = epi::file_storage::FileStorage::from_app_name(_app_name) {
return Some(Box::new(storage));
}
None
}

Self {
storage: create_storage(app_name),
last_auto_save: instant::Instant::now(),
}
}

pub fn storage(&self) -> Option<&dyn epi::Storage> {
self.storage.as_deref()
}

#[cfg(feature = "persistence")]
pub fn load_window_settings(&self) -> Option<crate::WindowSettings> {
epi::get_value(&**self.storage.as_ref()?, Self::WINDOW_KEY)
}

#[cfg(not(feature = "persistence"))]
pub fn load_window_settings(&self) -> Option<crate::WindowSettings> {
None
}

pub fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
#[cfg(feature = "persistence")]
pub fn load_memory(&self) -> Option<egui::Memory> {
epi::get_value(&**self.storage.as_ref()?, Self::EGUI_MEMORY_KEY)
}

#[cfg(not(feature = "persistence"))]
pub fn load_memory(&self) -> Option<egui::Memory> {
None
}

pub fn save(
&mut self,
_app: &mut dyn epi::App,
_egui_ctx: &egui::Context,
_window: &winit::window::Window,
) {
#[cfg(feature = "persistence")]
if let Some(storage) = &mut self.storage {
if _app.persist_native_window() {
epi::set_value(
storage.as_mut(),
Self::WINDOW_KEY,
&crate::WindowSettings::from_display(_window),
);
}
if _app.persist_egui_memory() {
epi::set_value(
storage.as_mut(),
Self::EGUI_MEMORY_KEY,
&*_egui_ctx.memory(),
);
}
_app.save(storage.as_mut());
storage.flush();
}
}

pub fn maybe_autosave(
&mut self,
app: &mut dyn epi::App,
egui_ctx: &egui::Context,
window: &winit::window::Window,
) {
let now = instant::Instant::now();
if now - self.last_auto_save > app.auto_save_interval() {
self.save(app, egui_ctx, window);
self.last_auto_save = now;
}
if let Some(storage) = epi::file_storage::FileStorage::from_app_name(_app_name) {
return Some(Box::new(storage));
}
None
}

// ----------------------------------------------------------------------------

/// Everything needed to make a winit-based integration for [`epi`].
pub struct EpiIntegration {
pub frame: epi::Frame,
pub persistence: crate::epi::Persistence,
last_auto_save: instant::Instant,
pub egui_ctx: egui::Context,
pending_full_output: egui::FullOutput,
egui_winit: crate::State,
Expand All @@ -235,15 +151,15 @@ impl EpiIntegration {
integration_name: &'static str,
max_texture_side: usize,
window: &winit::window::Window,
persistence: crate::epi::Persistence,
storage: Option<Box<dyn epi::Storage>>,
) -> Self {
let egui_ctx = egui::Context::default();

*egui_ctx.memory() = persistence.load_memory().unwrap_or_default();
*egui_ctx.memory() = load_egui_memory(storage.as_deref()).unwrap_or_default();

let prefer_dark_mode = prefer_dark_mode();

let frame = epi::Frame::new(epi::backend::FrameData {
let frame = epi::Frame {
info: epi::IntegrationInfo {
name: integration_name,
web_info: None,
Expand All @@ -252,7 +168,8 @@ impl EpiIntegration {
native_pixels_per_point: Some(crate::native_pixels_per_point(window)),
},
output: Default::default(),
});
storage,
};

if prefer_dark_mode == Some(true) {
egui_ctx.set_visuals(egui::Visuals::dark());
Expand All @@ -262,7 +179,7 @@ impl EpiIntegration {

Self {
frame,
persistence,
last_auto_save: instant::Instant::now(),
egui_ctx,
egui_winit: crate::State::new(max_texture_side, window),
pending_full_output: Default::default(),
Expand Down Expand Up @@ -311,7 +228,7 @@ impl EpiIntegration {

let raw_input = self.egui_winit.take_egui_input(window);
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
app.update(egui_ctx, &self.frame);
app.update(egui_ctx, &mut self.frame);
});
self.pending_full_output.append(full_output);
let full_output = std::mem::take(&mut self.pending_full_output);
Expand All @@ -327,7 +244,7 @@ impl EpiIntegration {
}

let frame_time = (instant::Instant::now() - frame_start).as_secs_f64() as f32;
self.frame.lock().info.cpu_usage = Some(frame_time);
self.frame.info.cpu_usage = Some(frame_time);

full_output
}
Expand All @@ -341,12 +258,59 @@ impl EpiIntegration {
.handle_platform_output(window, &self.egui_ctx, platform_output);
}

// ------------------------------------------------------------------------
// Persistance stuff:

pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
self.persistence
.maybe_autosave(&mut *app, &self.egui_ctx, window);
let now = instant::Instant::now();
if now - self.last_auto_save > app.auto_save_interval() {
self.save(app, window);
self.last_auto_save = now;
}
}

pub fn save(&mut self, _app: &mut dyn epi::App, _window: &winit::window::Window) {
#[cfg(feature = "persistence")]
if let Some(storage) = self.frame.storage_mut() {
if _app.persist_native_window() {
epi::set_value(
storage,
STORAGE_WINDOW_KEY,
&crate::WindowSettings::from_display(_window),
);
}
if _app.persist_egui_memory() {
epi::set_value(storage, STORAGE_EGUI_MEMORY_KEY, &*self.egui_ctx.memory());
}
_app.save(storage);
storage.flush();
}
}
}

#[cfg(feature = "persistence")]
const STORAGE_EGUI_MEMORY_KEY: &str = "egui";
#[cfg(feature = "persistence")]
const STORAGE_WINDOW_KEY: &str = "window";

pub fn load_window_settings(_storage: Option<&dyn epi::Storage>) -> Option<crate::WindowSettings> {
#[cfg(feature = "persistence")]
{
epi::get_value(_storage?, STORAGE_WINDOW_KEY)
}
#[cfg(not(feature = "persistence"))]
None
}

pub fn load_egui_memory(_storage: Option<&dyn epi::Storage>) -> Option<egui::Memory> {
#[cfg(feature = "persistence")]
{
epi::get_value(_storage?, STORAGE_EGUI_MEMORY_KEY)
}
#[cfg(not(feature = "persistence"))]
None
}

#[cfg(feature = "dark-light")]
fn prefer_dark_mode() -> Option<bool> {
match dark_light::detect() {
Expand Down
2 changes: 1 addition & 1 deletion egui_demo_lib/src/apps/color_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Default for ColorTest {
}

impl epi::App for ColorTest {
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
fn update(&mut self, ctx: &egui::Context, frame: &mut epi::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
if frame.is_web() {
ui.label(
Expand Down
2 changes: 1 addition & 1 deletion egui_demo_lib/src/apps/demo/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub struct DemoApp {
}

impl epi::App for DemoApp {
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut epi::Frame) {
self.demo_windows.ui(ctx);
}
}
2 changes: 1 addition & 1 deletion egui_demo_lib/src/apps/fractal_clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Default for FractalClock {
}

impl epi::App for FractalClock {
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
fn update(&mut self, ctx: &egui::Context, _frame: &mut epi::Frame) {
egui::CentralPanel::default()
.frame(Frame::dark_canvas(&ctx.style()))
.show(ctx, |ui| self.ui(ui, crate::seconds_since_midnight()));
Expand Down
Loading