diff --git a/samples/RenderTest/RenderTest.v2.ncrunchproject b/samples/RenderTest/RenderTest.v2.ncrunchproject
index 30815b1937..8e69ee9b4a 100644
--- a/samples/RenderTest/RenderTest.v2.ncrunchproject
+++ b/samples/RenderTest/RenderTest.v2.ncrunchproject
@@ -17,10 +17,11 @@
true
true
60000
-
-
-
+
+
+
AutoDetect
STA
x86
+ MissingOrIgnoredProjectReference
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
index aeffde81ed..69caba1738 100644
--- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj
+++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
@@ -124,6 +124,7 @@
+
diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index 3721544234..d9fd8e5012 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -6,6 +6,7 @@ using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
using Avalonia.VisualTree;
+using System.Collections.Generic;
namespace Avalonia.Rendering
{
@@ -30,6 +31,7 @@ namespace Avalonia.Rendering
_root = root;
_scene = new Scene(root);
+ _needsUpdate = true;
_renderLoop = renderLoop;
_renderLoop.Tick += OnRenderLoopTick;
}
@@ -50,6 +52,16 @@ namespace Avalonia.Rendering
_renderLoop.Tick -= OnRenderLoopTick;
}
+ public IEnumerable HitTest(Point p, Func filter)
+ {
+ if (_needsUpdate)
+ {
+ UpdateScene();
+ }
+
+ return _scene.HitTest(p, filter);
+ }
+
public void Render(Rect rect)
{
if (_renderTarget == null)
diff --git a/src/Avalonia.Visuals/Rendering/IRenderer.cs b/src/Avalonia.Visuals/Rendering/IRenderer.cs
index 119bb4c8d1..a297e82203 100644
--- a/src/Avalonia.Visuals/Rendering/IRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/IRenderer.cs
@@ -3,6 +3,7 @@
using System;
using Avalonia.VisualTree;
+using System.Collections.Generic;
namespace Avalonia.Rendering
{
@@ -11,6 +12,7 @@ namespace Avalonia.Rendering
bool DrawFps { get; set; }
void AddDirty(IVisual visual);
+ IEnumerable HitTest(Point p, Func filter);
void Render(Rect rect);
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Rendering/Renderer.cs b/src/Avalonia.Visuals/Rendering/Renderer.cs
index 3b2fe19be4..504fd40396 100644
--- a/src/Avalonia.Visuals/Rendering/Renderer.cs
+++ b/src/Avalonia.Visuals/Rendering/Renderer.cs
@@ -4,6 +4,7 @@
using System;
using Avalonia.Platform;
using Avalonia.VisualTree;
+using System.Collections.Generic;
namespace Avalonia.Rendering
{
@@ -35,6 +36,11 @@ namespace Avalonia.Rendering
_renderLoop.Tick -= OnRenderLoopTick;
}
+ public IEnumerable HitTest(Point p, Func filter)
+ {
+ throw new NotImplementedException();
+ }
+
public void Render(Rect rect)
{
if (_renderTarget == null)
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
index 89850f0c0e..db05533d4a 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
@@ -35,5 +35,10 @@ namespace Avalonia.Rendering.SceneGraph
context.Transform = Transform;
context.DrawGeometry(Brush, Pen, Geometry);
}
+
+ public bool HitTest(Point p)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneNode.cs
index 073d9716d7..e022970c1e 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneNode.cs
@@ -2,13 +2,14 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Collections.Generic;
using Avalonia.Media;
namespace Avalonia.Rendering.SceneGraph
{
public interface ISceneNode
{
+ bool HitTest(Point p);
+
void Render(IDrawingContextImpl context);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/IVisualNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/IVisualNode.cs
index 17fcb7e219..ddaf3a4e9c 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/IVisualNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/IVisualNode.cs
@@ -9,7 +9,9 @@ namespace Avalonia.Rendering.SceneGraph
{
public interface IVisualNode : ISceneNode
{
- IReadOnlyList Children { get; }
IVisual Visual { get; }
+ Rect ClipBounds { get; set; }
+ bool ClipToBounds { get; set; }
+ IReadOnlyList Children { get; }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
index f8aef2aed9..6d3e5c6a56 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
@@ -38,5 +38,10 @@ namespace Avalonia.Rendering.SceneGraph
context.Transform = Transform;
context.DrawImage(Source, Opacity, SourceRect, DestRect);
}
+
+ public bool HitTest(Point p)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
index 9ff0fbde4e..4b30e94b7d 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
@@ -31,5 +31,10 @@ namespace Avalonia.Rendering.SceneGraph
context.Transform = Transform;
context.DrawLine(Pen, P1, P2);
}
+
+ public bool HitTest(Point p)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
index 738cd189ad..d4fed636a1 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
@@ -46,5 +46,10 @@ namespace Avalonia.Rendering.SceneGraph
context.DrawRectangle(Pen, Rect, CornerRadius);
}
}
+
+ public bool HitTest(Point p)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
index f0212d23c3..77c1a45c90 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
@@ -31,6 +31,14 @@ namespace Avalonia.Rendering.SceneGraph
_index.Add(node.Visual, node);
}
+ public Scene Clone()
+ {
+ var index = new Dictionary();
+ var root = (VisualNode)Clone((VisualNode)Root, null, index);
+ var result = new Scene(root, index);
+ return result;
+ }
+
public IVisualNode FindNode(IVisual visual)
{
IVisualNode node;
@@ -38,12 +46,9 @@ namespace Avalonia.Rendering.SceneGraph
return node;
}
- public Scene Clone()
+ public IEnumerable HitTest(Point p, Func filter)
{
- var index = new Dictionary();
- var root = (VisualNode)Clone((VisualNode)Root, null, index);
- var result = new Scene(root, index);
- return result;
+ return HitTest(Root, p, null, filter);
}
private VisualNode Clone(VisualNode source, ISceneNode parent, Dictionary index)
@@ -68,5 +73,38 @@ namespace Avalonia.Rendering.SceneGraph
return result;
}
+
+ private IEnumerable HitTest(IVisualNode node, Point p, Rect? clip, Func filter)
+ {
+ if (filter?.Invoke(node.Visual) != false)
+ {
+ if (node.ClipToBounds)
+ {
+ // TODO: Handle geometry clip.
+ clip = clip == null ? node.ClipBounds : clip.Value.Intersect(node.ClipBounds);
+ }
+
+ if (!clip.HasValue || clip.Value.Contains(p))
+ {
+ for (var i = node.Children.Count - 1; i >= 0; --i)
+ {
+ var visualChild = node.Children[i] as IVisualNode;
+
+ if (visualChild != null)
+ {
+ foreach (var h in HitTest(visualChild, p, clip, filter))
+ {
+ yield return h;
+ }
+ }
+ }
+
+ if (node.HitTest(p))
+ {
+ yield return node.Visual;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
index b3ac55fe6a..4749c99925 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Linq;
using Avalonia.Media;
using Avalonia.Threading;
using Avalonia.VisualTree;
@@ -55,7 +56,7 @@ namespace Avalonia.Rendering.SceneGraph
using (context.PushTransformContainer())
{
node.Transform = contextImpl.Transform;
- node.Bounds = bounds;
+ node.ClipBounds = bounds * node.Transform;
node.ClipToBounds = clipToBounds;
node.GeometryClip = visual.Clip;
node.Opacity = opacity;
@@ -63,16 +64,7 @@ namespace Avalonia.Rendering.SceneGraph
visual.Render(context);
-#pragma warning disable 0618
- var transformed = new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform);
-#pragma warning restore 0618
-
- if (visual is Visual)
- {
- BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
- }
-
- foreach (var child in visual.VisualChildren)
+ foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
{
Update(context, scene, child, node);
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs
index 3718f16af4..f9bc16c807 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs
@@ -35,5 +35,10 @@ namespace Avalonia.Rendering.SceneGraph
origin == Origin &&
Equals(text, Text);
}
+
+ public bool HitTest(Point p)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
index 3f4cea5c30..1482d7d468 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Rendering.SceneGraph
public IVisual Visual { get; }
public Matrix Transform { get; set; }
- public Rect Bounds { get; set; }
+ public Rect ClipBounds { get; set; }
public bool ClipToBounds { get; set; }
public Geometry GeometryClip { get; set; }
public double Opacity { get; set; }
@@ -32,6 +32,11 @@ namespace Avalonia.Rendering.SceneGraph
return new VisualNode(Visual);
}
+ public bool HitTest(Point p)
+ {
+ return ClipBounds.Contains(p);
+ }
+
public void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
@@ -43,7 +48,7 @@ namespace Avalonia.Rendering.SceneGraph
if (ClipToBounds)
{
- context.PushClip(Bounds);
+ context.PushClip(ClipBounds);
}
foreach (var child in Children)
diff --git a/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs b/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs
new file mode 100644
index 0000000000..b9c43bcbc3
--- /dev/null
+++ b/src/Avalonia.Visuals/Rendering/ZIndexComparer.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Rendering
+{
+ public class ZIndexComparer : IComparer
+ {
+ public static readonly ZIndexComparer Instance = new ZIndexComparer();
+
+ public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex);
+ }
+}
diff --git a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
index e7876b762f..6eaef3363d 100644
--- a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
+++ b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
@@ -1,6 +1,7 @@
// 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 Avalonia.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -102,26 +103,9 @@ namespace Avalonia.VisualTree
{
Contract.Requires(visual != null);
- if (filter?.Invoke(visual) != false)
- {
- bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual)?.Contains(p) == true;
-
- if ((containsPoint || !visual.ClipToBounds) && visual.VisualChildren.Any())
- {
- foreach (var child in visual.VisualChildren.SortByZIndex())
- {
- foreach (var result in child.GetVisualsAt(p, filter))
- {
- yield return result;
- }
- }
- }
-
- if (containsPoint)
- {
- yield return visual;
- }
- }
+ var root = visual.GetVisualRoot();
+ p = visual.TranslatePoint(p, root);
+ return root.Renderer.HitTest(p, filter);
}
///
@@ -197,11 +181,11 @@ namespace Avalonia.VisualTree
///
/// The root visual or null if the visual is not rooted.
///
- public static IVisual GetVisualRoot(this IVisual visual)
+ public static IRenderRoot GetVisualRoot(this IVisual visual)
{
Contract.Requires(visual != null);
- return visual.VisualRoot as IVisual;
+ return visual as IRenderRoot ?? visual.VisualRoot;
}
///
diff --git a/tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj b/tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj
index 5ed05e9e33..26c73ad00a 100644
--- a/tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj
+++ b/tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj
@@ -86,7 +86,6 @@
-
diff --git a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs b/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs
deleted file mode 100644
index e4e7551f5c..0000000000
--- a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs
+++ /dev/null
@@ -1,484 +0,0 @@
-// 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 Avalonia.Controls;
-using Avalonia.Controls.Presenters;
-using Avalonia.Layout;
-using Avalonia.Media;
-using Avalonia.Platform;
-using Avalonia.Rendering;
-using Avalonia.UnitTests;
-using Moq;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Xunit;
-
-namespace Avalonia.Input.UnitTests
-{
- public class InputElement_HitTesting
- {
- [Fact]
- public void InputHitTest_Should_Find_Control_At_Point()
- {
- using (var application = UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
- {
- var container = new Decorator
- {
- Width = 200,
- Height = 200,
- Child = new Border
- {
- Width = 100,
- Height = 100,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- }
- };
-
- container.Measure(Size.Infinity);
- container.Arrange(new Rect(container.DesiredSize));
-
- var context = new DrawingContext(Mock.Of());
- context.Render(container);
-
- var result = container.InputHitTest(new Point(100, 100));
-
- Assert.Equal(container.Child, result);
- }
- }
-
- [Fact]
- public void InputHitTest_Should_Not_Find_Control_Outside_Point()
- {
- using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
- {
- var container = new Decorator
- {
- Width = 200,
- Height = 200,
- Child = new Border
- {
- Width = 100,
- Height = 100,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- }
- };
-
- container.Measure(Size.Infinity);
- container.Arrange(new Rect(container.DesiredSize));
-
- var context = new DrawingContext(Mock.Of());
- context.Render(container);
-
- var result = container.InputHitTest(new Point(10, 10));
-
- Assert.Equal(container, result);
- }
- }
-
- [Fact]
- public void InputHitTest_Should_Find_Top_Control_At_Point()
- {
- using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
- {
- var container = new Panel
- {
- Width = 200,
- Height = 200,
- Children = new Controls.Controls
- {
- new Border
- {
- Width = 100,
- Height = 100,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- },
- new Border
- {
- Width = 50,
- Height = 50,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- }
- }
- };
-
- container.Measure(Size.Infinity);
- container.Arrange(new Rect(container.DesiredSize));
-
- var context = new DrawingContext(Mock.Of());
- context.Render(container);
-
- var result = container.InputHitTest(new Point(100, 100));
-
- Assert.Equal(container.Children[1], result);
- }
- }
-
- [Fact]
- public void InputHitTest_Should_Find_Top_Control_At_Point_With_ZOrder()
- {
- using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
- {
- var container = new Panel
- {
- Width = 200,
- Height = 200,
- Children = new Controls.Controls
- {
- new Border
- {
- Width = 100,
- Height = 100,
- ZIndex = 1,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- },
- new Border
- {
- Width = 50,
- Height = 50,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center
- }
- }
- };
-
- container.Measure(Size.Infinity);
- container.Arrange(new Rect(container.DesiredSize));
-
- var context = new DrawingContext(Mock.Of());
- context.Render(container);
-
- var result = container.InputHitTest(new Point(100, 100));
-
- Assert.Equal(container.Children[0], result);
- }
- }
-
- [Fact]
- public void InputHitTest_Should_Find_Control_Translated_Outside_Parent_Bounds()
- {
- using (UnitTestApplication.Start(new TestServices(renderInterface: new MockRenderInterface())))
- {
- Border target;
- var container = new Panel
- {
- Width = 200,
- Height = 200,
- ClipToBounds = false,
- Children = new Controls.Controls
- {
- new Border
- {
- Width = 100,
- Height = 100,
- ZIndex = 1,
- HorizontalAlignment = HorizontalAlignment.Left,
- VerticalAlignment = VerticalAlignment.Top,
- Child = target = new Border
- {
- Width = 50,
- Height = 50,
- HorizontalAlignment = HorizontalAlignment.Left,
- VerticalAlignment = VerticalAlignment.Top,
- RenderTransform = new TranslateTransform(110, 110),
- }
- },
- }
- };
-
- container.Measure(Size.Infinity);
- container.Arrange(new Rect(container.DesiredSize));
-
- var context = new DrawingContext(Mock.Of());
- context.Render(container);
-
- var result = container.InputHitTest(new Point(120, 120));
-
- Assert.Equal(target, result);
- }
- }
-
- [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());
- 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());
- 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
- {
- public IFormattedTextImpl CreateFormattedText(string text, string fontFamilyName, double fontSize, FontStyle fontStyle, TextAlignment textAlignment, FontWeight fontWeight, TextWrapping wrapping)
- {
- throw new NotImplementedException();
- }
-
- public IRenderTarget CreateRenderTarget(IPlatformHandle handle)
- {
- throw new NotImplementedException();
- }
-
- public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)
- {
- throw new NotImplementedException();
- }
-
- public IStreamGeometryImpl CreateStreamGeometry()
- {
- return new MockStreamGeometry();
- }
-
- public IBitmapImpl LoadBitmap(Stream stream)
- {
- throw new NotImplementedException();
- }
-
- public IBitmapImpl LoadBitmap(string fileName)
- {
- throw new NotImplementedException();
- }
-
- class MockStreamGeometry : Avalonia.Platform.IStreamGeometryImpl
- {
- private MockStreamGeometryContext _impl = new MockStreamGeometryContext();
- public Rect Bounds
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public Matrix Transform
- {
- get
- {
- throw new NotImplementedException();
- }
-
- set
- {
- throw new NotImplementedException();
- }
- }
-
- public IStreamGeometryImpl Clone()
- {
- return this;
- }
-
- public bool FillContains(Point point)
- {
- return _impl.FillContains(point);
- }
-
- public Rect GetRenderBounds(double strokeThickness)
- {
- throw new NotImplementedException();
- }
-
- public IStreamGeometryContextImpl Open()
- {
- return _impl;
- }
-
- class MockStreamGeometryContext : IStreamGeometryContextImpl
- {
- private List points = new List();
- public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
- {
- throw new NotImplementedException();
- }
-
- public void BeginFigure(Point startPoint, bool isFilled)
- {
- points.Add(startPoint);
- }
-
- public void CubicBezierTo(Point point1, Point point2, Point point3)
- {
- throw new NotImplementedException();
- }
-
- public void Dispose()
- {
- }
-
- public void EndFigure(bool isClosed)
- {
- }
-
- public void LineTo(Point point)
- {
- points.Add(point);
- }
-
- public void QuadraticBezierTo(Point control, Point endPoint)
- {
- throw new NotImplementedException();
- }
-
- public void SetFillRule(FillRule fillRule)
- {
- }
-
- public bool FillContains(Point point)
- {
- // Use the algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html
- // to determine if the point is in the geometry (since it will always be convex in this situation)
- for (int i = 0; i < points.Count; i++)
- {
- var a = points[i];
- var b = points[(i + 1) % points.Count];
- var c = points[(i + 2) % points.Count];
-
- Vector v0 = c - a;
- Vector v1 = b - a;
- Vector v2 = point - a;
-
- var dot00 = v0 * v0;
- var dot01 = v0 * v1;
- var dot02 = v0 * v2;
- var dot11 = v1 * v1;
- var dot12 = v1 * v2;
-
-
- var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
- var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
- if ((u >= 0) && (v >= 0) && (u + v < 1)) return true;
- }
- return false;
- }
- }
- }
- }
- }
-}
diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs
index 1e257a698c..3f9b260225 100644
--- a/tests/Avalonia.LeakTests/ControlTests.cs
+++ b/tests/Avalonia.LeakTests/ControlTests.cs
@@ -54,7 +54,6 @@ namespace Avalonia.LeakTests
};
var result = run();
- PurgeMoqReferences();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is