Browse Source

Merge pull request #626 from AvaloniaUI/fix-transformed-bounds

Fix TransformedBounds for invisible controls.
pull/628/head
Jeremy Koritzinsky 10 years ago
committed by GitHub
parent
commit
7577e0ef69
  1. 8
      src/Avalonia.Controls/Primitives/AdornerLayer.cs
  2. 17
      src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
  3. 26
      src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs
  4. 2
      src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs
  5. 6
      tests/Avalonia.SceneGraph.UnitTests/VisualTree/BoundsTrackerTests.cs

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

@ -57,11 +57,11 @@ namespace Avalonia.Controls.Primitives
{
var info = (AdornedElementInfo)child.GetValue(s_adornedElementInfoProperty);
if (info != null)
if (info != null && info.Bounds.HasValue)
{
child.RenderTransform = new MatrixTransform(info.Bounds.Transform);
child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform);
child.RenderTransformOrigin = new RelativePoint(new Point(0,0), RelativeUnit.Absolute);
child.Arrange(info.Bounds.Bounds);
child.Arrange(info.Bounds.Value.Bounds);
}
else
{
@ -130,7 +130,7 @@ namespace Avalonia.Controls.Primitives
{
public IDisposable Subscription { get; set; }
public TransformedBounds Bounds { get; set; }
public TransformedBounds? Bounds { get; set; }
}
}
}

17
src/Avalonia.SceneGraph/Rendering/RendererMixin.cs

@ -142,11 +142,28 @@ namespace Avalonia.Rendering
var childClipRect = clipRect.Translate(-childBounds.Position);
context.Render(child, childClipRect);
}
else
{
ClearTransformedBounds(child);
}
}
ReturnListToPool(lst);
}
}
if (!visual.IsVisible)
{
ClearTransformedBounds(visual);
}
}
private static void ClearTransformedBounds(IVisual visual)
{
foreach (var e in visual.GetSelfAndVisualDescendents())
{
BoundsTracker.SetTransformedBounds((Visual)visual, null);
}
}
private static void ReturnListToPool(List<IVisual> lst)

26
src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs

@ -9,33 +9,43 @@ namespace Avalonia.VisualTree
/// Tracks the bounds of a control.
/// </summary>
/// <remarks>
/// This class is used by Adorners to track the control that the adorner is attached to.
/// 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
{
private static AttachedProperty<TransformedBounds> TransformedBoundsProperty =
AvaloniaProperty.RegisterAttached<BoundsTracker, Visual, TransformedBounds>("TransformedBounds");
/// <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)
public IObservable<TransformedBounds?> Track(Visual visual)
{
return visual.GetObservable(TransformedBoundsProperty);
}
internal static void SetTransformedBounds(Visual visual, TransformedBounds bounds)
/// <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, bounds);
visual.SetValue(TransformedBoundsProperty, value);
}
/// <summary>
/// Gets the transformed bounds of the visual.
/// </summary>
/// <param name="visual">The visual.</param>
/// <returns>The transformed bounds.</returns>
public static TransformedBounds GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty);
/// <returns>The transformed bounds or null if the visual is not visible.</returns>
public static TransformedBounds? GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty);
}
}

2
src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs

@ -104,7 +104,7 @@ namespace Avalonia.VisualTree
if (filter?.Invoke(visual) != false)
{
bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual).Contains(p);
bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual)?.Contains(p) == true;
if ((containsPoint || !visual.ClipToBounds) && visual.VisualChildren.Any())
{

6
tests/Avalonia.SceneGraph.UnitTests/VisualTree/BoundsTrackerTests.cs

@ -46,11 +46,11 @@ namespace Avalonia.SceneGraph.UnitTests.VisualTree
context.Render(tree);
var track = target.Track(control);
var results = new List<TransformedBounds>();
var results = new List<TransformedBounds?>();
track.Subscribe(results.Add);
Assert.Equal(new Rect(0, 0, 15, 15), results[0].Bounds);
Assert.Equal(Matrix.CreateTranslation(42, 42), results[0].Transform);
Assert.Equal(new Rect(0, 0, 15, 15), results[0].Value.Bounds);
Assert.Equal(Matrix.CreateTranslation(42, 42), results[0].Value.Transform);
}
}
}

Loading…
Cancel
Save