Browse Source

Implement PlacementMode.Center

pull/10492/head
Max Katz 4 years ago
parent
commit
733238a8af
  1. 9
      samples/ControlCatalog/Pages/FlyoutsPage.axaml
  2. 5
      src/Avalonia.Controls/PlacementMode.cs
  3. 45
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

9
samples/ControlCatalog/Pages/FlyoutsPage.axaml

@ -136,6 +136,15 @@
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Placement=Center">
<Button.Flyout>
<Flyout Placement="Center">
<Panel Width="100" Height="100">
<TextBlock Text="Flyout Content!" />
</Panel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Placement=TopEdgeAlignedLeft">
<Button.Flyout>
<Flyout Placement="TopEdgeAlignedLeft">

5
src/Avalonia.Controls/PlacementMode.cs

@ -31,6 +31,11 @@ namespace Avalonia.Controls
/// Preferred location is above the target element.
/// </summary>
Top,
/// <summary>
/// Preferred location is centered over the target element.
/// </summary>
Center,
/// <summary>
/// The popup is placed according to <see cref="Popup.PlacementAnchor"/> and <see cref="Popup.PlacementGravity"/> rules.

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

@ -464,21 +464,25 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
positionerParameters.Anchor = PopupAnchor.TopLeft;
positionerParameters.Gravity = PopupGravity.BottomRight;
}
else
else if (placement == PlacementMode.Center)
{
if (target == null)
throw new InvalidOperationException("Placement mode is not Pointer and PlacementTarget is null");
var matrix = target.TransformToVisual(topLevel);
if (matrix == null)
// Start with top left position, and add offset to move it to the center
var anchorRectangle = GetAnchorRectangle(topLevel, target, rect);
positionerParameters.AnchorRectangle = anchorRectangle;
positionerParameters.Anchor = PopupAnchor.TopLeft;
positionerParameters.Gravity = PopupGravity.BottomRight;
var targetSize = positionerParameters.Size;
if (targetSize != default)
{
if (target.GetVisualRoot() == null)
throw new InvalidOperationException("Target control is not attached to the visual tree");
throw new InvalidOperationException("Target control is not in the same tree as the popup parent");
positionerParameters.Offset += new Point(
(anchorRectangle.Width - targetSize.Width) / 2,
(anchorRectangle.Height - targetSize.Height) / 2);
}
var bounds = new Rect(default, target.Bounds.Size);
var anchorRect = rect ?? bounds;
positionerParameters.AnchorRectangle = anchorRect.Intersect(bounds).TransformToAABB(matrix.Value);
}
else
{
positionerParameters.AnchorRectangle = GetAnchorRectangle(topLevel, target, rect);
var parameters = placement switch
{
@ -528,6 +532,23 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
}
}
private static Rect GetAnchorRectangle(TopLevel topLevel, Visual target, Rect? rect)
{
if (target == null)
throw new InvalidOperationException("Placement mode is not Pointer and PlacementTarget is null");
var matrix = target.TransformToVisual(topLevel);
if (matrix == null)
{
if (target.GetVisualRoot() == null)
throw new InvalidOperationException("Target control is not attached to the visual tree");
throw new InvalidOperationException("Target control is not in the same tree as the popup parent");
}
var bounds = new Rect(default, target.Bounds.Size);
var anchorRect = rect ?? bounds;
return anchorRect.Intersect(bounds).TransformToAABB(matrix.Value);
}
}
}

Loading…
Cancel
Save