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)
{
Contract.Requires<ArgumentNullException>(element != null);
var transformedBounds = BoundsTracker.GetTransformedBounds((Visual)element);
if (element.IsVisible &&
element.IsHitTestVisible &&
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>()))
{
@ -41,7 +42,7 @@ namespace Avalonia.Input
}
}
if (transformedBounds.Contains(p))
if (containsPoint)
{
yield return element;
}

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

@ -1,17 +1,18 @@
// 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.
using System;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Moq;
using Xunit;
using System;
using System.Collections.Generic;
using System.IO;
using Xunit;
namespace Avalonia.Input.UnitTests
{
@ -43,14 +44,14 @@ namespace Avalonia.Input.UnitTests
var result = container.InputHitTest(new Point(100, 100));
Assert.Equal(container.Child, result);
Assert.Equal(container.Child, result);
}
}
[Fact]
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
{
@ -73,7 +74,7 @@ namespace Avalonia.Input.UnitTests
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));
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));
Assert.Equal(container.Children[0], result);
Assert.Equal(container.Children[0], result);
}
}
@ -168,6 +169,7 @@ namespace Avalonia.Input.UnitTests
{
Width = 200,
Height = 200,
ClipToBounds = false,
Children = new Controls.Controls
{
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
{

Loading…
Cancel
Save