From f65ae1918f882e47cd04f14643a89b306f891ef2 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sun, 10 Dec 2017 16:10:58 -0600 Subject: [PATCH] Change TransformedBounds to a direct property on Visual (exposed on IVisual) instead of using an attached property in BoundsTracker. --- .../Primitives/AdornerLayer.cs | 4 +- .../Rendering/ImmediateRenderer.cs | 9 ++-- .../Rendering/SceneGraph/SceneBuilder.cs | 12 ++--- src/Avalonia.Visuals/Visual.cs | 17 +++++++ .../VisualTree/BoundsTracker.cs | 51 ------------------- src/Avalonia.Visuals/VisualTree/IVisual.cs | 5 ++ ...ckerTests.cs => TransformedBoundsTests.cs} | 4 +- 7 files changed, 31 insertions(+), 71 deletions(-) delete mode 100644 src/Avalonia.Visuals/VisualTree/BoundsTracker.cs rename tests/Avalonia.Visuals.UnitTests/VisualTree/{BoundsTrackerTests.cs => TransformedBoundsTests.cs} (93%) diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index d7862881fb..a469f09867 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -18,8 +18,6 @@ namespace Avalonia.Controls.Primitives private static readonly AttachedProperty s_adornedElementInfoProperty = AvaloniaProperty.RegisterAttached("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(); diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 84313f0906..e830d5c313 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/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)) { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 8f4f487e08..41ff802164 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/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) { diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index 3662fe50be..5f3861a51a 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -32,6 +32,11 @@ namespace Avalonia public static readonly DirectProperty BoundsProperty = AvaloniaProperty.RegisterDirect(nameof(Bounds), o => o.Bounds); + public static readonly DirectProperty TransformedBoundsProperty = + AvaloniaProperty.RegisterDirect( + nameof(TransformedBounds), + o => o.TransformedBounds); + /// /// Defines the property. /// @@ -87,6 +92,7 @@ namespace Avalonia AvaloniaProperty.Register(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); } } + /// + /// Gets the bounds of the control relative to the window, accounting for rendering transforms. + /// + public TransformedBounds? TransformedBounds => _transformedBounds; + /// /// Gets a value indicating whether the control should be clipped to its bounds. /// @@ -253,6 +264,12 @@ namespace Avalonia /// Gets the root of the visual tree, if the control is attached to a visual tree. /// IRenderRoot IVisual.VisualRoot => VisualRoot; + + TransformedBounds? IVisual.TransformedBounds + { + get { return _transformedBounds; } + set { SetAndRaise(TransformedBoundsProperty, ref _transformedBounds, value); } + } /// /// Invalidates the visual and queues a repaint. diff --git a/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs b/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs deleted file mode 100644 index 42c4e3c98e..0000000000 --- a/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs +++ /dev/null @@ -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 -{ - /// - /// Tracks the bounds of a control. - /// - /// - /// 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. - /// - public class BoundsTracker - { - /// - /// Defines the TransformedBounds attached property. - /// - private static AttachedProperty TransformedBoundsProperty = - AvaloniaProperty.RegisterAttached("TransformedBounds"); - - /// - /// Starts tracking the specified visual. - /// - /// The visual. - /// An observable that returns the tracked bounds. - public IObservable Track(Visual visual) - { - return visual.GetObservable(TransformedBoundsProperty); - } - - /// - /// Sets the transformed bounds of the visual. - /// - /// The visual. - /// The transformed bounds. - internal static void SetTransformedBounds(Visual visual, TransformedBounds? value) - { - visual.SetValue(TransformedBoundsProperty, value); - } - - /// - /// Gets the transformed bounds of the visual. - /// - /// The visual. - /// The transformed bounds or null if the visual is not visible. - public static TransformedBounds? GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty); - } -} diff --git a/src/Avalonia.Visuals/VisualTree/IVisual.cs b/src/Avalonia.Visuals/VisualTree/IVisual.cs index 2047996c3e..278a802597 100644 --- a/src/Avalonia.Visuals/VisualTree/IVisual.cs +++ b/src/Avalonia.Visuals/VisualTree/IVisual.cs @@ -36,6 +36,11 @@ namespace Avalonia.VisualTree /// Rect Bounds { get; } + /// + /// Gets the bounds of the control relative to the window, accounting for rendering transforms. + /// + TransformedBounds? TransformedBounds { get; set; } + /// /// Gets a value indicating whether the control should be clipped to its bounds. /// diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs similarity index 93% rename from tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs rename to tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs index ea3a1cdd78..aabaac902d 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs +++ b/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(); track.Subscribe(results.Add);