Browse Source

Fixed overlay popups not automatically closing (#16564)

* Fixed overlay popups not automatically closing

* Fix overlay tooltip tests not actually generating overlay tooltips
Verify popup type whenever we verify that the popup is open

* Fixed overlay tooltips not being attached to the visual tree in tests
pull/16593/head
Tom Edwards 2 years ago
committed by GitHub
parent
commit
d1cdb29ba0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/Avalonia.Controls/ToolTipService.cs
  2. 97
      tests/Avalonia.Controls.UnitTests/ToolTipTests.cs

2
src/Avalonia.Controls/ToolTipService.cs

@ -78,7 +78,7 @@ namespace Avalonia.Controls
{ {
var currentToolTip = _tipControl?.GetValue(ToolTip.ToolTipProperty); var currentToolTip = _tipControl?.GetValue(ToolTip.ToolTipProperty);
if (root == currentToolTip?.VisualRoot) if (root == currentToolTip?.PopupHost?.HostedVisualTreeRoot)
{ {
// Don't update while the pointer is over a tooltip // Don't update while the pointer is over a tooltip
return; return;

97
tests/Avalonia.Controls.UnitTests/ToolTipTests.cs

@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reactive;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Avalonia.Controls.Primitives;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -15,18 +18,65 @@ namespace Avalonia.Controls.UnitTests
public class ToolTipTests_Popup : ToolTipTests public class ToolTipTests_Popup : ToolTipTests
{ {
protected override TestServices ConfigureServices(TestServices baseServices) => baseServices; protected override TestServices ConfigureServices(TestServices baseServices) => baseServices;
protected override void SetupWindowMock(Mock<IWindowImpl> windowImpl) { }
protected override void VerifyToolTipType(Control control)
{
var toolTip = control.GetValue(ToolTip.ToolTipProperty);
Assert.IsType<PopupRoot>(toolTip.PopupHost);
Assert.Same(toolTip.VisualRoot, toolTip.PopupHost);
}
} }
public class ToolTipTests_Overlay : ToolTipTests public class ToolTipTests_Overlay : ToolTipTests, IDisposable
{ {
private readonly IDisposable _toolTipOpenSubscription;
public ToolTipTests_Overlay()
{
_toolTipOpenSubscription = ToolTip.IsOpenProperty.Changed.Subscribe(new AnonymousObserver<AvaloniaPropertyChangedEventArgs<bool>>(e =>
{
if (e.Sender is Visual { VisualRoot: {} root } visual)
OverlayLayer.GetOverlayLayer(visual).Measure(root.ClientSize);
}));
}
public void Dispose()
{
_toolTipOpenSubscription.Dispose();
}
protected override TestServices ConfigureServices(TestServices baseServices) => protected override TestServices ConfigureServices(TestServices baseServices) =>
baseServices.With(windowingPlatform: new MockWindowingPlatform(popupImpl: window => null)); baseServices.With(windowingPlatform: new MockWindowingPlatform(popupImpl: window => null));
protected override void SetupWindowMock(Mock<IWindowImpl> windowImpl)
{
windowImpl.Setup(x => x.CreatePopup()).Returns(default(IPopupImpl));
}
protected override void VerifyToolTipType(Control control)
{
var toolTip = control.GetValue(ToolTip.ToolTipProperty);
Assert.IsType<OverlayPopupHost>(toolTip.PopupHost);
Assert.Same(toolTip.VisualRoot, control.VisualRoot);
}
} }
public abstract class ToolTipTests public abstract class ToolTipTests
{ {
protected abstract TestServices ConfigureServices(TestServices baseServices); protected abstract TestServices ConfigureServices(TestServices baseServices);
protected abstract void SetupWindowMock(Mock<IWindowImpl> windowImpl);
protected abstract void VerifyToolTipType(Control control);
private void AssertToolTipOpen(Control control)
{
Assert.True(ToolTip.GetIsOpen(control));
VerifyToolTipType(control);
}
private static readonly MouseDevice s_mouseDevice = new(new Pointer(0, PointerType.Mouse, true)); private static readonly MouseDevice s_mouseDevice = new(new Pointer(0, PointerType.Mouse, true));
[Fact] [Fact]
@ -46,7 +96,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(panel, target); SetupWindowAndActivateToolTip(panel, target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
panel.Children.Remove(target); panel.Children.Remove(target);
@ -74,7 +124,7 @@ namespace Avalonia.Controls.UnitTests
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
panel.Children.Remove(target); panel.Children.Remove(target);
@ -95,7 +145,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(target); SetupWindowAndActivateToolTip(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
} }
} }
@ -112,7 +162,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(target); SetupWindowAndActivateToolTip(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
Assert.Equal("Tip", target.GetValue(ToolTip.ToolTipProperty).Content); Assert.Equal("Tip", target.GetValue(ToolTip.ToolTipProperty).Content);
ToolTip.SetTip(target, "Tip1"); ToolTip.SetTip(target, "Tip1");
@ -139,7 +189,7 @@ namespace Avalonia.Controls.UnitTests
timer.ForceFire(); timer.ForceFire();
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
} }
} }
@ -188,6 +238,7 @@ namespace Avalonia.Controls.UnitTests
ToolTip.SetIsOpen(decorator, true); ToolTip.SetIsOpen(decorator, true);
Assert.Equal(new[] { ":open" }, toolTip.Classes); Assert.Equal(new[] { ":open" }, toolTip.Classes);
VerifyToolTipType(decorator);
} }
} }
@ -197,8 +248,11 @@ namespace Avalonia.Controls.UnitTests
using (UnitTestApplication.Start(ConfigureServices(TestServices.StyledWindow))) using (UnitTestApplication.Start(ConfigureServices(TestServices.StyledWindow)))
{ {
var toolTip = new ToolTip(); var toolTip = new ToolTip();
var window = new Window();
var windowImpl = MockWindowingPlatform.CreateWindowMock();
SetupWindowMock(windowImpl);
var window = new Window(windowImpl.Object);
var decorator = new Decorator() var decorator = new Decorator()
{ {
[ToolTip.TipProperty] = toolTip [ToolTip.TipProperty] = toolTip
@ -211,6 +265,7 @@ namespace Avalonia.Controls.UnitTests
window.Presenter.ApplyTemplate(); window.Presenter.ApplyTemplate();
ToolTip.SetIsOpen(decorator, true); ToolTip.SetIsOpen(decorator, true);
AssertToolTipOpen(decorator);
ToolTip.SetIsOpen(decorator, false); ToolTip.SetIsOpen(decorator, false);
Assert.Empty(toolTip.Classes); Assert.Empty(toolTip.Classes);
@ -230,7 +285,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(target); SetupWindowAndActivateToolTip(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
target[ToolTip.TipProperty] = null; target[ToolTip.TipProperty] = null;
@ -253,13 +308,13 @@ namespace Avalonia.Controls.UnitTests
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty));
mouseEnter(tooltip); mouseEnter(tooltip);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
} }
} }
@ -277,16 +332,16 @@ namespace Avalonia.Controls.UnitTests
var mouseEnter = SetupWindowAndGetMouseEnterAction(target); var mouseEnter = SetupWindowAndGetMouseEnterAction(target);
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty));
mouseEnter(tooltip); mouseEnter(tooltip);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
} }
} }
@ -311,12 +366,12 @@ namespace Avalonia.Controls.UnitTests
var mouseEnter = SetupWindowAndGetMouseEnterAction(panel); var mouseEnter = SetupWindowAndGetMouseEnterAction(panel);
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty));
mouseEnter(tooltip); mouseEnter(tooltip);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
mouseEnter(other); mouseEnter(other);
@ -352,7 +407,7 @@ namespace Avalonia.Controls.UnitTests
Assert.False(ToolTip.GetIsOpen(other)); // long delay Assert.False(ToolTip.GetIsOpen(other)); // long delay
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); // no delay AssertToolTipOpen(target); // no delay
mouseEnter(other); mouseEnter(other);
Assert.True(ToolTip.GetIsOpen(other)); // delay skipped, a tooltip was already open Assert.True(ToolTip.GetIsOpen(other)); // delay skipped, a tooltip was already open
@ -360,7 +415,7 @@ namespace Avalonia.Controls.UnitTests
// Now disable the between-show system // Now disable the between-show system
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
ToolTip.SetBetweenShowDelay(other, -1); ToolTip.SetBetweenShowDelay(other, -1);
@ -389,7 +444,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(target); SetupWindowAndActivateToolTip(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
target[ToolTip.TipProperty] = null; target[ToolTip.TipProperty] = null;
@ -442,7 +497,7 @@ namespace Avalonia.Controls.UnitTests
SetupWindowAndActivateToolTip(target); SetupWindowAndActivateToolTip(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
target[ToolTip.TipProperty] = null; target[ToolTip.TipProperty] = null;
@ -463,7 +518,7 @@ namespace Avalonia.Controls.UnitTests
var mouseEnter = SetupWindowAndGetMouseEnterAction(target); var mouseEnter = SetupWindowAndGetMouseEnterAction(target);
mouseEnter(target); mouseEnter(target);
Assert.True(ToolTip.GetIsOpen(target)); AssertToolTipOpen(target);
var topLevel = TopLevel.GetTopLevel(target); var topLevel = TopLevel.GetTopLevel(target);
topLevel.PlatformImpl.Input(new RawPointerEventArgs(s_mouseDevice, (ulong)DateTime.Now.Ticks, topLevel, topLevel.PlatformImpl.Input(new RawPointerEventArgs(s_mouseDevice, (ulong)DateTime.Now.Ticks, topLevel,
@ -476,6 +531,8 @@ namespace Avalonia.Controls.UnitTests
private Action<Control> SetupWindowAndGetMouseEnterAction(Control windowContent, [CallerMemberName] string testName = null) private Action<Control> SetupWindowAndGetMouseEnterAction(Control windowContent, [CallerMemberName] string testName = null)
{ {
var windowImpl = MockWindowingPlatform.CreateWindowMock(); var windowImpl = MockWindowingPlatform.CreateWindowMock();
SetupWindowMock(windowImpl);
var hitTesterMock = new Mock<IHitTester>(); var hitTesterMock = new Mock<IHitTester>();
var window = new Window(windowImpl.Object) var window = new Window(windowImpl.Object)

Loading…
Cancel
Save