`Context::begin_frame()` no longer returns anything.

Put your widgets into a `SidePanel`, `TopPanel`,
`Window` or into `ctx.background_ui()`.
This commit is contained in:
Emil Ernerfeldt 2020-10-24 10:56:23 +02:00
parent f86cb4a923
commit 44a7cac046
11 changed files with 54 additions and 37 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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<Context>,
info: &BackendInfo,
tex_allocator: Option<&mut dyn TextureAllocator>,
) -> AppOutput;

View File

@ -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<Option<Rect>>,
// 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<Self>, 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<Self>, 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<Self>) -> 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<Self>) -> 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)
}

View File

@ -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<Context>,
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

View File

@ -44,12 +44,10 @@ impl DemoWindows {
/// Show the app ui (menu bar and windows).
pub fn ui(
&mut self,
ui: &mut Ui,
ctx: &Arc<Context>,
env: &DemoEnvironment,
tex_allocator: Option<&mut dyn app::TextureAllocator>,
) {
let ctx = ui.ctx();
if self.previous_link != env.link {
match env.link {
None => {}

View File

@ -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());
}

View File

@ -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;

View File

@ -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);

View File

@ -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<egui::Context>,
_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();