Skip to content

Commit 1a060c0

Browse files
committed
better tooltip positioning (so tooltips don't cover the text they're annotating)
1 parent ed79216 commit 1a060c0

File tree

10 files changed

+103
-28
lines changed

10 files changed

+103
-28
lines changed

Intersect.Client.Core/Core/Input.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -374,13 +374,14 @@ MouseButton mouseButton
374374
return invocationList.Any(interceptor => interceptor(modifier, mouseButton));
375375
}
376376

377-
public static void OnMouseDown(Keys modifier, MouseButton mouseButton)
377+
public static bool TestInterceptMouse(Keys modifier, MouseButton mouseButton, bool down)
378378
{
379-
if (InvokeMouseButtonInterceptors(MouseDownIntercept, modifier, mouseButton))
380-
{
381-
return;
382-
}
379+
return modifier != Keys.Alt &&
380+
InvokeMouseButtonInterceptors(down ? MouseDownIntercept : MouseUpIntercept, modifier, mouseButton);
381+
}
383382

383+
public static void OnMouseDown(Keys modifier, MouseButton mouseButton)
384+
{
384385
var key = Keys.None;
385386
switch (mouseButton)
386387
{
@@ -465,11 +466,6 @@ public static void OnMouseDown(Keys modifier, MouseButton mouseButton)
465466

466467
public static void OnMouseUp(Keys modifier, MouseButton mouseButton)
467468
{
468-
if (InvokeMouseButtonInterceptors(MouseUpIntercept, modifier, mouseButton))
469-
{
470-
return;
471-
}
472-
473469
var key = Keys.LButton;
474470
switch (mouseButton)
475471
{

Intersect.Client.Core/Interface/Debugging/DebugWindow.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ private LabeledCheckBox CreateInfoCheckboxViewClickedNodeInDebugger(Base parent)
288288
Font = _defaultFont,
289289
IsChecked = _viewClickedNodeInDebugger,
290290
Text = Strings.Debug.ViewClickedNodeInDebugger,
291+
TooltipText = Strings.Debug.ViewClickedNodeInDebuggerTooltip,
291292
};
292293

293294
checkbox.CheckChanged += (_, _) =>

Intersect.Client.Core/Localization/Strings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,9 @@ public partial struct Debug
945945
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
946946
public static LocalizedString ViewClickedNodeInDebugger = @"View Clicked Node in Debugger";
947947

948+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
949+
public static LocalizedString ViewClickedNodeInDebuggerTooltip = @"Hold Alt to temporarily turn this off (so you can turn off this option)";
950+
948951
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
949952
public static LocalizedString EntitiesDrawn = @"Entities Drawn";
950953

Intersect.Client.Core/MonoGame/Input/MonoInput.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ private void CheckMouseButton(Keys modifier, ButtonState bs, MouseButton mb)
199199

200200
if (bs == ButtonState.Pressed && !MouseButtonDown(mb))
201201
{
202+
if (Core.Input.TestInterceptMouse(modifier, mb, down: true))
203+
{
204+
return;
205+
}
206+
202207
Interface.Interface.GwenInput.ProcessMessage(
203208
new GwenInputMessage(IntersectInput.InputEvent.MouseDown, GetMousePosition(), mb, Keys.Alt)
204209
);
@@ -207,6 +212,11 @@ private void CheckMouseButton(Keys modifier, ButtonState bs, MouseButton mb)
207212
}
208213
else if (bs == ButtonState.Released && MouseButtonDown(mb))
209214
{
215+
if (Core.Input.TestInterceptMouse(modifier, mb, down: false))
216+
{
217+
return;
218+
}
219+
210220
Interface.Interface.GwenInput.ProcessMessage(
211221
new GwenInputMessage(IntersectInput.InputEvent.MouseUp, GetMousePosition(), mb, Keys.Alt)
212222
);

Intersect.Client.Framework/Gwen/Control/Base.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,9 @@ public Cursor Cursor
717717

718718
public int GlobalY => Y + (Parent?.GlobalY ?? 0);
719719

720-
public Point PositionGlobal => new Point(X, Y) + (Parent?.PositionGlobal ?? Point.Empty);
720+
public Point PositionGlobal => new Point(X, Y) + (mActualParent?.PositionGlobal ?? Point.Empty);
721721

722-
public Rectangle BoundsGlobal => new Rectangle(PositionGlobal, Size);
722+
public Rectangle BoundsGlobal => new(PositionGlobal, Size);
723723

724724
/// <summary>
725725
/// Indicates whether the control is tabable (can be focused by pressing Tab).
@@ -1886,6 +1886,26 @@ public virtual Base Find(Predicate<Base> predicate, bool recurse = false)
18861886
: default;
18871887
}
18881888

1889+
public (Base Highest, Base Closest)? FindMatchingNodes<TComponent>() where TComponent : class
1890+
{
1891+
Base? highest = null;
1892+
Base? closest = null;
1893+
Base? currentComponent = this;
1894+
1895+
while (currentComponent is not null)
1896+
{
1897+
if (currentComponent is TComponent)
1898+
{
1899+
closest ??= currentComponent;
1900+
highest = currentComponent;
1901+
}
1902+
1903+
currentComponent = currentComponent.Parent;
1904+
}
1905+
1906+
return (highest is null || closest is null) ? null : (highest, closest);
1907+
}
1908+
18891909
/// <summary>
18901910
/// Finds all children that match the predicate.
18911911
/// </summary>

Intersect.Client.Framework/Gwen/Control/LabeledCheckBox.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Intersect.Client.Framework.Gwen.Control;
88
/// <summary>
99
/// CheckBox with label.
1010
/// </summary>
11-
public partial class LabeledCheckBox : Base
11+
public partial class LabeledCheckBox : Base, ITextContainer
1212
{
1313
private readonly Checkbox _checkbox;
1414

@@ -129,6 +129,8 @@ public string? Text
129129
set => _label.Text = value;
130130
}
131131

132+
public Color? TextPaddingDebugColor { get; set; }
133+
132134
/// <summary>
133135
/// Invoked when the control has been checked.
134136
/// </summary>

Intersect.Client.Framework/Gwen/Control/LabeledComboBox.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Intersect.Client.Framework.Gwen.Control;
66

7-
public partial class LabeledComboBox : Base, IAutoSizeToContents
7+
public partial class LabeledComboBox : Base, IAutoSizeToContents, ITextContainer
88
{
99
private readonly ComboBox _comboBox;
1010
private readonly Label _label;
@@ -112,4 +112,12 @@ protected override void OnChildBoundsChanged(Base child, Rectangle oldChildBound
112112

113113
Invalidate();
114114
}
115+
116+
string? ITextContainer.Text
117+
{
118+
get => _label.Text;
119+
set => _label.Text = value;
120+
}
121+
122+
public Color? TextPaddingDebugColor { get; set; }
115123
}

Intersect.Client.Framework/Gwen/Control/LabeledRadioButton.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Intersect.Client.Framework.Gwen.Control;
77
/// <summary>
88
/// RadioButton with label.
99
/// </summary>
10-
public partial class LabeledRadioButton : Base
10+
public partial class LabeledRadioButton : Base, ITextContainer
1111
{
1212

1313
private readonly Label mLabel;
@@ -45,12 +45,14 @@ public LabeledRadioButton(Base parent) : base(parent)
4545
/// <summary>
4646
/// Label text.
4747
/// </summary>
48-
public string Text
48+
public string? Text
4949
{
5050
get => mLabel.Text;
5151
set => mLabel.Text = value;
5252
}
5353

54+
public Color? TextPaddingDebugColor { get; set; }
55+
5456
// todo: would be nice to remove that
5557
internal RadioButton RadioButton => mRadioButton;
5658

Intersect.Client.Framework/Gwen/Control/LabeledSlider.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Intersect.Client.Framework.Gwen.Control;
99

10-
public partial class LabeledSlider : Base, IAutoSizeToContents, INumericInput
10+
public partial class LabeledSlider : Base, IAutoSizeToContents, INumericInput, ITextContainer
1111
{
1212
private readonly Label _label;
1313
private readonly Slider _slider;
@@ -343,4 +343,12 @@ public override void Focus(bool moveMouse = false)
343343
{
344344
base.Focus(moveMouse);
345345
}
346+
347+
public string? Text
348+
{
349+
get => _label.Text;
350+
set => _label.Text = value;
351+
}
352+
353+
public Color? TextPaddingDebugColor { get; set; }
346354
}

Intersect.Client.Framework/Gwen/ToolTip.cs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ public static void ControlDeleted(Base control)
6363
/// <param name="skin"></param>
6464
public static void RenderToolTip(Skin.Base skin)
6565
{
66-
if (_activeTooltipParent?.Tooltip == default)
66+
var activeTooltipParent = _activeTooltipParent;
67+
if (activeTooltipParent?.Tooltip == default)
6768
{
6869
return;
6970
}
7071

71-
var canvas = _activeTooltipParent.Canvas;
72+
var canvas = activeTooltipParent.Canvas;
7273
if (canvas == default)
7374
{
7475
return;
@@ -78,23 +79,47 @@ public static void RenderToolTip(Skin.Base skin)
7879

7980
var oldRenderOffset = render.RenderOffset;
8081
var mousePos = Input.InputHandler.MousePosition;
81-
var bounds = _activeTooltipParent.Tooltip.Bounds;
82+
var tooltipBounds = activeTooltipParent.Tooltip.Bounds;
8283

8384
var offset = Util.FloatRect(
84-
mousePos.X - bounds.Width * 0.5f,
85-
mousePos.Y - bounds.Height,
86-
bounds.Width,
87-
bounds.Height
85+
mousePos.X - tooltipBounds.Width * 0.5f,
86+
mousePos.Y - tooltipBounds.Height,
87+
tooltipBounds.Width,
88+
tooltipBounds.Height
8889
);
8990

90-
offset = Util.ClampRectToRect(offset, canvas.Bounds);
91+
var textContainerMatch = activeTooltipParent.FindMatchingNodes<ITextContainer>();
92+
93+
if (textContainerMatch is { Highest: { } highest, Closest: { } closest })
94+
{
95+
var closestBounds = closest.BoundsGlobal;
96+
var highestBounds = highest.BoundsGlobal;
97+
if (highestBounds.Top > tooltipBounds.Height)
98+
{
99+
offset.Y = highestBounds.Top - tooltipBounds.Height;
100+
}
101+
else
102+
{
103+
// TODO: check if we have enough space below
104+
offset.Y = highestBounds.Bottom;
105+
}
106+
107+
offset.X = highestBounds.X + (highestBounds.Width - tooltipBounds.Width) / 2;
108+
var closestBoundsX = closestBounds.X + closestBounds.Width * 0.25f;
109+
if (offset.X > closestBoundsX)
110+
{
111+
offset.X = closestBounds.X + (closestBounds.Width - tooltipBounds.Width) / 2;
112+
}
113+
}
114+
115+
var clampedOffset = Util.ClampRectToRect(offset, canvas.Bounds);
91116

92117
//Calculate offset on screen bounds
93-
render.AddRenderOffset(offset);
118+
render.AddRenderOffset(clampedOffset);
94119
render.EndClip();
95120

96-
skin.DrawToolTip(_activeTooltipParent.Tooltip);
97-
_activeTooltipParent.Tooltip.DoRender(skin);
121+
skin.DrawToolTip(activeTooltipParent.Tooltip);
122+
activeTooltipParent.Tooltip.DoRender(skin);
98123

99124
render.RenderOffset = oldRenderOffset;
100125
}

0 commit comments

Comments
 (0)