From 71194642063db397558c7df82b6c82f717ac6e39 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 26 Apr 2017 10:06:24 +0200 Subject: [PATCH] Added ImmediateRenderer hit tests. --- .../ImmediateRendererTests_HitTesting.cs | 420 ++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs new file mode 100644 index 0000000000..d18b7849c8 --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs @@ -0,0 +1,420 @@ +// 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.Linq; +using Avalonia.Controls; +using Avalonia.Controls.Presenters; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; +using Avalonia.UnitTests; +using Avalonia.VisualTree; +using Moq; +using Xunit; +using System; +using Avalonia.Controls.Shapes; + +namespace Avalonia.Visuals.UnitTests.Rendering +{ + public class ImmediateRendererTests_HitTesting + { + [Fact] + public void HitTest_Should_Find_Controls_At_Point() + { + using (TestApplication()) + { + var root = new TestRoot + { + Width = 200, + Height = 200, + Child = new Border + { + Width = 100, + Height = 100, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(root.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(100, 100), null); + + Assert.Equal(new[] { root.Child, root }, result); + } + } + + [Fact] + public void HitTest_Should_Not_Find_Invisible_Controls_At_Point() + { + using (TestApplication()) + { + Border visible; + var root = new TestRoot + { + Width = 200, + Height = 200, + Child = new Border + { + Width = 100, + Height = 100, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + IsVisible = false, + Child = visible = new Border + { + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + } + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(root.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(100, 100), null); + + Assert.Equal(new[] { root }, result); + } + } + + [Fact] + public void HitTest_Should_Not_Find_Control_Outside_Point() + { + using (TestApplication()) + { + var root = new TestRoot + { + Width = 200, + Height = 200, + Child = new Border + { + Width = 100, + Height = 100, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(root.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(10, 10), null); + + Assert.Equal(new[] { root }, result); + } + } + + [Fact] + public void HitTest_Should_Return_Top_Controls_First() + { + using (TestApplication()) + { + Panel container; + var root = new TestRoot + { + Child = container = new Panel + { + Width = 200, + Height = 200, + Children = new Controls.Controls + { + new Border + { + Width = 100, + Height = 100, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }, + new Border + { + Width = 50, + Height = 50, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + } + } + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(100, 100), null); + + Assert.Equal(new[] { container.Children[1], container.Children[0], container, root }, result); + } + } + + [Fact] + public void HitTest_Should_Return_Top_Controls_First_With_ZIndex() + { + using (TestApplication()) + { + Panel container; + var root = new TestRoot + { + Child = container = new Panel + { + Width = 200, + Height = 200, + Children = new Controls.Controls + { + new Border + { + Width = 100, + Height = 100, + ZIndex = 1, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }, + new Border + { + Width = 50, + Height = 50, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }, + new Border + { + Width = 75, + Height = 75, + ZIndex = 2, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + } + } + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(100, 100), null); + + Assert.Equal( + new[] + { + container.Children[2], + container.Children[0], + container.Children[1], + container, + root + }, + result); + } + } + + [Fact] + public void HitTest_Should_Find_Control_Translated_Outside_Parent_Bounds() + { + using (TestApplication()) + { + Border target; + Panel container; + var root = new TestRoot + { + Child = container = new Panel + { + Width = 200, + Height = 200, + Background = Brushes.Red, + ClipToBounds = false, + Children = new Controls.Controls + { + new Border + { + Width = 100, + Height = 100, + ZIndex = 1, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top, + Child = target = new Border + { + Width = 50, + Height = 50, + Background = Brushes.Red, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top, + RenderTransform = new TranslateTransform(110, 110), + } + }, + } + } + }; + + container.Measure(Size.Infinity); + container.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(120, 120), null); + + Assert.Equal(new IVisual[] { target, container }, result); + } + } + + [Fact] + public void HitTest_Should_Not_Find_Control_Outside_Parent_Bounds_When_Clipped() + { + using (TestApplication()) + { + Border target; + Panel container; + var root = new TestRoot + { + Child = container = new Panel + { + Width = 100, + Height = 200, + Background = Brushes.Red, + Children = new Controls.Controls + { + new Panel() + { + Width = 100, + Height = 100, + Background = Brushes.Red, + Margin = new Thickness(0, 100, 0, 0), + ClipToBounds = true, + Children = new Controls.Controls + { + (target = new Border() + { + Width = 100, + Height = 100, + Background = Brushes.Red, + Margin = new Thickness(0, -100, 0, 0) + }) + } + } + } + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(50, 50), null); + + Assert.Equal(new IVisual[] { container, root }, result); + } + } + + [Fact] + public void HitTest_Should_Not_Find_Control_Outside_Scroll_Viewport() + { + using (TestApplication()) + { + Border target; + Border item1; + Border item2; + ScrollContentPresenter scroll; + Panel container; + var root = new TestRoot + { + Child = container = new Panel + { + Width = 100, + Height = 200, + Background = Brushes.Red, + Children = new Controls.Controls + { + (target = new Border() + { + Name = "b1", + Width = 100, + Height = 100, + Background = Brushes.Red, + }), + new Border() + { + Name = "b2", + Width = 100, + Height = 100, + Background = Brushes.Red, + Margin = new Thickness(0, 100, 0, 0), + Child = scroll = new ScrollContentPresenter() + { + Content = new StackPanel() + { + Children = new Controls.Controls + { + (item1 = new Border() + { + Name = "b3", + Width = 100, + Height = 100, + Background = Brushes.Red, + }), + (item2 = new Border() + { + Name = "b4", + Width = 100, + Height = 100, + Background = Brushes.Red, + }), + } + } + } + } + } + } + }; + + scroll.UpdateChild(); + + root.Measure(Size.Infinity); + root.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + var result = root.Renderer.HitTest(new Point(50, 150), null).First(); + + Assert.Equal(item1, result); + + result = root.Renderer.HitTest(new Point(50, 50), null).First(); + + Assert.Equal(target, result); + + scroll.Offset = new Vector(0, 100); + + // We don't have LayoutManager set up so do the layout pass manually. + scroll.Parent.InvalidateArrange(); + container.InvalidateArrange(); + container.Arrange(new Rect(container.DesiredSize)); + root.Renderer.Paint(new Rect(root.ClientSize)); + + result = root.Renderer.HitTest(new Point(50, 150), null).First(); + Assert.Equal(item2, result); + + result = root.Renderer.HitTest(new Point(50, 50), null).First(); + Assert.Equal(target, result); + } + } + + private IDisposable TestApplication() + { + return UnitTestApplication.Start( + new TestServices( + renderInterface: new MockPlatformRenderInterface(), + renderer: (root, loop) => new ImmediateRenderer(root))); + } + } +}