Skip to content

Commit a7eed0a

Browse files
authored
Once you have waited for a tooltip to show, show the next one right away (#4585)
* Closes #4582 User-story: there are multiple icons in a row, and the user wants them explained. They hover over one until the tooltips appears. They then move on to the next and don't want to wait for that tooltip again.
1 parent 89968e6 commit a7eed0a

File tree

2 files changed

+63
-20
lines changed

2 files changed

+63
-20
lines changed

crates/egui/src/response.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -584,14 +584,7 @@ impl Response {
584584
return true;
585585
}
586586

587-
if self.context_menu_opened() {
588-
return false;
589-
}
590-
591-
if ComboBox::is_open(&self.ctx, self.id) {
592-
return false; // Don't cover the open ComboBox with a tooltip
593-
}
594-
587+
// Fast early-outs:
595588
if self.enabled {
596589
if !self.hovered || !self.ctx.input(|i| i.pointer.has_pointer()) {
597590
return false;
@@ -600,20 +593,44 @@ impl Response {
600593
return false;
601594
}
602595

603-
if self.ctx.style().interaction.show_tooltips_only_when_still {
604-
// We only show the tooltip when the mouse pointer is still,
605-
// but once shown we keep showing it until the mouse leaves the parent.
596+
if self.context_menu_opened() {
597+
return false;
598+
}
606599

607-
if !self.ctx.input(|i| i.pointer.is_still()) && !self.is_tooltip_open() {
608-
// wait for mouse to stop
609-
self.ctx.request_repaint();
610-
return false;
611-
}
600+
if ComboBox::is_open(&self.ctx, self.id) {
601+
return false; // Don't cover the open ComboBox with a tooltip
612602
}
613603

614-
if !self.is_tooltip_open() {
615-
let time_til_tooltip = self.ctx.style().interaction.tooltip_delay
616-
- self.ctx.input(|i| i.pointer.time_since_last_movement());
604+
let when_was_a_toolip_last_shown_id = Id::new("when_was_a_toolip_last_shown");
605+
let now = self.ctx.input(|i| i.time);
606+
607+
let when_was_a_toolip_last_shown = self
608+
.ctx
609+
.data(|d| d.get_temp::<f64>(when_was_a_toolip_last_shown_id));
610+
611+
let tooltip_delay = self.ctx.style().interaction.tooltip_delay;
612+
let tooltip_grace_time = self.ctx.style().interaction.tooltip_grace_time;
613+
614+
// There is a tooltip_delay before showing the first tooltip,
615+
// but once one tooltips is show, moving the mouse cursor to
616+
// another widget should show the tooltip for that widget right away.
617+
618+
// Let the user quickly move over some dead space to hover the next thing
619+
let tooltip_was_recently_shown = when_was_a_toolip_last_shown
620+
.map_or(false, |time| ((now - time) as f32) < tooltip_grace_time);
621+
622+
if !tooltip_was_recently_shown && !self.is_tooltip_open() {
623+
if self.ctx.style().interaction.show_tooltips_only_when_still {
624+
// We only show the tooltip when the mouse pointer is still.
625+
if !self.ctx.input(|i| i.pointer.is_still()) {
626+
// wait for mouse to stop
627+
self.ctx.request_repaint();
628+
return false;
629+
}
630+
}
631+
632+
let time_til_tooltip =
633+
tooltip_delay - self.ctx.input(|i| i.pointer.time_since_last_movement());
617634

618635
if 0.0 < time_til_tooltip {
619636
// Wait until the mouse has been still for a while
@@ -633,6 +650,12 @@ impl Response {
633650
return false;
634651
}
635652

653+
// All checks passed: show the tooltip!
654+
655+
// Remember that we're showing a tooltip
656+
self.ctx
657+
.data_mut(|data| data.insert_temp::<f64>(when_was_a_toolip_last_shown_id, now));
658+
636659
true
637660
}
638661

crates/egui/src/style.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,13 @@ pub struct Interaction {
658658
/// Delay in seconds before showing tooltips after the mouse stops moving
659659
pub tooltip_delay: f32,
660660

661+
/// If you have waited for a tooltip and then hover some other widget within
662+
/// this many seconds, then show the new tooltip right away,
663+
/// skipping [`Self::tooltip_delay`].
664+
///
665+
/// This lets the user quickly move over some dead space to hover the next thing.
666+
pub tooltip_grace_time: f32,
667+
661668
/// Can you select the text on a [`crate::Label`] by default?
662669
pub selectable_labels: bool,
663670

@@ -1102,7 +1109,8 @@ impl Default for Interaction {
11021109
resize_grab_radius_corner: 10.0,
11031110
interact_radius: 5.0,
11041111
show_tooltips_only_when_still: true,
1105-
tooltip_delay: 0.3,
1112+
tooltip_delay: 0.5,
1113+
tooltip_grace_time: 0.2,
11061114
selectable_labels: true,
11071115
multi_widget_text_select: true,
11081116
}
@@ -1590,6 +1598,7 @@ impl Interaction {
15901598
resize_grab_radius_corner,
15911599
show_tooltips_only_when_still,
15921600
tooltip_delay,
1601+
tooltip_grace_time,
15931602
selectable_labels,
15941603
multi_widget_text_select,
15951604
} = self;
@@ -1623,6 +1632,17 @@ impl Interaction {
16231632
.suffix(" s"),
16241633
);
16251634
ui.end_row();
1635+
1636+
ui.label("Tooltip grace time").on_hover_text(
1637+
"If a tooltip is open and you hover another widget within this grace period, show the next tooltip right away",
1638+
);
1639+
ui.add(
1640+
DragValue::new(tooltip_grace_time)
1641+
.clamp_range(0.0..=1.0)
1642+
.speed(0.05)
1643+
.suffix(" s"),
1644+
);
1645+
ui.end_row();
16261646
});
16271647

16281648
ui.checkbox(

0 commit comments

Comments
 (0)