From 44a7cac046e15739d523fdb4451b8f4ae0609b0e Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 24 Oct 2020 10:56:23 +0200 Subject: [PATCH] `Context::begin_frame()` no longer returns anything. Put your widgets into a `SidePanel`, `TopPanel`, `Window` or into `ctx.background_ui()`. --- CHANGELOG.md | 2 ++ README.md | 4 ++-- egui/benches/benchmark.rs | 11 ++++++----- egui/src/app.rs | 5 +++-- egui/src/context.rs | 26 ++++++++++++++++++++------ egui/src/demos/app.rs | 11 ++++++----- egui/src/demos/demo_windows.rs | 4 +--- egui/src/lib.rs | 8 ++++---- egui_glium/src/backend.rs | 4 ++-- egui_web/src/backend.rs | 8 ++++---- example_glium/src/main.rs | 8 ++++---- 11 files changed, 54 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2286d854..45e7a72c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ * Panels: you can now create panels using `SidePanel` and `TopPanel`. * Fix a bug where some regions would slowly grow for non-integral scales (`pixels_per_point`). * You can no longer throw windows +* `Context::begin_frame()` no longer returns anything. + * Put your widgets into a `SidePanel`, `TopPanel`, `Window` or into `ctx.background_ui()`. ## 0.2.0 - 2020-10-10 diff --git a/README.md b/README.md index 9c85ef20..46c00a7c 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,8 @@ let mut egui_ctx = egui::Context::new(); // Game loop: loop { let raw_input: egui::RawInput = my_integration.gather_input(); - let mut ui = egui_ctx.begin_frame(raw_input); - my_app.ui(&mut ui); // add windows and widgets to `ui` here + egui_ctx.begin_frame(raw_input); + my_app.ui(&mut egui_ctx); // add panels, windows and widgets to `egui_ctx` here let (output, paint_jobs) = egui_ctx.end_frame(); my_integration.paint(paint_jobs); my_integration.set_cursor_icon(output.cursor_icon); diff --git a/egui/benches/benchmark.rs b/egui/benches/benchmark.rs index 7ab1c251..c396316b 100644 --- a/egui/benches/benchmark.rs +++ b/egui/benches/benchmark.rs @@ -12,8 +12,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_windows_minimal", |b| { b.iter(|| { - let mut ui = ctx.begin_frame(raw_input.clone()); - demo_windows.ui(&mut ui, &Default::default(), None); + ctx.begin_frame(raw_input.clone()); + demo_windows.ui(&ctx, &Default::default(), None); ctx.end_frame() }) }); @@ -26,8 +26,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_windows_full", |b| { b.iter(|| { - let mut ui = ctx.begin_frame(raw_input.clone()); - demo_windows.ui(&mut ui, &Default::default(), None); + ctx.begin_frame(raw_input.clone()); + demo_windows.ui(&ctx, &Default::default(), None); ctx.end_frame() }) }); @@ -35,7 +35,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let mut ctx = egui::Context::new(); - let mut ui = ctx.begin_frame(raw_input); + ctx.begin_frame(raw_input); + let mut ui = ctx.background_ui(); c.bench_function("label", |b| { b.iter(|| { ui.label(egui::demos::LOREM_IPSUM_LONG); diff --git a/egui/src/app.rs b/egui/src/app.rs index 536e7043..c399e812 100644 --- a/egui/src/app.rs +++ b/egui/src/app.rs @@ -7,15 +7,16 @@ // TODO: move egui/src/app.rs to own crate, e.g. egui_framework ? -use crate::Ui; +use crate::Context; /// Implement this trait to write apps that can be compiled both natively using the [`egui_glium`](https://crates.io/crates/egui_glium) crate, /// and deployed as a web site using the [`egui_web`](https://crates.io/crates/egui_web) crate. pub trait App { /// Called each time the UI needs repainting, which may be many times per second. + /// Put your widgets into a `SidePanel`, `TopPanel`, `Window` or into `ctx.background_ui()`. fn ui( &mut self, - ui: &mut Ui, + ctx: &std::sync::Arc, info: &BackendInfo, tex_allocator: Option<&mut dyn TextureAllocator>, ) -> AppOutput; diff --git a/egui/src/context.rs b/egui/src/context.rs index 06f8bae5..d3200850 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -43,6 +43,7 @@ pub struct Context { input: InputState, /// Starts off as the screen_rect, shrinks as panels are added. + /// Becomes `Rect::nothing()` when `Context::background_ui` is called. available_rect: Mutex>, // The output of a frame: @@ -198,12 +199,14 @@ impl Context { // --------------------------------------------------------------------- /// Call at the start of every frame. - /// Returns a master fullscreen UI, covering the entire screen. - pub fn begin_frame(self: &mut Arc, new_input: RawInput) -> Ui { + /// To get a `Ui` to place widgets into you one or more of: + /// * `SidePanel` or `TopPanel` + /// * `Window` + /// * `Context::background_ui()` + pub fn begin_frame(self: &mut Arc, new_input: RawInput) { let mut self_: Self = (**self).clone(); self_.begin_frame_mut(new_input); *self = Arc::new(self_); - self.fullscreen_ui() } fn begin_frame_mut(&mut self, new_raw_input: RawInput) { @@ -275,9 +278,20 @@ impl Context { // --------------------------------------------------------------------- - /// A `Ui` for the entire screen, behind any windows. - fn fullscreen_ui(self: &Arc) -> Ui { - let rect = self.input.screen_rect(); + /// A `Ui` that covers the whole background (not used by panels). + /// + /// This is the same area that `Window`s are put in to, + /// so either put your UI into `background_ui()` or into `Window`s. + /// + /// Call this at most once per frame. + pub fn background_ui(self: &Arc) -> Ui { + let rect = self.available_rect(); + debug_assert!( + rect != Rect::nothing(), + "You already called `background_ui()` once this frame!" + ); + *self.available_rect.lock() = Some(Rect::nothing()); // Nothing left after this + let layer_id = LayerId::background(); Ui::new(self.clone(), layer_id, layer_id.id, rect, rect) } diff --git a/egui/src/demos/app.rs b/egui/src/demos/app.rs index 8719572f..5f1ee686 100644 --- a/egui/src/demos/app.rs +++ b/egui/src/demos/app.rs @@ -1,4 +1,5 @@ -use crate::{app, demos, History, Ui}; +use crate::{app, demos, Context, History, Ui}; +use std::sync::Arc; // ---------------------------------------------------------------------------- @@ -274,7 +275,7 @@ impl DemoApp { impl app::App for DemoApp { fn ui( &mut self, - ui: &mut Ui, + ctx: &Arc, info: &app::BackendInfo, tex_allocator: Option<&mut dyn app::TextureAllocator>, ) -> app::AppOutput { @@ -295,20 +296,20 @@ impl app::App for DemoApp { link, }; - self.demo_windows.ui(ui, &demo_environment, tex_allocator); + self.demo_windows.ui(ctx, &demo_environment, tex_allocator); let mut output = app::AppOutput::default(); crate::Window::new("Backend") .min_width(360.0) .scroll(false) - .show(ui.ctx(), |ui| { + .show(ctx, |ui| { output = self.backend_ui(ui, info); }); if self.run_mode == RunMode::Continuous { // Tell the backend to repaint as soon as possible - ui.ctx().request_repaint(); + ctx.request_repaint(); } output diff --git a/egui/src/demos/demo_windows.rs b/egui/src/demos/demo_windows.rs index 52ac7037..7a38b45c 100644 --- a/egui/src/demos/demo_windows.rs +++ b/egui/src/demos/demo_windows.rs @@ -44,12 +44,10 @@ impl DemoWindows { /// Show the app ui (menu bar and windows). pub fn ui( &mut self, - ui: &mut Ui, + ctx: &Arc, env: &DemoEnvironment, tex_allocator: Option<&mut dyn app::TextureAllocator>, ) { - let ctx = ui.ctx(); - if self.previous_link != env.link { match env.link { None => {} diff --git a/egui/src/lib.rs b/egui/src/lib.rs index 3374ffd1..a32391be 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -11,8 +11,8 @@ //! // Game loop: //! loop { //! let raw_input: egui::RawInput = my_integration.gather_input(); -//! let mut ui = egui_ctx.begin_frame(raw_input); -//! my_app.ui(&mut ui); // add windows and widgets to `ui` here +//! egui_ctx.begin_frame(raw_input); +//! my_app.ui(&egui_ctx); // add panels, windows and widgets to `egui_ctx` here //! let (output, paint_jobs) = egui_ctx.end_frame(); //! my_integration.paint(paint_jobs); //! my_integration.set_cursor_icon(output.cursor_icon); @@ -98,8 +98,8 @@ pub fn text_egui_e2e() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { - let mut ui = ctx.begin_frame(raw_input.clone()); - demo_windows.ui(&mut ui, &Default::default(), None); + ctx.begin_frame(raw_input.clone()); + demo_windows.ui(&ctx, &Default::default(), None); let (_output, paint_jobs) = ctx.end_frame(); assert!(!paint_jobs.is_empty()); } diff --git a/egui_glium/src/backend.rs b/egui_glium/src/backend.rs index c5eaabb1..be1a5a8f 100644 --- a/egui_glium/src/backend.rs +++ b/egui_glium/src/backend.rs @@ -77,8 +77,8 @@ pub fn run( native_pixels_per_point: Some(native_pixels_per_point(&display)), }; - let mut ui = ctx.begin_frame(raw_input.take()); - let app_output = app.ui(&mut ui, &backend_info, Some(&mut painter)); + ctx.begin_frame(raw_input.take()); + let app_output = app.ui(&ctx, &backend_info, Some(&mut painter)); let (egui_output, paint_jobs) = ctx.end_frame(); let frame_time = (Instant::now() - egui_start).as_secs_f64() as f32; diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index 4884c81b..e26a5b00 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -33,8 +33,7 @@ impl WebBackend { self.painter.canvas_id() } - /// Returns a master fullscreen UI, covering the entire screen. - pub fn begin_frame(&mut self, raw_input: egui::RawInput) -> egui::Ui { + pub fn begin_frame(&mut self, raw_input: egui::RawInput) { self.frame_start = Some(now_sec()); self.ctx.begin_frame(raw_input) } @@ -161,10 +160,11 @@ impl AppRunner { native_pixels_per_point: Some(native_pixels_per_point()), }; - let mut ui = self.web_backend.begin_frame(raw_input); + self.web_backend.begin_frame(raw_input); + let egui_ctx = &self.web_backend.ctx; let app_output = self .app - .ui(&mut ui, &backend_info, Some(&mut self.web_backend.painter)); + .ui(egui_ctx, &backend_info, Some(&mut self.web_backend.painter)); let (egui_output, paint_jobs) = self.web_backend.end_frame()?; handle_output(&egui_output); diff --git a/example_glium/src/main.rs b/example_glium/src/main.rs index 5ca5bc9b..e335c9ff 100644 --- a/example_glium/src/main.rs +++ b/example_glium/src/main.rs @@ -11,18 +11,18 @@ struct MyApp { } impl egui::app::App for MyApp { - /// This function will be called whenever the Ui needs to be shown, - /// which may be many times per second. + /// Called each time the UI needs repainting, which may be many times per second. + /// Put your widgets into a `SidePanel`, `TopPanel`, `Window` or into `ctx.background_ui()`. fn ui( &mut self, - ui: &mut egui::Ui, + ctx: &std::sync::Arc, _info: &egui::app::BackendInfo, _tex_allocator: Option<&mut dyn egui::app::TextureAllocator>, ) -> egui::app::AppOutput { let MyApp { my_string, value } = self; // Example used in `README.md`. - egui::Window::new("Debug").show(ui.ctx(), |ui| { + egui::Window::new("Debug").show(ctx, |ui| { ui.label(format!("Hello, world {}", 123)); if ui.button("Save").clicked { my_save_function();