mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Remove last_accesskit_update and add on_accesskit_update hook
This commit is contained in:
@@ -89,7 +89,6 @@ pub struct Harness<'a, State: 'static = ()> {
|
||||
plugins: Vec<Box<dyn Plugin<State>>>,
|
||||
entry_location: Option<&'static std::panic::Location<'static>>,
|
||||
consumed_event_locations: Vec<&'static std::panic::Location<'static>>,
|
||||
last_accesskit_update: Option<egui::accesskit::TreeUpdate>,
|
||||
|
||||
#[cfg(feature = "snapshot")]
|
||||
default_snapshot_options: SnapshotOptions,
|
||||
@@ -168,7 +167,7 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
app,
|
||||
ctx,
|
||||
input,
|
||||
kittest: kittest::State::new(initial_accesskit.clone()),
|
||||
kittest: kittest::State::new(initial_accesskit),
|
||||
output,
|
||||
response,
|
||||
state,
|
||||
@@ -181,7 +180,6 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
plugins,
|
||||
entry_location: None,
|
||||
consumed_event_locations: Vec::new(),
|
||||
last_accesskit_update: Some(initial_accesskit),
|
||||
|
||||
#[cfg(feature = "snapshot")]
|
||||
default_snapshot_options,
|
||||
@@ -247,12 +245,6 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
self._step_inner(false);
|
||||
}
|
||||
|
||||
/// The most recent AccessKit tree update, if any. Useful for plugins that mirror
|
||||
/// the accessibility tree to an external debugger.
|
||||
pub fn accesskit_tree_update(&self) -> Option<&egui::accesskit::TreeUpdate> {
|
||||
self.last_accesskit_update.as_ref()
|
||||
}
|
||||
|
||||
/// [`std::panic::Location`] of the most recent public `#[track_caller]` entry point
|
||||
/// (e.g. the caller of `step()` / `run()`), or `None` if no such call has been made yet.
|
||||
pub fn entry_location(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
@@ -378,7 +370,7 @@ impl<'a, State: 'static> Harness<'a, State> {
|
||||
.accesskit_update
|
||||
.take()
|
||||
.expect("AccessKit was disabled");
|
||||
self.last_accesskit_update = Some(accesskit_update.clone());
|
||||
self.dispatch(|p, h| p.on_accesskit_update(h, &accesskit_update));
|
||||
self.kittest.update(accesskit_update);
|
||||
self.renderer.handle_delta(&output.textures_delta);
|
||||
self.output = output;
|
||||
|
||||
@@ -36,7 +36,7 @@ use crate::{ExceededMaxStepsError, Harness};
|
||||
/// Plugin hooks receive `&mut Harness`. Calling [`Harness::step`] / [`Harness::run`] /
|
||||
/// etc. from inside a hook will recurse infinitely through your own `after_step`. If
|
||||
/// a plugin needs to advance the harness from inside a hook — e.g. an inspector that
|
||||
/// blocks on user input — use [`Harness::advance_frame`] instead.
|
||||
/// blocks on user input — use [`Harness::step_no_side_effects`] instead.
|
||||
#[expect(unused_variables, reason = "default no-op impls")]
|
||||
pub trait Plugin<State = ()>: Send + Any {
|
||||
/// Called once at the start of every `run()` / `try_run()` / `try_run_realtime()` /
|
||||
@@ -58,6 +58,18 @@ pub trait Plugin<State = ()>: Send + Any {
|
||||
/// 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(
|
||||
&mut self,
|
||||
harness: &mut Harness<'_, State>,
|
||||
tree: &egui::accesskit::TreeUpdate,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Called after a queued event has been pushed into the harness input, before the
|
||||
/// frame runs that consumes it.
|
||||
fn on_event(&mut self, harness: &mut Harness<'_, State>, event: &egui::Event) {}
|
||||
|
||||
@@ -119,20 +119,20 @@ fn on_event_fires_per_event() {
|
||||
assert_eq!(events, 2, "expected 2 on_event calls, got log: {log:?}");
|
||||
}
|
||||
|
||||
/// `advance_frame` does NOT fire `before_step`/`after_step`.
|
||||
/// `step_no_side_effects` does NOT fire `before_step`/`after_step`.
|
||||
#[test]
|
||||
fn advance_frame_skips_hooks() {
|
||||
fn step_no_side_effects_skips_hooks() {
|
||||
struct DrivingPlugin {
|
||||
log: Log,
|
||||
drove: bool,
|
||||
}
|
||||
impl<S> Plugin<S> for DrivingPlugin {
|
||||
impl<S: 'static> Plugin<S> for DrivingPlugin {
|
||||
fn after_step(&mut self, h: &mut Harness<'_, S>) {
|
||||
self.log.lock().unwrap().push("after_step".into());
|
||||
if !self.drove {
|
||||
self.drove = true;
|
||||
// Call advance_frame from inside a hook — must not recurse.
|
||||
h.advance_frame();
|
||||
// Call step_no_side_effects from inside a hook — must not recurse.
|
||||
h.step_no_side_effects();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ fn advance_frame_skips_hooks() {
|
||||
|
||||
let log = log.lock().unwrap();
|
||||
// Exactly one after_step from the user's step(), plus any from construction-time run_ok
|
||||
// (cleared above). advance_frame must NOT have produced another after_step.
|
||||
// (cleared above). step_no_side_effects must NOT have produced another after_step.
|
||||
assert_eq!(log.iter().filter(|s| s == &"after_step").count(), 1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user