1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 14:49:06 -04:00

Add Context::run_ui (#7736)

* Part of https://github.com/emilk/egui/issues/3524

Adds `Context::run_ui` as a convenience wrapper around `Context::run`.

This on the path to deprecate `run` and use a top-level `Ui` as the
entry-point for all of egui.
This commit is contained in:
Emil Ernerfeldt
2025-11-25 08:52:16 +01:00
committed by GitHub
parent 8d3539b6da
commit a624f37e2d
4 changed files with 66 additions and 31 deletions

View File

@@ -758,6 +758,47 @@ impl Context {
writer(&mut self.0.write())
}
/// Run the ui code for one frame.
///
/// At most [`Options::max_passes`] calls will be issued to `run_ui`,
/// and only on the rare occasion that [`Context::request_discard`] is called.
/// Usually, it `run_ui` will only be called once.
///
/// The [`Ui`] given to the callback will cover the entire [`Self::content_rect`],
/// with no margin or background color. Use [`crate::Frame`] to add that.
///
/// You can organize your GUI using [`crate::Panel`].
///
/// Instead of calling `run_ui`, you can alternatively use [`Self::begin_pass`] and [`Context::end_pass`].
///
/// ```
/// // One egui context that you keep reusing:
/// let mut ctx = egui::Context::default();
///
/// // Each frame:
/// let input = egui::RawInput::default();
/// let full_output = ctx.run_ui(input, |ui| {
/// ui.label("Hello egui!");
/// });
/// // handle full_output
/// ```
///
/// ## See also
/// * [`Self::run`]
#[must_use]
pub fn run_ui(&self, new_input: RawInput, mut run_ui: impl FnMut(&mut Ui)) -> FullOutput {
self.run_ui_dyn(new_input, &mut run_ui)
}
#[must_use]
fn run_ui_dyn(&self, new_input: RawInput, run_ui: &mut dyn FnMut(&mut Ui)) -> FullOutput {
self.run(new_input, |ctx| {
crate::CentralPanel::no_frame().show(ctx, |ui| {
run_ui(ui);
});
})
}
/// Run the ui code for one frame.
///
/// At most [`Options::max_passes`] calls will be issued to `run_ui`,
@@ -781,8 +822,16 @@ impl Context {
/// });
/// // handle full_output
/// ```
///
/// ## See also
/// * [`Self::run_ui`]
#[must_use]
pub fn run(&self, mut new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput {
pub fn run(&self, new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput {
self.run_dyn(new_input, &mut run_ui)
}
#[must_use]
fn run_dyn(&self, mut new_input: RawInput, run_ui: &mut dyn FnMut(&Self)) -> FullOutput {
profiling::function_scope!();
let viewport_id = new_input.viewport_id;
let max_passes = self.write(|ctx| ctx.memory.options.max_passes.get());

View File

@@ -691,8 +691,8 @@ pub enum WidgetType {
pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), |ctx| {
run_ui(ctx);
let _ = ctx.run_ui(Default::default(), |ui| {
run_ui(ui.ctx());
});
}
@@ -700,10 +700,8 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) {
let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), |ctx| {
crate::CentralPanel::default().show(ctx, |ui| {
add_contents(ui);
});
let _ = ctx.run_ui(Default::default(), |ui| {
add_contents(ui);
});
}

View File

@@ -28,10 +28,8 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// The most end-to-end benchmark.
c.bench_function("demo_with_tessellate__realistic", |b| {
b.iter(|| {
let full_output = ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
let full_output = ctx.run_ui(RawInput::default(), |ui| {
demo_windows.ui(ui);
});
ctx.tessellate(full_output.shapes, full_output.pixels_per_point)
});
@@ -39,18 +37,14 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_no_tessellate", |b| {
b.iter(|| {
ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
ctx.run_ui(RawInput::default(), |ui| {
demo_windows.ui(ui);
})
});
});
let full_output = ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
let full_output = ctx.run_ui(RawInput::default(), |ui| {
demo_windows.ui(ui);
});
c.bench_function("demo_only_tessellate", |b| {
b.iter(|| ctx.tessellate(full_output.shapes.clone(), full_output.pixels_per_point));
@@ -63,10 +57,8 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_full_no_tessellate", |b| {
b.iter(|| {
ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
ctx.run_ui(RawInput::default(), |ui| {
demo_windows.ui(ui);
})
});
});

View File

@@ -73,10 +73,8 @@ fn test_egui_e2e() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
let full_output = ctx.run_ui(raw_input.clone(), |ui| {
demo_windows.ui(ui);
});
let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point);
assert!(!clipped_primitives.is_empty());
@@ -94,10 +92,8 @@ fn test_egui_zero_window_size() {
const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui);
});
let full_output = ctx.run_ui(raw_input.clone(), |ui| {
demo_windows.ui(ui);
});
let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point);
assert!(