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

eframe: Replace Frame::update with fn logic and fn ui (#7775)

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

## What
This deprecates `eframe::App::update` and replaces it with two new
functions:

```rs
pub trait App {
	/// Called just before `ui`, and in the future this will
    /// also be called for background apps when needed.
	fn logic(&mut self, ctx: &egui::Context, frame: &mut Frame) { }
	
    /// Show your user interface to the user.
	fn ui(&mut self, ui: &mut egui::Ui, frame: &mut Frame);

	…
}
```

Similarly, `Context::run` is deprecated in favor of `Context::run_ui`.

`Plugin`s are now handed a `Ui` instead of just a `Context` in
`on_begin/end_frame`.

## TODO
…either in this PR or a later one
* [x] Deprecate `App::update`
* [x] Deprecate `Context::run`
* [x] Change plugins to get a `Ui`
* [x] Update kittest
* [x] Change viewports to get UI:s (`show_viewport_immediate` etc)
  - https://github.com/emilk/egui/pull/7779

## Later PRs
* [ ] Deprecate `Panel::show`
* [ ] Deprecate `CentralPanel::show`
* [ ] Deprecate `CentralPanel` ?
This commit is contained in:
Emil Ernerfeldt
2025-12-16 17:05:50 +01:00
committed by GitHub
parent 9487dc35ec
commit 2f6fe9c572
52 changed files with 417 additions and 321 deletions

View File

@@ -135,6 +135,31 @@ impl CreationContext<'_> {
/// Implement this trait to write apps that can be compiled for both web/wasm and desktop/native using [`eframe`](https://github.com/emilk/egui/tree/main/crates/eframe).
pub trait App {
/// Called once before each call to [`Self::ui`],
/// and additionally also called when the UI is hidden, but [`egui::Context::request_repaint`] was called.
///
/// You may NOT show any ui or do any painting during the call to [`Self::logic`].
///
/// The [`egui::Context`] can be cloned and saved if you like.
///
/// To force another call to [`Self::logic`], call [`egui::Context::request_repaint`] at any time (e.g. from another thread).
fn logic(&mut self, ctx: &egui::Context, frame: &mut Frame) {
_ = (ctx, frame);
}
/// Called each time the UI needs repainting, which may be many times per second.
///
/// The given [`egui::Ui`] has no margin or background color.
/// You can wrap your UI code in [`egui::CentralPanel`] or a [`egui::Frame::central_panel`] to remedy this.
///
/// The [`egui::Ui::ctx`] can be cloned and saved if you like.
/// To force a repaint, call [`egui::Context::request_repaint`] at any time (e.g. from another thread).
///
/// This is called for the root viewport ([`egui::ViewportId::ROOT`]).
/// Use [`egui::Context::show_viewport_deferred`] to spawn additional viewports (windows).
/// (A "viewport" in egui means an native OS window).
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut Frame);
/// Called each time the UI needs repainting, which may be many times per second.
///
/// Put your widgets into a [`egui::Panel`], [`egui::CentralPanel`], [`egui::Window`] or [`egui::Area`].
@@ -146,7 +171,10 @@ pub trait App {
/// This is called for the root viewport ([`egui::ViewportId::ROOT`]).
/// Use [`egui::Context::show_viewport_deferred`] to spawn additional viewports (windows).
/// (A "viewport" in egui means an native OS window).
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame);
#[deprecated = "Use Self::ui instead"]
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame) {
_ = (ctx, frame);
}
/// Get a handle to the app.
///

View File

@@ -35,7 +35,7 @@
//!
//! impl MyEguiApp {
//! fn new(cc: &eframe::CreationContext<'_>) -> Self {
//! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
//! // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_global_style.
//! // Restore app state using cc.storage (requires the "persistence" feature).
//! // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
//! // for e.g. egui::PaintCallback.
@@ -44,8 +44,8 @@
//! }
//!
//! impl eframe::App for MyEguiApp {
//! fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
//! egui::CentralPanel::default().show(ctx, |ui| {
//! fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
//! egui::CentralPanel::default().show_inside(ui, |ui| {
//! ui.heading("Hello World!");
//! });
//! }
@@ -232,7 +232,7 @@ pub mod icon_data;
///
/// impl MyEguiApp {
/// fn new(cc: &eframe::CreationContext<'_>) -> Self {
/// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_visuals.
/// // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_global_style.
/// // Restore app state using cc.storage (requires the "persistence" feature).
/// // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use
/// // for e.g. egui::PaintCallback.
@@ -241,8 +241,8 @@ pub mod icon_data;
/// }
///
/// impl eframe::App for MyEguiApp {
/// fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// ui.heading("Hello World!");
/// });
/// }
@@ -312,8 +312,8 @@ pub fn run_native(
/// }
///
/// impl eframe::App for MyEguiApp {
/// fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// ui.heading("Hello World!");
/// });
/// }
@@ -399,8 +399,9 @@ fn init_native(app_name: &str, native_options: &mut NativeOptions) -> Renderer {
/// let mut age = 42;
///
/// let options = eframe::NativeOptions::default();
/// eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// eframe::run_ui_native("My egui App", options, move |ui, _frame| {
/// // Wrap everything in a CentralPanel so we get some margins and a background color:
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// ui.heading("My egui Application");
/// ui.horizontal(|ui| {
/// let name_label = ui.label("Your name: ");
@@ -421,6 +422,65 @@ fn init_native(app_name: &str, native_options: &mut NativeOptions) -> Renderer {
/// This function can fail if we fail to set up a graphics context.
#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu_no_default_features"))]
pub fn run_ui_native(
app_name: &str,
native_options: NativeOptions,
ui_fun: impl FnMut(&mut egui::Ui, &mut Frame) + 'static,
) -> Result {
struct SimpleApp<U> {
ui_fun: U,
}
impl<U: FnMut(&mut egui::Ui, &mut Frame) + 'static> App for SimpleApp<U> {
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut Frame) {
(self.ui_fun)(ui, frame);
}
}
run_native(
app_name,
native_options,
Box::new(|_cc| Ok(Box::new(SimpleApp { ui_fun }))),
)
}
/// The simplest way to get started when writing a native app.
///
/// This does NOT support persistence of custom user data. For that you need to use [`run_native`].
/// However, it DOES support persistence of egui data (window positions and sizes, how far the user has scrolled in a
/// [`ScrollArea`](egui::ScrollArea), etc.) if the persistence feature is enabled.
///
/// # Example
/// ``` no_run
/// fn main() -> eframe::Result {
/// // Our application state:
/// let mut name = "Arthur".to_owned();
/// let mut age = 42;
///
/// let options = eframe::NativeOptions::default();
/// eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
/// egui::CentralPanel::default().show(ctx, |ui| {
/// ui.heading("My egui Application");
/// ui.horizontal(|ui| {
/// let name_label = ui.label("Your name: ");
/// ui.text_edit_singleline(&mut name)
/// .labelled_by(name_label.id);
/// });
/// ui.add(egui::Slider::new(&mut age, 0..=120).text("age"));
/// if ui.button("Increment").clicked() {
/// age += 1;
/// }
/// ui.label(format!("Hello '{name}', age {age}"));
/// });
/// })
/// }
/// ```
///
/// # Errors
/// This function can fail if we fail to set up a graphics context.
#[deprecated = "Use run_ui_native instead"]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(any(feature = "glow", feature = "wgpu_no_default_features"))]
pub fn run_simple_native(
app_name: &str,
native_options: NativeOptions,
@@ -431,6 +491,8 @@ pub fn run_simple_native(
}
impl<U: FnMut(&egui::Context, &mut Frame) + 'static> App for SimpleApp<U> {
fn ui(&mut self, _ui: &mut egui::Ui, _frame: &mut Frame) {}
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame) {
(self.update_fun)(ctx, frame);
}

View File

@@ -272,14 +272,27 @@ impl EpiIntegration {
app.raw_input_hook(&self.egui_ctx, &mut raw_input);
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
let full_output = self.egui_ctx.run_ui(raw_input, |ui| {
if let Some(viewport_ui_cb) = viewport_ui_cb {
// Child viewport
profiling::scope!("viewport_callback");
viewport_ui_cb(egui_ctx);
viewport_ui_cb(ui);
} else {
{
profiling::scope!("App::logic");
app.logic(ui.ctx(), &mut self.frame);
}
{
profiling::scope!("App::update");
app.update(egui_ctx, &mut self.frame);
#[expect(deprecated)]
app.update(ui.ctx(), &mut self.frame);
}
{
profiling::scope!("App::ui");
app.ui(ui, &mut self.frame);
}
}
});

View File

@@ -1362,7 +1362,7 @@ fn initialize_or_update_viewport(
ids: ViewportIdPair,
class: ViewportClass,
mut builder: ViewportBuilder,
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
viewport_ui_cb: Option<Arc<dyn Fn(&mut egui::Ui) + Send + Sync>>,
) -> &mut Viewport {
profiling::function_scope!();
@@ -1494,8 +1494,8 @@ fn render_immediate_viewport(
shapes,
pixels_per_point,
viewport_output,
} = egui_ctx.run(input, |ctx| {
viewport_ui_cb(ctx);
} = egui_ctx.run_ui(input, |ui| {
viewport_ui_cb(ui);
});
// ---------------------------------------------------

View File

@@ -1027,8 +1027,8 @@ fn render_immediate_viewport(
shapes,
pixels_per_point,
viewport_output,
} = egui_ctx.run(input, |ctx| {
viewport_ui_cb(ctx);
} = egui_ctx.run_ui(input, |ui| {
viewport_ui_cb(ui);
});
// ------------------------------------------
@@ -1155,7 +1155,7 @@ fn initialize_or_update_viewport<'a>(
ids: ViewportIdPair,
class: ViewportClass,
mut builder: ViewportBuilder,
viewport_ui_cb: Option<Arc<dyn Fn(&egui::Context) + Send + Sync>>,
viewport_ui_cb: Option<Arc<dyn Fn(&mut egui::Ui) + Send + Sync>>,
painter: &mut egui_wgpu::winit::Painter,
) -> &'a mut Viewport {
use std::collections::btree_map::Entry;

View File

@@ -273,8 +273,13 @@ impl AppRunner {
self.app.raw_input_hook(&self.egui_ctx, &mut raw_input);
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
self.app.update(egui_ctx, &mut self.frame);
let full_output = self.egui_ctx.run_ui(raw_input, |ui| {
self.app.logic(ui.ctx(), &mut self.frame);
#[expect(deprecated)]
self.app.update(ui.ctx(), &mut self.frame);
self.app.ui(ui, &mut self.frame);
});
let egui::FullOutput {
platform_output,

View File

@@ -291,13 +291,13 @@ impl<'a> PanelSizer<'a> {
/// See the [module level docs](crate::containers::panel) for more details.
///
/// ```
/// # egui::__run_test_ctx(|ctx| {
/// egui::Panel::left("my_left_panel").show(ctx, |ui| {
/// # egui::__run_test_ui(|ui| {
/// egui::Panel::left("my_left_panel").show_inside(ui, |ui| {
/// ui.label("Hello World!");
/// });
/// # });
/// ```
#[must_use = "You should call .show()"]
#[must_use = "You should call .show_inside()"]
pub struct Panel {
side: PanelSide,
id: Id,
@@ -963,16 +963,16 @@ impl Panel {
/// See the [module level docs](crate::containers::panel) for more details.
///
/// ```
/// # egui::__run_test_ctx(|ctx| {
/// egui::Panel::top("my_panel").show(ctx, |ui| {
/// # egui::__run_test_ui(|ui| {
/// egui::Panel::top("my_panel").show_inside(ui, |ui| {
/// ui.label("Hello World! From `Panel`, that must be before `CentralPanel`!");
/// });
/// egui::CentralPanel::default().show(ctx, |ui| {
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// ui.label("Hello World!");
/// });
/// # });
/// ```
#[must_use = "You should call .show()"]
#[must_use = "You should call .show_inside()"]
#[derive(Default)]
pub struct CentralPanel {
frame: Option<Frame>,

View File

@@ -790,9 +790,13 @@ impl Context {
#[must_use]
fn run_ui_dyn(&self, new_input: RawInput, run_ui: &mut dyn FnMut(&mut Ui)) -> FullOutput {
let plugins = self.read(|ctx| ctx.plugins.ordered_plugins());
#[expect(deprecated)]
self.run(new_input, |ctx| {
crate::CentralPanel::no_frame().show(ctx, |ui| {
plugins.on_begin_pass(ui);
run_ui(ui);
plugins.on_end_pass(ui);
});
})
}
@@ -824,6 +828,7 @@ impl Context {
/// ## See also
/// * [`Self::run_ui`]
#[must_use]
#[deprecated = "Call run_ui instead"]
pub fn run(&self, new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput {
self.run_dyn(new_input, &mut run_ui)
}
@@ -924,9 +929,6 @@ impl Context {
plugins.on_input(&mut new_input);
self.write(|ctx| ctx.begin_pass(new_input));
// Plugins run just after the pass starts:
plugins.on_begin_pass(self);
}
/// See [`Self::begin_pass`].
@@ -2378,15 +2380,14 @@ impl Context {
crate::gui_zoom::zoom_with_keyboard(self);
}
// Plugins run just before the pass ends.
let plugins = self.read(|ctx| ctx.plugins.ordered_plugins());
plugins.on_end_pass(self);
#[cfg(debug_assertions)]
self.debug_painting();
let mut output = self.write(|ctx| ctx.end_pass());
let plugins = self.read(|ctx| ctx.plugins.ordered_plugins());
plugins.on_output(&mut output);
output
}
@@ -4039,10 +4040,8 @@ impl Context {
viewport.class = ViewportClass::Deferred;
viewport.builder = viewport_builder;
viewport.used = true;
viewport.viewport_ui_cb = Some(Arc::new(move |ctx| {
crate::CentralPanel::no_frame().show(ctx, |ui| {
viewport.viewport_ui_cb = Some(Arc::new(move |ui| {
(viewport_ui_cb)(ui, ViewportClass::Deferred);
});
}));
});
}
@@ -4118,10 +4117,8 @@ impl Context {
let viewport = ImmediateViewport {
ids,
builder,
viewport_ui_cb: Box::new(move |ctx| {
crate::CentralPanel::no_frame().show(ctx, |ui| {
viewport_ui_cb: Box::new(move |ui| {
*out = Some((viewport_ui_cb)(ui, ViewportClass::Immediate));
});
}),
};
@@ -4246,11 +4243,11 @@ mod test {
// A single call, no request to discard:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
let output = ctx.run_ui(Default::default(), |ui| {
num_calls += 1;
assert_eq!(ctx.output(|o| o.num_completed_passes), 0);
assert!(!ctx.output(|o| o.requested_discard()));
assert!(!ctx.will_discard());
assert_eq!(ui.output(|o| o.num_completed_passes), 0);
assert!(!ui.output(|o| o.requested_discard()));
assert!(!ui.will_discard());
});
assert_eq!(num_calls, 1);
assert_eq!(output.platform_output.num_completed_passes, 1);
@@ -4260,10 +4257,10 @@ mod test {
// A single call, with a denied request to discard:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
let output = ctx.run_ui(Default::default(), |ui| {
num_calls += 1;
ctx.request_discard("test");
assert!(!ctx.will_discard(), "The request should have been denied");
ui.request_discard("test");
assert!(!ui.will_discard(), "The request should have been denied");
});
assert_eq!(num_calls, 1);
assert_eq!(output.platform_output.num_completed_passes, 1);
@@ -4291,10 +4288,10 @@ mod test {
// Normal single pass:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
assert_eq!(ctx.output(|o| o.num_completed_passes), 0);
assert!(!ctx.output(|o| o.requested_discard()));
assert!(!ctx.will_discard());
let output = ctx.run_ui(Default::default(), |ui| {
assert_eq!(ui.output(|o| o.num_completed_passes), 0);
assert!(!ui.output(|o| o.requested_discard()));
assert!(!ui.will_discard());
num_calls += 1;
});
assert_eq!(num_calls, 1);
@@ -4305,13 +4302,13 @@ mod test {
// Request discard once:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
let output = ctx.run_ui(Default::default(), |ui| {
assert_eq!(ui.output(|o| o.num_completed_passes), num_calls);
assert!(!ctx.will_discard());
assert!(!ui.will_discard());
if num_calls == 0 {
ctx.request_discard("test");
assert!(ctx.will_discard());
ui.request_discard("test");
assert!(ui.will_discard());
}
num_calls += 1;
@@ -4327,15 +4324,15 @@ mod test {
// Request discard twice:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
let output = ctx.run_ui(Default::default(), |ui| {
assert_eq!(ui.output(|o| o.num_completed_passes), num_calls);
assert!(!ctx.will_discard());
ctx.request_discard("test");
assert!(!ui.will_discard());
ui.request_discard("test");
if num_calls == 0 {
assert!(ctx.will_discard(), "First request granted");
assert!(ui.will_discard(), "First request granted");
} else {
assert!(!ctx.will_discard(), "Second request should be denied");
assert!(!ui.will_discard(), "Second request should be denied");
}
num_calls += 1;
@@ -4357,13 +4354,13 @@ mod test {
// Request discard three times:
{
let mut num_calls = 0;
let output = ctx.run(Default::default(), |ctx| {
assert_eq!(ctx.output(|o| o.num_completed_passes), num_calls);
let output = ctx.run_ui(Default::default(), |ui| {
assert_eq!(ui.output(|o| o.num_completed_passes), num_calls);
assert!(!ctx.will_discard());
assert!(!ui.will_discard());
if num_calls <= 2 {
ctx.request_discard("test");
assert!(ctx.will_discard());
ui.request_discard("test");
assert!(ui.will_discard());
}
num_calls += 1;

View File

@@ -5,7 +5,7 @@
//! to get callbacks on certain events ([`Plugin::on_begin_pass`], [`Plugin::on_end_pass`]).
use crate::{
Align, Align2, Color32, Context, FontFamily, FontId, Plugin, Rect, Shape, Vec2, WidgetText,
Align, Align2, Color32, Context, FontFamily, FontId, Plugin, Rect, Shape, Ui, Vec2, WidgetText,
text,
};
@@ -57,9 +57,9 @@ impl Plugin for DebugTextPlugin {
"DebugTextPlugin"
}
fn on_end_pass(&mut self, ctx: &Context) {
fn on_end_pass(&mut self, ui: &mut Ui) {
let entries = std::mem::take(&mut self.entries);
Self::paint_entries(ctx, entries);
Self::paint_entries(ui, entries);
}
}

View File

@@ -1,6 +1,6 @@
use std::{any::Any, sync::Arc};
use crate::{Context, CursorIcon, Plugin};
use crate::{Context, CursorIcon, Plugin, Ui};
/// Plugin for tracking drag-and-drop payload.
///
@@ -32,12 +32,12 @@ impl Plugin for DragAndDrop {
/// Interrupt drag-and-drop if the user presses the escape key.
///
/// This needs to happen at frame start so we can properly capture the escape key.
fn on_begin_pass(&mut self, ctx: &Context) {
fn on_begin_pass(&mut self, ui: &mut Ui) {
let has_any_payload = self.payload.is_some();
if has_any_payload {
let abort_dnd_due_to_escape_key =
ctx.input_mut(|i| i.consume_key(crate::Modifiers::NONE, crate::Key::Escape));
ui.input_mut(|i| i.consume_key(crate::Modifiers::NONE, crate::Key::Escape));
if abort_dnd_due_to_escape_key {
self.payload = None;
@@ -50,18 +50,18 @@ impl Plugin for DragAndDrop {
/// This is a catch-all safety net in case user code doesn't capture the drag payload itself.
/// This must happen at end-of-frame such that we don't shadow the mouse release event from user
/// code.
fn on_end_pass(&mut self, ctx: &Context) {
fn on_end_pass(&mut self, ui: &mut Ui) {
let has_any_payload = self.payload.is_some();
if has_any_payload {
let abort_dnd_due_to_mouse_release = ctx.input_mut(|i| i.pointer.any_released());
let abort_dnd_due_to_mouse_release = ui.input_mut(|i| i.pointer.any_released());
if abort_dnd_due_to_mouse_release {
self.payload = None;
} else {
// We set the cursor icon only if its default, as the user code might have
// explicitly set it already.
ctx.output_mut(|o| {
ui.output_mut(|o| {
if o.cursor_icon == CursorIcon::Default {
o.cursor_icon = CursorIcon::Grabbing;
}

View File

@@ -43,23 +43,6 @@
//! In some GUI frameworks this would require defining multiple types and functions with callbacks or message handlers,
//! but thanks to `egui` being immediate mode everything is one self-contained function!
//!
//! ### Getting a [`Ui`]
//!
//! Use one of [`Panel`], [`CentralPanel`], [`Window`] or [`Area`] to
//! get access to an [`Ui`] where you can put widgets. For example:
//!
//! ```
//! # egui::__run_test_ctx(|ctx| {
//! egui::CentralPanel::default().show(&ctx, |ui| {
//! ui.add(egui::Label::new("Hello World!"));
//! ui.label("A shorter and more convenient way to add a label.");
//! if ui.button("Click me").clicked() {
//! // take some action here
//! }
//! });
//! # });
//! ```
//!
//! ### Quick start
//!
//! ```

View File

@@ -1,4 +1,4 @@
use crate::{Context, FullOutput, RawInput};
use crate::{Context, FullOutput, RawInput, Ui};
use ahash::HashMap;
use epaint::mutex::{Mutex, MutexGuard};
use std::sync::Arc;
@@ -23,13 +23,13 @@ pub trait Plugin: Send + Sync + std::any::Any + 'static {
/// Called at the start of each pass.
///
/// Can be used to show ui, e.g. a [`crate::Window`] or [`crate::SidePanel`].
fn on_begin_pass(&mut self, ctx: &Context) {}
/// Can be used to show ui, e.g. a [`crate::Window`] or [`crate::Panel`].
fn on_begin_pass(&mut self, ui: &mut Ui) {}
/// Called at the end of each pass.
///
/// Can be used to show ui, e.g. a [`crate::Window`].
fn on_end_pass(&mut self, ctx: &Context) {}
fn on_end_pass(&mut self, ui: &mut Ui) {}
/// Called just before the input is processed.
///
@@ -147,17 +147,17 @@ impl PluginsOrdered {
}
}
pub fn on_begin_pass(&self, ctx: &Context) {
pub fn on_begin_pass(&self, ui: &mut Ui) {
profiling::scope!("plugins", "on_begin_pass");
self.for_each_dyn(|p| {
p.on_begin_pass(ctx);
p.on_begin_pass(ui);
});
}
pub fn on_end_pass(&self, ctx: &Context) {
pub fn on_end_pass(&self, ui: &mut Ui) {
profiling::scope!("plugins", "on_end_pass");
self.for_each_dyn(|p| {
p.on_end_pass(ctx);
p.on_end_pass(ui);
});
}
@@ -214,7 +214,7 @@ impl Plugins {
}
/// Generic event callback.
pub type ContextCallback = Arc<dyn Fn(&Context) + Send + Sync>;
pub type ContextCallback = Arc<dyn Fn(&mut Ui) + Send + Sync>;
#[derive(Default)]
pub(crate) struct CallbackPlugin {
@@ -227,21 +227,21 @@ impl Plugin for CallbackPlugin {
"CallbackPlugins"
}
fn on_begin_pass(&mut self, ctx: &Context) {
fn on_begin_pass(&mut self, ui: &mut Ui) {
profiling::function_scope!();
for (_debug_name, cb) in &self.on_begin_plugins {
profiling::scope!("on_begin_pass", *_debug_name);
(cb)(ctx);
(cb)(ui);
}
}
fn on_end_pass(&mut self, ctx: &Context) {
fn on_end_pass(&mut self, ui: &mut Ui) {
profiling::function_scope!();
for (_debug_name, cb) in &self.on_end_plugins {
profiling::scope!("on_end_pass", *_debug_name);
(cb)(ctx);
(cb)(ui);
}
}
}

View File

@@ -128,8 +128,8 @@ impl Plugin for LabelSelectionState {
"LabelSelectionState"
}
fn on_begin_pass(&mut self, ctx: &Context) {
if ctx.input(|i| i.pointer.any_pressed() && !i.modifiers.shift) {
fn on_begin_pass(&mut self, ui: &mut Ui) {
if ui.input(|i| i.pointer.any_pressed() && !i.modifiers.shift) {
// Maybe a new selection is about to begin, but the old one is over:
// state.selection = None; // TODO(emilk): this makes sense, but doesn't work as expected.
}
@@ -145,9 +145,9 @@ impl Plugin for LabelSelectionState {
self.painted_selections.clear();
}
fn on_end_pass(&mut self, ctx: &Context) {
fn on_end_pass(&mut self, ui: &mut Ui) {
if self.is_dragging {
ctx.set_cursor_icon(CursorIcon::Text);
ui.set_cursor_icon(CursorIcon::Text);
}
if !self.has_reached_primary || !self.has_reached_secondary {
@@ -159,7 +159,7 @@ impl Plugin for LabelSelectionState {
if let Some(selection) = prev_selection {
// This was the first frame of glitch, so hide the
// glitching by removing all painted selections:
ctx.graphics_mut(|layers| {
ui.graphics_mut(|layers| {
if let Some(list) = layers.get_mut(selection.layer_id) {
for (shape_idx, row_selections) in self.painted_selections.drain(..) {
list.mutate_shape(shape_idx, |shape| {
@@ -190,21 +190,21 @@ impl Plugin for LabelSelectionState {
}
}
let pressed_escape = ctx.input(|i| i.key_pressed(crate::Key::Escape));
let clicked_something_else = ctx.input(|i| i.pointer.any_pressed()) && !self.any_hovered;
let pressed_escape = ui.input(|i| i.key_pressed(crate::Key::Escape));
let clicked_something_else = ui.input(|i| i.pointer.any_pressed()) && !self.any_hovered;
let delected_everything = pressed_escape || clicked_something_else;
if delected_everything {
self.selection = None;
}
if ctx.input(|i| i.pointer.any_released()) {
if ui.input(|i| i.pointer.any_released()) {
self.is_dragging = false;
}
let text_to_copy = std::mem::take(&mut self.text_to_copy);
if !text_to_copy.is_empty() {
ctx.copy_text(text_to_copy);
ui.copy_text(text_to_copy);
}
}
}

View File

@@ -73,7 +73,7 @@ use std::sync::Arc;
use epaint::{Pos2, Vec2};
use crate::{Context, Id};
use crate::{Context, Id, Ui};
// ----------------------------------------------------------------------------
@@ -263,7 +263,7 @@ impl ViewportIdPair {
}
/// The user-code that shows the ui in the viewport, used for deferred viewports.
pub type DeferredViewportUiCallback = dyn Fn(&Context) + Sync + Send;
pub type DeferredViewportUiCallback = dyn Fn(&mut Ui) + Sync + Send;
/// Render the given viewport, calling the given ui callback.
pub type ImmediateViewportRendererCallback = dyn for<'a> Fn(&Context, ImmediateViewport<'a>);
@@ -1251,5 +1251,5 @@ pub struct ImmediateViewport<'a> {
pub builder: ViewportBuilder,
/// The user-code that shows the GUI.
pub viewport_ui_cb: Box<dyn FnMut(&Context) + 'a>,
pub viewport_ui_cb: Box<dyn FnMut(&mut Ui) + 'a>,
}

View File

@@ -5,11 +5,11 @@ use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler};
use eframe::epaint::text::TextWrapMode;
use egui::{
Button, Color32, Context, Event, Frame, FullOutput, Id, Key, KeyboardShortcut, Label,
Modifiers, Panel, RawInput, RichText, ScrollArea, Ui, collapsing_header::CollapsingState,
Button, Color32, Event, Frame, FullOutput, Id, Key, KeyboardShortcut, Label, Modifiers, Panel,
RawInput, RichText, ScrollArea, Ui, collapsing_header::CollapsingState,
};
/// This [`egui::Plugin`] adds an inspector Panel.
/// This [`egui::Plugin`] adds an inspector panel.
///
/// It can be opened with the `(Cmd/Ctrl)+Alt+I`. It shows the current AccessKit tree and details
/// for the selected node.
@@ -71,8 +71,8 @@ impl egui::Plugin for AccessibilityInspectorPlugin {
}
}
fn on_begin_pass(&mut self, ctx: &Context) {
if ctx.input_mut(|i| {
fn on_begin_pass(&mut self, ui: &mut Ui) {
if ui.input_mut(|i| {
i.consume_shortcut(&KeyboardShortcut::new(
Modifiers::COMMAND | Modifiers::ALT,
Key::I,
@@ -85,9 +85,9 @@ impl egui::Plugin for AccessibilityInspectorPlugin {
return;
}
ctx.enable_accesskit();
ui.enable_accesskit();
Panel::right(Self::id()).show(ctx, |ui| {
Panel::right(Self::id()).show_inside(ui, |ui| {
ui.heading("🔎 AccessKit Inspector");
if let Some(selected_node) = self.selected_node {
Panel::bottom(Self::id().with("details_panel"))

View File

@@ -271,7 +271,7 @@ impl eframe::App for WrapApp {
color.to_normalized_gamma_f32()
}
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
#[cfg(target_arch = "wasm32")]
if let Some(anchor) = frame
.info()
@@ -285,36 +285,36 @@ impl eframe::App for WrapApp {
}
#[cfg(not(target_arch = "wasm32"))]
if ctx.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::F11)) {
let fullscreen = ctx.input(|i| i.viewport().fullscreen.unwrap_or(false));
ctx.send_viewport_cmd(egui::ViewportCommand::Fullscreen(!fullscreen));
if ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::F11)) {
let fullscreen = ui.input(|i| i.viewport().fullscreen.unwrap_or(false));
ui.send_viewport_cmd(egui::ViewportCommand::Fullscreen(!fullscreen));
}
let mut cmd = Command::Nothing;
egui::Panel::top("wrap_app_top_bar")
.frame(egui::Frame::new().inner_margin(4))
.show(ctx, |ui| {
.show_inside(ui, |ui| {
ui.horizontal_wrapped(|ui| {
ui.visuals_mut().button_frame = false;
self.bar_contents(ui, frame, &mut cmd);
});
});
self.state.backend_panel.update(ctx, frame);
self.state.backend_panel.update(ui.ctx(), frame);
egui::CentralPanel::no_frame().show(ctx, |ui| {
if !is_mobile(ctx) {
egui::CentralPanel::no_frame().show_inside(ui, |ui| {
if !is_mobile(ui.ctx()) {
cmd = self.backend_panel(ui, frame);
}
self.show_selected_app(ui, frame);
});
self.state.backend_panel.end_of_frame(ctx);
self.state.backend_panel.end_of_frame(ui.ctx());
self.ui_file_drag_and_drop(ctx);
self.ui_file_drag_and_drop(ui.ctx());
self.run_cmd(ctx, cmd);
self.run_cmd(ui.ctx(), cmd);
}
#[cfg(feature = "glow")]

View File

@@ -66,10 +66,10 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{
let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), |ctx| {
let _ = ctx.run_ui(RawInput::default(), |ui| {
c.bench_function("label &str", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.label("the quick brown fox jumps over the lazy dog");
},
@@ -78,7 +78,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});
c.bench_function("label format!", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.label("the quick brown fox jumps over the lazy dog".to_owned());
},
@@ -90,7 +90,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{
let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), |ctx| {
let _ = ctx.run_ui(RawInput::default(), |ui| {
let mut group = c.benchmark_group("button");
// To ensure we have a valid image, let's use the font texture. The size
@@ -99,7 +99,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("1_button_text", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.add(Button::new("Hello World"));
},
@@ -108,7 +108,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});
group.bench_function("2_button_text_image", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.add(Button::image_and_text(image, "Hello World"));
},
@@ -117,7 +117,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});
group.bench_function("3_button_text_image_right_text", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.add(Button::image_and_text(image, "Hello World").right_text(""));
},
@@ -126,7 +126,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});
group.bench_function("4_button_italic", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|| create_benchmark_ui(ui),
|ui| {
ui.add(Button::new(RichText::new("Hello World").italics()));
},

View File

@@ -372,7 +372,7 @@ fn file_menu_button(ui: &mut Ui) {
mod tests {
use crate::{Demo as _, demo::demo_app_windows::DemoGroups};
use egui_kittest::kittest::{NodeT as _, Queryable as _};
use egui_kittest::kittest::Queryable as _;
use egui_kittest::{Harness, OsThreshold, SnapshotOptions, SnapshotResults};
#[test]
@@ -394,12 +394,15 @@ mod tests {
let name = remove_leading_emoji(demo.name());
let mut harness = Harness::new(|ctx| {
egui_extras::install_image_loaders(ctx);
demo.show(ctx, &mut true);
let mut harness = Harness::new_ui(|ui| {
egui_extras::install_image_loaders(ui);
demo.show(ui, &mut true);
});
let window = harness.queryable_node().children().next().unwrap();
let window = harness
.get_all_by_role(egui::accesskit::Role::Window)
.next()
.unwrap();
// TODO(lucasmerlin): Windows should probably have a label?
//let window = harness.get_by_label(name);

View File

@@ -176,9 +176,9 @@ mod tests {
..Modals::default()
};
let mut harness = Harness::new_state(
|ctx, modals| {
modals.show(ctx, &mut true);
let mut harness = Harness::new_ui_state(
|ui, modals| {
modals.show(ui, &mut true);
},
initial_state,
);
@@ -204,9 +204,9 @@ mod tests {
..Modals::default()
};
let mut harness = Harness::new_state(
|ctx, modals| {
modals.show(ctx, &mut true);
let mut harness = Harness::new_ui_state(
|ui, modals| {
modals.show(ui, &mut true);
},
initial_state,
);
@@ -228,9 +228,9 @@ mod tests {
..Modals::default()
};
let mut harness = Harness::new_state(
|ctx, modals| {
modals.show(ctx, &mut true);
let mut harness = Harness::new_ui_state(
|ui, modals| {
modals.show(ui, &mut true);
},
initial_state,
);
@@ -258,9 +258,9 @@ mod tests {
..Modals::default()
};
let mut harness = Harness::new_state(
|ctx, modals| {
modals.show(ctx, &mut true);
let mut harness = Harness::new_ui_state(
|ui, modals| {
modals.show(ui, &mut true);
},
initial_state,
);

View File

@@ -120,9 +120,9 @@ mod tests {
#[test]
pub fn should_type() {
let text = "Hello, world!".to_owned();
let mut harness = Harness::new_state(
move |ctx, text| {
CentralPanel::default().show(ctx, |ui| {
let mut harness = Harness::new_ui_state(
move |ui, text| {
CentralPanel::default().show_inside(ui, |ui| {
ui.text_edit_singleline(text);
});
},

View File

@@ -215,10 +215,11 @@ impl winit::application::ApplicationHandler<UserEvent> for GlowApp {
let mut redraw = || {
let mut quit = false;
self.egui_glow.as_mut().unwrap().run(
self.gl_window.as_mut().unwrap().window(),
|egui_ctx| {
egui::Panel::left("my_side_panel").show(egui_ctx, |ui| {
self.egui_glow
.as_mut()
.unwrap()
.run(self.gl_window.as_mut().unwrap().window(), |ui| {
egui::Panel::left("my_side_panel").show_inside(ui, |ui| {
ui.heading("Hello World!");
if ui.button("Quit").clicked() {
quit = true;
@@ -226,8 +227,7 @@ impl winit::application::ApplicationHandler<UserEvent> for GlowApp {
ui.color_edit_button_rgb(self.clear_color.as_mut().try_into().unwrap());
});
},
);
});
if quit {
event_loop.exit();

View File

@@ -65,7 +65,7 @@ impl EguiGlow {
}
/// Call [`Self::paint`] later to paint.
pub fn run(&mut self, window: &winit::window::Window, run_ui: impl FnMut(&egui::Context)) {
pub fn run(&mut self, window: &winit::window::Window, run_ui: impl FnMut(&mut egui::Ui)) {
let raw_input = self.egui_winit.take_egui_input(window);
let egui::FullOutput {
@@ -74,7 +74,7 @@ impl EguiGlow {
shapes,
pixels_per_point,
viewport_output,
} = self.egui_ctx.run(raw_input, run_ui);
} = self.egui_ctx.run_ui(raw_input, run_ui);
if viewport_output.len() > 1 {
log::warn!("Multiple viewports not yet supported by EguiGlow");

View File

@@ -24,40 +24,44 @@ pub(crate) enum AppKind<'a, State> {
impl<State> AppKind<'_, State> {
pub fn run(
&mut self,
ctx: &egui::Context,
ui: &mut egui::Ui,
state: &mut State,
sizing_pass: bool,
) -> Option<egui::Response> {
match self {
AppKind::Context(f) => {
debug_assert!(!sizing_pass, "Context closures cannot do a sizing pass");
f(ctx);
f(ui);
None
}
AppKind::ContextState(f) => {
debug_assert!(!sizing_pass, "Context closures cannot do a sizing pass");
f(ctx, state);
f(ui, state);
None
}
#[cfg(feature = "eframe")]
AppKind::Eframe((get_app, frame)) => {
let app = get_app(state);
app.update(ctx, frame);
app.logic(ui, frame);
#[expect(deprecated)]
app.update(ui, frame);
app.ui(ui, frame);
None
}
kind_ui => Some(kind_ui.run_ui(ctx, state, sizing_pass)),
kind_ui => Some(kind_ui.run_ui(ui, state, sizing_pass)),
}
}
fn run_ui(
&mut self,
ctx: &egui::Context,
ui: &mut egui::Ui,
state: &mut State,
sizing_pass: bool,
) -> egui::Response {
egui::CentralPanel::default()
.frame(Frame::NONE)
.show(ctx, |ui| {
let mut builder = egui::UiBuilder::new();
if sizing_pass {
builder.sizing_pass = true;
@@ -75,7 +79,5 @@ impl<State> AppKind<'_, State> {
});
})
.response
})
.inner
}
}

View File

@@ -167,6 +167,7 @@ impl<State> HarnessBuilder<State> {
/// assert_eq!(*harness.state(), true);
/// ```
#[track_caller]
#[deprecated = "use `build_ui_state` instead"]
pub fn build_state<'a>(
self,
app: impl FnMut(&egui::Context, &mut State) + 'a,
@@ -251,6 +252,7 @@ impl HarnessBuilder {
/// ```
#[must_use]
#[track_caller]
#[deprecated = "use `build_ui` instead"]
pub fn build<'a>(self, app: impl FnMut(&egui::Context) + 'a) -> Harness<'a> {
Harness::from_builder(self, AppKind::Context(Box::new(app)), (), None)
}

View File

@@ -137,8 +137,8 @@ impl<'a, State> Harness<'a, State> {
// We need to run egui for a single frame so that the AccessKit state can be initialized
// and users can immediately start querying for widgets.
let mut output = ctx.run(input.clone(), |ctx| {
response = app.run(ctx, &mut state, false);
let mut output = ctx.run_ui(input.clone(), |ui| {
response = app.run(ui, &mut state, false);
});
renderer.handle_delta(&output.textures_delta);
@@ -204,7 +204,9 @@ impl<'a, State> Harness<'a, State> {
/// assert_eq!(*harness.state(), true);
/// ```
#[track_caller]
#[deprecated = "use `new_ui_state` instead"]
pub fn new_state(app: impl FnMut(&egui::Context, &mut State) + 'a, state: State) -> Self {
#[expect(deprecated)]
Self::builder().build_state(app, state)
}
@@ -287,8 +289,8 @@ impl<'a, State> Harness<'a, State> {
fn _step(&mut self, sizing_pass: bool) {
self.input.predicted_dt = self.step_dt;
let mut output = self.ctx.run(self.input.take(), |ctx| {
self.response = self.app.run(ctx, &mut self.state, sizing_pass);
let mut output = self.ctx.run_ui(self.input.take(), |ui| {
self.response = self.app.run(ui, &mut self.state, sizing_pass);
});
self.kittest.update(
output
@@ -735,7 +737,9 @@ impl<'a> Harness<'a> {
/// });
/// ```
#[track_caller]
#[deprecated = "use `new_ui` instead"]
pub fn new(app: impl FnMut(&egui::Context) + 'a) -> Self {
#[expect(deprecated)]
Self::builder().build(app)
}

View File

@@ -1,7 +1,7 @@
//! Tests the accesskit accessibility output of egui.
use egui::{
CentralPanel, Context, RawInput, Window,
CentralPanel, Context, RawInput, Ui, Window,
accesskit::{NodeId, Role, TreeUpdate},
};
@@ -12,8 +12,8 @@ use egui::{
/// are put there because of the widgets rendered.
#[test]
fn empty_ui_should_return_tree_with_only_root_window() {
let output = accesskit_output_single_egui_frame(|ctx| {
CentralPanel::default().show(ctx, |_| {});
let output = accesskit_output_single_egui_frame(|_ui| {
// Nothing here beyond the default empty UI
});
assert_eq!(
@@ -42,8 +42,8 @@ fn empty_ui_should_return_tree_with_only_root_window() {
fn button_node() {
let button_text = "This is a test button!";
let output = accesskit_output_single_egui_frame(|ctx| {
CentralPanel::default().show(ctx, |ui| ui.button(button_text));
let output = accesskit_output_single_egui_frame(|ui| {
CentralPanel::default().show_inside(ui, |ui| ui.button(button_text));
});
let (_, button) = output
@@ -60,8 +60,8 @@ fn button_node() {
fn disabled_button_node() {
let button_text = "This is a test button!";
let output = accesskit_output_single_egui_frame(|ctx| {
CentralPanel::default().show(ctx, |ui| {
let output = accesskit_output_single_egui_frame(|ui| {
CentralPanel::default().show_inside(ui, |ui| {
ui.add_enabled(false, egui::Button::new(button_text))
});
});
@@ -81,8 +81,8 @@ fn toggle_button_node() {
let button_text = "A toggle button";
let mut selected = false;
let output = accesskit_output_single_egui_frame(|ctx| {
CentralPanel::default().show(ctx, |ui| ui.toggle_value(&mut selected, button_text));
let output = accesskit_output_single_egui_frame(|ui| {
CentralPanel::default().show_inside(ui, |ui| ui.toggle_value(&mut selected, button_text));
});
let (_, toggle) = output
@@ -97,8 +97,8 @@ fn toggle_button_node() {
#[test]
fn multiple_disabled_widgets() {
let output = accesskit_output_single_egui_frame(|ctx| {
CentralPanel::default().show(ctx, |ui| {
let output = accesskit_output_single_egui_frame(|ui| {
CentralPanel::default().show_inside(ui, |ui| {
ui.add_enabled_ui(false, |ui| {
let _ = ui.button("Button 1");
let _ = ui.button("Button 2");
@@ -120,12 +120,12 @@ fn multiple_disabled_widgets() {
#[test]
fn window_children() {
let output = accesskit_output_single_egui_frame(|ctx| {
let output = accesskit_output_single_egui_frame(|ui| {
let mut open = true;
Window::new("test window")
.open(&mut open)
.resizable(false)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
let _ = ui.button("A button");
});
});
@@ -138,13 +138,13 @@ fn window_children() {
assert_button_exists(&output, "Hide", window_id);
}
fn accesskit_output_single_egui_frame(run_ui: impl FnMut(&Context)) -> TreeUpdate {
fn accesskit_output_single_egui_frame(run_ui: impl FnMut(&mut Ui)) -> TreeUpdate {
let ctx = Context::default();
// Disable animations, so we do not need to wait for animations to end to see the result.
ctx.global_style_mut(|style| style.animation_time = 0.0);
ctx.enable_accesskit();
let output = ctx.run(RawInput::default(), run_ui);
let output = ctx.run_ui(RawInput::default(), run_ui);
output
.platform_output

View File

@@ -23,16 +23,16 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Try to close the window");
});
if ctx.input(|i| i.viewport().close_requested()) {
if ui.input(|i| i.viewport().close_requested()) {
if self.allowed_to_close {
// do nothing - we will close
} else {
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
ui.send_viewport_cmd(egui::ViewportCommand::CancelClose);
self.show_confirmation_dialog = true;
}
}
@@ -41,7 +41,7 @@ impl eframe::App for MyApp {
egui::Window::new("Do you want to quit?")
.collapsible(false)
.resizable(false)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
if ui.button("No").clicked() {
self.show_confirmation_dialog = false;

View File

@@ -43,8 +43,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.label("The triangle is being painted using ");

View File

@@ -86,8 +86,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("egui using custom fonts");
ui.text_edit_multiline(&mut self.text);
});

View File

@@ -65,8 +65,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, content);
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, content);
}
}

View File

@@ -44,11 +44,11 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::Window::new("Custom Keypad")
.default_pos([100.0, 100.0])
.title_bar(true)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(&mut self.name);
@@ -60,7 +60,7 @@ impl eframe::App for MyApp {
ui.label(format!("Hello '{}', age {}", self.name, self.age));
});
self.keypad.show(ctx);
self.keypad.show(ui.ctx());
}
fn raw_input_hook(&mut self, ctx: &egui::Context, raw_input: &mut egui::RawInput) {

View File

@@ -57,8 +57,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("egui using a customized style");
ui.label("Switch between dark and light mode to see the different styles in action.");
global_theme_preference_buttons(ui);

View File

@@ -31,8 +31,8 @@ impl eframe::App for MyApp {
egui::Rgba::TRANSPARENT.to_array() // Make sure we don't paint anything behind the rounded corners
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
custom_window_frame(ctx, "egui with custom frame", |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
custom_window_frame(ui.ctx(), "egui with custom frame", |ui| {
ui.label("This is just the contents of the window.");
ui.horizontal(|ui| {
ui.label("egui theme:");

View File

@@ -44,8 +44,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My External Eventloop Application");
ui.horizontal(|ui| {
@@ -82,7 +82,7 @@ impl eframe::App for MyApp {
ui.label("Blinky!");
});
ctx.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
ui.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
}
});
}

View File

@@ -76,8 +76,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My External Eventloop Application");
ui.horizontal(|ui| {
@@ -86,7 +86,7 @@ impl eframe::App for MyApp {
}
if ui.button("Increment Later").clicked() {
let value = self.value.clone();
let ctx = ctx.clone();
let ctx = ui.ctx().clone();
tokio::task::spawn_local(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
value.set(value.get() + 1);
@@ -123,7 +123,7 @@ impl eframe::App for MyApp {
ui.label("Blinky!");
});
ctx.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
ui.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
}
});
}

View File

@@ -25,8 +25,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Drag-and-drop files onto the window!");
if ui.button("Open file…").clicked()
@@ -73,10 +73,10 @@ impl eframe::App for MyApp {
}
});
preview_files_being_dropped(ctx);
preview_files_being_dropped(ui.ctx());
// Collect dropped files:
ctx.input(|i| {
ui.input(|i| {
if !i.raw.dropped_files.is_empty() {
self.dropped_files.clone_from(&i.raw.dropped_files);
}

View File

@@ -36,16 +36,16 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
// Reserve some space at the top so the demo ui isn't hidden behind the android status bar
// TODO(lucasmerlin): This is a pretty big hack, should be fixed once safe_area implemented
// for android:
// https://github.com/rust-windowing/winit/issues/3910
egui::Panel::top("status_bar_space").show(ctx, |ui| {
egui::Panel::top("status_bar_space").show_inside(ui, |ui| {
ui.set_height(32.0);
});
egui::CentralPanel::default().show(ctx, |ui| {
egui::CentralPanel::default().show_inside(ui, |ui| {
self.demo.ui(ui);
});
}

View File

@@ -36,8 +36,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
let name_label = ui.label("Your name: ");

View File

@@ -116,15 +116,15 @@ impl std::ops::Drop for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::Window::new("Main thread").show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::Window::new("Main thread").show(ui.ctx(), |ui| {
if ui.button("Spawn another thread").clicked() {
self.spawn_thread();
}
});
for (_handle, show_tx) in &self.threads {
let _ = show_tx.send(ctx.clone());
let _ = show_tx.send(ui.ctx().clone());
}
for _ in 0..self.threads.len() {

View File

@@ -15,8 +15,8 @@ fn main() -> eframe::Result {
let mut name = "Arthur".to_owned();
let mut age = 42;
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
eframe::run_ui_native("My egui App", options, move |ui, _frame| {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
let name_label = ui.label("Your name: ");

View File

@@ -24,8 +24,8 @@ fn main() -> eframe::Result {
struct MyApp {}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
egui::ScrollArea::both().show(ui, |ui| {
ui.image(egui::include_image!("cat.webp"))
.on_hover_text_at_pointer("WebP");

View File

@@ -20,8 +20,8 @@ struct Content {
}
impl eframe::App for Content {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Press/Hold/Release example. Press A to test.");
if ui.button("Clear").clicked() {
self.text.clear();
@@ -33,14 +33,14 @@ impl eframe::App for Content {
ui.label(&self.text);
});
if ctx.input(|i| i.key_pressed(Key::A)) {
if ui.input(|i| i.key_pressed(Key::A)) {
self.text.push_str("\nPressed");
}
if ctx.input(|i| i.key_down(Key::A)) {
if ui.input(|i| i.key_down(Key::A)) {
self.text.push_str("\nHeld");
ui.request_repaint(); // make sure we note the holding.
}
if ctx.input(|i| i.key_released(Key::A)) {
if ui.input(|i| i.key_released(Key::A)) {
self.text.push_str("\nReleased");
}
});

View File

@@ -35,8 +35,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from the root viewport");
ui.checkbox(
@@ -61,7 +61,7 @@ impl eframe::App for MyApp {
});
if self.show_immediate_viewport {
ctx.show_viewport_immediate(
ui.ctx().show_viewport_immediate(
egui::ViewportId::from_hash_of("immediate_viewport"),
egui::ViewportBuilder::default()
.with_title("Immediate Viewport")
@@ -87,7 +87,7 @@ impl eframe::App for MyApp {
if self.show_deferred_viewport.load(Ordering::Relaxed) {
let show_deferred_viewport = self.show_deferred_viewport.clone();
ctx.show_viewport_deferred(
ui.ctx().show_viewport_deferred(
egui::ViewportId::from_hash_of("deferred_viewport"),
egui::ViewportBuilder::default()
.with_title("Deferred Viewport")

View File

@@ -18,8 +18,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut eframe::egui::Ui, _frame: &mut eframe::Frame) {
CentralPanel::default().show_inside(ui, |ui| {
ui.label("PopupCloseBehavior::CloseOnClick popup");
ComboBox::from_label("ComboBox")
.selected_text(format!("{}", self.number))

View File

@@ -54,8 +54,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Example of how to use the puffin profiler with egui");
ui.separator();
@@ -103,7 +103,7 @@ impl eframe::App for MyApp {
});
if self.show_immediate_viewport {
ctx.show_viewport_immediate(
ui.ctx().show_viewport_immediate(
egui::ViewportId::from_hash_of("immediate_viewport"),
egui::ViewportBuilder::default()
.with_title("Immediate Viewport")
@@ -130,7 +130,7 @@ impl eframe::App for MyApp {
if self.show_deferred_viewport.load(Ordering::Relaxed) {
let show_deferred_viewport = self.show_deferred_viewport.clone();
ctx.show_viewport_deferred(
ui.ctx().show_viewport_deferred(
egui::ViewportId::from_hash_of("deferred_viewport"),
egui::ViewportBuilder::default()
.with_title("Deferred Viewport")

View File

@@ -27,8 +27,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
if let Some(screenshot) = self.screenshot.take() {
self.texture = Some(ui.ctx().load_texture(
"screenshot",
@@ -45,7 +45,7 @@ impl eframe::App for MyApp {
if ui.button("save to 'top_left.png'").clicked() {
self.save_to_file = true;
ctx.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
}
ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| {
@@ -54,17 +54,13 @@ impl eframe::App for MyApp {
.add(egui::Label::new("hover me!").sense(egui::Sense::hover()))
.hovered()
{
ctx.set_theme(egui::Theme::Dark);
ui.ctx().set_theme(egui::Theme::Dark);
} else {
ctx.set_theme(egui::Theme::Light);
ui.ctx().set_theme(egui::Theme::Light);
}
ctx.send_viewport_cmd(
egui::ViewportCommand::Screenshot(Default::default()),
);
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
} else if ui.button("take screenshot!").clicked() {
ctx.send_viewport_cmd(
egui::ViewportCommand::Screenshot(Default::default()),
);
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
}
});
});
@@ -101,7 +97,7 @@ impl eframe::App for MyApp {
}
});
ctx.request_repaint();
ui.request_repaint();
});
}
}

View File

@@ -43,8 +43,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
let label_text = if self.has_next {
"When this window is closed the next will be opened after a short delay"
} else {

View File

@@ -2,7 +2,7 @@
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::{CreationContext, NativeOptions, egui};
use egui::{Button, CentralPanel, Context, UserAttentionType};
use egui::{Button, CentralPanel, UserAttentionType};
use std::time::{Duration, SystemTime};
@@ -55,12 +55,12 @@ impl Application {
}
impl eframe::App for Application {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
if let Some(request_at) = self.request_at
&& request_at < SystemTime::now()
{
self.request_at = None;
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
ui.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
if self.auto_reset {
self.auto_reset = false;
self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout());
@@ -71,12 +71,12 @@ impl eframe::App for Application {
&& reset_at < SystemTime::now()
{
self.reset_at = None;
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
ui.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
UserAttentionType::Reset,
));
}
CentralPanel::default().show(ctx, |ui| {
CentralPanel::default().show_inside(ui, |ui| {
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.label("Attention type:");
@@ -131,6 +131,6 @@ impl eframe::App for Application {
});
});
ctx.request_repaint_after(Self::repaint_max_timeout());
ui.request_repaint_after(Self::repaint_max_timeout());
}
}

View File

@@ -25,7 +25,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
struct MyTestApp {}
impl eframe::App for MyTestApp {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
use glow::HasContext as _;
let gl = frame.gl().unwrap();
@@ -37,7 +37,7 @@ impl eframe::App for MyTestApp {
gl.clear(glow::COLOR_BUFFER_BIT);
}
egui::Window::new("Floating Window").show(ctx, |ui| {
egui::Window::new("Floating Window").show(ui.ctx(), |ui| {
ui.label("The background should be purple.");
});
}

View File

@@ -7,9 +7,9 @@ fn main() -> eframe::Result {
env_logger::init(); // Use `RUST_LOG=debug` to see logs.
let options = eframe::NativeOptions::default();
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
eframe::run_ui_native("My egui App", options, move |ui, _frame| {
// A bottom panel to force the tooltips to consider if the fit below or under the widget:
egui::Panel::bottom("bottom").show(ctx, |ui| {
egui::Panel::bottom("bottom").show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.label("Single tooltips:");
@@ -33,10 +33,10 @@ fn main() -> eframe::Result {
});
});
egui::CentralPanel::default().show(ctx, |ui| {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.horizontal(|ui| {
if ui.button("Reset egui memory").clicked() {
ctx.memory_mut(|mem| *mem = Default::default());
ui.memory_mut(|mem| *mem = Default::default());
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::BOTTOM), |ui| {

View File

@@ -31,10 +31,10 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
ctx.all_styles_mut(|style| style.interaction.tooltip_delay = 0.0);
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
ui.all_styles_mut(|style| style.interaction.tooltip_delay = 0.0);
egui::Panel::left("side_panel_left").show(ctx, |ui| {
egui::Panel::left("side_panel_left").show_inside(ui, |ui| {
ui.heading("Information");
ui.label(
"This is a demo/test environment of the `UiStack` feature. The tables display \
@@ -49,7 +49,7 @@ impl eframe::App for MyApp {
ui.checkbox(&mut self.show_memory, "📝 Memory");
ui.add_space(10.0);
if ui.button("Reset egui memory").clicked() {
ctx.memory_mut(|mem| *mem = Default::default());
ui.memory_mut(|mem| *mem = Default::default());
}
ui.add_space(20.0);
@@ -82,7 +82,7 @@ impl eframe::App for MyApp {
});
});
egui::Panel::right("side_panel_right").show(ctx, |ui| {
egui::Panel::right("side_panel_right").show_inside(ui, |ui| {
egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| {
stack_ui(ui);
@@ -92,7 +92,7 @@ impl eframe::App for MyApp {
});
});
egui::CentralPanel::default().show(ctx, |ui| {
egui::CentralPanel::default().show_inside(ui, |ui| {
egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| {
ui.label("stack here:");
stack_ui(ui);
@@ -172,7 +172,7 @@ impl eframe::App for MyApp {
egui::Panel::bottom("bottom_panel")
.resizable(true)
.show(ctx, |ui| {
.show_inside(ui, |ui| {
egui::ScrollArea::vertical()
.auto_shrink(false)
.show(ui, |ui| {
@@ -186,30 +186,31 @@ impl eframe::App for MyApp {
egui::Window::new("Window")
.pivot(egui::Align2::RIGHT_TOP)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
full_span_widget(ui, false);
ui.add_space(20.0);
stack_ui(ui);
});
let ctx = ui.ctx().clone();
egui::Window::new("🔧 Settings")
.open(&mut self.show_settings)
.vscroll(true)
.show(ctx, |ui| {
.show(&ctx, |ui| {
ctx.settings_ui(ui);
});
egui::Window::new("🔍 Inspection")
.open(&mut self.show_inspection)
.vscroll(true)
.show(ctx, |ui| {
.show(&ctx, |ui| {
ctx.inspection_ui(ui);
});
egui::Window::new("📝 Memory")
.open(&mut self.show_memory)
.resizable(false)
.show(ctx, |ui| {
.show(&ctx, |ui| {
ctx.memory_ui(ui);
});
}

View File

@@ -153,18 +153,18 @@ impl Default for App {
}
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Root viewport");
{
let mut embed_viewports = ctx.embed_viewports();
let mut embed_viewports = ui.embed_viewports();
ui.checkbox(&mut embed_viewports, "Embed all viewports");
if ui.button("Open all viewports").clicked() {
for viewport in &self.top {
viewport.write().set_visible_recursive(true);
}
}
ctx.set_embed_viewports(embed_viewports);
ui.set_embed_viewports(embed_viewports);
}
ui.checkbox(&mut self.close_button, "with close button");
generic_ui(ui, &self.top, self.close_button);