diff --git a/osu.Framework.Tests/Visual/TestCaseTooltip.cs b/osu.Framework.Tests/Visual/TestCaseTooltip.cs index ca67cd3740..d2a8b9b7e0 100644 --- a/osu.Framework.Tests/Visual/TestCaseTooltip.cs +++ b/osu.Framework.Tests/Visual/TestCaseTooltip.cs @@ -150,6 +150,8 @@ private class CustomTooltipSpriteText : Container, IHasTooltip public string TooltipText => tooltipText; + public double? AppearDelay => null; + public CustomTooltipSpriteText(string displayedText, string tooltipText) { this.tooltipText = tooltipText; @@ -177,6 +179,8 @@ private class TooltipTooltipContainer : TooltipContainer, IHasTooltip { public string TooltipText { get; set; } + double? IHasTooltip.AppearDelay => null; + public TooltipTooltipContainer(string tooltipText) { TooltipText = tooltipText; @@ -186,12 +190,16 @@ public TooltipTooltipContainer(string tooltipText) private class TooltipTextbox : TextBox, IHasTooltip { public string TooltipText => Text; + + public double? AppearDelay => null; } private class TooltipBox : Box, IHasTooltip { public string TooltipText { get; set; } + public double? AppearDelay => null; + public override bool HandleKeyboardInput => true; public override bool HandleMouseInput => true; } diff --git a/osu.Framework/Graphics/Cursor/IHasTooltip.cs b/osu.Framework/Graphics/Cursor/IHasTooltip.cs index eb44d17ede..6d2a520584 100644 --- a/osu.Framework/Graphics/Cursor/IHasTooltip.cs +++ b/osu.Framework/Graphics/Cursor/IHasTooltip.cs @@ -14,5 +14,10 @@ public interface IHasTooltip : IDrawable /// Tooltip that shows when hovering the drawable. /// string TooltipText { get; } + + /// + /// The delay until the tooltip should be displayed. Null means the from the containing the implementing this interface will be used. + /// + double? AppearDelay { get; } } } diff --git a/osu.Framework/Graphics/Cursor/TooltipContainer.cs b/osu.Framework/Graphics/Cursor/TooltipContainer.cs index a0848d73fa..59b37c7e1b 100644 --- a/osu.Framework/Graphics/Cursor/TooltipContainer.cs +++ b/osu.Framework/Graphics/Cursor/TooltipContainer.cs @@ -155,6 +155,7 @@ protected override void Update() private readonly List recentMousePositions = new List(); private double lastRecordedPositionTime; + private IHasTooltip lastCandidate; /// /// Determines which drawable should currently receive a tooltip, taking into account /// and . Returns null if no valid @@ -167,8 +168,19 @@ private IHasTooltip findTooltipTarget() if (inputManager.DraggedDrawable is IHasTooltip draggedTarget) return hasValidTooltip(draggedTarget) ? draggedTarget : null; + IHasTooltip targetCandidate = FindTargets().FirstOrDefault(t => t.TooltipText != null); + // check this first - if we find no target candidate we still want to clear the recorded positions and update the lastCandidate. + if (targetCandidate != lastCandidate) + { + recentMousePositions.Clear(); + lastCandidate = targetCandidate; + } + if (targetCandidate == null) + return null; + + double appearDelay = targetCandidate.AppearDelay ?? AppearDelay; // Always keep 10 positions at equally-sized time intervals that add up to AppearDelay. - double positionRecordInterval = AppearDelay / 10; + double positionRecordInterval = appearDelay / 10; if (Time.Current - lastRecordedPositionTime >= positionRecordInterval) { lastRecordedPositionTime = Time.Current; @@ -179,11 +191,15 @@ private IHasTooltip findTooltipTarget() }); } - recentMousePositions.RemoveAll(t => Time.Current - t.Time > AppearDelay); + // check that we have recorded enough positions to make a judgement about whether or not the cursor has been standing still for the required amount of time. + // we can skip this if the appear-delay is set to 0, since then tooltips can appear instantly and we don't need to wait to record enough positions. + if (appearDelay > 0 && (recentMousePositions.Count == 0 || lastRecordedPositionTime - recentMousePositions[0].Time < appearDelay - positionRecordInterval)) + return null; + recentMousePositions.RemoveAll(t => Time.Current - t.Time > appearDelay); // For determining whether to show a tooltip we first select only those positions // which happened within a shorter, alpha-adjusted appear delay. - double alphaModifiedAppearDelay = (1 - currentTooltip.Alpha) * AppearDelay; + double alphaModifiedAppearDelay = (1 - currentTooltip.Alpha) * appearDelay; var relevantPositions = recentMousePositions.Where(t => Time.Current - t.Time <= alphaModifiedAppearDelay); // We then check whether all relevant positions fall within a radius of AppearRadius within the @@ -194,7 +210,7 @@ private IHasTooltip findTooltipTarget() float appearRadiusSq = AppearRadius * AppearRadius; if (relevantPositions.All(t => Vector2Extensions.DistanceSquared(t.Position, first) < appearRadiusSq)) - return FindTargets().FirstOrDefault(t => t.TooltipText != null); + return targetCandidate; return null; }