mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Storage and frame refactor (#1418)
The purpose of this is to expose `frame.storage()` and `frame.storage_mut()` so users can save/load app state from the `App::update` function, without having to add another parameter to that function. Changes: * Added `Frame::storage()` and `Frame::storage_mut()` * `App::update` now takes a `&mut Frame` rather than just `&Frame` * `Frame` is no longer `Clone` or `Sync` (doesn't have to be since https://github.com/emilk/egui/pull/1366)
This commit is contained in:
@@ -124,96 +124,12 @@ pub fn handle_app_output(
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// For loading/saving app state and/or egui memory to disk.
|
||||
pub struct Persistence {
|
||||
storage: Option<Box<dyn epi::Storage>>,
|
||||
last_auto_save: instant::Instant,
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
impl Persistence {
|
||||
pub fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||
#[cfg(feature = "persistence")]
|
||||
const EGUI_MEMORY_KEY: &'static str = "egui";
|
||||
#[cfg(feature = "persistence")]
|
||||
const WINDOW_KEY: &'static str = "window";
|
||||
|
||||
pub fn from_app_name(app_name: &str) -> Self {
|
||||
fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = epi::file_storage::FileStorage::from_app_name(_app_name) {
|
||||
return Some(Box::new(storage));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
Self {
|
||||
storage: create_storage(app_name),
|
||||
last_auto_save: instant::Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn storage(&self) -> Option<&dyn epi::Storage> {
|
||||
self.storage.as_deref()
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
pub fn load_window_settings(&self) -> Option<crate::WindowSettings> {
|
||||
epi::get_value(&**self.storage.as_ref()?, Self::WINDOW_KEY)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
pub fn load_window_settings(&self) -> Option<crate::WindowSettings> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
pub fn load_memory(&self) -> Option<egui::Memory> {
|
||||
epi::get_value(&**self.storage.as_ref()?, Self::EGUI_MEMORY_KEY)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
pub fn load_memory(&self) -> Option<egui::Memory> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn save(
|
||||
&mut self,
|
||||
_app: &mut dyn epi::App,
|
||||
_egui_ctx: &egui::Context,
|
||||
_window: &winit::window::Window,
|
||||
) {
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = &mut self.storage {
|
||||
if _app.persist_native_window() {
|
||||
epi::set_value(
|
||||
storage.as_mut(),
|
||||
Self::WINDOW_KEY,
|
||||
&crate::WindowSettings::from_display(_window),
|
||||
);
|
||||
}
|
||||
if _app.persist_egui_memory() {
|
||||
epi::set_value(
|
||||
storage.as_mut(),
|
||||
Self::EGUI_MEMORY_KEY,
|
||||
&*_egui_ctx.memory(),
|
||||
);
|
||||
}
|
||||
_app.save(storage.as_mut());
|
||||
storage.flush();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_autosave(
|
||||
&mut self,
|
||||
app: &mut dyn epi::App,
|
||||
egui_ctx: &egui::Context,
|
||||
window: &winit::window::Window,
|
||||
) {
|
||||
let now = instant::Instant::now();
|
||||
if now - self.last_auto_save > app.auto_save_interval() {
|
||||
self.save(app, egui_ctx, window);
|
||||
self.last_auto_save = now;
|
||||
}
|
||||
if let Some(storage) = epi::file_storage::FileStorage::from_app_name(_app_name) {
|
||||
return Some(Box::new(storage));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -221,7 +137,7 @@ impl Persistence {
|
||||
/// Everything needed to make a winit-based integration for [`epi`].
|
||||
pub struct EpiIntegration {
|
||||
pub frame: epi::Frame,
|
||||
pub persistence: crate::epi::Persistence,
|
||||
last_auto_save: instant::Instant,
|
||||
pub egui_ctx: egui::Context,
|
||||
pending_full_output: egui::FullOutput,
|
||||
egui_winit: crate::State,
|
||||
@@ -235,15 +151,15 @@ impl EpiIntegration {
|
||||
integration_name: &'static str,
|
||||
max_texture_side: usize,
|
||||
window: &winit::window::Window,
|
||||
persistence: crate::epi::Persistence,
|
||||
storage: Option<Box<dyn epi::Storage>>,
|
||||
) -> Self {
|
||||
let egui_ctx = egui::Context::default();
|
||||
|
||||
*egui_ctx.memory() = persistence.load_memory().unwrap_or_default();
|
||||
*egui_ctx.memory() = load_egui_memory(storage.as_deref()).unwrap_or_default();
|
||||
|
||||
let prefer_dark_mode = prefer_dark_mode();
|
||||
|
||||
let frame = epi::Frame::new(epi::backend::FrameData {
|
||||
let frame = epi::Frame {
|
||||
info: epi::IntegrationInfo {
|
||||
name: integration_name,
|
||||
web_info: None,
|
||||
@@ -252,7 +168,8 @@ impl EpiIntegration {
|
||||
native_pixels_per_point: Some(crate::native_pixels_per_point(window)),
|
||||
},
|
||||
output: Default::default(),
|
||||
});
|
||||
storage,
|
||||
};
|
||||
|
||||
if prefer_dark_mode == Some(true) {
|
||||
egui_ctx.set_visuals(egui::Visuals::dark());
|
||||
@@ -262,7 +179,7 @@ impl EpiIntegration {
|
||||
|
||||
Self {
|
||||
frame,
|
||||
persistence,
|
||||
last_auto_save: instant::Instant::now(),
|
||||
egui_ctx,
|
||||
egui_winit: crate::State::new(max_texture_side, window),
|
||||
pending_full_output: Default::default(),
|
||||
@@ -311,7 +228,7 @@ impl EpiIntegration {
|
||||
|
||||
let raw_input = self.egui_winit.take_egui_input(window);
|
||||
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
||||
app.update(egui_ctx, &self.frame);
|
||||
app.update(egui_ctx, &mut self.frame);
|
||||
});
|
||||
self.pending_full_output.append(full_output);
|
||||
let full_output = std::mem::take(&mut self.pending_full_output);
|
||||
@@ -327,7 +244,7 @@ impl EpiIntegration {
|
||||
}
|
||||
|
||||
let frame_time = (instant::Instant::now() - frame_start).as_secs_f64() as f32;
|
||||
self.frame.lock().info.cpu_usage = Some(frame_time);
|
||||
self.frame.info.cpu_usage = Some(frame_time);
|
||||
|
||||
full_output
|
||||
}
|
||||
@@ -341,10 +258,57 @@ impl EpiIntegration {
|
||||
.handle_platform_output(window, &self.egui_ctx, platform_output);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Persistance stuff:
|
||||
|
||||
pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
||||
self.persistence
|
||||
.maybe_autosave(&mut *app, &self.egui_ctx, window);
|
||||
let now = instant::Instant::now();
|
||||
if now - self.last_auto_save > app.auto_save_interval() {
|
||||
self.save(app, window);
|
||||
self.last_auto_save = now;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&mut self, _app: &mut dyn epi::App, _window: &winit::window::Window) {
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = self.frame.storage_mut() {
|
||||
if _app.persist_native_window() {
|
||||
epi::set_value(
|
||||
storage,
|
||||
STORAGE_WINDOW_KEY,
|
||||
&crate::WindowSettings::from_display(_window),
|
||||
);
|
||||
}
|
||||
if _app.persist_egui_memory() {
|
||||
epi::set_value(storage, STORAGE_EGUI_MEMORY_KEY, &*self.egui_ctx.memory());
|
||||
}
|
||||
_app.save(storage);
|
||||
storage.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
const STORAGE_EGUI_MEMORY_KEY: &str = "egui";
|
||||
#[cfg(feature = "persistence")]
|
||||
const STORAGE_WINDOW_KEY: &str = "window";
|
||||
|
||||
pub fn load_window_settings(_storage: Option<&dyn epi::Storage>) -> Option<crate::WindowSettings> {
|
||||
#[cfg(feature = "persistence")]
|
||||
{
|
||||
epi::get_value(_storage?, STORAGE_WINDOW_KEY)
|
||||
}
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
None
|
||||
}
|
||||
|
||||
pub fn load_egui_memory(_storage: Option<&dyn epi::Storage>) -> Option<egui::Memory> {
|
||||
#[cfg(feature = "persistence")]
|
||||
{
|
||||
epi::get_value(_storage?, STORAGE_EGUI_MEMORY_KEY)
|
||||
}
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "dark-light")]
|
||||
|
||||
Reference in New Issue
Block a user