diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
index 2ca637213f..3031165c4c 100644
--- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
+++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
@@ -3,6 +3,7 @@ using System.ComponentModel;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Layout;
+using Avalonia.Logging;
#nullable enable
@@ -133,8 +134,12 @@ namespace Avalonia.Controls.Primitives
///
/// Hides the Flyout
///
- /// Whether or not this closing action can be cancelled
- public void Hide(bool canCancel = true)
+ public void Hide()
+ {
+ HideCore();
+ }
+
+ protected virtual void HideCore(bool canCancel = true)
{
if (!IsOpen)
{
@@ -181,7 +186,7 @@ namespace Avalonia.Controls.Primitives
}
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)
{
+ // 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)
{
+ // Only do this once when the Flyout opens & cache the result
if (_popup?.Host is PopupRoot root)
{
+ // Get the popup root bounds and convert to screen coordinates
var tmp = root.Bounds.Inflate(100);
var scPt = root.PointToScreen(tmp.TopLeft);
enlargedPopupRect = new Rect(scPt.X, scPt.Y, tmp.Width, tmp.Height);
}
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);
}
@@ -251,10 +266,15 @@ namespace Avalonia.Controls.Primitives
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);
if (!enlargedPopupRect?.Contains(new Point(pt.X, pt.Y)) ?? false)
{
- Hide(false);
+ HideCore(false);
enlargedPopupRect = null;
transientDisposable?.Dispose();
transientDisposable = null;
@@ -262,9 +282,11 @@ namespace Avalonia.Controls.Primitives
}
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)
{
- Hide(false);
+ HideCore(false);
enlargedPopupRect = null;
transientDisposable?.Dispose();
transientDisposable = null;
@@ -316,7 +338,7 @@ namespace Avalonia.Controls.Primitives
private void OnPopupClosed(object sender, EventArgs e)
{
- Hide();
+ HideCore();
}
private void PositionPopup(bool showAtPointer)
@@ -418,12 +440,6 @@ namespace Avalonia.Controls.Primitives
_popup.PlacementAnchor = PopupPositioning.PopupAnchor.BottomLeft;
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)...
default:
//This is just FlyoutPlacementMode.Top behavior (above & centered)
@@ -457,6 +473,11 @@ namespace Avalonia.Controls.Primitives
{
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);
}
}
diff --git a/src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs b/src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs
index 0cde3c7b97..2e77de3b3b 100644
--- a/src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs
+++ b/src/Avalonia.Controls/Flyouts/FlyoutPlacementMode.cs
@@ -22,10 +22,11 @@
///
Right = 3,
- ///
- /// Preferred location is centered on the screen
- ///
- Full = 4,
+ //TODO
+ //
+ // Preferred location is centered on the screen
+ //
+ //Full = 4,
///
/// Preferred location is above the target element, with the left edge of the flyout