Browse Source

[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
pull/70/head
Emil Ernerfeldt 4 years ago
parent
commit
8f034d391d
  1. 45
      Cargo.lock
  2. 10
      demo_glium/src/main.rs
  3. 5
      egui_glium/CHANGELOG.md
  4. 1
      egui_glium/Cargo.toml
  5. 59
      egui_glium/src/backend.rs

45
Cargo.lock

@ -33,7 +33,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75b7e6a93ecd6dbd2c225154d0fa7f86205574ecaa6c87429fb5f66ee677c44" checksum = "a75b7e6a93ecd6dbd2c225154d0fa7f86205574ecaa6c87429fb5f66ee677c44"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.2.0",
"lazy_static", "lazy_static",
"version_check", "version_check",
] ]
@ -553,6 +553,27 @@ dependencies = [
"syn", "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]] [[package]]
name = "dispatch" name = "dispatch"
version = "0.2.0" version = "0.2.0"
@ -592,6 +613,7 @@ version = "0.5.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"clipboard", "clipboard",
"directories-next",
"egui", "egui",
"glium", "glium",
"serde", "serde",
@ -669,6 +691,17 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 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]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.0" version = "0.2.0"
@ -1389,6 +1422,16 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 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]] [[package]]
name = "regex" name = "regex"
version = "1.4.2" version = "1.4.2"

10
demo_glium/src/main.rs

@ -3,12 +3,6 @@
#![warn(clippy::all)] #![warn(clippy::all)]
fn main() { fn main() {
// Persist app state to file: let app = egui::DemoApp::default();
let storage = egui_glium::storage::FileStorage::from_path(".egui_demo_glium.json"); egui_glium::run(Box::new(app));
// 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));
} }

5
egui_glium/CHANGELOG.md

@ -7,8 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased ## Unreleased
### Added
* `egui_glium` will auto-save your app state every 30 seconds.
### 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). * `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()` * Window title is now passed via the `trait` function `egui::App::name()`

1
egui_glium/Cargo.toml

@ -15,6 +15,7 @@ include = [ "**/*.rs", "Cargo.toml"]
[dependencies] [dependencies]
chrono = { version = "0.4" } chrono = { version = "0.4" }
clipboard = "0.5" clipboard = "0.5"
directories-next = "2"
egui = { version = "0.5.0", path = "../egui", features = ["serde", "serde_json"] } egui = { version = "0.5.0", path = "../egui", features = ["serde", "serde_json"] }
glium = "0.29" glium = "0.29"
serde = "1" serde = "1"

59
egui_glium/src/backend.rs

@ -63,18 +63,48 @@ fn create_display(
glium::Display::new(window_builder, context_builder, &event_loop).unwrap() glium::Display::new(window_builder, context_builder, &event_loop).unwrap()
} }
fn create_storage(app_name: &str) -> Option<Box<dyn egui::app::Storage>> {
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 /// Run an egui app
pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> ! { pub fn run(mut app: Box<dyn App>) -> ! {
let mut storage = create_storage(app.name());
if let Some(storage) = &mut storage {
app.load(storage.as_ref()); app.load(storage.as_ref());
let window_settings: Option<WindowSettings> = }
egui::app::get_value(storage.as_ref(), WINDOW_KEY);
let window_settings: Option<WindowSettings> = 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 event_loop = glutin::event_loop::EventLoop::with_user_event();
let display = create_display(app.name(), window_settings, &event_loop); let display = create_display(app.name(), window_settings, &event_loop);
let repaint_signal = std::sync::Arc::new(GliumRepaintSignal(event_loop.create_proxy())); let repaint_signal = std::sync::Arc::new(GliumRepaintSignal(event_loop.create_proxy()));
let mut ctx = egui::CtxRef::default(); 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); app.setup(&ctx);
let mut input_state = GliumInputState::from_pixels_per_point(native_pixels_per_point(&display)); let mut input_state = GliumInputState::from_pixels_per_point(native_pixels_per_point(&display));
@ -84,6 +114,8 @@ pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
let mut painter = Painter::new(&display); let mut painter = Painter::new(&display);
let mut clipboard = init_clipboard(); let mut clipboard = init_clipboard();
let mut last_auto_save = Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
let mut redraw = || { let mut redraw = || {
let frame_start = Instant::now(); let frame_start = Instant::now();
@ -153,6 +185,21 @@ pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
} }
handle_output(egui_output, &display, clipboard.as_mut()); 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 { match event {
@ -167,6 +214,8 @@ pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
display.gl_window().window().request_redraw(); // TODO: ask Egui if the events warrants a repaint instead display.gl_window().window().request_redraw(); // TODO: ask Egui if the events warrants a repaint instead
} }
glutin::event::Event::LoopDestroyed => { glutin::event::Event::LoopDestroyed => {
app.on_exit();
if let Some(storage) = &mut storage {
egui::app::set_value( egui::app::set_value(
storage.as_mut(), storage.as_mut(),
WINDOW_KEY, WINDOW_KEY,
@ -174,9 +223,9 @@ pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
); );
egui::app::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*ctx.memory()); egui::app::set_value(storage.as_mut(), EGUI_MEMORY_KEY, &*ctx.memory());
app.save(storage.as_mut()); app.save(storage.as_mut());
app.on_exit();
storage.flush(); storage.flush();
} }
}
glutin::event::Event::UserEvent(RequestRepaintEvent) => { glutin::event::Event::UserEvent(RequestRepaintEvent) => {
display.gl_window().window().request_redraw(); display.gl_window().window().request_redraw();

Loading…
Cancel
Save