mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Pass accesskit tree to after_step, drop on_accesskit_update
Replaces the separate on_accesskit_update hook with a `&TreeUpdate` parameter on `after_step` — one hook per step, tree delivered inline. `step_no_side_effects` now returns the TreeUpdate so plugins driving the harness from within their own hook (where nested dispatches are suppressed) can still see it. Also adds `#[track_caller]` to the internal `_step` / `_step_no_side_effects` / `_try_run` so `Location::caller()` inside `step()` walks up to the user's original call site when reached via `run()`.
This commit is contained in:
@@ -210,10 +210,13 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
|
||||
/// Advance the harness by one frame without firing plugin hooks.
|
||||
///
|
||||
/// This is useful for running steps within a plugin, without ending in an infinite loop where
|
||||
/// the plugin is called again.
|
||||
pub fn step_no_side_effects(&mut self) {
|
||||
self._step_no_side_effects(false);
|
||||
/// Returns the AccessKit tree update produced by the frame. Useful for plugins driving
|
||||
/// the harness from inside a hook: `after_step` normally delivers the tree, but nested
|
||||
/// hook dispatches are suppressed, so plugins that call this from within their own
|
||||
/// `after_step` need the return value to see the fresh tree.
|
||||
#[track_caller]
|
||||
pub fn step_no_side_effects(&mut self) -> egui::accesskit::TreeUpdate {
|
||||
self._step_no_side_effects(false)
|
||||
}
|
||||
|
||||
/// [`std::panic::Location`] of the most recent public `#[track_caller]` entry point
|
||||
@@ -322,15 +325,17 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
}
|
||||
|
||||
/// Run a single step, firing `before_step` / `after_step` plugin hooks.
|
||||
#[track_caller]
|
||||
fn _step(&mut self, sizing_pass: bool) {
|
||||
self.plugin_dispatch(|p, h| p.before_step(h));
|
||||
self._step_no_side_effects(sizing_pass);
|
||||
self.plugin_dispatch(|p, h| p.after_step(h));
|
||||
let accesskit_update = self._step_no_side_effects(sizing_pass);
|
||||
self.plugin_dispatch(|p, h| p.after_step(h, &accesskit_update));
|
||||
}
|
||||
|
||||
/// Core frame advance. Does NOT fire plugin hooks — callable from within
|
||||
/// hooks via [`Self::step_no_side_effects`] without recursing.
|
||||
fn _step_no_side_effects(&mut self, sizing_pass: bool) {
|
||||
#[track_caller]
|
||||
fn _step_no_side_effects(&mut self, sizing_pass: bool) -> egui::accesskit::TreeUpdate {
|
||||
self.input.predicted_dt = self.step_dt;
|
||||
|
||||
let mut output = self.ctx.run_ui(self.input.take(), |ui| {
|
||||
@@ -341,10 +346,10 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
.accesskit_update
|
||||
.take()
|
||||
.expect("AccessKit was disabled");
|
||||
self.plugin_dispatch(|p, h| p.on_accesskit_update(h, &accesskit_update));
|
||||
self.kittest.update(accesskit_update);
|
||||
self.kittest.update(accesskit_update.clone());
|
||||
self.renderer.handle_delta(&output.textures_delta);
|
||||
self.output = output;
|
||||
accesskit_update
|
||||
}
|
||||
|
||||
/// Calculate the rect that includes all popups and tooltips.
|
||||
@@ -412,6 +417,7 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn _try_run(&mut self, sleep: bool) -> Result<u64, ExceededMaxStepsError> {
|
||||
self.plugin_dispatch(|p, h| p.before_run(h));
|
||||
|
||||
|
||||
@@ -13,11 +13,12 @@ use crate::{ExceededMaxStepsError, Harness};
|
||||
/// State-agnostic plugins should impl for all `State` so they're reusable across harnesses:
|
||||
/// ```
|
||||
/// use egui_kittest::{Harness, Plugin};
|
||||
/// use egui::accesskit::TreeUpdate;
|
||||
///
|
||||
/// struct MyPlugin;
|
||||
///
|
||||
/// impl<S> Plugin<S> for MyPlugin {
|
||||
/// fn after_step(&mut self, _harness: &mut Harness<'_, S>) {
|
||||
/// fn after_step(&mut self, _harness: &mut Harness<'_, S>, _tree: &TreeUpdate) {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
@@ -48,17 +49,15 @@ pub trait Plugin<State = ()>: Send + 'static {
|
||||
fn before_step(&mut self, harness: &mut Harness<'_, State>) {}
|
||||
|
||||
/// Called immediately after each single-frame step.
|
||||
fn after_step(&mut self, harness: &mut Harness<'_, State>) {}
|
||||
|
||||
/// Called after each single-frame step with the AccessKit tree update egui produced
|
||||
/// for that frame, before it's applied to the internal kittest state.
|
||||
///
|
||||
/// Plugins that need the tree (e.g. to stream it to an external debugger) should
|
||||
/// clone it here — the harness no longer retains it after this hook returns.
|
||||
fn on_accesskit_update(
|
||||
/// `accesskit_update` is the AccessKit tree update egui produced for the frame that
|
||||
/// just ran. Plugins that need to retain it (e.g. to stream it to an external
|
||||
/// debugger) should clone it here — the harness doesn't hold on to it after this hook
|
||||
/// returns.
|
||||
fn after_step(
|
||||
&mut self,
|
||||
harness: &mut Harness<'_, State>,
|
||||
tree: &egui::accesskit::TreeUpdate,
|
||||
accesskit_update: &egui::accesskit::TreeUpdate,
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,11 @@ impl<S> Plugin<S> for CountingPlugin {
|
||||
fn before_step(&mut self, _h: &mut Harness<'_, S>) {
|
||||
self.push("before_step");
|
||||
}
|
||||
fn after_step(&mut self, _h: &mut Harness<'_, S>) {
|
||||
fn after_step(
|
||||
&mut self,
|
||||
_h: &mut Harness<'_, S>,
|
||||
_tree: &egui::accesskit::TreeUpdate,
|
||||
) {
|
||||
self.push("after_step");
|
||||
}
|
||||
fn on_event(&mut self, _h: &mut Harness<'_, S>, _event: &egui::Event) {
|
||||
@@ -127,7 +131,7 @@ fn step_no_side_effects_skips_hooks() {
|
||||
drove: bool,
|
||||
}
|
||||
impl<S: 'static> Plugin<S> for DrivingPlugin {
|
||||
fn after_step(&mut self, h: &mut Harness<'_, S>) {
|
||||
fn after_step(&mut self, h: &mut Harness<'_, S>, _tree: &egui::accesskit::TreeUpdate) {
|
||||
self.log.lock().unwrap().push("after_step".into());
|
||||
if !self.drove {
|
||||
self.drove = true;
|
||||
@@ -164,7 +168,7 @@ fn mid_dispatch_registration_is_deferred() {
|
||||
registered: bool,
|
||||
}
|
||||
impl<S: 'static> Plugin<S> for Registrar {
|
||||
fn after_step(&mut self, h: &mut Harness<'_, S>) {
|
||||
fn after_step(&mut self, h: &mut Harness<'_, S>, _tree: &egui::accesskit::TreeUpdate) {
|
||||
self.log.lock().unwrap().push("registrar:after_step".into());
|
||||
if !self.registered {
|
||||
self.registered = true;
|
||||
|
||||
Reference in New Issue
Block a user