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:
parent
bc0fdefceb
commit
b7ebe16cfb
27 changed files with 157 additions and 199 deletions
|
@ -8,8 +8,16 @@ NOTE: [`egui_web`](../egui_web/CHANGELOG.md), [`egui-winit`](../egui-winit/CHANG
|
||||||
* Change default for `NativeOptions::drag_and_drop_support` to `true` ([#1329](https://github.com/emilk/egui/pull/1329)).
|
* Change default for `NativeOptions::drag_and_drop_support` to `true` ([#1329](https://github.com/emilk/egui/pull/1329)).
|
||||||
* Remove the `egui_glium` feature. `eframe` will now always use `egui_glow` as the native backend ([#1357](https://github.com/emilk/egui/pull/1357)).
|
* Remove the `egui_glium` feature. `eframe` will now always use `egui_glow` as the native backend ([#1357](https://github.com/emilk/egui/pull/1357)).
|
||||||
* Removed `Frame::request_repaint` - just call `egui::Context::request_repaint` for the same effect ([#1366](https://github.com/emilk/egui/pull/1366)).
|
* Removed `Frame::request_repaint` - just call `egui::Context::request_repaint` for the same effect ([#1366](https://github.com/emilk/egui/pull/1366)).
|
||||||
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
|
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
|
||||||
* Add new `NativeOptions`: `vsync`, `multisampling`, `depth_buffer`, `stencil_buffer`.
|
* Added new `NativeOptions`: `vsync`, `multisampling`, `depth_buffer`, `stencil_buffer`.
|
||||||
|
* Changed app creation/setup ([#1363](https://github.com/emilk/egui/pull/1363)):
|
||||||
|
* Removed `App::setup` and `App::name`.
|
||||||
|
* Provide `CreationContext` when creating app with egui context, storage, integration info and glow context.
|
||||||
|
* Change interface of `run_native` and `start_web`.
|
||||||
|
* Added `Frame::storage()` and `Frame::storage_mut()` ([#1418](https://github.com/emilk/egui/pull/1418)).
|
||||||
|
* You can now load/save state in `App::update`
|
||||||
|
* Changed `App::update` to take `&mut Frame` instead of `&Frame`.
|
||||||
|
* `Frame` is no longer `Clone` or `Sync`.
|
||||||
|
|
||||||
|
|
||||||
## 0.17.0 - 2022-02-22
|
## 0.17.0 - 2022-02-22
|
||||||
|
|
|
@ -23,7 +23,7 @@ impl eframe::App for MyApp {
|
||||||
self.can_exit
|
self.can_exit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("Try to close the window");
|
ui.heading("Try to close the window");
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.spacing_mut().item_spacing.x = 0.0;
|
ui.spacing_mut().item_spacing.x = 0.0;
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
egui::widgets::global_dark_light_mode_buttons(ui);
|
egui::widgets::global_dark_light_mode_buttons(ui);
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("egui using custom fonts");
|
ui.heading("egui using custom fonts");
|
||||||
ui.text_edit_multiline(&mut self.text);
|
ui.text_edit_multiline(&mut self.text);
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl eframe::App for MyApp {
|
||||||
egui::Rgba::TRANSPARENT // Make sure we don't paint anything behind the rounded corners
|
egui::Rgba::TRANSPARENT // Make sure we don't paint anything behind the rounded corners
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
custon_window_frame(ctx, frame, "egui with custom frame", |ui| {
|
custon_window_frame(ctx, frame, "egui with custom frame", |ui| {
|
||||||
ui.label("This is just the contents of the window");
|
ui.label("This is just the contents of the window");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
@ -41,7 +41,7 @@ impl eframe::App for MyApp {
|
||||||
|
|
||||||
fn custon_window_frame(
|
fn custon_window_frame(
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
frame: &eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
title: &str,
|
title: &str,
|
||||||
add_contents: impl FnOnce(&mut egui::Ui),
|
add_contents: impl FnOnce(&mut egui::Ui),
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
let promise = self.promise.get_or_insert_with(|| {
|
let promise = self.promise.get_or_insert_with(|| {
|
||||||
// Begin download.
|
// Begin download.
|
||||||
// We download the image using `ehttp`, a library that works both in WASM and on native.
|
// We download the image using `ehttp`, a library that works both in WASM and on native.
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.label("Drag-and-drop files onto the window!");
|
ui.label("Drag-and-drop files onto the window!");
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("My egui Application");
|
ui.heading("My egui Application");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("This is an image:");
|
ui.heading("This is an image:");
|
||||||
self.image.show(ui);
|
self.image.show(ui);
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("SVG example");
|
ui.heading("SVG example");
|
||||||
ui.label("The SVG is rasterized and displayed as a texture.");
|
ui.label("The SVG is rasterized and displayed as a texture.");
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! impl eframe::App for MyEguiApp {
|
//! impl eframe::App for MyEguiApp {
|
||||||
//! fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
//! fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
//! egui::CentralPanel::default().show(ctx, |ui| {
|
//! egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
//! ui.heading("Hello World!");
|
//! ui.heading("Hello World!");
|
||||||
//! });
|
//! });
|
||||||
|
@ -126,7 +126,7 @@ pub fn start_web(canvas_id: &str, app_creator: AppCreator) -> Result<(), wasm_bi
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl eframe::App for MyEguiApp {
|
/// impl eframe::App for MyEguiApp {
|
||||||
/// fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
/// fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
/// egui::CentralPanel::default().show(ctx, |ui| {
|
/// egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
/// ui.heading("Hello World!");
|
/// ui.heading("Hello World!");
|
||||||
/// });
|
/// });
|
||||||
|
|
|
@ -124,96 +124,12 @@ pub fn handle_app_output(
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// For loading/saving app state and/or egui memory to disk.
|
/// For loading/saving app state and/or egui memory to disk.
|
||||||
pub struct Persistence {
|
pub fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||||
storage: Option<Box<dyn epi::Storage>>,
|
|
||||||
last_auto_save: instant::Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
|
||||||
impl Persistence {
|
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
const EGUI_MEMORY_KEY: &'static str = "egui";
|
if let Some(storage) = epi::file_storage::FileStorage::from_app_name(_app_name) {
|
||||||
#[cfg(feature = "persistence")]
|
return Some(Box::new(storage));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -221,7 +137,7 @@ impl Persistence {
|
||||||
/// Everything needed to make a winit-based integration for [`epi`].
|
/// Everything needed to make a winit-based integration for [`epi`].
|
||||||
pub struct EpiIntegration {
|
pub struct EpiIntegration {
|
||||||
pub frame: epi::Frame,
|
pub frame: epi::Frame,
|
||||||
pub persistence: crate::epi::Persistence,
|
last_auto_save: instant::Instant,
|
||||||
pub egui_ctx: egui::Context,
|
pub egui_ctx: egui::Context,
|
||||||
pending_full_output: egui::FullOutput,
|
pending_full_output: egui::FullOutput,
|
||||||
egui_winit: crate::State,
|
egui_winit: crate::State,
|
||||||
|
@ -235,15 +151,15 @@ impl EpiIntegration {
|
||||||
integration_name: &'static str,
|
integration_name: &'static str,
|
||||||
max_texture_side: usize,
|
max_texture_side: usize,
|
||||||
window: &winit::window::Window,
|
window: &winit::window::Window,
|
||||||
persistence: crate::epi::Persistence,
|
storage: Option<Box<dyn epi::Storage>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let egui_ctx = egui::Context::default();
|
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 prefer_dark_mode = prefer_dark_mode();
|
||||||
|
|
||||||
let frame = epi::Frame::new(epi::backend::FrameData {
|
let frame = epi::Frame {
|
||||||
info: epi::IntegrationInfo {
|
info: epi::IntegrationInfo {
|
||||||
name: integration_name,
|
name: integration_name,
|
||||||
web_info: None,
|
web_info: None,
|
||||||
|
@ -252,7 +168,8 @@ impl EpiIntegration {
|
||||||
native_pixels_per_point: Some(crate::native_pixels_per_point(window)),
|
native_pixels_per_point: Some(crate::native_pixels_per_point(window)),
|
||||||
},
|
},
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
});
|
storage,
|
||||||
|
};
|
||||||
|
|
||||||
if prefer_dark_mode == Some(true) {
|
if prefer_dark_mode == Some(true) {
|
||||||
egui_ctx.set_visuals(egui::Visuals::dark());
|
egui_ctx.set_visuals(egui::Visuals::dark());
|
||||||
|
@ -262,7 +179,7 @@ impl EpiIntegration {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
frame,
|
frame,
|
||||||
persistence,
|
last_auto_save: instant::Instant::now(),
|
||||||
egui_ctx,
|
egui_ctx,
|
||||||
egui_winit: crate::State::new(max_texture_side, window),
|
egui_winit: crate::State::new(max_texture_side, window),
|
||||||
pending_full_output: Default::default(),
|
pending_full_output: Default::default(),
|
||||||
|
@ -311,7 +228,7 @@ impl EpiIntegration {
|
||||||
|
|
||||||
let raw_input = self.egui_winit.take_egui_input(window);
|
let raw_input = self.egui_winit.take_egui_input(window);
|
||||||
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
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);
|
self.pending_full_output.append(full_output);
|
||||||
let full_output = std::mem::take(&mut self.pending_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;
|
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
|
full_output
|
||||||
}
|
}
|
||||||
|
@ -341,10 +258,57 @@ impl EpiIntegration {
|
||||||
.handle_platform_output(window, &self.egui_ctx, platform_output);
|
.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) {
|
pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
||||||
self.persistence
|
let now = instant::Instant::now();
|
||||||
.maybe_autosave(&mut *app, &self.egui_ctx, window);
|
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")]
|
#[cfg(feature = "dark-light")]
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Default for ColorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for ColorTest {
|
impl epi::App for ColorTest {
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut epi::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
if frame.is_web() {
|
if frame.is_web() {
|
||||||
ui.label(
|
ui.label(
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub struct DemoApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for DemoApp {
|
impl epi::App for DemoApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut epi::Frame) {
|
||||||
self.demo_windows.ui(ctx);
|
self.demo_windows.ui(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl Default for FractalClock {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for FractalClock {
|
impl epi::App for FractalClock {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut epi::Frame) {
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(Frame::dark_canvas(&ctx.style()))
|
.frame(Frame::dark_canvas(&ctx.style()))
|
||||||
.show(ctx, |ui| self.ui(ui, crate::seconds_since_midnight()));
|
.show(ctx, |ui| self.ui(ui, crate::seconds_since_midnight()));
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl Default for HttpApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for HttpApp {
|
impl epi::App for HttpApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut epi::Frame) {
|
||||||
egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| {
|
egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| {
|
||||||
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
||||||
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
||||||
|
@ -108,7 +108,7 @@ impl epi::App for HttpApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_url(ui: &mut egui::Ui, frame: &epi::Frame, url: &mut String) -> bool {
|
fn ui_url(ui: &mut egui::Ui, frame: &mut epi::Frame, url: &mut String) -> bool {
|
||||||
let mut trigger_fetch = false;
|
let mut trigger_fetch = false;
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl Default for BackendPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendPanel {
|
impl BackendPanel {
|
||||||
pub fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
pub fn update(&mut self, ctx: &egui::Context, frame: &mut epi::Frame) {
|
||||||
self.frame_history
|
self.frame_history
|
||||||
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
|
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ impl BackendPanel {
|
||||||
self.egui_windows.windows(ctx);
|
self.egui_windows.windows(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &epi::Frame) {
|
pub fn ui(&mut self, ui: &mut egui::Ui, frame: &mut epi::Frame) {
|
||||||
egui::trace!(ui);
|
egui::trace!(ui);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.heading("💻 Backend");
|
ui.heading("💻 Backend");
|
||||||
|
@ -142,7 +142,7 @@ impl BackendPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn integration_ui(&mut self, ui: &mut egui::Ui, frame: &epi::Frame) {
|
fn integration_ui(&mut self, ui: &mut egui::Ui, frame: &mut epi::Frame) {
|
||||||
if frame.is_web() {
|
if frame.is_web() {
|
||||||
ui.label("egui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
|
ui.label("egui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
|
||||||
ui.label(
|
ui.label(
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Default for EasyMarkEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for EasyMarkEditor {
|
impl epi::App for EasyMarkEditor {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut epi::Frame) {
|
||||||
egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| {
|
egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| {
|
||||||
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
||||||
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl epi::App for WrapApp {
|
||||||
egui::Rgba::TRANSPARENT // we set a `CentralPanel` fill color in `demo_windows.rs`
|
egui::Rgba::TRANSPARENT // we set a `CentralPanel` fill color in `demo_windows.rs`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &mut epi::Frame) {
|
||||||
if let Some(web_info) = frame.info().web_info.as_ref() {
|
if let Some(web_info) = frame.info().web_info.as_ref() {
|
||||||
if let Some(anchor) = web_info.location.hash.strip_prefix('#') {
|
if let Some(anchor) = web_info.location.hash.strip_prefix('#') {
|
||||||
self.selected_anchor = anchor.to_owned();
|
self.selected_anchor = anchor.to_owned();
|
||||||
|
@ -130,7 +130,7 @@ impl epi::App for WrapApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrapApp {
|
impl WrapApp {
|
||||||
fn bar_contents(&mut self, ui: &mut egui::Ui, frame: &epi::Frame) {
|
fn bar_contents(&mut self, ui: &mut egui::Ui, frame: &mut epi::Frame) {
|
||||||
// A menu-bar is a horizontal layout with some special styles applied.
|
// A menu-bar is a horizontal layout with some special styles applied.
|
||||||
// egui::menu::bar(ui, |ui| {
|
// egui::menu::bar(ui, |ui| {
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
|
|
@ -37,8 +37,8 @@ pub use epi::NativeOptions;
|
||||||
/// Run an egui app
|
/// Run an egui app
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi::AppCreator) -> ! {
|
pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi::AppCreator) -> ! {
|
||||||
let persistence = egui_winit::epi::Persistence::from_app_name(app_name);
|
let storage = egui_winit::epi::create_storage(app_name);
|
||||||
let window_settings = persistence.load_window_settings();
|
let window_settings = egui_winit::epi::load_window_settings(storage.as_deref());
|
||||||
let window_builder =
|
let window_builder =
|
||||||
egui_winit::epi::window_builder(native_options, &window_settings).with_title(app_name);
|
egui_winit::epi::window_builder(native_options, &window_settings).with_title(app_name);
|
||||||
let event_loop = winit::event_loop::EventLoop::with_user_event();
|
let event_loop = winit::event_loop::EventLoop::with_user_event();
|
||||||
|
@ -52,7 +52,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
painter.max_texture_side(),
|
painter.max_texture_side(),
|
||||||
gl_window.window(),
|
gl_window.window(),
|
||||||
persistence,
|
storage,
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
let mut app = app_creator(&epi::CreationContext {
|
let mut app = app_creator(&epi::CreationContext {
|
||||||
egui_ctx: integration.egui_ctx.clone(),
|
egui_ctx: integration.egui_ctx.clone(),
|
||||||
integration_info: integration.frame.info(),
|
integration_info: integration.frame.info(),
|
||||||
storage: integration.persistence.storage(),
|
storage: integration.frame.storage(),
|
||||||
gl: gl.clone(),
|
gl: gl.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -154,9 +154,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
gl_window.window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead
|
gl_window.window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead
|
||||||
}
|
}
|
||||||
winit::event::Event::LoopDestroyed => {
|
winit::event::Event::LoopDestroyed => {
|
||||||
integration
|
integration.save(&mut *app, gl_window.window());
|
||||||
.persistence
|
|
||||||
.save(&mut *app, &integration.egui_ctx, gl_window.window());
|
|
||||||
app.on_exit(&gl);
|
app.on_exit(&gl);
|
||||||
painter.destroy();
|
painter.destroy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ All notable changes to the `egui_web` integration will be noted in this file.
|
||||||
## Unreleased
|
## Unreleased
|
||||||
* egui code will no longer be called after panic ([#1306](https://github.com/emilk/egui/pull/1306)).
|
* egui code will no longer be called after panic ([#1306](https://github.com/emilk/egui/pull/1306)).
|
||||||
* Remove the "webgl" feature. `egui_web` now always use `glow` (which in turn wraps WebGL) ([#1356](https://github.com/emilk/egui/pull/1356)).
|
* Remove the "webgl" feature. `egui_web` now always use `glow` (which in turn wraps WebGL) ([#1356](https://github.com/emilk/egui/pull/1356)).
|
||||||
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
|
* Use full browser width by default ([#1378](https://github.com/emilk/egui/pull/1378)).
|
||||||
|
|
||||||
|
|
||||||
## 0.17.0 - 2022-02-22
|
## 0.17.0 - 2022-02-22
|
||||||
|
|
|
@ -130,7 +130,6 @@ pub struct AppRunner {
|
||||||
pub(crate) input: WebInput,
|
pub(crate) input: WebInput,
|
||||||
app: Box<dyn epi::App>,
|
app: Box<dyn epi::App>,
|
||||||
pub(crate) needs_repaint: std::sync::Arc<NeedRepaint>,
|
pub(crate) needs_repaint: std::sync::Arc<NeedRepaint>,
|
||||||
storage: LocalStorage,
|
|
||||||
last_save_time: f64,
|
last_save_time: f64,
|
||||||
screen_reader: crate::screen_reader::ScreenReader,
|
screen_reader: crate::screen_reader::ScreenReader,
|
||||||
pub(crate) text_cursor_pos: Option<egui::Pos2>,
|
pub(crate) text_cursor_pos: Option<egui::Pos2>,
|
||||||
|
@ -144,7 +143,7 @@ impl AppRunner {
|
||||||
|
|
||||||
let prefer_dark_mode = crate::prefer_dark_mode();
|
let prefer_dark_mode = crate::prefer_dark_mode();
|
||||||
|
|
||||||
let frame = epi::Frame::new(epi::backend::FrameData {
|
let frame = epi::Frame {
|
||||||
info: epi::IntegrationInfo {
|
info: epi::IntegrationInfo {
|
||||||
name: "egui_web",
|
name: "egui_web",
|
||||||
web_info: Some(epi::WebInfo {
|
web_info: Some(epi::WebInfo {
|
||||||
|
@ -155,7 +154,8 @@ impl AppRunner {
|
||||||
native_pixels_per_point: Some(native_pixels_per_point()),
|
native_pixels_per_point: Some(native_pixels_per_point()),
|
||||||
},
|
},
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
});
|
storage: Some(Box::new(LocalStorage::default())),
|
||||||
|
};
|
||||||
|
|
||||||
let needs_repaint: std::sync::Arc<NeedRepaint> = Default::default();
|
let needs_repaint: std::sync::Arc<NeedRepaint> = Default::default();
|
||||||
|
|
||||||
|
@ -175,12 +175,10 @@ impl AppRunner {
|
||||||
egui_ctx.set_visuals(egui::Visuals::light());
|
egui_ctx.set_visuals(egui::Visuals::light());
|
||||||
}
|
}
|
||||||
|
|
||||||
let storage = LocalStorage::default();
|
|
||||||
|
|
||||||
let app = app_creator(&epi::CreationContext {
|
let app = app_creator(&epi::CreationContext {
|
||||||
egui_ctx: egui_ctx.clone(),
|
egui_ctx: egui_ctx.clone(),
|
||||||
integration_info: frame.info(),
|
integration_info: frame.info(),
|
||||||
storage: Some(&storage),
|
storage: frame.storage(),
|
||||||
gl: painter.painter.gl().clone(),
|
gl: painter.painter.gl().clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -191,7 +189,6 @@ impl AppRunner {
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
app,
|
app,
|
||||||
needs_repaint,
|
needs_repaint,
|
||||||
storage,
|
|
||||||
last_save_time: now_sec(),
|
last_save_time: now_sec(),
|
||||||
screen_reader: Default::default(),
|
screen_reader: Default::default(),
|
||||||
text_cursor_pos: None,
|
text_cursor_pos: None,
|
||||||
|
@ -216,7 +213,9 @@ impl AppRunner {
|
||||||
if self.app.persist_egui_memory() {
|
if self.app.persist_egui_memory() {
|
||||||
save_memory(&self.egui_ctx);
|
save_memory(&self.egui_ctx);
|
||||||
}
|
}
|
||||||
self.app.save(&mut self.storage);
|
if let Some(storage) = self.frame.storage_mut() {
|
||||||
|
self.app.save(storage);
|
||||||
|
}
|
||||||
self.last_save_time = now;
|
self.last_save_time = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,7 +246,7 @@ impl AppRunner {
|
||||||
let raw_input = self.input.new_frame(canvas_size);
|
let raw_input = self.input.new_frame(canvas_size);
|
||||||
|
|
||||||
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
||||||
self.app.update(egui_ctx, &self.frame);
|
self.app.update(egui_ctx, &mut self.frame);
|
||||||
});
|
});
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
|
@ -271,7 +270,7 @@ impl AppRunner {
|
||||||
} = app_output;
|
} = app_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.frame.lock().info.cpu_usage = Some((now_sec() - frame_start) as f32);
|
self.frame.info.cpu_usage = Some((now_sec() - frame_start) as f32);
|
||||||
Ok((needs_repaint, clipped_primitives))
|
Ok((needs_repaint, clipped_primitives))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -509,11 +509,9 @@ fn install_document_events(runner_container: &AppRunnerContainer) -> Result<(),
|
||||||
runner_container.add_event_listener(
|
runner_container.add_event_listener(
|
||||||
&document,
|
&document,
|
||||||
"hashchange",
|
"hashchange",
|
||||||
|_: web_sys::Event, runner_lock| {
|
|_: web_sys::Event, mut runner_lock| {
|
||||||
let mut frame_lock = runner_lock.frame.lock();
|
|
||||||
|
|
||||||
// `epi::Frame::info(&self)` clones `epi::IntegrationInfo`, but we need to modify the original here
|
// `epi::Frame::info(&self)` clones `epi::IntegrationInfo`, but we need to modify the original here
|
||||||
if let Some(web_info) = &mut frame_lock.info.web_info {
|
if let Some(web_info) = &mut runner_lock.frame.info.web_info {
|
||||||
web_info.location.hash = location_hash();
|
web_info.location.hash = location_hash();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@ All notable changes to the epaint crate will be documented in this file.
|
||||||
|
|
||||||
|
|
||||||
## 0.16.0 - 2021-12-29
|
## 0.16.0 - 2021-12-29
|
||||||
* Anti-alias path ends ([#893](https://github.com/emilk/egui/pull/893)).
|
* Anti-alias path ends ([#893](https://github.com/emilk/egui/pull/893)).
|
||||||
* `Rgba` now implements `Hash` ([#886](https://github.com/emilk/egui/pull/886)).
|
* `Rgba` now implements `Hash` ([#886](https://github.com/emilk/egui/pull/886)).
|
||||||
* Renamed `Texture` to `FontImage`.
|
* Renamed `Texture` to `FontImage`.
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,7 @@ impl ImageData {
|
||||||
|
|
||||||
pub fn bytes_per_pixel(&self) -> usize {
|
pub fn bytes_per_pixel(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Color(_) => 4,
|
Self::Color(_) | Self::Font(_) => 4,
|
||||||
Self::Font(_) => 4,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ pub mod file_storage;
|
||||||
pub use egui; // Re-export for user convenience
|
pub use egui; // Re-export for user convenience
|
||||||
pub use glow; // Re-export for user convenience
|
pub use glow; // Re-export for user convenience
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
/// The is is how your app is created.
|
/// The is is how your app is created.
|
||||||
///
|
///
|
||||||
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
|
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
|
||||||
|
@ -50,10 +48,10 @@ pub trait App {
|
||||||
///
|
///
|
||||||
/// Put your widgets into a [`egui::SidePanel`], [`egui::TopBottomPanel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`].
|
/// Put your widgets into a [`egui::SidePanel`], [`egui::TopBottomPanel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`].
|
||||||
///
|
///
|
||||||
/// The [`egui::Context`] and [`Frame`] can be cloned and saved if you like.
|
/// The [`egui::Context`] can be cloned and saved if you like.
|
||||||
///
|
///
|
||||||
/// To force a repaint, call [`egui::Context::request_repaint`] at any time (e.g. from another thread).
|
/// To force a repaint, call [`egui::Context::request_repaint`] at any time (e.g. from another thread).
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &Frame);
|
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame);
|
||||||
|
|
||||||
/// Called on shutdown, and perhaps at regular intervals. Allows you to save state.
|
/// Called on shutdown, and perhaps at regular intervals. Allows you to save state.
|
||||||
///
|
///
|
||||||
|
@ -252,76 +250,78 @@ pub struct IconData {
|
||||||
/// allocate textures, and change settings (e.g. window size).
|
/// allocate textures, and change settings (e.g. window size).
|
||||||
///
|
///
|
||||||
/// [`Frame`] is cheap to clone and is safe to pass to other threads.
|
/// [`Frame`] is cheap to clone and is safe to pass to other threads.
|
||||||
#[derive(Clone)]
|
pub struct Frame {
|
||||||
pub struct Frame(pub Arc<Mutex<backend::FrameData>>);
|
/// Information about the integration.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub info: IntegrationInfo,
|
||||||
|
|
||||||
|
/// Where the app can issue commands back to the integration.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub output: backend::AppOutput,
|
||||||
|
|
||||||
|
/// A place where you can store custom data in a way that persists when you restart the app.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub storage: Option<Box<dyn Storage>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
/// Create a `Frame` - called by the integration.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn new(frame_data: backend::FrameData) -> Self {
|
|
||||||
Self(Arc::new(Mutex::new(frame_data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the underlying [`backend::FrameData`].
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn lock(&self) -> std::sync::MutexGuard<'_, backend::FrameData> {
|
|
||||||
self.0.lock().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// True if you are in a web environment.
|
/// True if you are in a web environment.
|
||||||
pub fn is_web(&self) -> bool {
|
pub fn is_web(&self) -> bool {
|
||||||
self.lock().info.web_info.is_some()
|
self.info.web_info.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the integration.
|
/// Information about the integration.
|
||||||
pub fn info(&self) -> IntegrationInfo {
|
pub fn info(&self) -> IntegrationInfo {
|
||||||
self.lock().info.clone()
|
self.info.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A place where you can store custom data in a way that persists when you restart the app.
|
||||||
|
pub fn storage(&self) -> Option<&dyn Storage> {
|
||||||
|
self.storage.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A place where you can store custom data in a way that persists when you restart the app.
|
||||||
|
pub fn storage_mut(&mut self) -> Option<&mut (dyn Storage + 'static)> {
|
||||||
|
self.storage.as_deref_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signal the app to stop/exit/quit the app (only works for native apps, not web apps).
|
/// Signal the app to stop/exit/quit the app (only works for native apps, not web apps).
|
||||||
/// The framework will not quit immediately, but at the end of the this frame.
|
/// The framework will not quit immediately, but at the end of the this frame.
|
||||||
pub fn quit(&self) {
|
pub fn quit(&mut self) {
|
||||||
self.lock().output.quit = true;
|
self.output.quit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the desired inner size of the window (in egui points).
|
/// Set the desired inner size of the window (in egui points).
|
||||||
pub fn set_window_size(&self, size: egui::Vec2) {
|
pub fn set_window_size(&mut self, size: egui::Vec2) {
|
||||||
self.lock().output.window_size = Some(size);
|
self.output.window_size = Some(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the desired title of the window.
|
/// Set the desired title of the window.
|
||||||
pub fn set_window_title(&self, title: &str) {
|
pub fn set_window_title(&mut self, title: &str) {
|
||||||
self.lock().output.window_title = Some(title.to_owned());
|
self.output.window_title = Some(title.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set whether to show window decorations (i.e. a frame around you app).
|
/// Set whether to show window decorations (i.e. a frame around you app).
|
||||||
/// If false it will be difficult to move and resize the app.
|
/// If false it will be difficult to move and resize the app.
|
||||||
pub fn set_decorations(&self, decorated: bool) {
|
pub fn set_decorations(&mut self, decorated: bool) {
|
||||||
self.lock().output.decorated = Some(decorated);
|
self.output.decorated = Some(decorated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When called, the native window will follow the
|
/// When called, the native window will follow the
|
||||||
/// movement of the cursor while the primary mouse button is down.
|
/// movement of the cursor while the primary mouse button is down.
|
||||||
///
|
///
|
||||||
/// Does not work on the web.
|
/// Does not work on the web.
|
||||||
pub fn drag_window(&self) {
|
pub fn drag_window(&mut self) {
|
||||||
self.lock().output.drag_window = true;
|
self.output.drag_window = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// for integrations only: call once per frame
|
/// for integrations only: call once per frame
|
||||||
pub fn take_app_output(&self) -> crate::backend::AppOutput {
|
#[doc(hidden)]
|
||||||
std::mem::take(&mut self.lock().output)
|
pub fn take_app_output(&mut self) -> crate::backend::AppOutput {
|
||||||
|
std::mem::take(&mut self.output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[test]
|
|
||||||
fn frame_impl_send_sync() {
|
|
||||||
fn assert_send_sync<T: Send + Sync>() {}
|
|
||||||
assert_send_sync::<Frame>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about the web environment (if applicable).
|
/// Information about the web environment (if applicable).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WebInfo {
|
pub struct WebInfo {
|
||||||
|
@ -464,20 +464,12 @@ pub const APP_KEY: &str = "app";
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// You only need to look here if you are writing a backend for `epi`.
|
/// You only need to look here if you are writing a backend for `epi`.
|
||||||
|
#[doc(hidden)]
|
||||||
pub mod backend {
|
pub mod backend {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The data required by [`Frame`] each frame.
|
|
||||||
pub struct FrameData {
|
|
||||||
/// Information about the integration.
|
|
||||||
pub info: IntegrationInfo,
|
|
||||||
|
|
||||||
/// Where the app can issue commands back to the integration.
|
|
||||||
pub output: AppOutput,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Action that can be taken by the user app.
|
/// Action that can be taken by the user app.
|
||||||
#[derive(Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct AppOutput {
|
pub struct AppOutput {
|
||||||
/// Set to `true` to stop the app.
|
/// Set to `true` to stop the app.
|
||||||
|
|
Loading…
Reference in a new issue