mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 05:10:03 -04:00
[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
This commit is contained in:
@@ -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<dyn App>` (you need to add `Box::new(app)` to your code).
|
||||
* Window title is now passed via the `trait` function `egui::App::name()`
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -63,18 +63,48 @@ fn create_display(
|
||||
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
|
||||
pub fn run(mut storage: Box<dyn egui::app::Storage>, mut app: Box<dyn App>) -> ! {
|
||||
app.load(storage.as_ref());
|
||||
let window_settings: Option<WindowSettings> =
|
||||
egui::app::get_value(storage.as_ref(), WINDOW_KEY);
|
||||
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());
|
||||
}
|
||||
|
||||
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 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<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
|
||||
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<dyn egui::app::Storage>, mut app: Box<dyn App>) -> !
|
||||
}
|
||||
|
||||
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<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
|
||||
}
|
||||
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) => {
|
||||
|
||||
Reference in New Issue
Block a user