Browse Source

Merge pull request #570 from donandren/hittesting2

hit testing fix
pull/573/head
Steven Kirk 10 years ago
committed by GitHub
parent
commit
642e7e8373
  1. 7
      src/Avalonia.Input/InputExtensions.cs
  2. 145
      tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs

7
src/Avalonia.Input/InputExtensions.cs

@ -24,13 +24,14 @@ namespace Avalonia.Input
public static IEnumerable<IInputElement> GetInputElementsAt(this IInputElement element, Point p) public static IEnumerable<IInputElement> GetInputElementsAt(this IInputElement element, Point p)
{ {
Contract.Requires<ArgumentNullException>(element != null); Contract.Requires<ArgumentNullException>(element != null);
var transformedBounds = BoundsTracker.GetTransformedBounds((Visual)element);
if (element.IsVisible && if (element.IsVisible &&
element.IsHitTestVisible && element.IsHitTestVisible &&
element.IsEnabledCore) element.IsEnabledCore)
{ {
if (element.VisualChildren.Any()) bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)element).Contains(p);
if ((containsPoint || !element.ClipToBounds) && element.VisualChildren.Any())
{ {
foreach (var child in ZSort(element.VisualChildren.OfType<IInputElement>())) foreach (var child in ZSort(element.VisualChildren.OfType<IInputElement>()))
{ {
@ -41,7 +42,7 @@ namespace Avalonia.Input
} }
} }
if (transformedBounds.Contains(p)) if (containsPoint)
{ {
yield return element; yield return element;
} }

145
tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs

@ -1,17 +1,18 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Moq; using Moq;
using Xunit; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Xunit;
namespace Avalonia.Input.UnitTests namespace Avalonia.Input.UnitTests
{ {
@ -43,14 +44,14 @@ namespace Avalonia.Input.UnitTests
var result = container.InputHitTest(new Point(100, 100)); var result = container.InputHitTest(new Point(100, 100));
Assert.Equal(container.Child, result); Assert.Equal(container.Child, result);
} }
} }
[Fact] [Fact]
public void InputHitTest_Should_Not_Find_Control_Outside_Point() public void InputHitTest_Should_Not_Find_Control_Outside_Point()
{ {
using (UnitTestApplication.Start(new TestServices(renderInterface:new MockRenderInterface()))) using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
{ {
var container = new Decorator var container = new Decorator
{ {
@ -73,7 +74,7 @@ namespace Avalonia.Input.UnitTests
var result = container.InputHitTest(new Point(10, 10)); var result = container.InputHitTest(new Point(10, 10));
Assert.Equal(container, result); Assert.Equal(container, result);
} }
} }
@ -113,7 +114,7 @@ namespace Avalonia.Input.UnitTests
var result = container.InputHitTest(new Point(100, 100)); var result = container.InputHitTest(new Point(100, 100));
Assert.Equal(container.Children[1], result); Assert.Equal(container.Children[1], result);
} }
} }
@ -154,7 +155,7 @@ namespace Avalonia.Input.UnitTests
var result = container.InputHitTest(new Point(100, 100)); var result = container.InputHitTest(new Point(100, 100));
Assert.Equal(container.Children[0], result); Assert.Equal(container.Children[0], result);
} }
} }
@ -168,6 +169,7 @@ namespace Avalonia.Input.UnitTests
{ {
Width = 200, Width = 200,
Height = 200, Height = 200,
ClipToBounds = false,
Children = new Controls.Controls Children = new Controls.Controls
{ {
new Border new Border
@ -201,6 +203,135 @@ namespace Avalonia.Input.UnitTests
} }
} }
[Fact]
public void InputHitTest_Should_Not_Find_Control_Outside_Parent_Bounds_When_Clipped()
{
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
{
Border target;
var container = new Panel
{
Width = 100,
Height = 200,
Children = new Controls.Controls
{
new Panel()
{
Width = 100,
Height = 100,
Margin = new Thickness(0, 100, 0, 0),
ClipToBounds = true,
Children = new Controls.Controls
{
(target = new Border()
{
Width = 100,
Height = 100,
Margin = new Thickness(0, -100, 0, 0)
})
}
}
}
};
container.Measure(Size.Infinity);
container.Arrange(new Rect(container.DesiredSize));
var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
context.Render(container);
var result = container.InputHitTest(new Point(50, 50));
Assert.NotEqual(target, result);
Assert.Equal(container, result);
}
}
[Fact]
public void InputHitTest_Should_Not_Find_Control_Outside_Scroll_ViewPort()
{
using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
{
Border target;
Border item1;
Border item2;
ScrollContentPresenter scroll;
var container = new Panel
{
Width = 100,
Height = 200,
Children = new Controls.Controls
{
(target = new Border()
{
Width = 100,
Height = 100
}),
new Border()
{
Width = 100,
Height = 100,
Margin = new Thickness(0, 100, 0, 0),
Child = scroll = new ScrollContentPresenter()
{
Content = new StackPanel()
{
Children = new Controls.Controls
{
(item1 = new Border()
{
Width = 100,
Height = 100,
}),
(item2 = new Border()
{
Width = 100,
Height = 100,
}),
}
}
}
}
}
};
scroll.UpdateChild();
container.Measure(Size.Infinity);
container.Arrange(new Rect(container.DesiredSize));
var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
context.Render(container);
var result = container.InputHitTest(new Point(50, 150));
Assert.Equal(item1, result);
result = container.InputHitTest(new Point(50, 50));
Assert.Equal(target, result);
scroll.Offset = new Vector(0, 100);
//we don't have setup LayoutManager so we will make it manually
scroll.Parent.InvalidateArrange();
container.InvalidateArrange();
container.Arrange(new Rect(container.DesiredSize));
context.Render(container);
result = container.InputHitTest(new Point(50, 150));
Assert.Equal(item2, result);
result = container.InputHitTest(new Point(50, 50));
Assert.NotEqual(item1, result);
Assert.Equal(target, result);
}
}
class MockRenderInterface : IPlatformRenderInterface class MockRenderInterface : IPlatformRenderInterface
{ {

Loading…
Cancel
Save