1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -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()) 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. /// Run the ui code for one frame.
/// ///
/// At most [`Options::max_passes`] calls will be issued to `run_ui`, /// At most [`Options::max_passes`] calls will be issued to `run_ui`,
@@ -781,8 +822,16 @@ impl Context {
/// }); /// });
/// // handle full_output /// // handle full_output
/// ``` /// ```
///
/// ## See also
/// * [`Self::run_ui`]
#[must_use] #[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!(); profiling::function_scope!();
let viewport_id = new_input.viewport_id; let viewport_id = new_input.viewport_id;
let max_passes = self.write(|ctx| ctx.memory.options.max_passes.get()); 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)) { pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
let ctx = Context::default(); let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), |ctx| { let _ = ctx.run_ui(Default::default(), |ui| {
run_ui(ctx); run_ui(ui.ctx());
}); });
} }
@@ -700,11 +700,9 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) { pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) {
let ctx = Context::default(); let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), |ctx| { let _ = ctx.run_ui(Default::default(), |ui| {
crate::CentralPanel::default().show(ctx, |ui| {
add_contents(ui); add_contents(ui);
}); });
});
} }
pub fn accesskit_root_id() -> Id { pub fn accesskit_root_id() -> Id {

View File

@@ -28,30 +28,24 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// The most end-to-end benchmark. // The most end-to-end benchmark.
c.bench_function("demo_with_tessellate__realistic", |b| { c.bench_function("demo_with_tessellate__realistic", |b| {
b.iter(|| { b.iter(|| {
let full_output = ctx.run(RawInput::default(), |ctx| { let full_output = ctx.run_ui(RawInput::default(), |ui| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui); demo_windows.ui(ui);
}); });
});
ctx.tessellate(full_output.shapes, full_output.pixels_per_point) ctx.tessellate(full_output.shapes, full_output.pixels_per_point)
}); });
}); });
c.bench_function("demo_no_tessellate", |b| { c.bench_function("demo_no_tessellate", |b| {
b.iter(|| { b.iter(|| {
ctx.run(RawInput::default(), |ctx| { ctx.run_ui(RawInput::default(), |ui| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui); demo_windows.ui(ui);
});
}) })
}); });
}); });
let full_output = ctx.run(RawInput::default(), |ctx| { let full_output = ctx.run_ui(RawInput::default(), |ui| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui); demo_windows.ui(ui);
}); });
});
c.bench_function("demo_only_tessellate", |b| { c.bench_function("demo_only_tessellate", |b| {
b.iter(|| ctx.tessellate(full_output.shapes.clone(), full_output.pixels_per_point)); 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(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_full_no_tessellate", |b| { c.bench_function("demo_full_no_tessellate", |b| {
b.iter(|| { b.iter(|| {
ctx.run(RawInput::default(), |ctx| { ctx.run_ui(RawInput::default(), |ui| {
egui::CentralPanel::default().show(ctx, |ui| {
demo_windows.ui(ui); demo_windows.ui(ui);
});
}) })
}); });
}); });

View File

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