From 70bfc7e09f1b1f794a77064b62a4932f9e60ef15 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 29 Aug 2023 15:22:07 +0200 Subject: [PATCH] Add `eframe::storage_dir` (#3286) * Add `eframe::storage_dir` Now you can easily tell where eframe stores its state * egui_plot: work even without the `serde` featur flag --- crates/eframe/src/epi/mod.rs | 14 +++----------- crates/eframe/src/lib.rs | 5 +++++ crates/eframe/src/native/epi_integration.rs | 2 +- crates/eframe/src/native/file_storage.rs | 21 +++++++++++++++++---- crates/egui_plot/src/lib.rs | 12 ++++++++++++ 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/crates/eframe/src/epi/mod.rs b/crates/eframe/src/epi/mod.rs index fd4f0280..6172bf42 100644 --- a/crates/eframe/src/epi/mod.rs +++ b/crates/eframe/src/epi/mod.rs @@ -139,13 +139,8 @@ pub trait App { /// Only called when the "persistence" feature is enabled. /// /// On web the state is stored to "Local Storage". - /// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is: - /// * Linux: `/home/UserName/.local/share/APP_ID` - /// * macOS: `/Users/UserName/Library/Application Support/APP_ID` - /// * Windows: `C:\Users\UserName\AppData\Roaming\APP_ID` /// - /// where `APP_ID` is determined by either [`NativeOptions::app_id`] or - /// the title argument to [`crate::run_native`]. + /// On native the path is picked using [`crate::storage_dir`]. fn save(&mut self, _storage: &mut dyn Storage) {} /// Called when the user attempts to close the desktop window and/or quit the application. @@ -422,13 +417,10 @@ pub struct NativeOptions { /// The application id, used for determining the folder to persist the app to. /// - /// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is: - /// * Linux: `/home/UserName/.local/share/APP_ID` - /// * macOS: `/Users/UserName/Library/Application Support/APP_ID` - /// * Windows: `C:\Users\UserName\AppData\Roaming\APP_ID` + /// On native the path is picked using [`crate::storage_dir`]. /// /// If you don't set [`Self::app_id`], the title argument to [`crate::run_native`] - /// will be used instead. + /// will be used as app id instead. /// /// ### On Wayland /// On Wayland this sets the Application ID for the window. diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index 8093339e..63c7cdee 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -159,6 +159,11 @@ pub use web::{WebLogger, WebRunner}; #[cfg(any(feature = "glow", feature = "wgpu"))] mod native; +#[cfg(not(target_arch = "wasm32"))] +#[cfg(any(feature = "glow", feature = "wgpu"))] +#[cfg(feature = "persistence")] +pub use native::file_storage::storage_dir; + /// This is how you start a native (desktop) app. /// /// The first argument is name of your app, used for the title bar of the native window diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 65c5ccbe..1204521d 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -331,7 +331,7 @@ pub fn handle_app_output( /// For loading/saving app state and/or egui memory to disk. pub fn create_storage(_app_name: &str) -> Option> { #[cfg(feature = "persistence")] - if let Some(storage) = super::file_storage::FileStorage::from_app_name(_app_name) { + if let Some(storage) = super::file_storage::FileStorage::from_app_id(_app_name) { return Some(Box::new(storage)); } None diff --git a/crates/eframe/src/native/file_storage.rs b/crates/eframe/src/native/file_storage.rs index 2f316a8c..eae742cf 100644 --- a/crates/eframe/src/native/file_storage.rs +++ b/crates/eframe/src/native/file_storage.rs @@ -3,6 +3,20 @@ use std::{ path::{Path, PathBuf}, }; +/// The folder where `eframe` will store its state. +/// +/// The given `app_id` is either [`crate::NativeOptions::app_id`] or +/// the title argument to [`crate::run_native`]. +/// +/// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is: +/// * Linux: `/home/UserName/.local/share/APP_ID` +/// * macOS: `/Users/UserName/Library/Application Support/APP_ID` +/// * Windows: `C:\Users\UserName\AppData\Roaming\APP_ID` +pub fn storage_dir(app_id: &str) -> Option { + directories_next::ProjectDirs::from("", "", app_id) + .map(|proj_dirs| proj_dirs.data_dir().to_path_buf()) +} + // ---------------------------------------------------------------------------- /// A key-value store backed by a [RON](https://github.com/ron-rs/ron) file on disk. @@ -24,7 +38,7 @@ impl Drop for FileStorage { impl FileStorage { /// Store the state in this .ron file. - pub fn from_ron_filepath(ron_filepath: impl Into) -> Self { + fn from_ron_filepath(ron_filepath: impl Into) -> Self { let ron_filepath: PathBuf = ron_filepath.into(); log::debug!("Loading app state from {:?}…", ron_filepath); Self { @@ -36,9 +50,8 @@ impl FileStorage { } /// Find a good place to put the files that the OS likes. - pub fn from_app_name(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(); + pub fn from_app_id(app_id: &str) -> Option { + if let Some(data_dir) = storage_dir(app_id) { if let Err(err) = std::fs::create_dir_all(&data_dir) { log::warn!( "Saving disabled: Failed to create app path at {:?}: {}", diff --git a/crates/egui_plot/src/lib.rs b/crates/egui_plot/src/lib.rs index 08a6ebd1..835a75d1 100644 --- a/crates/egui_plot/src/lib.rs +++ b/crates/egui_plot/src/lib.rs @@ -126,6 +126,7 @@ struct PlotMemory { last_click_pos_for_zoom: Option, } +#[cfg(feature = "serde")] impl PlotMemory { pub fn load(ctx: &Context, id: Id) -> Option { ctx.data_mut(|d| d.get_persisted(id)) @@ -136,6 +137,17 @@ impl PlotMemory { } } +#[cfg(not(feature = "serde"))] +impl PlotMemory { + pub fn load(ctx: &Context, id: Id) -> Option { + ctx.data_mut(|d| d.get_temp(id)) + } + + pub fn store(self, ctx: &Context, id: Id) { + ctx.data_mut(|d| d.insert_temp(id, self)); + } +} + // ---------------------------------------------------------------------------- /// Indicates a vertical or horizontal cursor line in plot coordinates.