Browse Source

Merge pull request #1223 from AvaloniaUI/fixes/1221-getvisualsat-returns-non-children

Supply root to IRenderer.HitTest.
pull/1228/head
Jeremy Koritzinsky 8 years ago
committed by GitHub
parent
commit
81fa0bb09d
  1. 4
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  2. 8
      src/Avalonia.Visuals/Rendering/IRenderer.cs
  3. 4
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  4. 7
      src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
  5. 2
      src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
  6. 4
      tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
  7. 2
      tests/Avalonia.LeakTests/ControlTests.cs
  8. 32
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs
  9. 22
      tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs
  10. 103
      tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensions_GetVisualsAt.cs

4
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -106,7 +106,7 @@ namespace Avalonia.Rendering
public void Dispose() => Stop();
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
{
if (_renderLoop == null && (_dirty == null || _dirty.Count > 0))
{
@ -114,7 +114,7 @@ namespace Avalonia.Rendering
UpdateScene();
}
return _scene?.HitTest(p, filter) ?? Enumerable.Empty<IVisual>();
return _scene?.HitTest(p, root, filter) ?? Enumerable.Empty<IVisual>();
}
/// <inheritdoc/>

8
src/Avalonia.Visuals/Rendering/IRenderer.cs

@ -33,9 +33,13 @@ namespace Avalonia.Rendering
/// Hit tests a location to find the visuals at the specified point.
/// </summary>
/// <param name="p">The point, in client coordinates.</param>
/// <param name="filter">An optional filter.</param>
/// <param name="root">The root of the subtree to search.</param>
/// <param name="filter">
/// A filter predicate. If the predicate returns false then the visual and all its
/// children will be excluded from the results.
/// </param>
/// <returns>The visuals at the specified point, topmost first.</returns>
IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter);
IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter);
/// <summary>
/// Called when a resize notification is received by the control being rendered.

4
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

@ -136,9 +136,9 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
{
return HitTest(_root, p, filter);
return HitTest(root, p, filter);
}
/// <inheritdoc/>

7
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
@ -113,11 +114,13 @@ namespace Avalonia.Rendering.SceneGraph
/// Gets the visuals at a point in the scene.
/// </summary>
/// <param name="p">The point.</param>
/// <param name="root">The root of the subtree to search.</param>
/// <param name="filter">A filter. May be null.</param>
/// <returns>The visuals at the specified point.</returns>
public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
{
return HitTest(Root, p, null, filter);
var node = FindNode(root);
return (node != null) ? HitTest(node, p, null, filter) : Enumerable.Empty<IVisual>();
}
/// <summary>

2
src/Avalonia.Visuals/VisualTree/VisualExtensions.cs

@ -133,7 +133,7 @@ namespace Avalonia.VisualTree
var root = visual.GetVisualRoot();
p = visual.TranslatePoint(p, root);
return root.Renderer.HitTest(p, filter);
return root.Renderer.HitTest(p, visual, filter);
}
/// <summary>

4
tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs

@ -59,7 +59,7 @@ namespace Avalonia.Input.UnitTests
}
};
renderer.Setup(x => x.HitTest(It.IsAny<Point>(), It.IsAny<Func<IVisual, bool>>()))
renderer.Setup(x => x.HitTest(It.IsAny<Point>(), It.IsAny<IVisual>(), It.IsAny<Func<IVisual, bool>>()))
.Returns(new[] { decorator });
inputManager.ProcessInput(new RawMouseEventArgs(
@ -75,7 +75,7 @@ namespace Avalonia.Input.UnitTests
Assert.False(canvas.IsPointerOver);
Assert.True(root.IsPointerOver);
renderer.Setup(x => x.HitTest(It.IsAny<Point>(), It.IsAny<Func<IVisual, bool>>()))
renderer.Setup(x => x.HitTest(It.IsAny<Point>(), It.IsAny<IVisual>(), It.IsAny<Func<IVisual, bool>>()))
.Returns(new[] { canvas });
inputManager.ProcessInput(new RawMouseEventArgs(

2
tests/Avalonia.LeakTests/ControlTests.cs

@ -357,7 +357,7 @@ namespace Avalonia.LeakTests
{
}
public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter) => null;
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter) => null;
public void Paint(Rect rect)
{

32
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs

@ -42,7 +42,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { root.Child }, result);
}
@ -70,7 +70,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Empty(result);
}
@ -107,7 +107,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Empty(result);
}
@ -136,7 +136,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = root.Renderer.HitTest(new Point(10, 10), null);
var result = root.Renderer.HitTest(new Point(10, 10), root, null);
Assert.Empty(result);
}
@ -180,7 +180,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(container.DesiredSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { container.Children[1], container.Children[0] }, result);
}
@ -234,7 +234,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(container.DesiredSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { container.Children[2], container.Children[0], container.Children[1] }, result);
}
@ -283,7 +283,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
container.Measure(Size.Infinity);
container.Arrange(new Rect(container.DesiredSize));
var result = root.Renderer.HitTest(new Point(120, 120), null);
var result = root.Renderer.HitTest(new Point(120, 120), root, null);
Assert.Equal(new IVisual[] { target, container }, result);
}
@ -331,7 +331,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(container.DesiredSize));
var result = root.Renderer.HitTest(new Point(50, 50), null);
var result = root.Renderer.HitTest(new Point(50, 50), root, null);
Assert.Equal(new[] { container }, result);
}
@ -404,11 +404,11 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(container.DesiredSize));
var result = root.Renderer.HitTest(new Point(50, 150), null).First();
var result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item1, result);
result = root.Renderer.HitTest(new Point(50, 50), null).First();
result = root.Renderer.HitTest(new Point(50, 50), root, null).First();
Assert.Equal(target, result);
@ -419,10 +419,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
container.InvalidateArrange();
container.Arrange(new Rect(container.DesiredSize));
result = root.Renderer.HitTest(new Point(50, 150), null).First();
result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item2, result);
result = root.Renderer.HitTest(new Point(50, 50), null).First();
result = root.Renderer.HitTest(new Point(50, 50), root, null).First();
Assert.Equal(target, result);
}
}
@ -452,10 +452,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { path }, result);
result = root.Renderer.HitTest(new Point(10, 10), null);
result = root.Renderer.HitTest(new Point(10, 10), root, null);
Assert.Empty(result);
}
}
@ -492,10 +492,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
var result = root.Renderer.HitTest(new Point(200, 200), null);
var result = root.Renderer.HitTest(new Point(200, 200), root, null);
Assert.Equal(new IVisual[] { canvas, border }, result);
result = root.Renderer.HitTest(new Point(110, 110), null);
result = root.Renderer.HitTest(new Point(110, 110), root, null);
Assert.Empty(result);
}
}

22
tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs

@ -40,7 +40,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(root.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { root.Child, root }, result);
}
@ -78,7 +78,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(root.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { root }, result);
}
@ -108,7 +108,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(root.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(10, 10), null);
var result = root.Renderer.HitTest(new Point(10, 10), root, null);
Assert.Equal(new[] { root }, result);
}
@ -153,7 +153,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(new[] { container.Children[1], container.Children[0], container, root }, result);
}
@ -208,7 +208,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(100, 100), null);
var result = root.Renderer.HitTest(new Point(100, 100), root, null);
Assert.Equal(
new[]
@ -267,7 +267,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
container.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(120, 120), null);
var result = root.Renderer.HitTest(new Point(120, 120), root, null);
Assert.Equal(new IVisual[] { target, container }, result);
}
@ -316,7 +316,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(50, 50), null);
var result = root.Renderer.HitTest(new Point(50, 50), root, null);
Assert.Equal(new IVisual[] { container, root }, result);
}
@ -390,11 +390,11 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
var result = root.Renderer.HitTest(new Point(50, 150), null).First();
var result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item1, result);
result = root.Renderer.HitTest(new Point(50, 50), null).First();
result = root.Renderer.HitTest(new Point(50, 50), root, null).First();
Assert.Equal(target, result);
@ -406,10 +406,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
container.Arrange(new Rect(container.DesiredSize));
root.Renderer.Paint(new Rect(root.ClientSize));
result = root.Renderer.HitTest(new Point(50, 150), null).First();
result = root.Renderer.HitTest(new Point(50, 150), root, null).First();
Assert.Equal(item2, result);
result = root.Renderer.HitTest(new Point(50, 50), null).First();
result = root.Renderer.HitTest(new Point(50, 50), root, null).First();
Assert.Equal(target, result);
}
}

103
tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensions_GetVisualsAt.cs

@ -0,0 +1,103 @@
using System;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Visuals.UnitTests.VisualTree
{
public class VisualExtensions_GetVisualsAt
{
[Fact]
public void Should_Find_Control()
{
using (TestApplication())
{
Border target;
var root = new TestRoot
{
Width = 200,
Height = 200,
Child = new StackPanel
{
Background = Brushes.White,
Children =
{
(target = new Border
{
Width = 100,
Height = 200,
Background = Brushes.Red,
}),
new Border
{
Width = 100,
Height = 200,
Background = Brushes.Green,
}
},
Orientation = Orientation.Horizontal,
}
};
root.Renderer = new DeferredRenderer(root, null);
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = target.GetVisualsAt(new Point(50, 50));
Assert.Same(target, result.Single());
}
}
[Fact]
public void Should_Not_Find_Sibling_Control()
{
using (TestApplication())
{
Border target;
var root = new TestRoot
{
Width = 200,
Height = 200,
Child = new StackPanel
{
Background = Brushes.White,
Children =
{
(target = new Border
{
Width = 100,
Height = 200,
Background = Brushes.Red,
}),
new Border
{
Width = 100,
Height = 200,
Background = Brushes.Green,
}
},
Orientation = Orientation.Horizontal,
}
};
root.Renderer = new DeferredRenderer(root, null);
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var result = target.GetVisualsAt(new Point(150, 50));
Assert.Empty(result);
}
}
private IDisposable TestApplication()
{
return UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
}
}
}
Loading…
Cancel
Save