Browse Source

Added ResizeX/Y constraint adjustments.

And set these by default on `Popup`/`ContextMenu`.
pull/3970/head
Steven Kirk 6 years ago
parent
commit
11c83727bf
  1. 6
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  2. 3
      src/Avalonia.Controls/Primitives/Popup.cs
  3. 18
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  4. 71
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
  5. 6
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs
  6. 3
      src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs

6
src/Avalonia.Controls/Primitives/OverlayPopupHost.cs

@ -124,10 +124,8 @@ namespace Avalonia.Controls.Primitives
}, DispatcherPriority.Layout); }, DispatcherPriority.Layout);
} }
Point IManagedPopupPositionerPopup.TranslatePoint(Point pt) => pt; double IManagedPopupPositionerPopup.Scaling => 1;
Size IManagedPopupPositionerPopup.TranslateSize(Size size) => size;
public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver) public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver)
{ {
var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup(); var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup();

3
src/Avalonia.Controls/Primitives/Popup.cs

@ -50,7 +50,8 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty = public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty =
AvaloniaProperty.Register<Popup, PopupPositionerConstraintAdjustment>( AvaloniaProperty.Register<Popup, PopupPositionerConstraintAdjustment>(
nameof(PlacementConstraintAdjustment), nameof(PlacementConstraintAdjustment),
PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY); PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY |
PopupPositionerConstraintAdjustment.ResizeX | PopupPositionerConstraintAdjustment.ResizeY);
/// <summary> /// <summary>
/// Defines the <see cref="PlacementGravity"/> property. /// Defines the <see cref="PlacementGravity"/> property.

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

@ -230,7 +230,23 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
/// </remarks> /// </remarks>
FlipY = 8, FlipY = 8,
All = SlideX|SlideY|FlipX|FlipY /// <summary>
/// Horizontally resize the surface
/// </summary>
/// <remarks>
/// Resize the surface horizontally so that it is completely unconstrained.
/// </remarks>
ResizeX = 16,
/// <summary>
/// Vertically resize the surface
/// </summary>
/// <remarks>
/// Resize the surface vertically so that it is completely unconstrained.
/// </remarks>
ResizeY = 16,
All = SlideX|SlideY|FlipX|FlipY|ResizeX|ResizeY
} }
static class PopupPositioningEdgeHelper static class PopupPositioningEdgeHelper

71
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Transactions;
namespace Avalonia.Controls.Primitives.PopupPositioning namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
@ -8,9 +9,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; } IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; }
Rect ParentClientAreaScreenGeometry { get; } Rect ParentClientAreaScreenGeometry { get; }
double Scaling { get; }
void MoveAndResize(Point devicePoint, Size virtualSize); void MoveAndResize(Point devicePoint, Size virtualSize);
Point TranslatePoint(Point pt);
Size TranslateSize(Size size);
} }
public class ManagedPopupPositionerScreenInfo public class ManagedPopupPositionerScreenInfo
@ -79,16 +79,23 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
public void Update(PopupPositionerParameters parameters) public void Update(PopupPositionerParameters parameters)
{ {
var rect = Calculate(
Update(_popup.TranslateSize(parameters.Size), parameters.Size, parameters.Size * _popup.Scaling,
new Rect(_popup.TranslatePoint(parameters.AnchorRectangle.TopLeft), new Rect(
_popup.TranslateSize(parameters.AnchorRectangle.Size)), parameters.AnchorRectangle.TopLeft * _popup.Scaling,
parameters.Anchor, parameters.Gravity, parameters.ConstraintAdjustment, parameters.AnchorRectangle.Size * _popup.Scaling),
_popup.TranslatePoint(parameters.Offset)); parameters.Anchor,
parameters.Gravity,
parameters.ConstraintAdjustment,
parameters.Offset * _popup.Scaling);
_popup.MoveAndResize(
rect.Position,
rect.Size / _popup.Scaling);
} }
private void Update(Size translatedSize, Size originalSize, private Rect Calculate(Size translatedSize,
Rect anchorRect, PopupAnchor anchor, PopupGravity gravity, Rect anchorRect, PopupAnchor anchor, PopupGravity gravity,
PopupPositionerConstraintAdjustment constraintAdjustment, Point offset) PopupPositionerConstraintAdjustment constraintAdjustment, Point offset)
{ {
@ -137,6 +144,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
return true; return true;
} }
static bool IsValid(in Rect rc) => rc.Width > 0 && rc.Height > 0;
Rect GetUnconstrained(PopupAnchor a, PopupGravity g) => Rect GetUnconstrained(PopupAnchor a, PopupGravity g) =>
new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize); new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize);
@ -161,6 +170,27 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
geo = geo.WithX(bounds.Right - geo.Width); geo = geo.WithX(bounds.Right - geo.Width);
} }
// Resize the rect horizontally if allowed.
if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeX) != 0)
{
var unconstrainedRect = geo;
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Left))
{
unconstrainedRect = unconstrainedRect.WithX(bounds.X);
}
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Right))
{
unconstrainedRect = unconstrainedRect.WithWidth(bounds.Width - unconstrainedRect.X);
}
if (IsValid(unconstrainedRect))
{
geo = unconstrainedRect;
}
}
// If flipping geometry and anchor is allowed and helps, use the flipped one, // If flipping geometry and anchor is allowed and helps, use the flipped one,
// otherwise leave it as is // otherwise leave it as is
if (!FitsInBounds(geo, PopupAnchor.VerticalMask) if (!FitsInBounds(geo, PopupAnchor.VerticalMask)
@ -179,7 +209,28 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
geo = geo.WithY(bounds.Bottom - geo.Height); geo = geo.WithY(bounds.Bottom - geo.Height);
} }
_popup.MoveAndResize(geo.TopLeft, originalSize); // Resize the rect vertically if allowed.
if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeY) != 0)
{
var unconstrainedRect = geo;
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Top))
{
unconstrainedRect = unconstrainedRect.WithY(bounds.Y);
}
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Bottom))
{
unconstrainedRect = unconstrainedRect.WithHeight(bounds.Height - unconstrainedRect.Y);
}
if (IsValid(unconstrainedRect))
{
geo = unconstrainedRect;
}
}
return geo;
} }
} }
} }

6
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs

@ -32,7 +32,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
// Popup positioner operates with abstract coordinates, but in our case they are pixel ones // Popup positioner operates with abstract coordinates, but in our case they are pixel ones
var point = _parent.PointToScreen(default); var point = _parent.PointToScreen(default);
var size = TranslateSize(_parent.ClientSize); var size = _parent.ClientSize * Scaling;
return new Rect(point.X, point.Y, size.Width, size.Height); return new Rect(point.X, point.Y, size.Width, size.Height);
} }
@ -43,8 +43,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
_moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling); _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling);
} }
public virtual Point TranslatePoint(Point pt) => pt * _parent.Scaling; public virtual double Scaling => _parent.Scaling;
public virtual Size TranslateSize(Size size) => size * _parent.Scaling;
} }
} }

3
src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs

@ -9,8 +9,7 @@ namespace Avalonia.Native
{ {
} }
public override Point TranslatePoint(Point pt) => pt;
public override Size TranslateSize(Size size) => size; public override double Scaling => 1;
} }
} }

Loading…
Cancel
Save