Skip to content

Add Plugin::on_widget_under_pointer to support widget inspector#7652

Merged
emilk merged 5 commits intoemilk:mainfrom
membrane-io:juan/egui-dev-tools
Oct 27, 2025
Merged

Add Plugin::on_widget_under_pointer to support widget inspector#7652
emilk merged 5 commits intoemilk:mainfrom
membrane-io:juan/egui-dev-tools

Conversation

@juancampa
Copy link
Copy Markdown
Contributor

@juancampa juancampa commented Oct 21, 2025

This PR adds Plugin::on_widget_under_pointer which gets called whenever a widget is created whose rect contains the pointer.

The point of the hook is to capture a stack trace which can be used to map widgets to their corresponding source code so it must be called while the widget is being created. The obvious concern is performance impact. However, since it's only called for rects under the cursor, the effect seems negligible afaict. It's under debug_assertions just in case.

This change is needed so we can publish the widget inspector we've been working on. Basically a plugin that allows us to jump from any widget back to their corresponding source code.

This video shows the plugin configured to open the corresponding code in github, but normally it would open your local editor.

Update: Live demo (Firefox/Safari not yet supported. Cmd-I to inspect. Tab to cycle filters. Click to open). It will try to open a file under /home/runner/work/egui/egui/ so it won't work, but you get the idea.

Screenshot.2025-10-20.at.22.17.19.mp4

What's next

After this gets merged I plan to publish the above plugin as its own crate, that way we can iterate and release quickly while things are still changing. I agree it would make sense to eventually merge it into the main egui repo (like @emilk suggested in #4650).

  • I have followed the instructions in the PR template

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 21, 2025

Preview available at https://egui-pr-preview.github.io/pr/7652-juanegui-dev-tools
Note that it might take a couple seconds for the update to show up after the preview_build workflow has completed.

View snapshot changes at kitdiff

@juancampa juancampa marked this pull request as draft October 21, 2025 02:58
@juancampa juancampa marked this pull request as ready for review October 21, 2025 03:52
@juancampa
Copy link
Copy Markdown
Contributor Author

juancampa commented Oct 21, 2025

Something that limits how much we can build in this plugin is that we don't want to create new widgets. So the UI must be done in epaint-land. Wondering if creating a separate egui context would make sense to create widgets without affecting the main egui instance, or if that's too hacky for some reason.

@lucasmerlin lucasmerlin added this to the 0.34.0 milestone Oct 21, 2025
Copy link
Copy Markdown
Owner

@emilk emilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very… specific addition to trait Plugin. But it makes perfectly sense for an inspector/debug plugin like yours.

Btw, for callstacks, we have egui/src/callstack.rs that is not part of the public API. Maybe it should be? Have you tried using it for your work?

juancampa and others added 2 commits October 22, 2025 07:23
Co-authored-by: Emil Ernerfeldt <[email protected]>
Co-authored-by: Emil Ernerfeldt <[email protected]>
@juancampa
Copy link
Copy Markdown
Contributor Author

Have you tried using it for your work?

I was initially using it, yeah. But then realized that immediately resolving stack traces significantly affect performance. Our web app would get slower the more widgets were hovered.

Instead, the plugin calls trace N times during the app's update but only resolve one of them during pass_end. Similarly for web, we capture N Error objects but only read .stack once. Browsers lazily generate the stack string so it makes everything faster.

IMO, the best path forward would be to eventually merge the plugin into egui (once it has matured a bit more) and replace the cmd+shift+ctrl+alt logic with it.

@emilk emilk added the egui label Oct 22, 2025
@emilk
Copy link
Copy Markdown
Owner

emilk commented Oct 23, 2025

note that the CI needs a little fix!

@michalsustr
Copy link
Copy Markdown

Great work!

In the future, it would be great to have the plugin to inspect styling properties from planned #3284, like WidgetStyle etc.

@emilk emilk merged commit 2669344 into emilk:main Oct 27, 2025
26 checks passed
@juancampa
Copy link
Copy Markdown
Contributor Author

In the future, it would be great to have the plugin to inspect styling properties

I'm hoping we can do that soon!

I want to go even further and use the DWARF data (which contains struct layouts) to inspect stuff in egui::Memory! Kind of similar to egui_inspect or egui_struct but without having to preemptively decorate any struct with derive macros. Basically do it the same way debuggers do it when you stop at a breakpoint.

We have all the pieces to do that now (except maybe another plugin hook). It's just a matter of putting it together

emilk added a commit that referenced this pull request Nov 13, 2025
)

This PR adds `Plugin::on_widget_under_pointer` which gets called
whenever a widget is created whose rect contains the pointer.

The point of the hook is to capture a stack trace which can be used to
map widgets to their corresponding source code so it must be called
while the widget is being created. The obvious concern is performance
impact. However, since it's only called for rects under the cursor, the
effect seems negligible afaict. It's under `debug_assertions` just in
case.

This change is needed so we can publish the widget inspector we've been
working on. Basically a plugin that allows us to jump from any widget
back to their corresponding source code.

This video shows the plugin configured to open the corresponding code in
github, but normally it would open your local editor.

Update: [Live demo](https://membrane-io.github.io/egui/) (Firefox/Safari
not yet supported. `Cmd-I` to inspect. `Tab` to cycle filters. `Click`
to open). It will try to open a file under
`/home/runner/work/egui/egui/` so it won't work, but you get the idea.


https://github.com/user-attachments/assets/afe4d6af-7f67-44b5-be25-44f7564d9a3a

## What's next

After this gets merged I plan to publish the above plugin as its own
crate, that way we can iterate and release quickly while things are
still changing. I agree it would make sense to eventually merge it into
the main egui repo (like @emilk suggested in #4650).

* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
This was referenced Nov 13, 2025
emilk added a commit to rerun-io/rerun that referenced this pull request Nov 26, 2025
Changes in snapshot images should be pixel-alignment improvements thanks
to
* emilk/egui#7710


---

## egui changelog
### ⭐ Added
* Add `Plugin::on_widget_under_pointer` to support widget inspector
[#7652](emilk/egui#7652) by
[@juancampa](https://github.com/juancampa)
* Add `Response::total_drag_delta` and `PointerState::total_drag_delta`
[#7708](emilk/egui#7708) by
[@emilk](https://github.com/emilk)

### 🔧 Changed
* Improve accessibility and testability of `ComboBox`
[#7658](emilk/egui#7658) by
[@lucasmerlin](https://github.com/lucasmerlin)

### 🐛 Fixed
* Fix `profiling::scope` compile error when profiling using `tracing`
backend [#7646](emilk/egui#7646) by
[@PPakalns](https://github.com/PPakalns)
* Fix edge cases in "smart aiming" in sliders
[#7680](emilk/egui#7680) by
[@emilk](https://github.com/emilk)
* Hide scroll bars when dragging other things
[#7689](emilk/egui#7689) by
[@emilk](https://github.com/emilk)
* Prevent widgets sometimes appearing to move relative to each other
[#7710](emilk/egui#7710) by
[@emilk](https://github.com/emilk)
* Fix `ui.response().interact(Sense::click())` being flakey
[#7713](emilk/egui#7713) by
[@lucasmerlin](https://github.com/lucasmerlin)

## eframe changelog
* Fix jittering during window resize on MacOS for WGPU/Metal
[#7641](emilk/egui#7641) by
[@aspcartman](https://github.com/aspcartman)
* Make sure `native_pixels_per_point` is set during app creation
[#7683](emilk/egui#7683) by
[@emilk](https://github.com/emilk)

---------

Co-authored-by: Lucas Meurer <[email protected]>
Co-authored-by: lucasmerlin <[email protected]>
@emilk
Copy link
Copy Markdown
Owner

emilk commented Dec 14, 2025

Unfortunately this causes a deadlock for any plugin that adds a UI, because when hovering that ui we will call on_widget_under_pointer from within the own plugin

Repro: cargo r -p egui_demo_app --all-features + cmd+alt+i to open AccessibilityInspectorPlugin

@juancampa
Copy link
Copy Markdown
Contributor Author

We just upgraded our egui fork so I can finally continue this work.

The quick fix would be to flip a boolean in Plugins::on_begin_pass/Plugins::on_end_pass so that this hook doesn't get called while plugins are potentially creating widgets. This won't let us inspect the UI of plugins though which could be helpful. So instead we can keep an active_idx: Option<usize> in Plugins, that way we only skip the call for itself.

I'll try the second option and report back.

Masterchef365 pushed a commit to Masterchef365/egui that referenced this pull request Apr 3, 2026
…ilk#7652)

This PR adds `Plugin::on_widget_under_pointer` which gets called
whenever a widget is created whose rect contains the pointer.

The point of the hook is to capture a stack trace which can be used to
map widgets to their corresponding source code so it must be called
while the widget is being created. The obvious concern is performance
impact. However, since it's only called for rects under the cursor, the
effect seems negligible afaict. It's under `debug_assertions` just in
case.

This change is needed so we can publish the widget inspector we've been
working on. Basically a plugin that allows us to jump from any widget
back to their corresponding source code.

This video shows the plugin configured to open the corresponding code in
github, but normally it would open your local editor.

Update: [Live demo](https://membrane-io.github.io/egui/) (Firefox/Safari
not yet supported. `Cmd-I` to inspect. `Tab` to cycle filters. `Click`
to open). It will try to open a file under
`/home/runner/work/egui/egui/` so it won't work, but you get the idea.


https://github.com/user-attachments/assets/afe4d6af-7f67-44b5-be25-44f7564d9a3a

## What's next

After this gets merged I plan to publish the above plugin as its own
crate, that way we can iterate and release quickly while things are
still changing. I agree it would make sense to eventually merge it into
the main egui repo (like @emilk suggested in emilk#4650).

* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants