[eframe] Make persistence, http and time optional features
Saves on compile times.
This commit is contained in:
parent
00269f96c0
commit
69d31a5e47
30 changed files with 412 additions and 303 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -692,7 +692,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"eframe",
|
||||
"egui_demo_lib",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -704,7 +703,6 @@ dependencies = [
|
|||
"epi",
|
||||
"image",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syntect",
|
||||
]
|
||||
|
||||
|
|
8
check.sh
8
check.sh
|
@ -1,15 +1,15 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
cargo check --workspace --all-targets --all-features --release
|
||||
cargo check --workspace --all-targets
|
||||
cargo check --workspace --all-targets --all-features
|
||||
cargo check -p egui_demo_app --lib --target wasm32-unknown-unknown
|
||||
cargo check -p egui_demo_app --lib --target wasm32-unknown-unknown --all-features
|
||||
cargo fmt --all -- --check
|
||||
CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all #-W clippy::pedantic -W clippy::restriction -W clippy::nursery
|
||||
cargo test --workspace --all-targets --all-features
|
||||
cargo test --workspace --doc
|
||||
|
||||
cargo check -p egui_web --lib --target wasm32-unknown-unknown
|
||||
cargo check -p egui_demo_app --lib --target wasm32-unknown-unknown
|
||||
|
||||
# For finding bloat:
|
||||
# cargo bloat --release --bin demo_glium -n 200 | rg egui
|
||||
|
||||
|
|
|
@ -15,13 +15,19 @@ include = [ "**/*.rs", "Cargo.toml"]
|
|||
[lib]
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.6.0", path = "../egui", features = ["serde"] }
|
||||
epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
|
||||
egui = { version = "0.6.0", path = "../egui" }
|
||||
epi = { version = "0.6.0", path = "../epi" }
|
||||
|
||||
# For compiling natively:
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egui_glium = { path = "../egui_glium", features = ["http"] }
|
||||
egui_glium = { path = "../egui_glium" }
|
||||
|
||||
# For compiling to web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
egui_web = { path = "../egui_web" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = ["egui_glium/http", "egui_web/http"]
|
||||
persistence = ["epi/persistence", "egui_glium/persistence", "egui_web/persistence"]
|
||||
time = ["egui_glium/time"] # for seconds_since_midnight
|
||||
|
|
|
@ -9,6 +9,10 @@ edition = "2018"
|
|||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
eframe = { version = "0.6.0", path = "../eframe"}
|
||||
egui_demo_lib = { version = "0.6.0", path = "../egui_demo_lib"}
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
eframe = { version = "0.6.0", path = "../eframe", features = ["time"] }
|
||||
egui_demo_lib = { version = "0.6.0", path = "../egui_demo_lib" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = ["eframe/http", "egui_demo_lib/http"]
|
||||
persistence = ["eframe/persistence", "egui_demo_lib/persistence"]
|
||||
|
|
|
@ -15,18 +15,24 @@ include = [ "**/*.rs", "Cargo.toml"]
|
|||
[lib]
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.6.0", path = "../egui", features = ["serde"] }
|
||||
epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
egui = { version = "0.6.0", path = "../egui" }
|
||||
epi = { version = "0.6.0", path = "../epi" }
|
||||
|
||||
# Http fetch app:
|
||||
image = { version = "0.23", default_features = false, features = ["jpeg", "png"] }
|
||||
syntect = { version = "4", default_features = false, features = ["default-fancy"] }
|
||||
# feature "http":
|
||||
image = { version = "0.23", default_features = false, features = ["jpeg", "png"], optional = true }
|
||||
syntect = { version = "4", default_features = false, features = ["default-fancy"], optional = true }
|
||||
|
||||
# feature "persistence":
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", default-features = false }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = ["image", "syntect", "epi/http"]
|
||||
persistence = ["epi/persistence", "serde"]
|
||||
|
||||
[[bench]]
|
||||
name = "benchmark"
|
||||
harness = false
|
||||
|
|
|
@ -9,9 +9,9 @@ const RED: Color32 = Color32::RED;
|
|||
const TRANSPARENT: Color32 = Color32::TRANSPARENT;
|
||||
const WHITE: Color32 = Color32::WHITE;
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct ColorTest {
|
||||
#[serde(skip)]
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
tex_mngr: TextureManager,
|
||||
vertex_gradients: bool,
|
||||
texture_gradients: bool,
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
///
|
||||
/// Implements `epi::App` so it can be used with
|
||||
/// [`egui_glium`](https://crates.io/crates/egui_glium) and [`egui_web`](https://crates.io/crates/egui_web).
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct DemoApp {
|
||||
demo_windows: super::DemoWindows,
|
||||
}
|
||||
|
@ -13,10 +14,12 @@ impl epi::App for DemoApp {
|
|||
"✨ Egui Demo"
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn load(&mut self, storage: &dyn epi::Storage) {
|
||||
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn save(&mut self, storage: &mut dyn epi::Storage) {
|
||||
epi::set_value(storage, epi::APP_KEY, self);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use egui::{containers::*, *};
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct DancingStrings {}
|
||||
|
||||
impl Default for DancingStrings {
|
||||
|
|
|
@ -2,8 +2,8 @@ use super::*;
|
|||
use egui::{color::*, *};
|
||||
|
||||
/// Showcase some ui code
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct DemoWindow {
|
||||
num_columns: usize,
|
||||
|
||||
|
@ -106,8 +106,9 @@ impl DemoWindow {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(PartialEq)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
struct ColorWidgets {
|
||||
srgba_unmul: [u8; 4],
|
||||
srgba_premul: [u8; 4],
|
||||
|
@ -176,8 +177,8 @@ impl ColorWidgets {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
struct BoxPainting {
|
||||
size: Vec2,
|
||||
corner_radius: f32,
|
||||
|
@ -220,8 +221,8 @@ impl BoxPainting {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
struct LayoutDemo {
|
||||
// Identical to contents of `egui::Layout`
|
||||
main_dir: Direction,
|
||||
|
@ -363,7 +364,8 @@ enum Action {
|
|||
Delete,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
struct Tree(Vec<Tree>);
|
||||
|
||||
impl Tree {
|
||||
|
|
|
@ -2,11 +2,11 @@ use egui::{CtxRef, Resize, ScrollArea, Ui, Window};
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
struct Demos {
|
||||
/// open, view
|
||||
#[serde(skip)] // TODO: serialize the `open` state.
|
||||
#[cfg_attr(feature = "persistence", serde(skip))] // TODO: serialize the `open` state.
|
||||
demos: Vec<(bool, Box<dyn super::Demo>)>,
|
||||
}
|
||||
impl Default for Demos {
|
||||
|
@ -40,8 +40,9 @@ impl Demos {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A menu bar in which you can select different demo windows to show.
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct DemoWindows {
|
||||
open_windows: OpenWindows,
|
||||
|
||||
|
@ -189,7 +190,7 @@ impl DemoWindows {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
struct OpenWindows {
|
||||
demo: bool,
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use egui::*;
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct Painting {
|
||||
lines: Vec<Vec<Vec2>>,
|
||||
stroke: Stroke,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use egui::{color::*, *};
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct Scrolls {
|
||||
track_item: usize,
|
||||
tracking: bool,
|
||||
|
|
|
@ -2,8 +2,9 @@ use egui::*;
|
|||
use std::f64::INFINITY;
|
||||
|
||||
/// Showcase sliders
|
||||
#[derive(PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(PartialEq)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct Sliders {
|
||||
pub min: f64,
|
||||
pub max: f64,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use egui::{color::*, *};
|
||||
|
||||
#[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
enum Enum {
|
||||
First,
|
||||
Second,
|
||||
|
@ -13,8 +14,8 @@ impl Default for Enum {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct Widgets {
|
||||
button_enabled: bool,
|
||||
count: usize,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::__egui_github_link_file;
|
||||
|
||||
#[derive(Clone, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct WindowOptions {
|
||||
title: String,
|
||||
title_bar: bool,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use egui::{containers::*, widgets::*, *};
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
#[derive(PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(PartialEq)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct FractalClock {
|
||||
paused: bool,
|
||||
time: f64,
|
||||
|
|
|
@ -30,17 +30,17 @@ impl Resource {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct HttpApp {
|
||||
url: String,
|
||||
|
||||
#[serde(skip)]
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
in_progress: Option<Receiver<Result<Response, String>>>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
result: Option<Result<Resource, String>>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
tex_mngr: TexMngr,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
mod color_test;
|
||||
mod demo;
|
||||
mod fractal_clock;
|
||||
#[cfg(feature = "http")]
|
||||
mod http_app;
|
||||
|
||||
pub use color_test::ColorTest;
|
||||
pub use demo::DemoApp;
|
||||
pub use fractal_clock::FractalClock;
|
||||
#[cfg(feature = "http")]
|
||||
pub use http_app::HttpApp;
|
||||
|
||||
pub use demo::DemoWindows; // used for tests
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// All the different demo apps.
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct Apps {
|
||||
demo: crate::apps::DemoApp,
|
||||
#[cfg(feature = "http")]
|
||||
http: crate::apps::HttpApp,
|
||||
clock: crate::apps::FractalClock,
|
||||
color_test: crate::apps::ColorTest,
|
||||
|
@ -12,6 +14,7 @@ impl Apps {
|
|||
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut dyn epi::App)> {
|
||||
vec![
|
||||
("demo", &mut self.demo as &mut dyn epi::App),
|
||||
#[cfg(feature = "http")]
|
||||
("http", &mut self.http as &mut dyn epi::App),
|
||||
("clock", &mut self.clock as &mut dyn epi::App),
|
||||
("colors", &mut self.color_test as &mut dyn epi::App),
|
||||
|
@ -21,8 +24,9 @@ impl Apps {
|
|||
}
|
||||
|
||||
/// Wraps many demo/test apps into one.
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
pub struct WrapApp {
|
||||
selected_anchor: String,
|
||||
apps: Apps,
|
||||
|
@ -34,10 +38,12 @@ impl epi::App for WrapApp {
|
|||
"Egui Demo Apps"
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn load(&mut self, storage: &dyn epi::Storage) {
|
||||
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn save(&mut self, storage: &mut dyn epi::Storage) {
|
||||
epi::set_value(storage, epi::APP_KEY, self);
|
||||
}
|
||||
|
@ -167,18 +173,20 @@ impl Default for RunMode {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "persistence", serde(default))]
|
||||
struct BackendPanel {
|
||||
open: bool,
|
||||
|
||||
#[serde(skip)] // go back to `Reactive` mode each time we start
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
// go back to `Reactive` mode each time we start
|
||||
run_mode: RunMode,
|
||||
|
||||
/// current slider value for current gui scale
|
||||
pixels_per_point: Option<f32>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
frame_history: crate::frame_history::FrameHistory,
|
||||
}
|
||||
|
||||
|
|
|
@ -13,17 +13,32 @@ keywords = ["glium", "egui", "gui", "gamedev"]
|
|||
include = [ "**/*.rs", "Cargo.toml"]
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4" }
|
||||
clipboard = "0.5"
|
||||
directories-next = "2"
|
||||
egui = { version = "0.6.0", path = "../egui", features = ["serde"] }
|
||||
epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
|
||||
egui = { version = "0.6.0", path = "../egui" }
|
||||
epi = { version = "0.6.0", path = "../epi" }
|
||||
glium = "0.29"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
ureq = { version = "1.5", optional = true }
|
||||
webbrowser = "0.5"
|
||||
|
||||
# feature "http":
|
||||
ureq = { version = "1.5", optional = true }
|
||||
|
||||
# feature "persistence":
|
||||
directories-next = { version = "2", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
|
||||
# feature "time"
|
||||
chrono = { version = "0.4", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = ["ureq"]
|
||||
persistence = [
|
||||
"directories-next",
|
||||
"egui/serde",
|
||||
"epi/serde_json",
|
||||
"epi/serde",
|
||||
"serde_json",
|
||||
"serde",
|
||||
]
|
||||
time = ["chrono"] # for seconds_since_midnight
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
use crate::{window_settings::WindowSettings, *};
|
||||
use egui::Color32;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::{storage::WindowSettings, *};
|
||||
|
||||
pub use egui::Color32;
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
const EGUI_MEMORY_KEY: &str = "egui";
|
||||
#[cfg(feature = "persistence")]
|
||||
const WINDOW_KEY: &str = "window";
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn deserialize_window_settings(storage: &Option<Box<dyn epi::Storage>>) -> Option<WindowSettings> {
|
||||
epi::get_value(&**storage.as_ref()?, WINDOW_KEY)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
fn deserialize_window_settings(_: &Option<Box<dyn epi::Storage>>) -> Option<WindowSettings> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn deserialize_memory(storage: &Option<Box<dyn epi::Storage>>) -> Option<egui::Memory> {
|
||||
epi::get_value(&**storage.as_ref()?, EGUI_MEMORY_KEY)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
fn deserialize_memory(_: &Option<Box<dyn epi::Storage>>) -> Option<egui::Memory> {
|
||||
None
|
||||
}
|
||||
|
||||
impl epi::TextureAllocator for Painter {
|
||||
fn alloc(&mut self) -> egui::TextureId {
|
||||
self.alloc_user_texture()
|
||||
|
@ -69,6 +89,12 @@ fn create_display(
|
|||
display
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn create_storage(app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||
if let Some(proj_dirs) = directories_next::ProjectDirs::from("", "", app_name) {
|
||||
let data_dir = proj_dirs.data_dir().to_path_buf();
|
||||
|
@ -81,7 +107,7 @@ fn create_storage(app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
|||
} else {
|
||||
let mut config_dir = data_dir;
|
||||
config_dir.push("app.json");
|
||||
let storage = crate::storage::FileStorage::from_path(config_dir);
|
||||
let storage = crate::persistence::FileStorage::from_path(config_dir);
|
||||
Some(Box::new(storage))
|
||||
}
|
||||
} else {
|
||||
|
@ -97,7 +123,7 @@ fn integration_info(
|
|||
epi::IntegrationInfo {
|
||||
web_info: None,
|
||||
cpu_usage: previous_frame_time,
|
||||
seconds_since_midnight: Some(seconds_since_midnight()),
|
||||
seconds_since_midnight: seconds_since_midnight(),
|
||||
native_pixels_per_point: Some(native_pixels_per_point(&display)),
|
||||
}
|
||||
}
|
||||
|
@ -110,9 +136,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
app.load(storage.as_ref());
|
||||
}
|
||||
|
||||
let window_settings: Option<WindowSettings> = storage
|
||||
.as_mut()
|
||||
.and_then(|storage| epi::get_value(storage.as_ref(), WINDOW_KEY));
|
||||
let window_settings = deserialize_window_settings(&storage);
|
||||
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
||||
let display = create_display(app.name(), window_settings, app.is_resizable(), &event_loop);
|
||||
|
||||
|
@ -121,10 +145,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
)));
|
||||
|
||||
let mut ctx = egui::CtxRef::default();
|
||||
*ctx.memory() = storage
|
||||
.as_mut()
|
||||
.and_then(|storage| epi::get_value(storage.as_ref(), EGUI_MEMORY_KEY))
|
||||
.unwrap_or_default();
|
||||
*ctx.memory() = deserialize_memory(&storage).unwrap_or_default();
|
||||
|
||||
app.setup(&ctx);
|
||||
|
||||
|
@ -135,8 +156,10 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
let mut painter = Painter::new(&display);
|
||||
let mut clipboard = init_clipboard();
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
let mut last_auto_save = Instant::now();
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
let http = std::sync::Arc::new(crate::http::GliumHttp {});
|
||||
|
||||
if app.warm_up_enabled() {
|
||||
|
@ -151,6 +174,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
let mut frame = epi::backend::FrameBuilder {
|
||||
info: integration_info(&display, None),
|
||||
tex_allocator: Some(&mut painter),
|
||||
#[cfg(feature = "http")]
|
||||
http: http.clone(),
|
||||
output: &mut app_output,
|
||||
repaint_signal: repaint_signal.clone(),
|
||||
|
@ -183,6 +207,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
let mut frame = epi::backend::FrameBuilder {
|
||||
info: integration_info(&display, previous_frame_time),
|
||||
tex_allocator: Some(&mut painter),
|
||||
#[cfg(feature = "http")]
|
||||
http: http.clone(),
|
||||
output: &mut app_output,
|
||||
repaint_signal: repaint_signal.clone(),
|
||||
|
@ -236,6 +261,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
|
||||
handle_output(egui_output, &display, clipboard.as_mut());
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = &mut storage {
|
||||
let now = Instant::now();
|
||||
if now - last_auto_save > app.auto_save_interval() {
|
||||
|
@ -265,6 +291,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
|
|||
}
|
||||
glutin::event::Event::LoopDestroyed => {
|
||||
app.on_exit();
|
||||
#[cfg(feature = "persistence")]
|
||||
if let Some(storage) = &mut storage {
|
||||
epi::set_value(
|
||||
storage.as_mut(),
|
||||
|
|
|
@ -13,7 +13,9 @@ mod backend;
|
|||
#[cfg(feature = "http")]
|
||||
pub mod http;
|
||||
mod painter;
|
||||
pub mod storage;
|
||||
#[cfg(feature = "persistence")]
|
||||
pub mod persistence;
|
||||
pub mod window_settings;
|
||||
|
||||
pub use backend::*;
|
||||
pub use painter::Painter;
|
||||
|
@ -279,10 +281,17 @@ pub fn init_clipboard() -> Option<ClipboardContext> {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Time of day as seconds since midnight. Used for clock in demo app.
|
||||
pub fn seconds_since_midnight() -> f64 {
|
||||
use chrono::Timelike;
|
||||
let time = chrono::Local::now().time();
|
||||
time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64)
|
||||
pub fn seconds_since_midnight() -> Option<f64> {
|
||||
#[cfg(feature = "time")]
|
||||
{
|
||||
use chrono::Timelike;
|
||||
let time = chrono::Local::now().time();
|
||||
let seconds_since_midnight =
|
||||
time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64);
|
||||
Some(seconds_since_midnight)
|
||||
}
|
||||
#[cfg(not(feature = "time"))]
|
||||
None
|
||||
}
|
||||
|
||||
pub fn screen_size_in_pixels(display: &glium::Display) -> Vec2 {
|
||||
|
|
87
egui_glium/src/persistence.rs
Normal file
87
egui_glium/src/persistence.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A key-value store backed by a JSON file on disk.
|
||||
/// Used to restore egui state, glium window position/size and app state.
|
||||
pub struct FileStorage {
|
||||
path: PathBuf,
|
||||
kv: HashMap<String, String>,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl FileStorage {
|
||||
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
||||
let path: PathBuf = path.into();
|
||||
Self {
|
||||
kv: read_json(&path).unwrap_or_default(),
|
||||
path,
|
||||
dirty: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl epi::Storage for FileStorage {
|
||||
fn get_string(&self, key: &str) -> Option<String> {
|
||||
self.kv.get(key).cloned()
|
||||
}
|
||||
|
||||
fn set_string(&mut self, key: &str, value: String) {
|
||||
if self.kv.get(key) != Some(&value) {
|
||||
self.kv.insert(key.to_owned(), value);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
if self.dirty {
|
||||
serde_json::to_writer(std::fs::File::create(&self.path).unwrap(), &self.kv).unwrap();
|
||||
self.dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub fn read_json<T>(memory_json_path: impl AsRef<Path>) -> Option<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
match std::fs::File::open(memory_json_path) {
|
||||
Ok(file) => {
|
||||
let reader = std::io::BufReader::new(file);
|
||||
match serde_json::from_reader(reader) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: Failed to parse json: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_err) => {
|
||||
// File probably doesn't exist. That's fine.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Alternative to `FileStorage`
|
||||
pub fn read_memory(ctx: &egui::Context, memory_json_path: impl AsRef<std::path::Path>) {
|
||||
let memory: Option<egui::Memory> = read_json(memory_json_path);
|
||||
if let Some(memory) = memory {
|
||||
*ctx.memory() = memory;
|
||||
}
|
||||
}
|
||||
|
||||
/// Alternative to `FileStorage`
|
||||
pub fn write_memory(
|
||||
ctx: &egui::Context,
|
||||
memory_json_path: impl AsRef<std::path::Path>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
serde_json::to_writer_pretty(std::fs::File::create(memory_json_path)?, &*ctx.memory())?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// A key-value store backed by a JSON file on disk.
|
||||
/// Used to restore egui state, glium window position/size and app state.
|
||||
pub struct FileStorage {
|
||||
path: PathBuf,
|
||||
kv: HashMap<String, String>,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl FileStorage {
|
||||
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
||||
let path: PathBuf = path.into();
|
||||
Self {
|
||||
kv: read_json(&path).unwrap_or_default(),
|
||||
path,
|
||||
dirty: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl epi::Storage for FileStorage {
|
||||
fn get_string(&self, key: &str) -> Option<String> {
|
||||
self.kv.get(key).cloned()
|
||||
}
|
||||
|
||||
fn set_string(&mut self, key: &str, value: String) {
|
||||
if self.kv.get(key) != Some(&value) {
|
||||
self.kv.insert(key.to_owned(), value);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
if self.dirty {
|
||||
serde_json::to_writer(std::fs::File::create(&self.path).unwrap(), &self.kv).unwrap();
|
||||
self.dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub fn read_json<T>(memory_json_path: impl AsRef<Path>) -> Option<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
match std::fs::File::open(memory_json_path) {
|
||||
Ok(file) => {
|
||||
let reader = std::io::BufReader::new(file);
|
||||
match serde_json::from_reader(reader) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: Failed to parse json: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_err) => {
|
||||
// File probably doesn't exist. That's fine.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Alternative to `FileStorage`
|
||||
pub fn read_memory(ctx: &egui::Context, memory_json_path: impl AsRef<std::path::Path>) {
|
||||
let memory: Option<egui::Memory> = read_json(memory_json_path);
|
||||
if let Some(memory) = memory {
|
||||
*ctx.memory() = memory;
|
||||
}
|
||||
}
|
||||
|
||||
/// Alternative to `FileStorage`
|
||||
pub fn write_memory(
|
||||
ctx: &egui::Context,
|
||||
memory_json_path: impl AsRef<std::path::Path>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
serde_json::to_writer_pretty(std::fs::File::create(memory_json_path)?, &*ctx.memory())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
use glium::glutin;
|
||||
|
||||
#[derive(Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct WindowSettings {
|
||||
/// outer position of window in physical pixels
|
||||
pos: Option<egui::Pos2>,
|
||||
/// Inner size of window in logical pixels
|
||||
inner_size_points: Option<egui::Vec2>,
|
||||
}
|
||||
|
||||
impl WindowSettings {
|
||||
pub fn from_json_file(
|
||||
settings_json_path: impl AsRef<std::path::Path>,
|
||||
) -> Option<WindowSettings> {
|
||||
read_json(settings_json_path)
|
||||
}
|
||||
|
||||
pub fn from_display(display: &glium::Display) -> Self {
|
||||
let scale_factor = display.gl_window().window().scale_factor();
|
||||
let inner_size_points = display
|
||||
.gl_window()
|
||||
.window()
|
||||
.inner_size()
|
||||
.to_logical::<f32>(scale_factor);
|
||||
|
||||
Self {
|
||||
pos: display
|
||||
.gl_window()
|
||||
.window()
|
||||
.outer_position()
|
||||
.ok()
|
||||
.map(|p| egui::pos2(p.x as f32, p.y as f32)),
|
||||
|
||||
inner_size_points: Some(egui::vec2(
|
||||
inner_size_points.width as f32,
|
||||
inner_size_points.height as f32,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_size(
|
||||
&self,
|
||||
window: glutin::window::WindowBuilder,
|
||||
) -> glutin::window::WindowBuilder {
|
||||
if let Some(inner_size_points) = self.inner_size_points {
|
||||
window.with_inner_size(glutin::dpi::LogicalSize {
|
||||
width: inner_size_points.x as f64,
|
||||
height: inner_size_points.y as f64,
|
||||
})
|
||||
} else {
|
||||
window
|
||||
}
|
||||
|
||||
// Not yet available in winit: https://github.com/rust-windowing/winit/issues/1190
|
||||
// if let Some(pos) = self.pos {
|
||||
// *window = window.with_outer_pos(glutin::dpi::PhysicalPosition {
|
||||
// x: pos.x as f64,
|
||||
// y: pos.y as f64,
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn restore_positions(&self, display: &glium::Display) {
|
||||
// not needed, done by `initialize_size`
|
||||
// let size = self.size.unwrap_or_else(|| vec2(1024.0, 800.0));
|
||||
// display
|
||||
// .gl_window()
|
||||
// .window()
|
||||
// .set_inner_size(glutin::dpi::PhysicalSize {
|
||||
// width: size.x as f64,
|
||||
// height: size.y as f64,
|
||||
// });
|
||||
|
||||
if let Some(pos) = self.pos {
|
||||
display
|
||||
.gl_window()
|
||||
.window()
|
||||
.set_outer_position(glutin::dpi::PhysicalPosition::new(
|
||||
pos.x as f64,
|
||||
pos.y as f64,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
85
egui_glium/src/window_settings.rs
Normal file
85
egui_glium/src/window_settings.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use glium::glutin;
|
||||
|
||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct WindowSettings {
|
||||
/// outer position of window in physical pixels
|
||||
pos: Option<egui::Pos2>,
|
||||
/// Inner size of window in logical pixels
|
||||
inner_size_points: Option<egui::Vec2>,
|
||||
}
|
||||
|
||||
impl WindowSettings {
|
||||
#[cfg(feature = "persistence")]
|
||||
pub fn from_json_file(
|
||||
settings_json_path: impl AsRef<std::path::Path>,
|
||||
) -> Option<WindowSettings> {
|
||||
crate::persistence::read_json(settings_json_path)
|
||||
}
|
||||
|
||||
pub fn from_display(display: &glium::Display) -> Self {
|
||||
let scale_factor = display.gl_window().window().scale_factor();
|
||||
let inner_size_points = display
|
||||
.gl_window()
|
||||
.window()
|
||||
.inner_size()
|
||||
.to_logical::<f32>(scale_factor);
|
||||
|
||||
Self {
|
||||
pos: display
|
||||
.gl_window()
|
||||
.window()
|
||||
.outer_position()
|
||||
.ok()
|
||||
.map(|p| egui::pos2(p.x as f32, p.y as f32)),
|
||||
|
||||
inner_size_points: Some(egui::vec2(
|
||||
inner_size_points.width as f32,
|
||||
inner_size_points.height as f32,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_size(
|
||||
&self,
|
||||
window: glutin::window::WindowBuilder,
|
||||
) -> glutin::window::WindowBuilder {
|
||||
if let Some(inner_size_points) = self.inner_size_points {
|
||||
window.with_inner_size(glutin::dpi::LogicalSize {
|
||||
width: inner_size_points.x as f64,
|
||||
height: inner_size_points.y as f64,
|
||||
})
|
||||
} else {
|
||||
window
|
||||
}
|
||||
|
||||
// Not yet available in winit: https://github.com/rust-windowing/winit/issues/1190
|
||||
// if let Some(pos) = self.pos {
|
||||
// *window = window.with_outer_pos(glutin::dpi::PhysicalPosition {
|
||||
// x: pos.x as f64,
|
||||
// y: pos.y as f64,
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn restore_positions(&self, display: &glium::Display) {
|
||||
// not needed, done by `initialize_size`
|
||||
// let size = self.size.unwrap_or_else(|| vec2(1024.0, 800.0));
|
||||
// display
|
||||
// .gl_window()
|
||||
// .window()
|
||||
// .set_inner_size(glutin::dpi::PhysicalSize {
|
||||
// width: size.x as f64,
|
||||
// height: size.y as f64,
|
||||
// });
|
||||
|
||||
if let Some(pos) = self.pos {
|
||||
display
|
||||
.gl_window()
|
||||
.window()
|
||||
.set_outer_position(glutin::dpi::PhysicalPosition::new(
|
||||
pos.x as f64,
|
||||
pos.y as f64,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,47 +16,54 @@ include = [ "**/*.rs", "Cargo.toml"]
|
|||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
egui = { version = "0.6.0", path = "../egui", features = ["serde"] }
|
||||
epi = { version = "0.6.0", path = "../epi", features = ["serde", "serde_json"] }
|
||||
egui = { version = "0.6.0", path = "../egui" }
|
||||
epi = { version = "0.6.0", path = "../epi" }
|
||||
js-sys = "0.3"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = [
|
||||
"epi/http",
|
||||
"web-sys/Headers",
|
||||
"web-sys/Request",
|
||||
"web-sys/RequestInit",
|
||||
"web-sys/RequestMode",
|
||||
"web-sys/Response",
|
||||
]
|
||||
persistence = ["serde", "serde_json"]
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
'Clipboard',
|
||||
'ClipboardEvent',
|
||||
'console',
|
||||
'CssStyleDeclaration',
|
||||
'DataTransfer',
|
||||
'Document',
|
||||
'DomRect',
|
||||
'Element',
|
||||
'Headers',
|
||||
'HtmlCanvasElement',
|
||||
'HtmlElement',
|
||||
'KeyboardEvent',
|
||||
'Location',
|
||||
'MouseEvent',
|
||||
'Navigator',
|
||||
'Performance',
|
||||
'Request',
|
||||
'RequestInit',
|
||||
'RequestMode',
|
||||
'Response',
|
||||
'Storage',
|
||||
'Touch',
|
||||
'TouchEvent',
|
||||
'TouchList',
|
||||
'WebGlBuffer',
|
||||
'WebGlProgram',
|
||||
'WebGlRenderingContext',
|
||||
'WebGlShader',
|
||||
'WebGlTexture',
|
||||
'WebGlUniformLocation',
|
||||
'WheelEvent',
|
||||
'Window',
|
||||
"Clipboard",
|
||||
"ClipboardEvent",
|
||||
"console",
|
||||
"CssStyleDeclaration",
|
||||
"DataTransfer",
|
||||
"Document",
|
||||
"DomRect",
|
||||
"Element",
|
||||
"HtmlCanvasElement",
|
||||
"HtmlElement",
|
||||
"KeyboardEvent",
|
||||
"Location",
|
||||
"MouseEvent",
|
||||
"Navigator",
|
||||
"Performance",
|
||||
"Storage",
|
||||
"Touch",
|
||||
"TouchEvent",
|
||||
"TouchList",
|
||||
"WebGlBuffer",
|
||||
"WebGlProgram",
|
||||
"WebGlRenderingContext",
|
||||
"WebGlShader",
|
||||
"WebGlTexture",
|
||||
"WebGlUniformLocation",
|
||||
"WheelEvent",
|
||||
"Window",
|
||||
]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::*;
|
||||
|
||||
pub use egui::{pos2, Color32};
|
||||
use http::WebHttp;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -144,7 +143,8 @@ pub struct AppRunner {
|
|||
pub(crate) needs_repaint: std::sync::Arc<NeedRepaint>,
|
||||
storage: LocalStorage,
|
||||
last_save_time: f64,
|
||||
http: Arc<WebHttp>,
|
||||
#[cfg(feature = "http")]
|
||||
http: Arc<http::WebHttp>,
|
||||
}
|
||||
|
||||
impl AppRunner {
|
||||
|
@ -160,7 +160,8 @@ impl AppRunner {
|
|||
needs_repaint: Default::default(),
|
||||
storage,
|
||||
last_save_time: now_sec(),
|
||||
http: Arc::new(WebHttp {}),
|
||||
#[cfg(feature = "http")]
|
||||
http: Arc::new(http::WebHttp {}),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -210,6 +211,7 @@ impl AppRunner {
|
|||
native_pixels_per_point: Some(native_pixels_per_point()),
|
||||
},
|
||||
tex_allocator: Some(&mut self.web_backend.painter),
|
||||
#[cfg(feature = "http")]
|
||||
http: self.http.clone(),
|
||||
output: &mut app_output,
|
||||
repaint_signal: self.needs_repaint.clone(),
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#![warn(clippy::all, rust_2018_idioms)]
|
||||
|
||||
pub mod backend;
|
||||
#[cfg(feature = "http")]
|
||||
pub mod http;
|
||||
pub mod webgl;
|
||||
|
||||
|
@ -154,6 +155,7 @@ pub fn local_storage_remove(key: &str) {
|
|||
local_storage().map(|storage| storage.remove_item(key));
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
pub fn load_memory(ctx: &egui::Context) {
|
||||
if let Some(memory_string) = local_storage_get("egui_memory_json") {
|
||||
match serde_json::from_str(&memory_string) {
|
||||
|
@ -167,6 +169,10 @@ pub fn load_memory(ctx: &egui::Context) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
pub fn load_memory(_: &egui::Context) {}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
pub fn save_memory(ctx: &egui::Context) {
|
||||
match serde_json::to_string(&*ctx.memory()) {
|
||||
Ok(json) => {
|
||||
|
@ -178,6 +184,9 @@ pub fn save_memory(ctx: &egui::Context) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "persistence"))]
|
||||
pub fn save_memory(_: &egui::Context) {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LocalStorage {}
|
||||
|
||||
|
|
|
@ -18,3 +18,8 @@ include = [ "**/*.rs", "Cargo.toml"]
|
|||
egui = { version = "0.6.0", path = "../egui" }
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
http = []
|
||||
persistence = ["serde", "serde_json"]
|
||||
|
|
|
@ -150,6 +150,7 @@ impl<'a> Frame<'a> {
|
|||
|
||||
/// Very simple Http fetch API.
|
||||
/// Calls the given callback when done.
|
||||
#[cfg(feature = "http")]
|
||||
pub fn http_fetch(
|
||||
&self,
|
||||
request: http::Request,
|
||||
|
@ -257,6 +258,7 @@ pub const APP_KEY: &str = "app";
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
/// `epi` supports simple HTTP requests with [`Frame::http_fetch`].
|
||||
pub mod http {
|
||||
/// A simple http requests.
|
||||
|
@ -310,6 +312,7 @@ pub mod backend {
|
|||
use super::*;
|
||||
|
||||
/// Implements `Http` requests.
|
||||
#[cfg(feature = "http")]
|
||||
pub trait Http {
|
||||
/// Calls the given callback when done.
|
||||
fn fetch_dyn(
|
||||
|
@ -326,6 +329,7 @@ pub mod backend {
|
|||
/// A way to allocate textures (on integrations that support it).
|
||||
pub tex_allocator: Option<&'a mut dyn TextureAllocator>,
|
||||
/// Do http requests.
|
||||
#[cfg(feature = "http")]
|
||||
pub http: std::sync::Arc<dyn backend::Http>,
|
||||
/// Where the app can issue commands back to the integration.
|
||||
pub output: &'a mut AppOutput,
|
||||
|
|
Loading…
Reference in a new issue