From 8f034d391d573eb00c87fa1fcc19cbfac14fb790 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 19 Dec 2020 21:06:59 +0100 Subject: [PATCH] [egui_glium] Your app state will auto-save to a good directory Directory found with https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir --- Cargo.lock | 45 ++++++++++++++++++++++- demo_glium/src/main.rs | 10 ++---- egui_glium/CHANGELOG.md | 5 +++ egui_glium/Cargo.toml | 1 + egui_glium/src/backend.rs | 75 ++++++++++++++++++++++++++++++++------- 5 files changed, 114 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 815fdca7..1d90113c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75b7e6a93ecd6dbd2c225154d0fa7f86205574ecaa6c87429fb5f66ee677c44" dependencies = [ - "getrandom", + "getrandom 0.2.0", "lazy_static", "version_check", ] @@ -553,6 +553,27 @@ dependencies = [ "syn", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -592,6 +613,7 @@ version = "0.5.0" dependencies = [ "chrono", "clipboard", + "directories-next", "egui", "glium", "serde", @@ -669,6 +691,17 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.0" @@ -1389,6 +1422,16 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.15", + "redox_syscall", +] + [[package]] name = "regex" version = "1.4.2" diff --git a/demo_glium/src/main.rs b/demo_glium/src/main.rs index 62899896..ac6e0bfe 100644 --- a/demo_glium/src/main.rs +++ b/demo_glium/src/main.rs @@ -3,12 +3,6 @@ #![warn(clippy::all)] fn main() { - // Persist app state to file: - let storage = egui_glium::storage::FileStorage::from_path(".egui_demo_glium.json"); - - // Alternative: store nowhere - // let storage = egui::app::DummyStorage::default(); - - let app: egui::DemoApp = egui::app::get_value(&storage, egui::app::APP_KEY).unwrap_or_default(); - egui_glium::run(Box::new(storage), Box::new(app)); + let app = egui::DemoApp::default(); + egui_glium::run(Box::new(app)); } diff --git a/egui_glium/CHANGELOG.md b/egui_glium/CHANGELOG.md index cf4f1e72..176d75b2 100644 --- a/egui_glium/CHANGELOG.md +++ b/egui_glium/CHANGELOG.md @@ -7,8 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +### Added + +* `egui_glium` will auto-save your app state every 30 seconds. + ### 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` (you need to add `Box::new(app)` to your code). * Window title is now passed via the `trait` function `egui::App::name()` diff --git a/egui_glium/Cargo.toml b/egui_glium/Cargo.toml index 83604911..5a2dd6ce 100644 --- a/egui_glium/Cargo.toml +++ b/egui_glium/Cargo.toml @@ -15,6 +15,7 @@ include = [ "**/*.rs", "Cargo.toml"] [dependencies] chrono = { version = "0.4" } clipboard = "0.5" +directories-next = "2" egui = { version = "0.5.0", path = "../egui", features = ["serde", "serde_json"] } glium = "0.29" serde = "1" diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index 69a3caa6..773f5b4d 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -63,18 +63,48 @@ fn create_display( glium::Display::new(window_builder, context_builder, &event_loop).unwrap() } +fn create_storage(app_name: &str) -> Option> { + if let Some(proj_dirs) = directories_next::ProjectDirs::from("", "", app_name) { + let data_dir = proj_dirs.data_dir().to_path_buf(); + if let Err(err) = std::fs::create_dir_all(&data_dir) { + eprintln!( + "Saving disabled: Failed to create app path at {:?}: {}", + data_dir, err + ); + None + } else { + let mut config_dir = data_dir; + config_dir.push("app.json"); + let storage = crate::storage::FileStorage::from_path(config_dir); + Some(Box::new(storage)) + } + } else { + eprintln!("Saving disabled: Failed to find path to data_dir."); + None + } +} + /// Run an egui app -pub fn run(mut storage: Box, mut app: Box) -> ! { - app.load(storage.as_ref()); - let window_settings: Option = - egui::app::get_value(storage.as_ref(), WINDOW_KEY); +pub fn run(mut app: Box) -> ! { + let mut storage = create_storage(app.name()); + + if let Some(storage) = &mut storage { + app.load(storage.as_ref()); + } + + let window_settings: Option = storage + .as_mut() + .and_then(|storage| egui::app::get_value(storage.as_ref(), WINDOW_KEY)); let event_loop = glutin::event_loop::EventLoop::with_user_event(); let display = create_display(app.name(), window_settings, &event_loop); let repaint_signal = std::sync::Arc::new(GliumRepaintSignal(event_loop.create_proxy())); let mut ctx = egui::CtxRef::default(); - *ctx.memory() = egui::app::get_value(storage.as_ref(), EGUI_MEMORY_KEY).unwrap_or_default(); + *ctx.memory() = storage + .as_mut() + .and_then(|storage| egui::app::get_value(storage.as_ref(), EGUI_MEMORY_KEY)) + .unwrap_or_default(); app.setup(&ctx); let mut input_state = GliumInputState::from_pixels_per_point(native_pixels_per_point(&display)); @@ -84,6 +114,8 @@ pub fn run(mut storage: Box, mut app: Box) -> ! let mut painter = Painter::new(&display); let mut clipboard = init_clipboard(); + let mut last_auto_save = Instant::now(); + event_loop.run(move |event, _, control_flow| { let mut redraw = || { let frame_start = Instant::now(); @@ -153,6 +185,21 @@ pub fn run(mut storage: Box, mut app: Box) -> ! } handle_output(egui_output, &display, clipboard.as_mut()); + + if let Some(storage) = &mut storage { + let now = Instant::now(); + if now - last_auto_save > app.auto_save_interval() { + egui::app::set_value( + storage.as_mut(), + WINDOW_KEY, + &WindowSettings::from_display(&display), + ); + egui::app::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*ctx.memory()); + app.save(storage.as_mut()); + storage.flush(); + last_auto_save = now; + } + } }; match event { @@ -167,15 +214,17 @@ pub fn run(mut storage: Box, mut app: Box) -> ! display.gl_window().window().request_redraw(); // TODO: ask Egui if the events warrants a repaint instead } glutin::event::Event::LoopDestroyed => { - egui::app::set_value( - storage.as_mut(), - WINDOW_KEY, - &WindowSettings::from_display(&display), - ); - egui::app::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*ctx.memory()); - app.save(storage.as_mut()); app.on_exit(); - storage.flush(); + if let Some(storage) = &mut storage { + egui::app::set_value( + storage.as_mut(), + WINDOW_KEY, + &WindowSettings::from_display(&display), + ); + egui::app::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*ctx.memory()); + app.save(storage.as_mut()); + storage.flush(); + } } glutin::event::Event::UserEvent(RequestRepaintEvent) => {