@ -1,7 +1,7 @@
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Text ;
using Avalonia.Input ;
using Avalonia.Input.Raw ;
using Avalonia.Layout ;
# nullable enable
@ -20,12 +20,19 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty < FlyoutPlacementMode > PlacementProperty =
AvaloniaProperty . Register < FlyoutBase , FlyoutPlacementMode > ( nameof ( Placement ) ) ;
public static readonly DirectProperty < FlyoutBase , FlyoutShowMode > ShowModeProperty =
AvaloniaProperty . RegisterDirect < FlyoutBase , FlyoutShowMode > ( nameof ( ShowMode ) ,
x = > x . ShowMode , ( x , v ) = > x . ShowMode = v ) ;
public static readonly AttachedProperty < FlyoutBase ? > AttachedFlyoutProperty =
AvaloniaProperty . RegisterAttached < FlyoutBase , Control , FlyoutBase ? > ( "AttachedFlyout" , null ) ;
private bool _ isOpen ;
private Control ? _ target ;
protected Popup ? _ popup ;
private FlyoutShowMode _ showMode = FlyoutShowMode . Standard ;
Rect ? enlargedPopupRect ;
IDisposable ? transientDisposable ;
public bool IsOpen
{
@ -39,6 +46,12 @@ namespace Avalonia.Controls.Primitives
set = > SetValue ( PlacementProperty , value ) ;
}
public FlyoutShowMode ShowMode
{
get = > _ showMode ;
set = > SetAndRaise ( ShowModeProperty , ref _ showMode , value ) ;
}
public Control ? Target
{
get = > _ target ;
@ -96,7 +109,11 @@ namespace Avalonia.Controls.Primitives
}
IsOpen = _ popup . IsOpen = false ;
// Ensure this isn't active
transientDisposable ? . Dispose ( ) ;
transientDisposable = null ;
OnClosed ( ) ;
}
@ -142,6 +159,72 @@ namespace Avalonia.Controls.Primitives
PositionPopup ( showAtPointer ) ;
IsOpen = _ popup . IsOpen = true ;
OnOpened ( ) ;
if ( ShowMode = = FlyoutShowMode . Standard )
{
// Try and focus content inside Flyout
if ( _ popup . Child . Focusable )
{
FocusManager . Instance ? . Focus ( _ popup . Child ) ;
}
else
{
var nextFocus = KeyboardNavigationHandler . GetNext ( _ popup . Child , NavigationDirection . Next ) ;
if ( nextFocus ! = null )
{
FocusManager . Instance ? . Focus ( nextFocus ) ;
}
}
}
else if ( ShowMode = = FlyoutShowMode . TransientWithDismissOnPointerMoveAway )
{
transientDisposable = InputManager . Instance ? . Process . Subscribe ( HandleTransientDismiss ) ;
}
}
private void HandleTransientDismiss ( RawInputEventArgs args )
{
if ( args is RawPointerEventArgs pArgs & & pArgs . Type = = RawPointerEventType . Move )
{
if ( enlargedPopupRect = = null )
{
if ( _ popup ? . Host is PopupRoot root )
{
var tmp = root . Bounds . Inflate ( 1 0 0 ) ;
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
enlargedPopupRect = host . Bounds . Inflate ( 1 0 0 ) ;
}
return ;
}
if ( _ popup ? . Host is PopupRoot )
{
var pt = pArgs . Root . PointToScreen ( pArgs . Position ) ;
if ( ! enlargedPopupRect ? . Contains ( new Point ( pt . X , pt . Y ) ) ? ? false )
{
Hide ( false ) ;
enlargedPopupRect = null ;
transientDisposable ? . Dispose ( ) ;
transientDisposable = null ;
}
}
else if ( _ popup ? . Host is OverlayPopupHost )
{
if ( ! enlargedPopupRect ? . Contains ( pArgs . Position ) ? ? false )
{
Hide ( false ) ;
enlargedPopupRect = null ;
transientDisposable ? . Dispose ( ) ;
transientDisposable = null ;
}
}
}
}
protected virtual void OnOpening ( )