Browse Source

Filter-out child elements during hit-testing too

pull/8847/head
Nikita Tsukanov 4 years ago
parent
commit
4207a5f93b
  1. 11
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  2. 4
      src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
  3. 10
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  4. 2
      src/Avalonia.Base/Rendering/Composition/Visual.cs
  5. 27
      tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs

11
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -84,7 +84,16 @@ public class CompositingRenderer : IRendererWithCompositor
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
{
var res = CompositionTarget.TryHitTest(p, filter);
Func<CompositionVisual, bool>? f = null;
if (filter != null)
f = v =>
{
if (v is CompositionDrawListVisual dlv)
return filter(dlv.Visual);
return true;
};
var res = CompositionTarget.TryHitTest(p, f);
if(res == null)
yield break;
foreach(var v in res)

4
src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs

@ -54,13 +54,11 @@ internal class CompositionDrawListVisual : CompositionContainerVisual
Visual = visual;
}
internal override bool HitTest(Point pt, Func<IVisual, bool>? filter)
internal override bool HitTest(Point pt)
{
var custom = Visual as ICustomHitTest;
if (DrawList == null && custom == null)
return false;
if (filter != null && !filter(Visual))
return false;
if (custom != null)
{
// Simulate the old behavior

10
src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs

@ -31,7 +31,7 @@ namespace Avalonia.Rendering.Composition
/// <param name="point"></param>
/// <param name="filter"></param>
/// <returns></returns>
public PooledList<CompositionVisual>? TryHitTest(Point point, Func<IVisual, bool>? filter)
public PooledList<CompositionVisual>? TryHitTest(Point point, Func<CompositionVisual, bool>? filter)
{
Server.Readback.NextRead();
if (Root == null)
@ -88,10 +88,14 @@ namespace Avalonia.Rendering.Composition
}
void HitTestCore(CompositionVisual visual, Point globalPoint, PooledList<CompositionVisual> result,
Func<IVisual, bool>? filter)
Func<CompositionVisual, bool>? filter)
{
if (visual.Visible == false)
return;
if (filter != null && !filter(visual))
return;
if (!TryTransformTo(visual, globalPoint, out var point))
return;
@ -111,7 +115,7 @@ namespace Avalonia.Rendering.Composition
}
// Hit-test the current node
if (visual.HitTest(point, filter))
if (visual.HitTest(point))
result.Add(visual);
}

2
src/Avalonia.Base/Rendering/Composition/Visual.cs

@ -53,6 +53,6 @@ namespace Avalonia.Rendering.Composition
internal object? Tag { get; set; }
internal virtual bool HitTest(Point point, Func<IVisual, bool>? filter) => true;
internal virtual bool HitTest(Point point) => true;
}
}

27
tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs

@ -432,6 +432,33 @@ public class CompositorHitTestingTests : CompositorTestsBase
s.AssertHitTest(new Point(5, 10), null, targetRectangle);
}
}
[Fact]
public void HitTest_Filter_Should_Filter_Out_Children()
{
using (var s = new CompositorServices(new Size(200, 200)))
{
Border child, parent;
s.TopLevel.Content = parent = new Border
{
Width = 100,
Height = 100,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Child = child = new Border
{
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
}
};
s.AssertHitTest(new Point(100, 100), null, child, parent);
s.AssertHitTest(new Point(100, 100), v => v != parent);
}
}
private IDisposable TestApplication()
{

Loading…
Cancel
Save