Browse Source

Add Popup.ShouldUseOverlayLayer property (#5629)

* Implement Popup.ShouldUseOverlayLayer property

* Add ShouldUseOverlayLayer tests
pull/18069/head
Maxwell Katz 1 year ago
committed by GitHub
parent
commit
98a388d3a3
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  2. 39
      src/Avalonia.Controls/Primitives/Popup.cs
  3. 32
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

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

@ -194,10 +194,16 @@ namespace Avalonia.Controls.Primitives
// TODO12: mark PrivateAPI or internal.
[Unstable("PopupHost is considered an internal API. Use Popup or any Popup-based controls (Flyout, Tooltip) instead.")]
public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver)
=> CreatePopupHost(target, dependencyResolver, false);
internal static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver, bool shouldUseOverlayLayer)
{
if (TopLevel.GetTopLevel(target) is { } topLevel && topLevel.PlatformImpl?.CreatePopup() is { } popupImpl)
if (!shouldUseOverlayLayer)
{
return new PopupRoot(topLevel, popupImpl, dependencyResolver);
if (TopLevel.GetTopLevel(target) is { } topLevel && topLevel.PlatformImpl?.CreatePopup() is { } popupImpl)
{
return new PopupRoot(topLevel, popupImpl, dependencyResolver);
}
}
if (OverlayLayer.GetOverlayLayer(target) is { } overlayLayer)

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

@ -141,8 +141,21 @@ namespace Avalonia.Controls.Primitives
public static readonly AttachedProperty<bool> TakesFocusFromNativeControlProperty =
AvaloniaProperty.RegisterAttached<Popup, Control, bool>(nameof(TakesFocusFromNativeControl), true);
/// <summary>
/// Defines the <see cref="ShouldUseOverlayLayer"/> property.
/// </summary>
public static readonly StyledProperty<bool> ShouldUseOverlayLayerProperty =
AvaloniaProperty.Register<Popup, bool>(nameof(ShouldUseOverlayLayer));
/// <summary>
/// Defines the <see cref="IsUsingOverlayLayer"/> property.
/// </summary>
public static readonly DirectProperty<Popup, bool> IsUsingOverlayLayerProperty = AvaloniaProperty.RegisterDirect<Popup, bool>(
nameof(IsUsingOverlayLayer), o => o.IsUsingOverlayLayer);
private bool _isOpenRequested;
private bool _ignoreIsOpenChanged;
private bool _isUsingOverlayLayer;
private PopupOpenState? _openState;
private Action<IPopupHost?>? _popupHostChangedHandler;
@ -386,6 +399,29 @@ namespace Avalonia.Controls.Primitives
set => SetValue(TakesFocusFromNativeControlProperty, value);
}
/// <summary>
/// Gets or sets a value that indicates whether the popup should be shown in the overlay layer of the parent window.
/// </summary>
/// <remarks>
/// When <see cref="ShouldUseOverlayLayer"/> is "false" implementation depends on the platform.
/// Use <see cref="IsUsingOverlayLayer"/> to get actual popup behavior.
/// This is an equvalent of `OverlayPopups` property of the platform options, but settable independently per each popup.
/// </remarks>
public bool ShouldUseOverlayLayer
{
get => GetValue(ShouldUseOverlayLayerProperty);
set => SetValue(ShouldUseOverlayLayerProperty, value);
}
/// <summary>
/// Gets a value that indicates whether the popup is shown in the overlay layer of the parent window.
/// </summary>
public bool IsUsingOverlayLayer
{
get => _isUsingOverlayLayer;
private set => SetAndRaise(IsUsingOverlayLayerProperty, ref _isUsingOverlayLayer, value);
}
IPopupHost? IPopupHostProvider.PopupHost => Host;
event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
@ -423,7 +459,7 @@ namespace Avalonia.Controls.Primitives
_isOpenRequested = false;
var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver, ShouldUseOverlayLayer);
var handlerCleanup = new CompositeDisposable(7);
UpdateHostSizing(popupHost, topLevel, placementTarget);
@ -541,6 +577,7 @@ namespace Avalonia.Controls.Primitives
WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint);
popupHost.Show();
IsUsingOverlayLayer = popupHost is OverlayPopupHost;
if (TakesFocusFromNativeControl)
popupHost.TakeFocus();

32
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -1260,6 +1260,38 @@ namespace Avalonia.Controls.UnitTests.Primitives
return result;
}
[Fact]
public void Popup_Open_With_Correct_IsUsingOverlayLayer_And_Disabled_OverlayLayer()
{
using (CreateServices())
{
var target = new Popup();
target.IsOpen = true;
target.ShouldUseOverlayLayer = false;
var window = PreparedWindow(target);
window.Show();
Assert.Equal(UsePopupHost, target.IsUsingOverlayLayer);
}
}
[Fact]
public void Popup_Open_With_Correct_IsUsingOverlayLayer_And_Enabled_OverlayLayer()
{
using (CreateServices())
{
var target = new Popup();
target.IsOpen = true;
target.ShouldUseOverlayLayer = true;
var window = PreparedWindow(target);
window.Show();
Assert.Equal(true, target.IsUsingOverlayLayer);
}
}
private IDisposable CreateServices()
{
return UnitTestApplication.Start(TestServices.StyledWindow.With(

Loading…
Cancel
Save