From 4212d3c6955307718bc29cda305881d00defaed6 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 11 Jul 2021 19:47:53 +0200 Subject: [PATCH] Allow for disabling clipping of adorners. Cleanup AdornerLayer class. --- .../Primitives/AdornerLayer.cs | 67 +++++++++++++------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index a397608aba..52c8273b6c 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -1,19 +1,33 @@ using System; using System.Collections.Specialized; -using System.Linq; -using System.Resources; using Avalonia.Media; using Avalonia.Rendering; -using Avalonia.Utilities; using Avalonia.VisualTree; +#nullable enable + namespace Avalonia.Controls.Primitives { - // TODO: Need to track position of adorned elements and move the adorner if they move. + /// + /// Represents a surface for showing adorners. + /// Adorners are always on top of the adorned element and are positioned to stay relative to the adorned element. + /// + /// + /// TODO: Need to track position of adorned elements and move the adorner if they move. + /// public class AdornerLayer : Canvas, ICustomSimpleHitTest { - public static readonly AttachedProperty AdornedElementProperty = - AvaloniaProperty.RegisterAttached("AdornedElement"); + /// + /// Allows for getting and setting of the adorned element. + /// + public static readonly AttachedProperty AdornedElementProperty = + AvaloniaProperty.RegisterAttached("AdornedElement"); + + /// + /// Allows for controlling clipping of the adorner. + /// + public static readonly AttachedProperty IsClipEnabledProperty = + AvaloniaProperty.RegisterAttached("IsClipEnabled", true); private static readonly AttachedProperty s_adornedElementInfoProperty = AvaloniaProperty.RegisterAttached("AdornedElementInfo"); @@ -28,7 +42,7 @@ namespace Avalonia.Controls.Primitives Children.CollectionChanged += ChildrenCollectionChanged; } - public static Visual GetAdornedElement(Visual adorner) + public static Visual? GetAdornedElement(Visual adorner) { return adorner.GetValue(AdornedElementProperty); } @@ -38,12 +52,19 @@ namespace Avalonia.Controls.Primitives adorner.SetValue(AdornedElementProperty, adorned); } - public static AdornerLayer GetAdornerLayer(IVisual visual) + public static AdornerLayer? GetAdornerLayer(IVisual visual) + { + return visual.FindAncestorOfType()?.AdornerLayer; + } + + public static bool GetIsClipEnabled(Visual adorner) { - return visual.GetVisualAncestors() - .OfType() - .FirstOrDefault() - ?.AdornerLayer; + return adorner.GetValue(IsClipEnabledProperty); + } + + public static void SetIsClipEnabled(Visual adorner, bool isClipEnabled) + { + adorner.SetValue(IsClipEnabledProperty, isClipEnabled); } protected override Size MeasureOverride(Size availableSize) @@ -70,12 +91,13 @@ namespace Avalonia.Controls.Primitives foreach (var child in Children) { var info = child.GetValue(s_adornedElementInfoProperty); + var isClipEnabled = child.GetValue(IsClipEnabledProperty); if (info != null && info.Bounds.HasValue) { child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform); child.RenderTransformOrigin = new RelativePoint(new Point(0,0), RelativeUnit.Absolute); - UpdateClip(child, info.Bounds.Value); + UpdateClip(child, info.Bounds.Value, isClipEnabled); child.Arrange(info.Bounds.Value.Bounds); } else @@ -87,16 +109,23 @@ namespace Avalonia.Controls.Primitives return finalSize; } - private static void AdornedElementChanged(AvaloniaPropertyChangedEventArgs e) + private static void AdornedElementChanged(AvaloniaPropertyChangedEventArgs e) { var adorner = (Visual)e.Sender; - var adorned = (Visual)e.NewValue; + var adorned = e.NewValue.GetValueOrDefault(); var layer = adorner.GetVisualParent(); layer?.UpdateAdornedElement(adorner, adorned); } - private void UpdateClip(IControl control, TransformedBounds bounds) + private void UpdateClip(IControl control, TransformedBounds bounds, bool isEnabled) { + if (!isEnabled) + { + control.Clip = null; + + return; + } + if (!(control.Clip is RectangleGeometry clip)) { clip = new RectangleGeometry(); @@ -129,13 +158,13 @@ namespace Avalonia.Controls.Primitives InvalidateArrange(); } - private void UpdateAdornedElement(Visual adorner, Visual adorned) + private void UpdateAdornedElement(Visual adorner, Visual? adorned) { var info = adorner.GetValue(s_adornedElementInfoProperty); if (info != null) { - info.Subscription.Dispose(); + info.Subscription!.Dispose(); if (adorned == null) { @@ -163,7 +192,7 @@ namespace Avalonia.Controls.Primitives private class AdornedElementInfo { - public IDisposable Subscription { get; set; } + public IDisposable? Subscription { get; set; } public TransformedBounds? Bounds { get; set; } }