Browse Source

Change TransformedBounds to a direct property on Visual (exposed on IVisual) instead of using an attached property in BoundsTracker.

pull/1312/head
Jeremy Koritzinsky 8 years ago
parent
commit
f65ae1918f
  1. 4
      src/Avalonia.Controls/Primitives/AdornerLayer.cs
  2. 9
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  3. 12
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  4. 17
      src/Avalonia.Visuals/Visual.cs
  5. 51
      src/Avalonia.Visuals/VisualTree/BoundsTracker.cs
  6. 5
      src/Avalonia.Visuals/VisualTree/IVisual.cs
  7. 4
      tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs

4
src/Avalonia.Controls/Primitives/AdornerLayer.cs

@ -18,8 +18,6 @@ namespace Avalonia.Controls.Primitives
private static readonly AttachedProperty<AdornedElementInfo> s_adornedElementInfoProperty =
AvaloniaProperty.RegisterAttached<AdornerLayer, Visual, AdornedElementInfo>("AdornedElementInfo");
private readonly BoundsTracker _tracker = new BoundsTracker();
static AdornerLayer()
{
AdornedElementProperty.Changed.Subscribe(AdornedElementChanged);
@ -118,7 +116,7 @@ namespace Avalonia.Controls.Primitives
adorner.SetValue(s_adornedElementInfoProperty, info);
}
info.Subscription = _tracker.Track(adorned).Subscribe(x =>
info.Subscription = adorned.GetObservable(TransformedBoundsProperty).Subscribe(x =>
{
info.Bounds = x;
InvalidateArrange();

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

@ -169,7 +169,7 @@ namespace Avalonia.Rendering
{
foreach (var e in visual.GetSelfAndVisualDescendants())
{
BoundsTracker.SetTransformedBounds((Visual)visual, null);
visual.TransformedBounds = null;
}
}
@ -197,7 +197,7 @@ namespace Avalonia.Rendering
if (filter?.Invoke(visual) != false)
{
bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual)?.Contains(p) == true;
bool containsPoint = visual.TransformedBounds?.Contains(p) == true;
if ((containsPoint || !visual.ClipToBounds) && visual.VisualChildren.Count > 0)
{
@ -257,10 +257,7 @@ namespace Avalonia.Rendering
new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform);
#pragma warning restore 0618
if (visual is Visual)
{
BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
}
visual.TransformedBounds = transformed;
foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
{

12
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -209,11 +209,8 @@ namespace Avalonia.Rendering.SceneGraph
}
catch { }
if (visual is Visual)
{
var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
}
var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
visual.TransformedBounds = transformed;
if (forceRecurse)
{
@ -279,10 +276,7 @@ namespace Avalonia.Rendering.SceneGraph
scene.Layers[node.LayerRoot].Dirty.Add(node.Bounds);
if (node.Visual is Visual v)
{
BoundsTracker.SetTransformedBounds(v, null);
}
node.Visual.TransformedBounds = null;
foreach (VisualNode child in node.Children)
{

17
src/Avalonia.Visuals/Visual.cs

@ -32,6 +32,11 @@ namespace Avalonia
public static readonly DirectProperty<Visual, Rect> BoundsProperty =
AvaloniaProperty.RegisterDirect<Visual, Rect>(nameof(Bounds), o => o.Bounds);
public static readonly DirectProperty<Visual, TransformedBounds?> TransformedBoundsProperty =
AvaloniaProperty.RegisterDirect<Visual, TransformedBounds?>(
nameof(TransformedBounds),
o => o.TransformedBounds);
/// <summary>
/// Defines the <see cref="ClipToBounds"/> property.
/// </summary>
@ -87,6 +92,7 @@ namespace Avalonia
AvaloniaProperty.Register<Visual, int>(nameof(ZIndex));
private Rect _bounds;
private TransformedBounds? _transformedBounds;
private IRenderRoot _visualRoot;
private IVisual _visualParent;
@ -135,6 +141,11 @@ namespace Avalonia
protected set { SetAndRaise(BoundsProperty, ref _bounds, value); }
}
/// <summary>
/// Gets the bounds of the control relative to the window, accounting for rendering transforms.
/// </summary>
public TransformedBounds? TransformedBounds => _transformedBounds;
/// <summary>
/// Gets a value indicating whether the control should be clipped to its bounds.
/// </summary>
@ -253,6 +264,12 @@ namespace Avalonia
/// Gets the root of the visual tree, if the control is attached to a visual tree.
/// </summary>
IRenderRoot IVisual.VisualRoot => VisualRoot;
TransformedBounds? IVisual.TransformedBounds
{
get { return _transformedBounds; }
set { SetAndRaise(TransformedBoundsProperty, ref _transformedBounds, value); }
}
/// <summary>
/// Invalidates the visual and queues a repaint.

51
src/Avalonia.Visuals/VisualTree/BoundsTracker.cs

@ -1,51 +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 System;
namespace Avalonia.VisualTree
{
/// <summary>
/// Tracks the bounds of a control.
/// </summary>
/// <remarks>
/// This class is used to track a controls's bounds for hit testing.
/// TODO: This shouldn't be implemented as an attached property: it would be more performant
/// to just store bounds in some sort of central repository.
/// </remarks>
public class BoundsTracker
{
/// <summary>
/// Defines the TransformedBounds attached property.
/// </summary>
private static AttachedProperty<TransformedBounds?> TransformedBoundsProperty =
AvaloniaProperty.RegisterAttached<BoundsTracker, Visual, TransformedBounds?>("TransformedBounds");
/// <summary>
/// Starts tracking the specified visual.
/// </summary>
/// <param name="visual">The visual.</param>
/// <returns>An observable that returns the tracked bounds.</returns>
public IObservable<TransformedBounds?> Track(Visual visual)
{
return visual.GetObservable(TransformedBoundsProperty);
}
/// <summary>
/// Sets the transformed bounds of the visual.
/// </summary>
/// <param name="visual">The visual.</param>
/// <param name="value">The transformed bounds.</param>
internal static void SetTransformedBounds(Visual visual, TransformedBounds? value)
{
visual.SetValue(TransformedBoundsProperty, value);
}
/// <summary>
/// Gets the transformed bounds of the visual.
/// </summary>
/// <param name="visual">The visual.</param>
/// <returns>The transformed bounds or null if the visual is not visible.</returns>
public static TransformedBounds? GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty);
}
}

5
src/Avalonia.Visuals/VisualTree/IVisual.cs

@ -36,6 +36,11 @@ namespace Avalonia.VisualTree
/// </summary>
Rect Bounds { get; }
/// <summary>
/// Gets the bounds of the control relative to the window, accounting for rendering transforms.
/// </summary>
TransformedBounds? TransformedBounds { get; set; }
/// <summary>
/// Gets a value indicating whether the control should be clipped to its bounds.
/// </summary>

4
tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs → tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs

@ -17,7 +17,7 @@ using Avalonia.Platform;
namespace Avalonia.Visuals.UnitTests.VisualTree
{
public class BoundsTrackerTests
public class TransformedBoundsTests
{
[Fact]
public void Should_Track_Bounds()
@ -46,7 +46,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
tree.Arrange(new Rect(0, 0, 100, 100));
ImmediateRenderer.Render(tree, context);
var track = target.Track(control);
var track = control.GetObservable(Visual.TransformedBoundsProperty);
var results = new List<TransformedBounds?>();
track.Subscribe(results.Add);
Loading…
Cancel
Save