Consider all non-interactie widgets under the mouse pointer hovered (#4291)
At least all those above any interactive widget. * Closes https://github.com/emilk/egui/issues/4286 I feel there is still more thinking to be done about what is considered `hovered` and how it relates to `contains_pointer`, but this PR at least fixes tooltips for uninteractive widgets
This commit is contained in:
parent
21835c3176
commit
bb06befef1
|
|
@ -242,18 +242,39 @@ pub(crate) fn interact(
|
||||||
.chain(&long_touched)
|
.chain(&long_touched)
|
||||||
.copied()
|
.copied()
|
||||||
.collect()
|
.collect()
|
||||||
} else if hits.click.is_some() || hits.drag.is_some() {
|
|
||||||
// We are hovering over an interactive widget or two.
|
|
||||||
hits.click.iter().chain(&hits.drag).map(|w| w.id).collect()
|
|
||||||
} else {
|
} else {
|
||||||
// Whatever is topmost is what we are hovering.
|
// We may be hovering a an interactive widget or two.
|
||||||
// TODO(emilk): consider handle hovering over multiple top-most widgets?
|
// We must also consider the case where non-interactive widgets
|
||||||
// TODO(emilk): allow hovering close widgets?
|
// are _on top_ of an interactive widget.
|
||||||
hits.contains_pointer
|
// For instance: a label in a draggable window.
|
||||||
.last()
|
// In that case we want to hover _both_ widgets,
|
||||||
.map(|w| w.id)
|
// otherwise we won't see tooltips for the label.
|
||||||
.into_iter()
|
//
|
||||||
.collect()
|
// Because of how `Ui` work, we will often allocate the `Ui` rect
|
||||||
|
// _after_ adding the children in it (once we know the size it will occopy)
|
||||||
|
// so we will also have a lot of such `Ui` widgets rects covering almost any widget.
|
||||||
|
//
|
||||||
|
// So: we want to hover _all_ widgets above the interactive widget (if any),
|
||||||
|
// but none below it (an interactive widget stops the hover search).
|
||||||
|
//
|
||||||
|
// To know when to stop we need to first know the order of the widgets,
|
||||||
|
// which luckily we have in the `WidgetRects`.
|
||||||
|
|
||||||
|
let order = |id| widgets.order(id).map(|(_layer, order)| order); // we ignore the layer, since all widgets at this point is in the same layer
|
||||||
|
|
||||||
|
let click_order = hits.click.and_then(|w| order(w.id)).unwrap_or(0);
|
||||||
|
let drag_order = hits.drag.and_then(|w| order(w.id)).unwrap_or(0);
|
||||||
|
let top_interactive_order = click_order.max(drag_order);
|
||||||
|
|
||||||
|
let mut hovered: IdSet = hits.click.iter().chain(&hits.drag).map(|w| w.id).collect();
|
||||||
|
|
||||||
|
for w in &hits.contains_pointer {
|
||||||
|
if top_interactive_order <= order(w.id).unwrap_or(0) {
|
||||||
|
hovered.insert(w.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hovered
|
||||||
};
|
};
|
||||||
|
|
||||||
InteractionSnapshot {
|
InteractionSnapshot {
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,11 @@ impl WidgetRects {
|
||||||
self.by_id.get(&id).map(|(_, w)| w)
|
self.by_id.get(&id).map(|(_, w)| w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In which layer, and in which order in that layer?
|
||||||
|
pub fn order(&self, id: Id) -> Option<(LayerId, usize)> {
|
||||||
|
self.by_id.get(&id).map(|(idx, w)| (w.layer_id, *idx))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains(&self, id: Id) -> bool {
|
pub fn contains(&self, id: Id) -> bool {
|
||||||
self.by_id.contains_key(&id)
|
self.by_id.contains_key(&id)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue