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

Expose interactive rects from the last pass (#8211)

## Summary

Adds `Context::interactive_rects_last_pass() -> Vec<Rect>`, an
integration-facing helper that returns the same widget interaction
rectangles egui uses for hit-testing in the last completed pass.

The method filters out disabled widgets, non-interactive widgets, and
layers that currently do not allow interaction. It also applies
per-layer transforms so the returned rectangles are in global viewport
coordinates.

## Motivation

Some egui integrations need to declare platform-level input regions
before pointer events can reach egui itself. A concrete example is a
transparent or click-through overlay: the platform/windowing layer must
know which parts of the overlay should receive input and which parts
should pass through to whatever is underneath.

Today egui keeps this information internally in `WidgetRects` and uses
it for its own hit-testing, but integrations cannot enumerate those
rectangles. Downstream integrations therefore need app-level side
channels where each app manually reports its clickable rectangles. That
is fragile because it duplicates data egui already has, is easy for
applications to forget, and tends to go stale when widgets move or
popups/menus appear.

This method exposes only the already-derived, integration-relevant
result instead of making `WidgetRects` itself part of the public API.

## Notes

- The method uses the last completed pass because that is the same data
egui uses for interaction at the start of the next pass.
- Rectangles are returned in layer order for deterministic output.
- Non-positive or non-finite rectangles are skipped.

## Verification

- `cargo check -p egui`
- `cargo test -p egui --lib`

Co-authored-by: psyche314 <psyche314@users.noreply.github.com>
This commit is contained in:
psyche314
2026-06-10 16:00:41 +08:00
committed by GitHub
parent 923ddcf30d
commit 704d86e4aa

View File

@@ -1307,6 +1307,52 @@ impl Context {
.map(|widget_rect| self.get_response(widget_rect)) .map(|widget_rect| self.get_response(widget_rect))
} }
/// Rectangles that could receive pointer input in the last completed pass.
///
/// This exposes the same widget rectangles egui uses for hit-testing, after
/// filtering out disabled widgets, non-interactive widgets, and layers that
/// are currently blocked from interaction. The returned rectangles are in
/// global viewport coordinates, with layer transforms applied.
///
/// This is meant for integrations that must declare platform input regions
/// before pointer events can be delivered to egui, such as transparent or
/// click-through overlays.
#[must_use]
pub fn interactive_rects_last_pass(&self) -> Vec<Rect> {
self.read(|ctx| {
let Some(viewport) = ctx.viewports.get(&ctx.viewport_id()) else {
return Vec::new();
};
let mut layers: Vec<LayerId> = viewport.prev_pass.widgets.layer_ids().collect();
layers.sort_by(|&a, &b| ctx.memory.areas().compare_order(a, b));
let mut rects = Vec::new();
for layer_id in layers {
if !ctx.memory.allows_interaction(layer_id) {
continue;
}
let to_global = ctx.memory.to_global.get(&layer_id).copied();
for widget in viewport.prev_pass.widgets.get_layer(layer_id) {
if !widget.enabled || !widget.sense.interactive() {
continue;
}
let rect = if let Some(to_global) = to_global {
to_global * widget.interact_rect
} else {
widget.interact_rect
};
if rect.is_positive() && rect.is_finite() {
rects.push(rect);
}
}
}
rects
})
}
/// Do all interaction for an existing widget, without (re-)registering it. /// Do all interaction for an existing widget, without (re-)registering it.
pub(crate) fn get_response(&self, widget_rect: WidgetRect) -> Response { pub(crate) fn get_response(&self, widget_rect: WidgetRect) -> Response {
use response::Flags; use response::Flags;