eframe app creation refactor (#1363)
* Change how eframe apps are created * eframe: re-export epi::* so users don't need to care about what epi is
This commit is contained in:
parent
c768d1d48e
commit
c8f6cae362
26 changed files with 387 additions and 444 deletions
|
@ -1,6 +1,11 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native("Confirm exit", options, |_cc| Box::new(MyApp::default()));
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
|
@ -8,17 +13,13 @@ struct MyApp {
|
||||||
is_exiting: bool,
|
is_exiting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"Confirm exit"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_exit_event(&mut self) -> bool {
|
fn on_exit_event(&mut self) -> bool {
|
||||||
self.is_exiting = true;
|
self.is_exiting = true;
|
||||||
self.can_exit
|
self.can_exit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &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");
|
||||||
});
|
});
|
||||||
|
@ -42,8 +43,3 @@ impl epi::App for MyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions::default();
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,25 +8,42 @@
|
||||||
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Default)]
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native("Custom 3D painting in eframe", options, |cc| {
|
||||||
|
Box::new(MyApp::new(cc))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
rotating_triangle: Arc<Mutex<Option<RotatingTriangle>>>,
|
/// Behind an `Arc<Mutex<…>>` so we can pass it to [`egui::PaintCallback`] and paint later.
|
||||||
|
rotating_triangle: Arc<Mutex<RotatingTriangle>>,
|
||||||
angle: f32,
|
angle: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl MyApp {
|
||||||
fn name(&self) -> &str {
|
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
"Custom 3D painting inside an egui window"
|
Self {
|
||||||
|
rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))),
|
||||||
|
angle: 0.0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
impl eframe::App for MyApp {
|
||||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("Here is some 3D stuff:");
|
ui.horizontal(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing.x = 0.0;
|
||||||
|
ui.label("The triangle is being painted using ");
|
||||||
|
ui.hyperlink_to("glow", "https://github.com/grovesNL/glow");
|
||||||
|
ui.label(" (OpenGL).");
|
||||||
|
});
|
||||||
|
|
||||||
egui::ScrollArea::both().show(ui, |ui| {
|
egui::ScrollArea::both().show(ui, |ui| {
|
||||||
egui::Frame::dark_canvas(ui.style()).show(ui, |ui| {
|
egui::Frame::dark_canvas(ui.style()).show(ui, |ui| {
|
||||||
|
@ -35,14 +52,10 @@ impl epi::App for MyApp {
|
||||||
ui.label("Drag to rotate!");
|
ui.label("Drag to rotate!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let mut frame = egui::Frame::window(&*ctx.style());
|
fn on_exit(&mut self, gl: &glow::Context) {
|
||||||
frame.fill = frame.fill.linear_multiply(0.5); // transparent
|
self.rotating_triangle.lock().destroy(gl)
|
||||||
egui::Window::new("3D stuff in a window")
|
|
||||||
.frame(frame)
|
|
||||||
.show(ctx, |ui| {
|
|
||||||
self.custom_painting(ui);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,17 +66,15 @@ impl MyApp {
|
||||||
|
|
||||||
self.angle += response.drag_delta().x * 0.01;
|
self.angle += response.drag_delta().x * 0.01;
|
||||||
|
|
||||||
|
// Clone locals so we can move them into the paint callback:
|
||||||
let angle = self.angle;
|
let angle = self.angle;
|
||||||
let rotating_triangle = self.rotating_triangle.clone();
|
let rotating_triangle = self.rotating_triangle.clone();
|
||||||
|
|
||||||
let callback = egui::epaint::PaintCallback {
|
let callback = egui::PaintCallback {
|
||||||
rect,
|
rect,
|
||||||
callback: std::sync::Arc::new(move |render_ctx| {
|
callback: std::sync::Arc::new(move |render_ctx| {
|
||||||
if let Some(painter) = render_ctx.downcast_ref::<egui_glow::Painter>() {
|
if let Some(painter) = render_ctx.downcast_ref::<egui_glow::Painter>() {
|
||||||
let mut rotating_triangle = rotating_triangle.lock();
|
rotating_triangle.lock().paint(painter.gl(), angle);
|
||||||
let rotating_triangle = rotating_triangle
|
|
||||||
.get_or_insert_with(|| RotatingTriangle::new(painter.gl()));
|
|
||||||
rotating_triangle.paint(painter.gl(), angle);
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Can't do custom painting because we are not using a glow context");
|
eprintln!("Can't do custom painting because we are not using a glow context");
|
||||||
}
|
}
|
||||||
|
@ -163,9 +174,7 @@ impl RotatingTriangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: figure out how to call this in a nice way
|
fn destroy(&self, gl: &glow::Context) {
|
||||||
#[allow(unused)]
|
|
||||||
fn destroy(self, gl: &glow::Context) {
|
|
||||||
use glow::HasContext as _;
|
use glow::HasContext as _;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.delete_program(self.program);
|
gl.delete_program(self.program);
|
||||||
|
@ -186,8 +195,3 @@ impl RotatingTriangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions::default();
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,66 +1,61 @@
|
||||||
use eframe::{egui, epi};
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native("egui example: custom font", options, |cc| {
|
||||||
|
Box::new(MyApp::new(cc))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_custom_fonts(ctx: &egui::Context) {
|
||||||
|
// Start with the default fonts (we will be adding to them rather than replacing them).
|
||||||
|
let mut fonts = egui::FontDefinitions::default();
|
||||||
|
|
||||||
|
// Install my own font (maybe supporting non-latin characters).
|
||||||
|
// .ttf and .otf files supported.
|
||||||
|
fonts.font_data.insert(
|
||||||
|
"my_font".to_owned(),
|
||||||
|
egui::FontData::from_static(include_bytes!("../../epaint/fonts/Hack-Regular.ttf")),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Put my font first (highest priority) for proportional text:
|
||||||
|
fonts
|
||||||
|
.families
|
||||||
|
.entry(egui::FontFamily::Proportional)
|
||||||
|
.or_default()
|
||||||
|
.insert(0, "my_font".to_owned());
|
||||||
|
|
||||||
|
// Put my font as last fallback for monospace:
|
||||||
|
fonts
|
||||||
|
.families
|
||||||
|
.entry(egui::FontFamily::Monospace)
|
||||||
|
.or_default()
|
||||||
|
.push("my_font".to_owned());
|
||||||
|
|
||||||
|
// Tell egui to use these fonts:
|
||||||
|
ctx.set_fonts(fonts);
|
||||||
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MyApp {
|
impl MyApp {
|
||||||
fn default() -> Self {
|
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
|
setup_custom_fonts(&cc.egui_ctx);
|
||||||
Self {
|
Self {
|
||||||
text: "Edit this text field if you want".to_owned(),
|
text: "Edit this text field if you want".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
"egui example: custom font"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
ctx: &egui::Context,
|
|
||||||
_frame: &epi::Frame,
|
|
||||||
_storage: Option<&dyn epi::Storage>,
|
|
||||||
_gl: &std::rc::Rc<epi::glow::Context>,
|
|
||||||
) {
|
|
||||||
// Start with the default fonts (we will be adding to them rather than replacing them).
|
|
||||||
let mut fonts = egui::FontDefinitions::default();
|
|
||||||
|
|
||||||
// Install my own font (maybe supporting non-latin characters).
|
|
||||||
// .ttf and .otf files supported.
|
|
||||||
fonts.font_data.insert(
|
|
||||||
"my_font".to_owned(),
|
|
||||||
egui::FontData::from_static(include_bytes!("../../epaint/fonts/Hack-Regular.ttf")),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Put my font first (highest priority) for proportional text:
|
|
||||||
fonts
|
|
||||||
.families
|
|
||||||
.entry(egui::FontFamily::Proportional)
|
|
||||||
.or_default()
|
|
||||||
.insert(0, "my_font".to_owned());
|
|
||||||
|
|
||||||
// Put my font as last fallback for monospace:
|
|
||||||
fonts
|
|
||||||
.families
|
|
||||||
.entry(egui::FontFamily::Monospace)
|
|
||||||
.or_default()
|
|
||||||
.push("my_font".to_owned());
|
|
||||||
|
|
||||||
// Tell egui to use these fonts:
|
|
||||||
ctx.set_fonts(fonts);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions::default();
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
use egui_extras::RetainedImage;
|
use egui_extras::RetainedImage;
|
||||||
use poll_promise::Promise;
|
use poll_promise::Promise;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let options = eframe::NativeOptions::default();
|
let options = eframe::NativeOptions::default();
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
eframe::run_native(
|
||||||
|
"Download and show an image with eframe/egui",
|
||||||
|
options,
|
||||||
|
|_cc| Box::new(MyApp::default()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -15,12 +19,8 @@ struct MyApp {
|
||||||
promise: Option<Promise<ehttp::Result<RetainedImage>>>,
|
promise: Option<Promise<ehttp::Result<RetainedImage>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
"Download and show an image with eframe/egui"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::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.
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
drag_and_drop_support: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
eframe::run_native(
|
||||||
|
"Native file dialogs and drag-and-drop files",
|
||||||
|
options,
|
||||||
|
|_cc| Box::new(MyApp::default()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
|
@ -8,12 +20,8 @@ struct MyApp {
|
||||||
picked_path: Option<String>,
|
picked_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
"Native file dialogs and drag-and-drop files"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::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!");
|
||||||
|
|
||||||
|
@ -93,11 +101,3 @@ impl MyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions {
|
|
||||||
drag_and_drop_support: true,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native("My egui App", options, |_cc| Box::new(MyApp::default()));
|
||||||
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -16,12 +21,8 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
||||||
"My egui App"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::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| {
|
||||||
|
@ -39,8 +40,3 @@ impl epi::App for MyApp {
|
||||||
frame.set_window_size(ctx.used_size());
|
frame.set_window_size(ctx.used_size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions::default();
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
use egui_extras::RetainedImage;
|
use egui_extras::RetainedImage;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native("Show an image with eframe/egui", options, |_cc| {
|
||||||
|
Box::new(MyApp::default())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
image: RetainedImage,
|
image: RetainedImage,
|
||||||
}
|
}
|
||||||
|
@ -19,12 +26,8 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
"Show an image with eframe/egui"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::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);
|
||||||
|
@ -37,8 +40,3 @@ impl epi::App for MyApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions::default();
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,15 @@
|
||||||
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
initial_window_size: Some(egui::vec2(1000.0, 700.0)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
eframe::run_native("svg example", options, |_cc| Box::new(MyApp::default()));
|
||||||
|
}
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
svg_image: egui_extras::RetainedImage,
|
svg_image: egui_extras::RetainedImage,
|
||||||
|
@ -22,12 +30,8 @@ impl Default for MyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl eframe::App for MyApp {
|
||||||
fn name(&self) -> &str {
|
fn update(&mut self, ctx: &egui::Context, _frame: &eframe::Frame) {
|
||||||
"svg example"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::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.");
|
||||||
|
@ -39,11 +43,3 @@ impl epi::App for MyApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options = eframe::NativeOptions {
|
|
||||||
initial_window_size: Some(egui::vec2(1000.0, 700.0)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,27 +16,32 @@
|
||||||
//!
|
//!
|
||||||
//! ## Usage, native:
|
//! ## Usage, native:
|
||||||
//! ``` no_run
|
//! ``` no_run
|
||||||
//! use eframe::{epi, egui};
|
//! use eframe::egui;
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! let native_options = eframe::NativeOptions::default();
|
||||||
|
//! eframe::run_native("My egui App", native_options, |cc| Box::new(MyEguiApp::new(cc)));
|
||||||
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Default)]
|
//! #[derive(Default)]
|
||||||
//! struct MyEguiApp {}
|
//! struct MyEguiApp {}
|
||||||
//!
|
//!
|
||||||
//! impl epi::App for MyEguiApp {
|
//! impl MyEguiApp {
|
||||||
//! fn name(&self) -> &str {
|
//! fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
//! "My egui App"
|
//! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
|
||||||
//! }
|
//! // Restore app state using cc.storage (requires the "persistence" feature).
|
||||||
|
//! // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
|
||||||
|
//! // for e.g. egui::PaintCallback.
|
||||||
|
//! Self::default()
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
//! impl eframe::App for MyEguiApp {
|
||||||
|
//! fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
||||||
//! egui::CentralPanel::default().show(ctx, |ui| {
|
//! egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
//! ui.heading("Hello World!");
|
//! ui.heading("Hello World!");
|
||||||
//! });
|
//! });
|
||||||
//! }
|
//! }
|
||||||
//!}
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! let app = MyEguiApp::default();
|
|
||||||
//! let native_options = eframe::NativeOptions::default();
|
|
||||||
//! eframe::run_native(Box::new(app), native_options);
|
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -49,8 +54,7 @@
|
||||||
//! #[cfg(target_arch = "wasm32")]
|
//! #[cfg(target_arch = "wasm32")]
|
||||||
//! #[wasm_bindgen]
|
//! #[wasm_bindgen]
|
||||||
//! pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
//! pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
||||||
//! let app = MyEguiApp::default();
|
//! eframe::start_web(canvas_id, |cc| Box::new(MyApp::new(cc)))
|
||||||
//! eframe::start_web(canvas_id, Box::new(app))
|
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -65,10 +69,11 @@
|
||||||
)]
|
)]
|
||||||
#![allow(clippy::needless_doctest_main)]
|
#![allow(clippy::needless_doctest_main)]
|
||||||
|
|
||||||
|
// Re-export all useful libraries:
|
||||||
pub use {egui, egui::emath, egui::epaint, epi};
|
pub use {egui, egui::emath, egui::epaint, epi};
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
// Re-export everything in `epi` so `eframe` users don't have to care about what `epi` is:
|
||||||
pub use epi::NativeOptions;
|
pub use epi::*;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// When compiling for web
|
// When compiling for web
|
||||||
|
@ -83,16 +88,6 @@ pub use egui_web::wasm_bindgen;
|
||||||
/// fill the whole width of the browser.
|
/// fill the whole width of the browser.
|
||||||
/// This can be changed by overriding [`epi::Frame::max_size_points`].
|
/// This can be changed by overriding [`epi::Frame::max_size_points`].
|
||||||
///
|
///
|
||||||
/// ### Usage, native:
|
|
||||||
/// ``` no_run
|
|
||||||
/// fn main() {
|
|
||||||
/// let app = MyEguiApp::default();
|
|
||||||
/// let native_options = eframe::NativeOptions::default();
|
|
||||||
/// eframe::run_native(Box::new(app), native_options);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Web
|
|
||||||
/// ``` no_run
|
/// ``` no_run
|
||||||
/// #[cfg(target_arch = "wasm32")]
|
/// #[cfg(target_arch = "wasm32")]
|
||||||
/// use wasm_bindgen::prelude::*;
|
/// use wasm_bindgen::prelude::*;
|
||||||
|
@ -104,45 +99,54 @@ pub use egui_web::wasm_bindgen;
|
||||||
/// #[cfg(target_arch = "wasm32")]
|
/// #[cfg(target_arch = "wasm32")]
|
||||||
/// #[wasm_bindgen]
|
/// #[wasm_bindgen]
|
||||||
/// pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
/// pub fn start(canvas_id: &str) -> Result<(), eframe::wasm_bindgen::JsValue> {
|
||||||
/// let app = MyEguiApp::default();
|
/// eframe::start_web(canvas_id, |cc| Box::new(MyEguiApp::new(cc)))
|
||||||
/// eframe::start_web(canvas_id, Box::new(app))
|
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub fn start_web(canvas_id: &str, app: Box<dyn epi::App>) -> Result<(), wasm_bindgen::JsValue> {
|
pub fn start_web(canvas_id: &str, app_creator: AppCreator) -> Result<(), wasm_bindgen::JsValue> {
|
||||||
egui_web::start(canvas_id, app)?;
|
egui_web::start(canvas_id, app_creator)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// When compiling natively
|
// When compiling natively
|
||||||
|
|
||||||
|
/// This is how you start a native (desktop) app.
|
||||||
|
///
|
||||||
|
/// The first argument is name of your app, used for the title bar of the native window
|
||||||
|
/// and the save location of persistence (see [`epi::App::save`]).
|
||||||
|
///
|
||||||
/// Call from `fn main` like this:
|
/// Call from `fn main` like this:
|
||||||
/// ``` no_run
|
/// ``` no_run
|
||||||
/// use eframe::{epi, egui};
|
/// use eframe::egui;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let native_options = eframe::NativeOptions::default();
|
||||||
|
/// eframe::run_native("MyApp", native_options, |cc| Box::new(MyEguiApp::new(cc)));
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// #[derive(Default)]
|
/// #[derive(Default)]
|
||||||
/// struct MyEguiApp {}
|
/// struct MyEguiApp {}
|
||||||
///
|
///
|
||||||
/// impl epi::App for MyEguiApp {
|
/// impl MyEguiApp {
|
||||||
/// fn name(&self) -> &str {
|
/// fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
/// "My egui App"
|
/// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
|
||||||
/// }
|
/// // Restore app state using cc.storage (requires the "persistence" feature).
|
||||||
|
/// // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
|
||||||
|
/// // for e.g. egui::PaintCallback.
|
||||||
|
/// Self::default()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
/// impl eframe::App for MyEguiApp {
|
||||||
|
/// fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) {
|
||||||
/// egui::CentralPanel::default().show(ctx, |ui| {
|
/// egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
/// ui.heading("Hello World!");
|
/// ui.heading("Hello World!");
|
||||||
/// });
|
/// });
|
||||||
/// }
|
/// }
|
||||||
///}
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let app = MyEguiApp::default();
|
|
||||||
/// let native_options = eframe::NativeOptions::default();
|
|
||||||
/// eframe::run_native(Box::new(app), native_options);
|
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn run_native(app: Box<dyn epi::App>, native_options: epi::NativeOptions) -> ! {
|
pub fn run_native(app_name: &str, native_options: NativeOptions, app_creator: AppCreator) -> ! {
|
||||||
egui_glow::run(app, &native_options)
|
egui_glow::run(app_name, &native_options, app_creator)
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,12 +216,11 @@ 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 {
|
||||||
frame: epi::Frame,
|
pub frame: epi::Frame,
|
||||||
persistence: crate::epi::Persistence,
|
pub persistence: crate::epi::Persistence,
|
||||||
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,
|
||||||
pub app: Box<dyn epi::App>,
|
|
||||||
/// When set, it is time to quit
|
/// When set, it is time to quit
|
||||||
quit: bool,
|
quit: bool,
|
||||||
can_drag_window: bool,
|
can_drag_window: bool,
|
||||||
|
@ -232,9 +231,7 @@ 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,
|
||||||
gl: &std::rc::Rc<glow::Context>,
|
|
||||||
persistence: crate::epi::Persistence,
|
persistence: crate::epi::Persistence,
|
||||||
app: Box<dyn epi::App>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let egui_ctx = egui::Context::default();
|
let egui_ctx = egui::Context::default();
|
||||||
|
|
||||||
|
@ -259,41 +256,21 @@ impl EpiIntegration {
|
||||||
egui_ctx.set_visuals(egui::Visuals::light());
|
egui_ctx.set_visuals(egui::Visuals::light());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut slf = Self {
|
Self {
|
||||||
frame,
|
frame,
|
||||||
persistence,
|
persistence,
|
||||||
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(),
|
||||||
app,
|
|
||||||
quit: false,
|
quit: false,
|
||||||
can_drag_window: false,
|
can_drag_window: false,
|
||||||
};
|
|
||||||
|
|
||||||
slf.setup(window, gl);
|
|
||||||
if slf.app.warm_up_enabled() {
|
|
||||||
slf.warm_up(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(&mut self, window: &winit::window::Window, gl: &std::rc::Rc<glow::Context>) {
|
pub fn warm_up(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
||||||
self.app
|
|
||||||
.setup(&self.egui_ctx, &self.frame, self.persistence.storage(), gl);
|
|
||||||
let app_output = self.frame.take_app_output();
|
|
||||||
|
|
||||||
if app_output.quit {
|
|
||||||
self.quit = self.app.on_exit_event();
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn warm_up(&mut self, window: &winit::window::Window) {
|
|
||||||
let saved_memory: egui::Memory = self.egui_ctx.memory().clone();
|
let saved_memory: egui::Memory = self.egui_ctx.memory().clone();
|
||||||
self.egui_ctx.memory().set_everything_is_visible(true);
|
self.egui_ctx.memory().set_everything_is_visible(true);
|
||||||
let full_output = self.update(window);
|
let full_output = self.update(app, window);
|
||||||
self.pending_full_output.append(full_output); // Handle it next frame
|
self.pending_full_output.append(full_output); // Handle it next frame
|
||||||
*self.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
|
*self.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
|
||||||
self.egui_ctx.clear_animations();
|
self.egui_ctx.clear_animations();
|
||||||
|
@ -304,11 +281,11 @@ impl EpiIntegration {
|
||||||
self.quit
|
self.quit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) {
|
pub fn on_event(&mut self, app: &mut dyn epi::App, event: &winit::event::WindowEvent<'_>) {
|
||||||
use winit::event::{ElementState, MouseButton, WindowEvent};
|
use winit::event::{ElementState, MouseButton, WindowEvent};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => self.quit = self.app.on_exit_event(),
|
WindowEvent::CloseRequested => self.quit = app.on_exit_event(),
|
||||||
WindowEvent::Destroyed => self.quit = true,
|
WindowEvent::Destroyed => self.quit = true,
|
||||||
WindowEvent::MouseInput {
|
WindowEvent::MouseInput {
|
||||||
button: MouseButton::Left,
|
button: MouseButton::Left,
|
||||||
|
@ -321,12 +298,16 @@ impl EpiIntegration {
|
||||||
self.egui_winit.on_event(&self.egui_ctx, event);
|
self.egui_winit.on_event(&self.egui_ctx, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, window: &winit::window::Window) -> egui::FullOutput {
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
app: &mut dyn epi::App,
|
||||||
|
window: &winit::window::Window,
|
||||||
|
) -> egui::FullOutput {
|
||||||
let frame_start = instant::Instant::now();
|
let frame_start = instant::Instant::now();
|
||||||
|
|
||||||
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| {
|
||||||
self.app.update(egui_ctx, &self.frame);
|
app.update(egui_ctx, &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);
|
||||||
|
@ -336,7 +317,7 @@ impl EpiIntegration {
|
||||||
app_output.drag_window &= self.can_drag_window; // Necessary on Windows; see https://github.com/emilk/egui/pull/1108
|
app_output.drag_window &= self.can_drag_window; // Necessary on Windows; see https://github.com/emilk/egui/pull/1108
|
||||||
self.can_drag_window = false;
|
self.can_drag_window = false;
|
||||||
if app_output.quit {
|
if app_output.quit {
|
||||||
self.quit = self.app.on_exit_event();
|
self.quit = app.on_exit_event();
|
||||||
}
|
}
|
||||||
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
||||||
}
|
}
|
||||||
|
@ -356,15 +337,9 @@ impl EpiIntegration {
|
||||||
.handle_platform_output(window, &self.egui_ctx, platform_output);
|
.handle_platform_output(window, &self.egui_ctx, platform_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_autosave(&mut self, window: &winit::window::Window) {
|
pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
||||||
self.persistence
|
self.persistence
|
||||||
.maybe_autosave(&mut *self.app, &self.egui_ctx, window);
|
.maybe_autosave(&mut *app, &self.egui_ctx, window);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn on_exit(&mut self, window: &winit::window::Window) {
|
|
||||||
self.app.on_exit();
|
|
||||||
self.persistence
|
|
||||||
.save(&mut *self.app, &self.egui_ctx, window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,8 +386,8 @@ pub use epaint::{
|
||||||
color, mutex,
|
color, mutex,
|
||||||
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
|
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
|
||||||
textures::TexturesDelta,
|
textures::TexturesDelta,
|
||||||
AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, Rgba, Rounding, Shape,
|
AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, PaintCallback, Rgba,
|
||||||
Stroke, TextureHandle, TextureId,
|
Rounding, Shape, Stroke, TextureHandle, TextureId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod text {
|
pub mod text {
|
||||||
|
|
|
@ -19,6 +19,5 @@ pub fn start(canvas_id: &str) -> Result<(), wasm_bindgen::JsValue> {
|
||||||
// Redirect tracing to console.log and friends:
|
// Redirect tracing to console.log and friends:
|
||||||
tracing_wasm::set_as_global_default();
|
tracing_wasm::set_as_global_default();
|
||||||
|
|
||||||
let app = egui_demo_lib::WrapApp::default();
|
eframe::start_web(canvas_id, |cc| Box::new(egui_demo_lib::WrapApp::new(cc)))
|
||||||
eframe::start_web(canvas_id, Box::new(app))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,13 @@ fn main() {
|
||||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let app = egui_demo_lib::WrapApp::default();
|
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
// Let's show off that we support transparent windows
|
// Let's show off that we support transparent windows
|
||||||
transparent: true,
|
transparent: true,
|
||||||
drag_and_drop_support: true,
|
drag_and_drop_support: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(Box::new(app), options);
|
eframe::run_native("egui demo app", options, |cc| {
|
||||||
|
Box::new(egui_demo_lib::WrapApp::new(cc))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,6 @@ impl Default for ColorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for ColorTest {
|
impl epi::App for ColorTest {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"🎨 Color test"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
if frame.is_web() {
|
if frame.is_web() {
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
/// Demonstrates how to make an app using egui.
|
|
||||||
///
|
|
||||||
/// Implements `epi::App` so it can be used with
|
|
||||||
/// [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium), [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) and [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web).
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
|
@ -10,28 +6,6 @@ pub struct DemoApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for DemoApp {
|
impl epi::App for DemoApp {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"✨ Demos"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
_ctx: &egui::Context,
|
|
||||||
_frame: &epi::Frame,
|
|
||||||
_storage: Option<&dyn epi::Storage>,
|
|
||||||
_gl: &std::rc::Rc<epi::glow::Context>,
|
|
||||||
) {
|
|
||||||
#[cfg(feature = "persistence")]
|
|
||||||
if let Some(storage) = _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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||||
self.demo_windows.ui(ctx);
|
self.demo_windows.ui(ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,6 @@ impl Default for FractalClock {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for FractalClock {
|
impl epi::App for FractalClock {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"🕑 Fractal Clock"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(Frame::dark_canvas(&ctx.style()))
|
.frame(Frame::dark_canvas(&ctx.style()))
|
||||||
|
|
|
@ -54,10 +54,6 @@ impl Default for HttpApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for HttpApp {
|
impl epi::App for HttpApp {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"⬇ HTTP"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, frame: &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);
|
||||||
|
|
|
@ -30,10 +30,6 @@ impl Default for EasyMarkEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for EasyMarkEditor {
|
impl epi::App for EasyMarkEditor {
|
||||||
fn name(&self) -> &str {
|
|
||||||
"🖹 EasyMark editor"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &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);
|
||||||
|
|
|
@ -12,14 +12,26 @@ pub struct Apps {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Apps {
|
impl Apps {
|
||||||
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut dyn epi::App)> {
|
fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &str, &mut dyn epi::App)> {
|
||||||
vec![
|
vec![
|
||||||
("demo", &mut self.demo as &mut dyn epi::App),
|
("✨ Demos", "demo", &mut self.demo as &mut dyn epi::App),
|
||||||
("easymark", &mut self.easy_mark_editor as &mut dyn epi::App),
|
(
|
||||||
|
"🖹 EasyMark editor",
|
||||||
|
"easymark",
|
||||||
|
&mut self.easy_mark_editor as &mut dyn epi::App,
|
||||||
|
),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
("http", &mut self.http as &mut dyn epi::App),
|
("⬇ 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),
|
"🕑 Fractal Clock",
|
||||||
|
"clock",
|
||||||
|
&mut self.clock as &mut dyn epi::App,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"🎨 Color test",
|
||||||
|
"colors",
|
||||||
|
&mut self.color_test as &mut dyn epi::App,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
}
|
}
|
||||||
|
@ -37,24 +49,17 @@ pub struct WrapApp {
|
||||||
dropped_files: Vec<egui::DroppedFile>,
|
dropped_files: Vec<egui::DroppedFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for WrapApp {
|
impl WrapApp {
|
||||||
fn name(&self) -> &str {
|
pub fn new(_cc: &epi::CreationContext<'_>) -> Self {
|
||||||
"egui demo apps"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
_ctx: &egui::Context,
|
|
||||||
_frame: &epi::Frame,
|
|
||||||
_storage: Option<&dyn epi::Storage>,
|
|
||||||
_gl: &std::rc::Rc<epi::glow::Context>,
|
|
||||||
) {
|
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
if let Some(storage) = _storage {
|
if let Some(storage) = _cc.storage {
|
||||||
*self = epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
|
return epi::get_value(storage, epi::APP_KEY).unwrap_or_default();
|
||||||
}
|
}
|
||||||
|
Self::default()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl epi::App for WrapApp {
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
fn save(&mut self, storage: &mut dyn epi::Storage) {
|
fn save(&mut self, storage: &mut dyn epi::Storage) {
|
||||||
epi::set_value(storage, epi::APP_KEY, self);
|
epi::set_value(storage, epi::APP_KEY, self);
|
||||||
|
@ -111,7 +116,7 @@ impl epi::App for WrapApp {
|
||||||
|
|
||||||
let mut found_anchor = false;
|
let mut found_anchor = false;
|
||||||
|
|
||||||
for (anchor, app) in self.apps.iter_mut() {
|
for (_name, anchor, app) in self.apps.iter_mut() {
|
||||||
if anchor == self.selected_anchor || ctx.memory().everything_is_visible() {
|
if anchor == self.selected_anchor || ctx.memory().everything_is_visible() {
|
||||||
app.update(ctx, frame);
|
app.update(ctx, frame);
|
||||||
found_anchor = true;
|
found_anchor = true;
|
||||||
|
@ -138,9 +143,9 @@ impl WrapApp {
|
||||||
ui.checkbox(&mut self.backend_panel.open, "💻 Backend");
|
ui.checkbox(&mut self.backend_panel.open, "💻 Backend");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
for (anchor, app) in self.apps.iter_mut() {
|
for (name, anchor, _app) in self.apps.iter_mut() {
|
||||||
if ui
|
if ui
|
||||||
.selectable_label(self.selected_anchor == anchor, app.name())
|
.selectable_label(self.selected_anchor == anchor, name)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
self.selected_anchor = anchor.to_owned();
|
self.selected_anchor = anchor.to_owned();
|
||||||
|
|
|
@ -4,41 +4,6 @@
|
||||||
|
|
||||||
use glium::glutin;
|
use glium::glutin;
|
||||||
|
|
||||||
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {
|
|
||||||
let window_builder = glutin::window::WindowBuilder::new()
|
|
||||||
.with_resizable(true)
|
|
||||||
.with_inner_size(glutin::dpi::LogicalSize {
|
|
||||||
width: 800.0,
|
|
||||||
height: 600.0,
|
|
||||||
})
|
|
||||||
.with_title("egui_glium example");
|
|
||||||
|
|
||||||
let context_builder = glutin::ContextBuilder::new()
|
|
||||||
.with_depth_buffer(0)
|
|
||||||
.with_srgb(true)
|
|
||||||
.with_stencil_buffer(0)
|
|
||||||
.with_vsync(true);
|
|
||||||
|
|
||||||
glium::Display::new(window_builder, context_builder, event_loop).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_glium_image(png_data: &[u8]) -> glium::texture::RawImage2d<u8> {
|
|
||||||
// Load image using the image crate:
|
|
||||||
let image = image::load_from_memory(png_data).unwrap().to_rgba8();
|
|
||||||
let image_dimensions = image.dimensions();
|
|
||||||
|
|
||||||
// Premultiply alpha:
|
|
||||||
let pixels: Vec<_> = image
|
|
||||||
.into_vec()
|
|
||||||
.chunks_exact(4)
|
|
||||||
.map(|p| egui::Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
|
|
||||||
.flat_map(|color| color.to_array())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Convert to glium image:
|
|
||||||
glium::texture::RawImage2d::from_raw_rgba(pixels, image_dimensions)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
||||||
let display = create_display(&event_loop);
|
let display = create_display(&event_loop);
|
||||||
|
@ -127,3 +92,38 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {
|
||||||
|
let window_builder = glutin::window::WindowBuilder::new()
|
||||||
|
.with_resizable(true)
|
||||||
|
.with_inner_size(glutin::dpi::LogicalSize {
|
||||||
|
width: 800.0,
|
||||||
|
height: 600.0,
|
||||||
|
})
|
||||||
|
.with_title("egui_glium example");
|
||||||
|
|
||||||
|
let context_builder = glutin::ContextBuilder::new()
|
||||||
|
.with_depth_buffer(0)
|
||||||
|
.with_srgb(true)
|
||||||
|
.with_stencil_buffer(0)
|
||||||
|
.with_vsync(true);
|
||||||
|
|
||||||
|
glium::Display::new(window_builder, context_builder, event_loop).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_glium_image(png_data: &[u8]) -> glium::texture::RawImage2d<u8> {
|
||||||
|
// Load image using the image crate:
|
||||||
|
let image = image::load_from_memory(png_data).unwrap().to_rgba8();
|
||||||
|
let image_dimensions = image.dimensions();
|
||||||
|
|
||||||
|
// Premultiply alpha:
|
||||||
|
let pixels: Vec<_> = image
|
||||||
|
.into_vec()
|
||||||
|
.chunks_exact(4)
|
||||||
|
.map(|p| egui::Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
|
||||||
|
.flat_map(|color| color.to_array())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Convert to glium image:
|
||||||
|
glium::texture::RawImage2d::from_raw_rgba(pixels, image_dimensions)
|
||||||
|
}
|
||||||
|
|
|
@ -4,24 +4,6 @@
|
||||||
|
|
||||||
use glium::glutin;
|
use glium::glutin;
|
||||||
|
|
||||||
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {
|
|
||||||
let window_builder = glutin::window::WindowBuilder::new()
|
|
||||||
.with_resizable(true)
|
|
||||||
.with_inner_size(glutin::dpi::LogicalSize {
|
|
||||||
width: 800.0,
|
|
||||||
height: 600.0,
|
|
||||||
})
|
|
||||||
.with_title("egui_glium example");
|
|
||||||
|
|
||||||
let context_builder = glutin::ContextBuilder::new()
|
|
||||||
.with_depth_buffer(0)
|
|
||||||
.with_srgb(true)
|
|
||||||
.with_stencil_buffer(0)
|
|
||||||
.with_vsync(true);
|
|
||||||
|
|
||||||
glium::Display::new(window_builder, context_builder, event_loop).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
let event_loop = glutin::event_loop::EventLoop::with_user_event();
|
||||||
let display = create_display(&event_loop);
|
let display = create_display(&event_loop);
|
||||||
|
@ -89,3 +71,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {
|
||||||
|
let window_builder = glutin::window::WindowBuilder::new()
|
||||||
|
.with_resizable(true)
|
||||||
|
.with_inner_size(glutin::dpi::LogicalSize {
|
||||||
|
width: 800.0,
|
||||||
|
height: 600.0,
|
||||||
|
})
|
||||||
|
.with_title("egui_glium example");
|
||||||
|
|
||||||
|
let context_builder = glutin::ContextBuilder::new()
|
||||||
|
.with_depth_buffer(0)
|
||||||
|
.with_srgb(true)
|
||||||
|
.with_stencil_buffer(0)
|
||||||
|
.with_vsync(true);
|
||||||
|
|
||||||
|
glium::Display::new(window_builder, context_builder, event_loop).unwrap()
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
//!
|
//!
|
||||||
//! The main type you want to use is [`EguiGlium`].
|
//! The main type you want to use is [`EguiGlium`].
|
||||||
//!
|
//!
|
||||||
//! This library is an [`epi`] backend.
|
|
||||||
//! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead.
|
//! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead.
|
||||||
|
|
||||||
// Forbid warnings in release builds:
|
// Forbid warnings in release builds:
|
||||||
|
|
|
@ -2,42 +2,6 @@
|
||||||
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
fn create_display(
|
|
||||||
event_loop: &glutin::event_loop::EventLoop<()>,
|
|
||||||
) -> (
|
|
||||||
glutin::WindowedContext<glutin::PossiblyCurrent>,
|
|
||||||
glow::Context,
|
|
||||||
) {
|
|
||||||
let window_builder = glutin::window::WindowBuilder::new()
|
|
||||||
.with_resizable(true)
|
|
||||||
.with_inner_size(glutin::dpi::LogicalSize {
|
|
||||||
width: 800.0,
|
|
||||||
height: 600.0,
|
|
||||||
})
|
|
||||||
.with_title("egui_glow example");
|
|
||||||
|
|
||||||
let gl_window = unsafe {
|
|
||||||
glutin::ContextBuilder::new()
|
|
||||||
.with_depth_buffer(0)
|
|
||||||
.with_srgb(true)
|
|
||||||
.with_stencil_buffer(0)
|
|
||||||
.with_vsync(true)
|
|
||||||
.build_windowed(window_builder, event_loop)
|
|
||||||
.unwrap()
|
|
||||||
.make_current()
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) };
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
use glow::HasContext as _;
|
|
||||||
gl.enable(glow::FRAMEBUFFER_SRGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
(gl_window, gl)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut clear_color = [0.1, 0.1, 0.1];
|
let mut clear_color = [0.1, 0.1, 0.1];
|
||||||
|
|
||||||
|
@ -116,3 +80,39 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_display(
|
||||||
|
event_loop: &glutin::event_loop::EventLoop<()>,
|
||||||
|
) -> (
|
||||||
|
glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||||
|
glow::Context,
|
||||||
|
) {
|
||||||
|
let window_builder = glutin::window::WindowBuilder::new()
|
||||||
|
.with_resizable(true)
|
||||||
|
.with_inner_size(glutin::dpi::LogicalSize {
|
||||||
|
width: 800.0,
|
||||||
|
height: 600.0,
|
||||||
|
})
|
||||||
|
.with_title("egui_glow example");
|
||||||
|
|
||||||
|
let gl_window = unsafe {
|
||||||
|
glutin::ContextBuilder::new()
|
||||||
|
.with_depth_buffer(0)
|
||||||
|
.with_srgb(true)
|
||||||
|
.with_stencil_buffer(0)
|
||||||
|
.with_vsync(true)
|
||||||
|
.build_windowed(window_builder, event_loop)
|
||||||
|
.unwrap()
|
||||||
|
.make_current()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
use glow::HasContext as _;
|
||||||
|
gl.enable(glow::FRAMEBUFFER_SRGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
(gl_window, gl)
|
||||||
|
}
|
||||||
|
|
|
@ -39,24 +39,23 @@ pub use epi::NativeOptions;
|
||||||
|
|
||||||
/// Run an egui app
|
/// Run an egui app
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
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 persistence = egui_winit::epi::Persistence::from_app_name(app_name);
|
||||||
let window_settings = persistence.load_window_settings();
|
let window_settings = persistence.load_window_settings();
|
||||||
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();
|
||||||
let (gl_window, gl) = create_display(window_builder, &event_loop);
|
let (gl_window, gl) = create_display(window_builder, &event_loop);
|
||||||
let gl = std::rc::Rc::new(gl);
|
let gl = std::rc::Rc::new(gl);
|
||||||
|
|
||||||
let mut painter = crate::Painter::new(gl.clone(), None, "")
|
let mut painter = crate::Painter::new(gl.clone(), None, "")
|
||||||
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
|
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
|
||||||
|
|
||||||
let mut integration = egui_winit::epi::EpiIntegration::new(
|
let mut integration = egui_winit::epi::EpiIntegration::new(
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
painter.max_texture_side(),
|
painter.max_texture_side(),
|
||||||
gl_window.window(),
|
gl_window.window(),
|
||||||
&gl,
|
|
||||||
persistence,
|
persistence,
|
||||||
app,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -66,6 +65,17 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut app = app_creator(&epi::CreationContext {
|
||||||
|
egui_ctx: integration.egui_ctx.clone(),
|
||||||
|
integration_info: integration.frame.info(),
|
||||||
|
storage: integration.persistence.storage(),
|
||||||
|
gl: gl.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if app.warm_up_enabled() {
|
||||||
|
integration.warm_up(app.as_mut(), gl_window.window());
|
||||||
|
}
|
||||||
|
|
||||||
let mut is_focused = true;
|
let mut is_focused = true;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
@ -84,7 +94,7 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
needs_repaint,
|
needs_repaint,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = integration.update(gl_window.window());
|
} = integration.update(app.as_mut(), gl_window.window());
|
||||||
|
|
||||||
integration.handle_platform_output(gl_window.window(), platform_output);
|
integration.handle_platform_output(gl_window.window(), platform_output);
|
||||||
|
|
||||||
|
@ -92,7 +102,7 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
|
|
||||||
// paint:
|
// paint:
|
||||||
{
|
{
|
||||||
let color = integration.app.clear_color();
|
let color = app.clear_color();
|
||||||
unsafe {
|
unsafe {
|
||||||
use glow::HasContext as _;
|
use glow::HasContext as _;
|
||||||
gl.disable(glow::SCISSOR_TEST);
|
gl.disable(glow::SCISSOR_TEST);
|
||||||
|
@ -120,7 +130,7 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
integration.maybe_autosave(gl_window.window());
|
integration.maybe_autosave(app.as_mut(), gl_window.window());
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
@ -139,7 +149,7 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
gl_window.resize(physical_size);
|
gl_window.resize(physical_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
integration.on_event(&event);
|
integration.on_event(app.as_mut(), &event);
|
||||||
if integration.should_quit() {
|
if integration.should_quit() {
|
||||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +157,10 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
|
||||||
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.on_exit(gl_window.window());
|
integration
|
||||||
|
.persistence
|
||||||
|
.save(&mut *app, &integration.egui_ctx, gl_window.window());
|
||||||
|
app.on_exit(&gl);
|
||||||
painter.destroy();
|
painter.destroy();
|
||||||
}
|
}
|
||||||
winit::event::Event::UserEvent(RequestRepaintEvent) => {
|
winit::event::Event::UserEvent(RequestRepaintEvent) => {
|
||||||
|
|
|
@ -139,7 +139,7 @@ pub struct AppRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppRunner {
|
impl AppRunner {
|
||||||
pub fn new(canvas_id: &str, app: Box<dyn epi::App>) -> Result<Self, JsValue> {
|
pub fn new(canvas_id: &str, app_creator: epi::AppCreator) -> Result<Self, JsValue> {
|
||||||
let painter = WrappedGlowPainter::new(canvas_id).map_err(JsValue::from)?;
|
let painter = WrappedGlowPainter::new(canvas_id).map_err(JsValue::from)?;
|
||||||
|
|
||||||
let prefer_dark_mode = crate::prefer_dark_mode();
|
let prefer_dark_mode = crate::prefer_dark_mode();
|
||||||
|
@ -177,6 +177,13 @@ impl AppRunner {
|
||||||
|
|
||||||
let storage = LocalStorage::default();
|
let storage = LocalStorage::default();
|
||||||
|
|
||||||
|
let app = app_creator(&epi::CreationContext {
|
||||||
|
egui_ctx: egui_ctx.clone(),
|
||||||
|
integration_info: frame.info(),
|
||||||
|
storage: Some(&storage),
|
||||||
|
gl: painter.painter.gl().clone(),
|
||||||
|
});
|
||||||
|
|
||||||
let mut runner = Self {
|
let mut runner = Self {
|
||||||
frame,
|
frame,
|
||||||
egui_ctx,
|
egui_ctx,
|
||||||
|
@ -194,11 +201,6 @@ impl AppRunner {
|
||||||
|
|
||||||
runner.input.raw.max_texture_side = Some(runner.painter.max_texture_side());
|
runner.input.raw.max_texture_side = Some(runner.painter.max_texture_side());
|
||||||
|
|
||||||
let gl = runner.painter.painter.gl();
|
|
||||||
runner
|
|
||||||
.app
|
|
||||||
.setup(&runner.egui_ctx, &runner.frame, Some(&runner.storage), gl);
|
|
||||||
|
|
||||||
Ok(runner)
|
Ok(runner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,8 +329,8 @@ impl AppRunner {
|
||||||
|
|
||||||
/// Install event listeners to register different input events
|
/// Install event listeners to register different input events
|
||||||
/// and start running the given app.
|
/// and start running the given app.
|
||||||
pub fn start(canvas_id: &str, app: Box<dyn epi::App>) -> Result<AppRunnerRef, JsValue> {
|
pub fn start(canvas_id: &str, app_creator: epi::AppCreator) -> Result<AppRunnerRef, JsValue> {
|
||||||
let mut runner = AppRunner::new(canvas_id, app)?;
|
let mut runner = AppRunner::new(canvas_id, app_creator)?;
|
||||||
runner.warm_up()?;
|
runner.warm_up()?;
|
||||||
start_runner(runner)
|
start_runner(runner)
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,30 @@ pub use glow; // Re-export for user convenience
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
/// The is is how your app is created.
|
||||||
|
///
|
||||||
|
/// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc.
|
||||||
|
pub type AppCreator = fn(&CreationContext<'_>) -> Box<dyn App>;
|
||||||
|
|
||||||
|
/// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app.
|
||||||
|
pub struct CreationContext<'s> {
|
||||||
|
/// The egui Context.
|
||||||
|
///
|
||||||
|
/// You can use this to customize the look of egui, e.g to call [`egui::Context::set_fonts`],
|
||||||
|
/// [`egui::Context::set_visuals`] etc.
|
||||||
|
pub egui_ctx: egui::Context,
|
||||||
|
|
||||||
|
/// Information about the surrounding environment.
|
||||||
|
pub integration_info: IntegrationInfo,
|
||||||
|
|
||||||
|
/// You can use the storage to restore app state(requires the "persistence" feature).
|
||||||
|
pub storage: Option<&'s dyn Storage>,
|
||||||
|
|
||||||
|
/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that
|
||||||
|
/// you might want to use later from a [`egui::PaintCallback`].
|
||||||
|
pub gl: std::rc::Rc<glow::Context>,
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Implement this trait to write apps that can be compiled both natively using the [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) crate,
|
/// Implement this trait to write apps that can be compiled both natively using the [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) crate,
|
||||||
|
@ -109,39 +133,20 @@ pub trait App {
|
||||||
///
|
///
|
||||||
/// The [`egui::Context`] and [`Frame`] can be cloned and saved if you like.
|
/// The [`egui::Context`] and [`Frame`] can be cloned and saved if you like.
|
||||||
///
|
///
|
||||||
/// To force a repaint, call either [`egui::Context::request_repaint`] during the call to `update`,
|
/// To force a repaint, call [`egui::Context::request_repaint`] at any time (e.g. from another thread).
|
||||||
/// or call [`Frame::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: &Frame);
|
||||||
|
|
||||||
/// Called exactly once at startup, before any call to [`Self::update`].
|
|
||||||
///
|
|
||||||
/// Allows you to do setup code, e.g to call [`egui::Context::set_fonts`],
|
|
||||||
/// [`egui::Context::set_visuals`] etc.
|
|
||||||
///
|
|
||||||
/// Also allows you to restore state, if there is a storage (requires the "persistence" feature).
|
|
||||||
///
|
|
||||||
/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that
|
|
||||||
/// you might want to use later from a [`egui::PaintCallback`].
|
|
||||||
fn setup(
|
|
||||||
&mut self,
|
|
||||||
_ctx: &egui::Context,
|
|
||||||
_frame: &Frame,
|
|
||||||
_storage: Option<&dyn Storage>,
|
|
||||||
_gl: &std::rc::Rc<glow::Context>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// Only called when the "persistence" feature is enabled.
|
/// Only called when the "persistence" feature is enabled.
|
||||||
///
|
///
|
||||||
/// On web the states is stored to "Local Storage".
|
/// On web the state is stored to "Local Storage".
|
||||||
/// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is:
|
/// On native the path is picked using [`directories_next::ProjectDirs::data_dir`](https://docs.rs/directories-next/2.0.0/directories_next/struct.ProjectDirs.html#method.data_dir) which is:
|
||||||
/// * Linux: `/home/UserName/.local/share/APPNAME`
|
/// * Linux: `/home/UserName/.local/share/APPNAME`
|
||||||
/// * macOS: `/Users/UserName/Library/Application Support/APPNAME`
|
/// * macOS: `/Users/UserName/Library/Application Support/APPNAME`
|
||||||
/// * Windows: `C:\Users\UserName\AppData\Roaming\APPNAME`
|
/// * Windows: `C:\Users\UserName\AppData\Roaming\APPNAME`
|
||||||
///
|
///
|
||||||
/// where `APPNAME` is what is returned by [`Self::name()`].
|
/// where `APPNAME` is what is given to `eframe::run_native`.
|
||||||
fn save(&mut self, _storage: &mut dyn Storage) {}
|
fn save(&mut self, _storage: &mut dyn Storage) {}
|
||||||
|
|
||||||
/// Called before an exit that can be aborted.
|
/// Called before an exit that can be aborted.
|
||||||
|
@ -156,17 +161,14 @@ pub trait App {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called once on shutdown (before or after [`Self::save`]). If you need to abort an exit use
|
/// Called once on shutdown, after [`Self::save`].
|
||||||
/// [`Self::on_exit_event`]
|
///
|
||||||
fn on_exit(&mut self) {}
|
/// If you need to abort an exit use [`Self::on_exit_event`].
|
||||||
|
fn on_exit(&mut self, _gl: &glow::Context) {}
|
||||||
|
|
||||||
// ---------
|
// ---------
|
||||||
// Settings:
|
// Settings:
|
||||||
|
|
||||||
/// The name of your App, used for the title bar of native windows
|
|
||||||
/// and the save location of persistence (see [`Self::save`]).
|
|
||||||
fn name(&self) -> &str;
|
|
||||||
|
|
||||||
/// Time between automatic calls to [`Self::save`]
|
/// Time between automatic calls to [`Self::save`]
|
||||||
fn auto_save_interval(&self) -> std::time::Duration {
|
fn auto_save_interval(&self) -> std::time::Duration {
|
||||||
std::time::Duration::from_secs(30)
|
std::time::Duration::from_secs(30)
|
||||||
|
|
Loading…
Reference in a new issue