Browse Source
* Add non-overlay popup support to the headless platform When AvaloniaHeadlessPlatformOptions.UsePlatformPopups is enabled, popups are hosted in dedicated headless top-levels positioned via ManagedPopupPositioner instead of the parent's overlay layer. HeadlessWindowExtensions.GetOpenPopups exposes the popups open above a given toplevel. PointToScreen/PointToClient now account for the window position, so popup placement can be asserted in desktop coordinates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename UsePlatformPopups to OverlayPopups for consistency with other platforms Inverted semantics to match Win32/X11/macOS options; defaults to true for now so existing headless test suites keep overlay popup behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>pull/21918/head
committed by
GitHub
6 changed files with 258 additions and 13 deletions
@ -0,0 +1,185 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.Input; |
|||
using Avalonia.Layout; |
|||
using Avalonia.Media; |
|||
using Avalonia.Threading; |
|||
|
|||
namespace Avalonia.Headless.UnitTests; |
|||
|
|||
public class PopupTests |
|||
{ |
|||
#if NUNIT
|
|||
[AvaloniaTest] |
|||
#elif XUNIT
|
|||
[AvaloniaFact] |
|||
#endif
|
|||
public void Point_To_Screen_Respects_Window_Position() |
|||
{ |
|||
var window = new Window { Width = 100, Height = 100 }; |
|||
window.Position = new PixelPoint(100, 200); |
|||
window.Show(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
AssertHelper.Equal(new PixelPoint(110, 220), window.PointToScreen(new Point(10, 20))); |
|||
AssertHelper.Equal(new Point(10, 20), window.PointToClient(new PixelPoint(110, 220))); |
|||
|
|||
window.Close(); |
|||
} |
|||
|
|||
#if NUNIT
|
|||
[AvaloniaTest] |
|||
#elif XUNIT
|
|||
[AvaloniaFact] |
|||
#endif
|
|||
public void Popup_Uses_Dedicated_TopLevel_And_Is_Discoverable() |
|||
{ |
|||
var target = new Border { Background = Brushes.Red }; |
|||
var popup = new Popup |
|||
{ |
|||
PlacementTarget = target, |
|||
Child = new Border { Width = 20, Height = 20 } |
|||
}; |
|||
var window = new Window |
|||
{ |
|||
Width = 100, |
|||
Height = 100, |
|||
Content = new Panel { Children = { target, popup } } |
|||
}; |
|||
window.Show(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
AssertHelper.Equal(0, window.GetOpenPopups().Count); |
|||
|
|||
popup.Open(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
AssertHelper.True(popup.IsOpen); |
|||
AssertHelper.False(popup.IsUsingOverlayLayer); |
|||
AssertHelper.Equal(1, window.GetOpenPopups().Count); |
|||
AssertHelper.True(window.GetOpenPopups()[0] is PopupRoot); |
|||
|
|||
popup.Close(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
AssertHelper.Equal(0, window.GetOpenPopups().Count); |
|||
|
|||
window.Close(); |
|||
} |
|||
|
|||
#if NUNIT
|
|||
[AvaloniaTest] |
|||
#elif XUNIT
|
|||
[AvaloniaFact] |
|||
#endif
|
|||
public void Can_Click_Button_Inside_Platform_Popup() |
|||
{ |
|||
var clickCount = 0; |
|||
var button = new Button { Width = 80, Height = 30 }; |
|||
button.Click += (_, _) => clickCount++; |
|||
|
|||
var target = new Border { Background = Brushes.Red }; |
|||
var popup = new Popup { PlacementTarget = target, Child = button }; |
|||
var window = new Window |
|||
{ |
|||
Width = 100, |
|||
Height = 100, |
|||
Content = new Panel { Children = { target, popup } } |
|||
}; |
|||
window.Show(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
popup.Open(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
var popupRoot = window.GetOpenPopups()[0]; |
|||
popupRoot.MouseDown(new Point(40, 15), MouseButton.Left); |
|||
popupRoot.MouseUp(new Point(40, 15), MouseButton.Left); |
|||
|
|||
AssertHelper.Equal(1, clickCount); |
|||
|
|||
window.Close(); |
|||
} |
|||
|
|||
#if NUNIT
|
|||
[AvaloniaTest] |
|||
#elif XUNIT
|
|||
[AvaloniaFact] |
|||
#endif
|
|||
public void Popup_Placement_Respects_Window_Position() |
|||
{ |
|||
var target = new Border |
|||
{ |
|||
Width = 20, |
|||
Height = 20, |
|||
HorizontalAlignment = HorizontalAlignment.Left, |
|||
VerticalAlignment = VerticalAlignment.Top, |
|||
Background = Brushes.Red |
|||
}; |
|||
var popup = new Popup |
|||
{ |
|||
PlacementTarget = target, |
|||
Placement = PlacementMode.Bottom, |
|||
Child = new Border { Width = 20, Height = 20 } |
|||
}; |
|||
var window = new Window |
|||
{ |
|||
Width = 100, |
|||
Height = 100, |
|||
Content = new Panel { Children = { target, popup } } |
|||
}; |
|||
window.Position = new PixelPoint(100, 200); |
|||
window.Show(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
popup.Open(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
var popupRoot = window.GetOpenPopups()[0]; |
|||
var expected = target.PointToScreen(new Point(0, target.Bounds.Height)); |
|||
AssertHelper.Equal(expected, popupRoot.PointToScreen(default)); |
|||
|
|||
window.Close(); |
|||
} |
|||
|
|||
#if NUNIT
|
|||
[AvaloniaTest] |
|||
#elif XUNIT
|
|||
[AvaloniaFact] |
|||
#endif
|
|||
public void Nested_Popup_Is_Child_Of_Popup_Root() |
|||
{ |
|||
var nestedTarget = new Border { Width = 20, Height = 20, Background = Brushes.Green }; |
|||
var nestedPopup = new Popup |
|||
{ |
|||
PlacementTarget = nestedTarget, |
|||
Child = new Border { Width = 10, Height = 10 } |
|||
}; |
|||
var target = new Border { Background = Brushes.Red }; |
|||
var popup = new Popup |
|||
{ |
|||
PlacementTarget = target, |
|||
Child = new Panel { Children = { nestedTarget, nestedPopup } } |
|||
}; |
|||
var window = new Window |
|||
{ |
|||
Width = 100, |
|||
Height = 100, |
|||
Content = new Panel { Children = { target, popup } } |
|||
}; |
|||
window.Show(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
popup.Open(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
nestedPopup.Open(); |
|||
Dispatcher.UIThread.RunJobs(); |
|||
|
|||
var popupRoot = window.GetOpenPopups()[0]; |
|||
AssertHelper.Equal(1, window.GetOpenPopups().Count); |
|||
AssertHelper.Equal(1, popupRoot.GetOpenPopups().Count); |
|||
AssertHelper.True(popupRoot.GetOpenPopups()[0] is PopupRoot); |
|||
|
|||
window.Close(); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue