diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneTooltip.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneTooltip.cs index fc5ae4856c..34f81f9a00 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneTooltip.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneTooltip.cs @@ -265,6 +265,16 @@ private void generateTest(bool cursorlessTooltip) Text = "with real time updates!", Size = new Vector2(400, 30), }, + new CustomTallTooltipSpriteTextAlt("this one doesn't overlap!") + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + new CustomTallTooltipSpriteText("this one is anchored down and overlaps!") + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, new TooltipContainer { AutoSizeAxes = Axes.Both, @@ -353,6 +363,26 @@ public CustomTooltipSpriteTextAlt(string displayedContent, string tooltipContent public override ITooltip GetCustomTooltip() => new CustomTooltipAlt(); } + private partial class CustomTallTooltipSpriteText : CustomTooltipSpriteText + { + public CustomTallTooltipSpriteText(string displayedContent, string tooltipContent = null) + : base(displayedContent, tooltipContent) + { + } + + public override ITooltip GetCustomTooltip() => new CustomTallTooltip(); + } + + private partial class CustomTallTooltipSpriteTextAlt : CustomTooltipSpriteText + { + public CustomTallTooltipSpriteTextAlt(string displayedContent, string tooltipContent = null) + : base(displayedContent, tooltipContent) + { + } + + public override ITooltip GetCustomTooltip() => new CustomTallTooltipAlt(); + } + private class CustomContent { public readonly LocalisableString Text; @@ -367,7 +397,7 @@ private partial class CustomTooltip : CompositeDrawable, ITooltip { private static int i; - private readonly SpriteText text; + protected readonly SpriteText Text; public CustomTooltip() { @@ -380,7 +410,7 @@ public CustomTooltip() RelativeSizeAxes = Axes.Both, Colour = FrameworkColour.GreenDark, }, - text = new SpriteText + Text = new SpriteText { Font = FrameworkFont.Regular.With(size: 16), Padding = new MarginPadding(5), @@ -395,9 +425,10 @@ public CustomTooltip() }; } - public void SetContent(CustomContent content) => text.Text = content.Text; + public void SetContent(CustomContent content) => Text.Text = content.Text; public void Move(Vector2 pos) => Position = pos; + public virtual bool AllowCursorOverlap => true; } private partial class CustomTooltipAlt : CustomTooltip @@ -410,6 +441,21 @@ public CustomTooltipAlt() } } + private partial class CustomTallTooltip : CustomTooltip + { + public CustomTallTooltip() + { + AutoSizeAxes = Axes.Both; + + Text.Width = 0; + } + } + + private partial class CustomTallTooltipAlt : CustomTallTooltip + { + public override bool AllowCursorOverlap => false; + } + private partial class TooltipSpriteText : Container, IHasTooltip { public LocalisableString TooltipText { get; } diff --git a/osu.Framework/Graphics/Cursor/ITooltip.cs b/osu.Framework/Graphics/Cursor/ITooltip.cs index 2cec948cf0..30afa4b155 100644 --- a/osu.Framework/Graphics/Cursor/ITooltip.cs +++ b/osu.Framework/Graphics/Cursor/ITooltip.cs @@ -21,6 +21,16 @@ public interface ITooltip : IDrawable /// /// The position the tooltip should be moved to. void Move(Vector2 pos); + + /// + /// Whether to allow the cursor to overlap the tooltip. If true, the tooltip will try to stay anchored + /// to the bottom-right of the cursor while keeping itself on screen, potentially overlapping the cursor. + /// If false, the tooltip will move to the top-right when the content doesn't fit with the current cursor location. + /// + /// + /// If true, this can be used to avoid abrupt position changes when the content is near the bottom window edge. + /// + bool AllowCursorOverlap { get; } } /// diff --git a/osu.Framework/Graphics/Cursor/TooltipContainer.cs b/osu.Framework/Graphics/Cursor/TooltipContainer.cs index 3f4c65ab5b..8dc9d84dfc 100644 --- a/osu.Framework/Graphics/Cursor/TooltipContainer.cs +++ b/osu.Framework/Graphics/Cursor/TooltipContainer.cs @@ -129,15 +129,23 @@ private Vector2 computeMouseTooltipPosition() Vector2 southEast = new Vector2(1).Normalized(); Vector2 tooltipPos = cursorCentre + southEast * boundingRadius; + const float edge_padding = 5; + // Clamp position to tooltip container - tooltipPos.X = Math.Min(tooltipPos.X, DrawWidth - CurrentTooltip.DrawSize.X - 5); - float dX = Math.Max(0, tooltipPos.X - cursorCentre.X); - float dY = MathF.Sqrt(boundingRadius * boundingRadius - dX * dX); + tooltipPos.X = Math.Min(tooltipPos.X, DrawWidth - CurrentTooltip.DrawSize.X - edge_padding); - if (tooltipPos.Y > DrawHeight - CurrentTooltip.DrawSize.Y - 5) - tooltipPos.Y = cursorCentre.Y - dY - CurrentTooltip.DrawSize.Y; + if (CurrentTooltip.AllowCursorOverlap) + tooltipPos.Y = Math.Min(tooltipPos.Y, DrawHeight - CurrentTooltip.DrawSize.Y - edge_padding); else - tooltipPos.Y = cursorCentre.Y + dY; + { + float dX = Math.Max(0, tooltipPos.X - cursorCentre.X); + float dY = MathF.Sqrt(boundingRadius * boundingRadius - dX * dX); + + if (tooltipPos.Y > DrawHeight - CurrentTooltip.DrawSize.Y - edge_padding) + tooltipPos.Y = Math.Max(cursorCentre.Y - dY - CurrentTooltip.DrawSize.Y, edge_padding); + else + tooltipPos.Y = cursorCentre.Y + dY; + } return tooltipPos; } @@ -418,6 +426,8 @@ public virtual void Refresh() /// /// The new position of the tooltip. public virtual void Move(Vector2 pos) => Position = pos; + + public bool AllowCursorOverlap => false; } } }