Browse Source

FlyoutBase updates

pull/5682/head
amwx 5 years ago
parent
commit
8786250eb2
  1. 47
      src/Avalonia.Controls/Flyouts/FlyoutBase.cs
  2. 9
      src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs

47
src/Avalonia.Controls/Flyouts/FlyoutBase.cs

@ -3,6 +3,7 @@ using System.ComponentModel;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging;
#nullable enable #nullable enable
@ -133,8 +134,12 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Hides the Flyout /// Hides the Flyout
/// </summary> /// </summary>
/// <param name="canCancel">Whether or not this closing action can be cancelled</param> public void Hide()
public void Hide(bool canCancel = true) {
HideCore();
}
protected virtual void HideCore(bool canCancel = true)
{ {
if (!IsOpen) if (!IsOpen)
{ {
@ -181,7 +186,7 @@ namespace Avalonia.Controls.Primitives
} }
else // Close before opening a new one else // Close before opening a new one
{ {
Hide(false); HideCore(false);
} }
} }
@ -232,17 +237,27 @@ namespace Avalonia.Controls.Primitives
{ {
if (args is RawPointerEventArgs pArgs && pArgs.Type == RawPointerEventType.Move) if (args is RawPointerEventArgs pArgs && pArgs.Type == RawPointerEventType.Move)
{ {
// In ShowMode = TransientWithDismissOnPointerMoveAway, the Flyout is kept
// shown as long as the pointer is within a certain px distance from the
// flyout itself. I'm not sure what WinUI uses, but I'm defaulting to
// 100px, which seems about right
// enlargedPopupRect is the Flyout bounds enlarged 100px
// For windowed popups, enlargedPopupRect is in screen coordinates,
// for overlay popups, its in OverlayLayer coordinates
if (enlargedPopupRect == null) if (enlargedPopupRect == null)
{ {
// Only do this once when the Flyout opens & cache the result
if (_popup?.Host is PopupRoot root) if (_popup?.Host is PopupRoot root)
{ {
// Get the popup root bounds and convert to screen coordinates
var tmp = root.Bounds.Inflate(100); var tmp = root.Bounds.Inflate(100);
var scPt = root.PointToScreen(tmp.TopLeft); var scPt = root.PointToScreen(tmp.TopLeft);
enlargedPopupRect = new Rect(scPt.X, scPt.Y, tmp.Width, tmp.Height); enlargedPopupRect = new Rect(scPt.X, scPt.Y, tmp.Width, tmp.Height);
} }
else if (_popup?.Host is OverlayPopupHost host) else if (_popup?.Host is OverlayPopupHost host)
{ {
// Overlay popups are in Window client coordinates, just use that // Overlay popups are in OverlayLayer coordinates, just use that
enlargedPopupRect = host.Bounds.Inflate(100); enlargedPopupRect = host.Bounds.Inflate(100);
} }
@ -251,10 +266,15 @@ namespace Avalonia.Controls.Primitives
if (_popup?.Host is PopupRoot) if (_popup?.Host is PopupRoot)
{ {
// As long as the pointer stays within the enlargedPopupRect
// the flyout stays open. If it leaves, close it
// Despite working in screen coordinates, leaving the TopLevel
// window will not close this (as pointer events stop), which
// does match UWP
var pt = pArgs.Root.PointToScreen(pArgs.Position); var pt = pArgs.Root.PointToScreen(pArgs.Position);
if (!enlargedPopupRect?.Contains(new Point(pt.X, pt.Y)) ?? false) if (!enlargedPopupRect?.Contains(new Point(pt.X, pt.Y)) ?? false)
{ {
Hide(false); HideCore(false);
enlargedPopupRect = null; enlargedPopupRect = null;
transientDisposable?.Dispose(); transientDisposable?.Dispose();
transientDisposable = null; transientDisposable = null;
@ -262,9 +282,11 @@ namespace Avalonia.Controls.Primitives
} }
else if (_popup?.Host is OverlayPopupHost) else if (_popup?.Host is OverlayPopupHost)
{ {
// Same as above here, but just different coordinate space
// so we don't need to translate
if (!enlargedPopupRect?.Contains(pArgs.Position) ?? false) if (!enlargedPopupRect?.Contains(pArgs.Position) ?? false)
{ {
Hide(false); HideCore(false);
enlargedPopupRect = null; enlargedPopupRect = null;
transientDisposable?.Dispose(); transientDisposable?.Dispose();
transientDisposable = null; transientDisposable = null;
@ -316,7 +338,7 @@ namespace Avalonia.Controls.Primitives
private void OnPopupClosed(object sender, EventArgs e) private void OnPopupClosed(object sender, EventArgs e)
{ {
Hide(); HideCore();
} }
private void PositionPopup(bool showAtPointer) private void PositionPopup(bool showAtPointer)
@ -418,12 +440,6 @@ namespace Avalonia.Controls.Primitives
_popup.PlacementAnchor = PopupPositioning.PopupAnchor.BottomLeft; _popup.PlacementAnchor = PopupPositioning.PopupAnchor.BottomLeft;
break; break;
case FlyoutPlacementMode.Full:
//Not sure how the get this to work
//Popup should display at max size in the middle of the VisualRoot/Window of the Target
throw new NotSupportedException("FlyoutPlacementMode.Full is not supported at this time");
//break;
//includes Auto (not sure what determines that)... //includes Auto (not sure what determines that)...
default: default:
//This is just FlyoutPlacementMode.Top behavior (above & centered) //This is just FlyoutPlacementMode.Top behavior (above & centered)
@ -457,6 +473,11 @@ namespace Avalonia.Controls.Primitives
{ {
if (c.ContextFlyout != null) if (c.ContextFlyout != null)
{ {
if (c.ContextMenu != null)
{
Logger.TryGet(LogEventLevel.Verbose, "FlyoutBase")?.Log(c, "ContextMenu and ContextFlyout are both set, defaulting to ContextMenu");
return;
}
c.ContextFlyout.ShowAt(c, true); c.ContextFlyout.ShowAt(c, true);
} }
} }

9
src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs

@ -22,10 +22,11 @@
/// </summary> /// </summary>
Right = 3, Right = 3,
/// <summary> //TODO
/// Preferred location is centered on the screen // <summary>
/// </summary> // Preferred location is centered on the screen
Full = 4, // </summary>
//Full = 4,
/// <summary> /// <summary>
/// Preferred location is above the target element, with the left edge of the flyout /// Preferred location is above the target element, with the left edge of the flyout

Loading…
Cancel
Save