|
|
|
@ -1,45 +1,26 @@ |
|
|
|
using System; |
|
|
|
using System.Reactive.Disposables; |
|
|
|
using Avalonia.Markup.Xaml; |
|
|
|
using Avalonia.Platform; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using Avalonia.Data; |
|
|
|
using Avalonia.Input; |
|
|
|
using Avalonia.Input.Raw; |
|
|
|
using Avalonia.Rendering; |
|
|
|
using Avalonia.Threading; |
|
|
|
using Avalonia.UnitTests; |
|
|
|
using Avalonia.Utilities; |
|
|
|
using Avalonia.VisualTree; |
|
|
|
using Moq; |
|
|
|
using Xunit; |
|
|
|
|
|
|
|
namespace Avalonia.Controls.UnitTests |
|
|
|
{ |
|
|
|
public class TolTipTests |
|
|
|
public class ToolTipTests |
|
|
|
{ |
|
|
|
private MouseTestHelper _mouseHelper = new MouseTestHelper(); |
|
|
|
private static readonly MouseDevice s_mouseDevice = new(new Pointer(0, PointerType.Mouse, true)); |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Should_Not_Open_On_Detached_Control() |
|
|
|
{ |
|
|
|
//issue #3188
|
|
|
|
var control = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
Assert.False(control.IsAttachedToVisualTree); |
|
|
|
|
|
|
|
//here in issue #3188 exception is raised
|
|
|
|
_mouseHelper.Enter(control); |
|
|
|
|
|
|
|
Assert.False(ToolTip.GetIsOpen(control)); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Should_Close_When_Control_Detaches() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var panel = new Panel(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
@ -50,15 +31,7 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
|
|
|
|
panel.Children.Add(target); |
|
|
|
|
|
|
|
window.Content = panel; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
|
|
|
|
Assert.True(target.IsAttachedToVisualTree); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
SetupWindowAndActivateToolTip(panel, target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
@ -71,27 +44,22 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Close_When_Tip_Is_Opened_And_Detached_From_Visual_Tree() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var xaml = @"
|
|
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|
|
|
<Panel x:Name='PART_panel'> |
|
|
|
<Decorator x:Name='PART_target' ToolTip.Tip='{Binding Tip}' ToolTip.ShowDelay='0' /> |
|
|
|
</Panel> |
|
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); |
|
|
|
|
|
|
|
window.DataContext = new ToolTipViewModel(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
var target = new Decorator |
|
|
|
{ |
|
|
|
[!ToolTip.TipProperty] = new Binding("Tip"), |
|
|
|
[ToolTip.ShowDelayProperty] = 0, |
|
|
|
}; |
|
|
|
|
|
|
|
var target = window.Find<Decorator>("PART_target"); |
|
|
|
var panel = window.Find<Panel>("PART_panel"); |
|
|
|
|
|
|
|
Assert.True(target.IsAttachedToVisualTree); |
|
|
|
var panel = new Panel(); |
|
|
|
panel.Children.Add(target); |
|
|
|
|
|
|
|
var mouseEnter = SetupWindowAndGetMouseEnterAction(panel); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
panel.DataContext = new ToolTipViewModel(); |
|
|
|
|
|
|
|
mouseEnter(target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
@ -104,25 +72,15 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Open_On_Pointer_Enter() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
|
|
|
|
Assert.True(target.IsAttachedToVisualTree); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
SetupWindowAndActivateToolTip(target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
} |
|
|
|
@ -131,28 +89,19 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Content_Should_Update_When_Tip_Property_Changes_And_Already_Open() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
SetupWindowAndActivateToolTip(target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
Assert.Equal("Tip", target.GetValue(ToolTip.ToolTipProperty).Content); |
|
|
|
|
|
|
|
|
|
|
|
ToolTip.SetTip(target, "Tip1"); |
|
|
|
Assert.Equal("Tip1", target.GetValue(ToolTip.ToolTipProperty).Content); |
|
|
|
} |
|
|
|
@ -161,25 +110,15 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Open_On_Pointer_Enter_With_Delay() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 1 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
|
|
|
|
Assert.True(target.IsAttachedToVisualTree); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
SetupWindowAndActivateToolTip(target); |
|
|
|
|
|
|
|
var timer = Assert.Single(Dispatcher.SnapshotTimersForUnitTests()); |
|
|
|
Assert.Equal(TimeSpan.FromMilliseconds(1), timer.Interval); |
|
|
|
@ -268,23 +207,15 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Close_On_Null_Tip() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
SetupWindowAndActivateToolTip(target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
@ -297,28 +228,23 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Not_Close_When_Pointer_Is_Moved_Over_ToolTip() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
var mouseEnter = SetupWindowAndGetMouseEnterAction(target); |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
mouseEnter(target); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); |
|
|
|
_mouseHelper.Enter(tooltip); |
|
|
|
_mouseHelper.Leave(target); |
|
|
|
|
|
|
|
mouseEnter(tooltip); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
} |
|
|
|
@ -327,33 +253,25 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Not_Close_When_Pointer_Is_Moved_From_ToolTip_To_Original_Control() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
[ToolTip.ShowDelayProperty] = 0 |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = target; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
var mouseEnter = SetupWindowAndGetMouseEnterAction(target); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
mouseEnter(target); |
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); |
|
|
|
_mouseHelper.Enter(tooltip); |
|
|
|
_mouseHelper.Leave(target); |
|
|
|
mouseEnter(tooltip); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
_mouseHelper.Leave(tooltip); |
|
|
|
mouseEnter(target); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
} |
|
|
|
@ -362,10 +280,8 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
[Fact] |
|
|
|
public void Should_Close_When_Pointer_Is_Moved_From_ToolTip_To_Another_Control() |
|
|
|
{ |
|
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
|
|
|
using (UnitTestApplication.Start(TestServices.FocusableWindow)) |
|
|
|
{ |
|
|
|
var window = new Window(); |
|
|
|
|
|
|
|
var target = new Decorator() |
|
|
|
{ |
|
|
|
[ToolTip.TipProperty] = "Tip", |
|
|
|
@ -379,27 +295,74 @@ namespace Avalonia.Controls.UnitTests |
|
|
|
Children = { target, other } |
|
|
|
}; |
|
|
|
|
|
|
|
window.Content = panel; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
var mouseEnter = SetupWindowAndGetMouseEnterAction(panel); |
|
|
|
|
|
|
|
_mouseHelper.Enter(target); |
|
|
|
mouseEnter(target); |
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
var tooltip = Assert.IsType<ToolTip>(target.GetValue(ToolTip.ToolTipProperty)); |
|
|
|
_mouseHelper.Enter(tooltip); |
|
|
|
_mouseHelper.Leave(target); |
|
|
|
mouseEnter(tooltip); |
|
|
|
|
|
|
|
Assert.True(ToolTip.GetIsOpen(target)); |
|
|
|
|
|
|
|
_mouseHelper.Enter(other); |
|
|
|
_mouseHelper.Leave(tooltip); |
|
|
|
mouseEnter(other); |
|
|
|
|
|
|
|
Assert.False(ToolTip.GetIsOpen(target)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private Action<Control> SetupWindowAndGetMouseEnterAction(Control windowContent, [CallerMemberName] string testName = null) |
|
|
|
{ |
|
|
|
var windowImpl = MockWindowingPlatform.CreateWindowMock(); |
|
|
|
var hitTesterMock = new Mock<IHitTester>(); |
|
|
|
|
|
|
|
var window = new Window(windowImpl.Object) |
|
|
|
{ |
|
|
|
HitTesterOverride = hitTesterMock.Object, |
|
|
|
Content = windowContent, |
|
|
|
Title = testName, |
|
|
|
}; |
|
|
|
|
|
|
|
window.ApplyStyling(); |
|
|
|
window.ApplyTemplate(); |
|
|
|
window.Presenter.ApplyTemplate(); |
|
|
|
window.Show(); |
|
|
|
|
|
|
|
Assert.True(windowContent.IsAttachedToVisualTree); |
|
|
|
Assert.True(windowContent.IsMeasureValid); |
|
|
|
Assert.True(windowContent.IsVisible); |
|
|
|
|
|
|
|
var controlIds = new Dictionary<Control, int>(); |
|
|
|
|
|
|
|
return control => |
|
|
|
{ |
|
|
|
Point point; |
|
|
|
|
|
|
|
if (control == null) |
|
|
|
{ |
|
|
|
point = default; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (!controlIds.TryGetValue(control, out int id)) |
|
|
|
{ |
|
|
|
id = controlIds[control] = controlIds.Count; |
|
|
|
} |
|
|
|
point = new Point(id, int.MaxValue); |
|
|
|
} |
|
|
|
|
|
|
|
hitTesterMock.Setup(m => m.HitTestFirst(point, window, It.IsAny<Func<Visual, bool>>())) |
|
|
|
.Returns(control); |
|
|
|
|
|
|
|
windowImpl.Object.Input(new RawPointerEventArgs(s_mouseDevice, (ulong)DateTime.Now.Ticks, window, |
|
|
|
RawPointerEventType.Move, point, RawInputModifiers.None)); |
|
|
|
|
|
|
|
Assert.True(control == null || control.IsPointerOver); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupWindowAndActivateToolTip(Control windowContent, Control targetOverride = null, [CallerMemberName] string testName = null) => |
|
|
|
SetupWindowAndGetMouseEnterAction(windowContent, testName)(targetOverride ?? windowContent); |
|
|
|
} |
|
|
|
|
|
|
|
internal class ToolTipViewModel |
|
|
|
|