Browse Source

Fixed positioning of popups attached to adorners (#14439)

Co-authored-by: Max Katz <maxkatz6@outlook.com>
pull/14876/head
Bartosz Korczyński 3 years ago
committed by GitHub
parent
commit
4a1e2411cd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 30
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  2. 47
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

30
src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

@ -468,7 +468,16 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{
if (target == null)
throw new InvalidOperationException("Placement mode is not Pointer and PlacementTarget is null");
var matrix = target.TransformToVisual(topLevel);
Matrix? matrix;
if (TryGetAdorner(target, out var adorned, out var adornerLayer))
{
matrix = adorned!.TransformToVisual(topLevel) * target.TransformToVisual(adornerLayer!);
}
else
{
matrix = target.TransformToVisual(topLevel);
}
if (matrix == null)
{
if (target.GetVisualRoot() == null)
@ -529,6 +538,25 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
}
}
private static bool TryGetAdorner(Visual target, out Visual? adorned, out Visual? adornerLayer)
{
var element = target;
while (element != null)
{
if (AdornerLayer.GetAdornedElement(element) is { } adornedElement)
{
adorned = adornedElement;
adornerLayer = AdornerLayer.GetAdornerLayer(adorned);
return true;
}
element = element.VisualParent;
}
adorned = null;
adornerLayer = null;
return false;
}
}
}

47
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -1143,6 +1143,53 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
[Fact]
public void Popup_Attached_To_Adorner_Respects_Adorner_Position()
{
using (CreateServices())
{
var popupTarget = new Border() { Height = 30, Background = Brushes.Red, [DockPanel.DockProperty] = Dock.Top };
var popupContent = new Border() { Height = 30, Width = 50, Background = Brushes.Yellow };
var popup = new Popup
{
Child = popupContent,
Placement = PlacementMode.AnchorAndGravity,
PlacementTarget = popupTarget,
PlacementAnchor = PopupAnchor.BottomRight,
PlacementGravity = PopupGravity.BottomRight
};
var adorner = new DockPanel() { Children = { popupTarget, popup },
HorizontalAlignment = HorizontalAlignment.Left,
Width = 40,
Margin = new Thickness(50, 5, 0, 0) };
var adorned = new Border() {
Width = 100,
Height = 100,
Background = Brushes.Blue,
[Canvas.LeftProperty] = 20,
[Canvas.TopProperty] = 40
};
var windowContent = new Canvas();
windowContent.Children.Add(adorned);
var root = PreparedWindow(windowContent);
var adornerLayer = AdornerLayer.GetAdornerLayer(adorned);
adornerLayer.Children.Add(adorner);
AdornerLayer.SetAdornedElement(adorner, adorned);
root.LayoutManager.ExecuteInitialLayoutPass();
popup.Open();
Dispatcher.UIThread.RunJobs(DispatcherPriority.AfterRender);
// X: Adorned Canvas.Left + Adorner Margin Left + Adorner Width
// Y: Adorned Canvas.Top + Adorner Margin Top + Adorner Height
Assert.Equal(new PixelPoint(110, 75), popupContent.PointToScreen(new Point(0, 0)));
}
}
private static PopupRoot CreateRoot(TopLevel popupParent, IPopupImpl impl = null)
{
impl ??= popupParent.PlatformImpl.CreatePopup();

Loading…
Cancel
Save