diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index e7b53691cda..ecfff3fe6ce 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -150,6 +150,7 @@ pub trait App { /// On web the state is stored to "Local Storage". /// /// On native the path is picked using [`crate::storage_dir`]. + /// The path can be customized via [`NativeOptions::persistence_path`]. fn save(&mut self, _storage: &mut dyn Storage) {} /// Called once on shutdown, after [`Self::save`]. @@ -362,6 +363,10 @@ pub struct NativeOptions { /// Controls whether or not the native window position and size will be /// persisted (only if the "persistence" feature is enabled). pub persist_window: bool, + + /// The folder where `eframe` will store the app state. If not set, eframe will get the paths + /// from [directories_next]. + pub persistence_path: Option, } #[cfg(not(target_arch = "wasm32"))] @@ -379,6 +384,8 @@ impl Clone for NativeOptions { #[cfg(feature = "wgpu")] wgpu_options: self.wgpu_options.clone(), + persistence_path: self.persistence_path.clone(), + ..*self } } @@ -418,6 +425,8 @@ impl Default for NativeOptions { wgpu_options: egui_wgpu::WgpuConfiguration::default(), persist_window: true, + + persistence_path: None, } } } diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index b09f0f0e0c7..7be09c164ac 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -1,6 +1,8 @@ //! Common tools used by [`super::glow_integration`] and [`super::wgpu_integration`]. use web_time::Instant; + +use std::path::PathBuf; use winit::event_loop::EventLoopWindowTarget; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; @@ -129,6 +131,16 @@ pub fn create_storage(_app_name: &str) -> Option> { None } +#[allow(clippy::unnecessary_wraps)] +pub fn create_storage_with_file(_file: impl Into) -> Option> { + #[cfg(feature = "persistence")] + return Some(Box::new( + super::file_storage::FileStorage::from_ron_filepath(_file), + )); + #[cfg(not(feature = "persistence"))] + None +} + // ---------------------------------------------------------------------------- /// Everything needed to make a winit-based integration for [`epi`]. diff --git a/crates/eframe/src/native/file_storage.rs b/crates/eframe/src/native/file_storage.rs index 51c668abdeb..970c35a4f41 100644 --- a/crates/eframe/src/native/file_storage.rs +++ b/crates/eframe/src/native/file_storage.rs @@ -41,7 +41,7 @@ impl Drop for FileStorage { impl FileStorage { /// Store the state in this .ron file. - fn from_ron_filepath(ron_filepath: impl Into) -> Self { + pub(crate) fn from_ron_filepath(ron_filepath: impl Into) -> Self { crate::profile_function!(); let ron_filepath: PathBuf = ron_filepath.into(); log::debug!("Loading app state from {:?}…", ron_filepath); diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index f08ed14d623..9a67e4af3d9 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -195,13 +195,17 @@ impl GlowWinitApp { ) -> Result<&mut GlowWinitRunning> { crate::profile_function!(); - let storage = epi_integration::create_storage( - self.native_options - .viewport - .app_id - .as_ref() - .unwrap_or(&self.app_name), - ); + let storage = if let Some(file) = &self.native_options.persistence_path { + epi_integration::create_storage_with_file(file) + } else { + epi_integration::create_storage( + self.native_options + .viewport + .app_id + .as_ref() + .unwrap_or(&self.app_name), + ) + }; let egui_ctx = create_egui_context(storage.as_deref()); diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index 1287ce8a01f..2276d7cb037 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -420,13 +420,17 @@ impl WinitApp for WgpuWinitApp { self.recreate_window(event_loop, running); running } else { - let storage = epi_integration::create_storage( - self.native_options - .viewport - .app_id - .as_ref() - .unwrap_or(&self.app_name), - ); + let storage = if let Some(file) = &self.native_options.persistence_path { + epi_integration::create_storage_with_file(file) + } else { + epi_integration::create_storage( + self.native_options + .viewport + .app_id + .as_ref() + .unwrap_or(&self.app_name), + ) + }; let egui_ctx = winit_integration::create_egui_context(storage.as_deref()); let (window, builder) = create_window( &egui_ctx,