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:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user