[app] Simplify interface to egui::app::App

This commit is contained in:
Emil Ernerfeldt 2020-10-24 19:23:16 +02:00
parent daa7a2bdb2
commit 7638ca9962
9 changed files with 66 additions and 56 deletions

View file

@ -13,7 +13,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_windows_minimal", |b| {
b.iter(|| {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), None);
demo_windows.ui(&ctx, &Default::default(), &mut None);
ctx.end_frame()
})
});
@ -27,7 +27,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_windows_full", |b| {
b.iter(|| {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), None);
demo_windows.ui(&ctx, &Default::default(), &mut None);
ctx.end_frame()
})
});

View file

@ -17,23 +17,31 @@ pub trait App {
fn ui(
&mut self,
ctx: &std::sync::Arc<Context>,
info: &BackendInfo,
tex_allocator: Option<&mut dyn TextureAllocator>,
) -> AppOutput;
integration_context: &mut IntegrationContext<'_>,
);
/// Called once on shutdown. Allows you to save state.
fn on_exit(&mut self, _storage: &mut dyn Storage) {}
}
pub struct IntegrationContext<'a> {
/// Information about the integration.
pub info: IntegrationInfo,
/// A way to allocate textures (on integrations that support it).
pub tex_allocator: Option<&'a mut dyn TextureAllocator>,
/// Where the app can issue commands back to the integration.
pub output: AppOutput,
}
#[derive(Clone, Debug)]
pub struct WebInfo {
/// e.g. "#fragment" part of "www.example.com/index.html#fragment"
pub web_location_hash: String,
}
/// Information about the backend passed to the use app each frame.
/// Information about the integration passed to the use app each frame.
#[derive(Clone, Debug)]
pub struct BackendInfo {
pub struct IntegrationInfo {
/// If the app is running in a Web context, this returns information about the environment.
pub web_info: Option<WebInfo>,

View file

@ -90,7 +90,7 @@ impl Context {
pub fn available_rect(&self) -> Rect {
self.available_rect
.lock()
.expect("Called `avaiblable_rect()` before `begin_frame()`")
.expect("Called `available_rect()` before `begin_frame()`")
}
pub fn memory(&self) -> MutexGuard<'_, Memory> {

View file

@ -183,11 +183,11 @@ pub struct DemoApp {
}
impl DemoApp {
fn backend_ui(&mut self, ui: &mut Ui, info: &app::BackendInfo) -> app::AppOutput {
fn backend_ui(&mut self, ui: &mut Ui, integration_context: &mut app::IntegrationContext<'_>) {
self.frame_history
.on_new_frame(ui.input().time, info.cpu_usage);
.on_new_frame(ui.input().time, integration_context.info.cpu_usage);
let is_web = info.web_info.is_some();
let is_web = integration_context.info.web_info.is_some();
if is_web {
ui.label("Egui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
@ -210,18 +210,16 @@ impl DemoApp {
ui.separator();
let mut output = app::AppOutput::default();
output.pixels_per_point = self.pixels_per_point_ui(ui, info);
integration_context.output.pixels_per_point =
self.pixels_per_point_ui(ui, &integration_context.info);
if !is_web {
ui.separator();
output.quit |= ui.button("Quit").clicked;
integration_context.output.quit |= ui.button("Quit").clicked;
}
output
}
fn pixels_per_point_ui(&mut self, ui: &mut Ui, info: &app::BackendInfo) -> Option<f32> {
fn pixels_per_point_ui(&mut self, ui: &mut Ui, info: &app::IntegrationInfo) -> Option<f32> {
self.pixels_per_point = self
.pixels_per_point
.or(info.native_pixels_per_point)
@ -276,10 +274,10 @@ impl app::App for DemoApp {
fn ui(
&mut self,
ctx: &Arc<Context>,
info: &app::BackendInfo,
tex_allocator: Option<&mut dyn app::TextureAllocator>,
) -> app::AppOutput {
let web_location_hash = info
integration_context: &mut crate::app::IntegrationContext<'_>,
) {
let web_location_hash = integration_context
.info
.web_info
.as_ref()
.map(|info| info.web_location_hash.clone())
@ -292,27 +290,27 @@ impl app::App for DemoApp {
};
let demo_environment = demos::DemoEnvironment {
seconds_since_midnight: info.seconds_since_midnight,
seconds_since_midnight: integration_context.info.seconds_since_midnight,
link,
};
self.demo_windows.ui(ctx, &demo_environment, tex_allocator);
let mut output = app::AppOutput::default();
self.demo_windows.ui(
ctx,
&demo_environment,
&mut integration_context.tex_allocator,
);
crate::Window::new("Backend")
.min_width(360.0)
.scroll(false)
.show(ctx, |ui| {
output = self.backend_ui(ui, info);
self.backend_ui(ui, integration_context);
});
if self.run_mode == RunMode::Continuous {
// Tell the backend to repaint as soon as possible
ctx.request_repaint();
}
output
}
#[cfg(feature = "serde_json")]

View file

@ -46,7 +46,7 @@ impl DemoWindows {
&mut self,
ctx: &Arc<Context>,
env: &DemoEnvironment,
tex_allocator: Option<&mut dyn app::TextureAllocator>,
tex_allocator: &mut Option<&mut dyn app::TextureAllocator>,
) {
if self.previous_link != env.link {
match env.link {
@ -93,7 +93,7 @@ impl DemoWindows {
&mut self,
ctx: &Arc<Context>,
env: &DemoEnvironment,
mut tex_allocator: Option<&mut dyn app::TextureAllocator>,
tex_allocator: &mut Option<&mut dyn app::TextureAllocator>,
) {
let Self {
open_windows,
@ -135,7 +135,7 @@ impl DemoWindows {
.scroll(true)
.open(&mut open_windows.color_test)
.show(ctx, |ui| {
color_test.ui(ui, &mut tex_allocator);
color_test.ui(ui, tex_allocator);
});
fractal_clock.window(

View file

@ -99,7 +99,7 @@ pub fn text_egui_e2e() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx, &Default::default(), None);
demo_windows.ui(&ctx, &Default::default(), &mut None);
let (_output, paint_jobs) = ctx.end_frame();
assert!(!paint_jobs.is_empty());
}

View file

@ -75,15 +75,19 @@ pub fn run(
raw_input.screen_size =
screen_size_in_pixels(&display) / raw_input.pixels_per_point.unwrap();
let backend_info = egui::app::BackendInfo {
web_info: None,
cpu_usage: previous_frame_time,
seconds_since_midnight: Some(seconds_since_midnight()),
native_pixels_per_point: Some(native_pixels_per_point(&display)),
};
ctx.begin_frame(raw_input.take());
let app_output = app.ui(&ctx, &backend_info, Some(&mut painter));
let mut integration_context = egui::app::IntegrationContext {
info: egui::app::IntegrationInfo {
web_info: None,
cpu_usage: previous_frame_time,
seconds_since_midnight: Some(seconds_since_midnight()),
native_pixels_per_point: Some(native_pixels_per_point(&display)),
},
tex_allocator: Some(&mut painter),
output: Default::default(),
};
app.ui(&ctx, &mut integration_context);
let app_output = integration_context.output;
let (egui_output, paint_jobs) = ctx.end_frame();
let frame_time = (Instant::now() - egui_start).as_secs_f64() as f32;

View file

@ -150,21 +150,24 @@ impl AppRunner {
resize_canvas_to_screen_size(self.web_backend.canvas_id());
let raw_input = self.web_input.new_frame(self.pixels_per_point);
self.web_backend.begin_frame(raw_input);
let backend_info = egui::app::BackendInfo {
web_info: Some(WebInfo {
web_location_hash: location_hash().unwrap_or_default(),
}),
cpu_usage: self.web_backend.previous_frame_time,
seconds_since_midnight: Some(seconds_since_midnight()),
native_pixels_per_point: Some(native_pixels_per_point()),
let mut integration_context = egui::app::IntegrationContext {
info: egui::app::IntegrationInfo {
web_info: Some(WebInfo {
web_location_hash: location_hash().unwrap_or_default(),
}),
cpu_usage: self.web_backend.previous_frame_time,
seconds_since_midnight: Some(seconds_since_midnight()),
native_pixels_per_point: Some(native_pixels_per_point()),
},
tex_allocator: Some(&mut self.web_backend.painter),
output: Default::default(),
};
self.web_backend.begin_frame(raw_input);
let egui_ctx = &self.web_backend.ctx;
let app_output = self
.app
.ui(egui_ctx, &backend_info, Some(&mut self.web_backend.painter));
self.app.ui(egui_ctx, &mut integration_context);
let app_output = integration_context.output;
let (egui_output, paint_jobs) = self.web_backend.end_frame()?;
handle_output(&egui_output);

View file

@ -16,9 +16,8 @@ impl egui::app::App for MyApp {
fn ui(
&mut self,
ctx: &std::sync::Arc<egui::Context>,
_info: &egui::app::BackendInfo,
_tex_allocator: Option<&mut dyn egui::app::TextureAllocator>,
) -> egui::app::AppOutput {
_integration_context: &mut egui::app::IntegrationContext,
) {
let MyApp { my_string, value } = self;
// Example used in `README.md`.
@ -30,8 +29,6 @@ impl egui::app::App for MyApp {
ui.text_edit(my_string);
ui.add(egui::Slider::f32(value, 0.0..=1.0).text("float"));
});
Default::default()
}
fn on_exit(&mut self, storage: &mut dyn egui::app::Storage) {