mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-21 08:32:21 +08:00
421 lines
13 KiB
C#
421 lines
13 KiB
C#
using AtomUI.Controls.Primitives;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AtomUIMenu = AtomUI.Desktop.Controls.Menu;
|
|
using AtomUIMenuItem = AtomUI.Desktop.Controls.MenuItem;
|
|
using AtomUIPopup = AtomUI.Desktop.Controls.Popup;
|
|
using AtomUIWindow = AtomUI.Desktop.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Menu;
|
|
|
|
public class MenuPinnedOpenTests
|
|
{
|
|
static MenuPinnedOpenTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Pin_Opens_Menu_Active_Submenu_And_Physical_Popup()
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
parentItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
var popup = FindPopup(parentItem);
|
|
menu.IsOpen.ShouldBeTrue();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
popup.IsPopupPinnedOpen.ShouldBeTrue();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public void Popup_Pin_Only_Pins_The_Active_Submenu_Chain(bool grouped)
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
var firstChild = new AtomUIMenuItem { Header = "Open", IsSubMenuOpen = true };
|
|
firstChild.Items.Add(new AtomUIMenuItem { Header = "Recent" });
|
|
var secondChild = new AtomUIMenuItem { Header = "Edit" };
|
|
secondChild.Items.Add(new AtomUIMenuItem { Header = "Copy" });
|
|
if (grouped)
|
|
{
|
|
parentItem.Items.Add(new MenuItemGroup { Header = "Group", Items = { firstChild, secondChild } });
|
|
}
|
|
else
|
|
{
|
|
parentItem.Items.Add(firstChild);
|
|
parentItem.Items.Add(secondChild);
|
|
}
|
|
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
firstChild.IsSubMenuOpen.ShouldBeTrue();
|
|
firstChild.IsPopupPinnedOpen.ShouldBeTrue();
|
|
secondChild.IsSubMenuOpen.ShouldBeFalse();
|
|
secondChild.IsPopupPinnedOpen.ShouldBeFalse();
|
|
|
|
// Navigation must release the old pin before Avalonia closes siblings.
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
secondChild.Open();
|
|
Dispatcher.UIThread.RunJobs();
|
|
firstChild.IsSubMenuOpen.ShouldBeFalse();
|
|
firstChild.IsPopupPinnedOpen.ShouldBeFalse();
|
|
FindPopup(firstChild).IsOpen.ShouldBeFalse();
|
|
secondChild.IsSubMenuOpen.ShouldBeTrue();
|
|
secondChild.IsPopupPinnedOpen.ShouldBeTrue();
|
|
|
|
secondChild.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
secondChild.IsSubMenuOpen.ShouldBeTrue();
|
|
FindPopup(secondChild).IsOpen.ShouldBeTrue();
|
|
|
|
firstChild.Open();
|
|
Dispatcher.UIThread.RunJobs();
|
|
firstChild.IsSubMenuOpen.ShouldBeTrue();
|
|
secondChild.IsSubMenuOpen.ShouldBeFalse();
|
|
}
|
|
|
|
menu.IsPopupPinnedOpen = false;
|
|
firstChild.IsPopupPinnedOpen.ShouldBeFalse();
|
|
firstChild.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
firstChild.IsSubMenuOpen.ShouldBeFalse();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Pin_Rejects_Menu_Close_Requests()
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
parentItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
var popup = FindPopup(parentItem);
|
|
|
|
menu.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeTrue();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
|
|
menu.CloseImmediately();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeTrue();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Pin_Rejects_Active_Submenu_Collapse()
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
parentItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
parentItem.SetCurrentValue(MenuItem.IsSubMenuOpenProperty, false);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
FindPopup(parentItem).IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Pin_Closes_For_Detach_And_Reopens_After_Reattach()
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
parentItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
var popup = FindPopup(parentItem);
|
|
var windowContent = window.Content;
|
|
|
|
window.Content = null;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeFalse();
|
|
parentItem.IsSubMenuOpen.ShouldBeFalse();
|
|
parentItem.IsPopupPinnedOpen.ShouldBeFalse();
|
|
popup.IsPopupPinnedOpen.ShouldBeFalse();
|
|
popup.IsOpen.ShouldBeFalse();
|
|
|
|
window.Content = windowContent;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeTrue();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Unpin_Leaves_Menu_Open_And_Restores_Normal_Close()
|
|
{
|
|
var parentItem = new AtomUIMenuItem { Header = "File" };
|
|
parentItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(parentItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
var popup = FindPopup(parentItem);
|
|
parentItem.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
|
|
menu.IsPopupPinnedOpen = false;
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeTrue();
|
|
parentItem.IsSubMenuOpen.ShouldBeTrue();
|
|
parentItem.IsPopupPinnedOpen.ShouldBeFalse();
|
|
popup.IsPopupPinnedOpen.ShouldBeFalse();
|
|
popup.IsOpen.ShouldBeTrue();
|
|
|
|
menu.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
menu.IsOpen.ShouldBeFalse();
|
|
parentItem.IsSubMenuOpen.ShouldBeFalse();
|
|
popup.IsOpen.ShouldBeFalse();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Popup_Pin_Releases_Removed_Item_And_Transfers_To_The_Next_Submenu()
|
|
{
|
|
var firstItem = new AtomUIMenuItem { Header = "File" };
|
|
firstItem.Items.Add(new AtomUIMenuItem { Header = "Open" });
|
|
var secondItem = new AtomUIMenuItem { Header = "Edit" };
|
|
secondItem.Items.Add(new AtomUIMenuItem { Header = "Copy" });
|
|
var menu = new AtomUIMenu
|
|
{
|
|
IsMotionEnabled = false,
|
|
Width = 320
|
|
};
|
|
menu.Items.Add(firstItem);
|
|
menu.Items.Add(secondItem);
|
|
var window = ShowInWindow(menu);
|
|
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
var firstPopup = FindPopup(firstItem);
|
|
firstPopup.IsOpen.ShouldBeTrue();
|
|
|
|
menu.Items.Remove(firstItem);
|
|
Dispatcher.UIThread.RunJobs();
|
|
window.UpdateLayout();
|
|
|
|
firstItem.IsPopupPinnedOpen.ShouldBeFalse();
|
|
firstItem.IsSubMenuOpen.ShouldBeFalse();
|
|
firstPopup.IsPopupPinnedOpen.ShouldBeFalse();
|
|
firstPopup.IsOpen.ShouldBeFalse();
|
|
secondItem.IsPopupPinnedOpen.ShouldBeTrue();
|
|
secondItem.IsSubMenuOpen.ShouldBeTrue();
|
|
FindPopup(secondItem).IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Pinned_Flyout_Preserves_One_Declared_Branch_And_Transfers_Pin_On_Navigation()
|
|
{
|
|
var first = new AtomUIMenuItem { Header = "First", IsSubMenuOpen = true };
|
|
first.Items.Add(new AtomUIMenuItem { Header = "Leaf" });
|
|
var second = new AtomUIMenuItem { Header = "Second" };
|
|
second.Items.Add(new AtomUIMenuItem { Header = "Leaf" });
|
|
var flyout = new MenuFlyout { IsMotionEnabled = false, Items = { first, second } };
|
|
var button = new SplitButton { Content = "Menu", Flyout = flyout, IsMotionEnabled = false };
|
|
var window = ShowInWindow(button);
|
|
try
|
|
{
|
|
button.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
window.UpdateLayout();
|
|
Dispatcher.UIThread.RunJobs();
|
|
first.IsPopupPinnedOpen.ShouldBeTrue();
|
|
first.IsSubMenuOpen.ShouldBeTrue();
|
|
second.IsPopupPinnedOpen.ShouldBeFalse();
|
|
second.IsSubMenuOpen.ShouldBeFalse();
|
|
|
|
second.Open();
|
|
Dispatcher.UIThread.RunJobs();
|
|
first.IsSubMenuOpen.ShouldBeFalse();
|
|
first.IsPopupPinnedOpen.ShouldBeFalse();
|
|
second.IsSubMenuOpen.ShouldBeTrue();
|
|
second.IsPopupPinnedOpen.ShouldBeTrue();
|
|
flyout.IsOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
button.IsPopupPinnedOpen = false;
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Top_Level_Pinned_Menu_Transfers_Pin_Before_Closing_Previous_Submenu()
|
|
{
|
|
var first = new AtomUIMenuItem { Header = "First", Items = { new AtomUIMenuItem { Header = "Leaf" } } };
|
|
var second = new AtomUIMenuItem { Header = "Second", Items = { new AtomUIMenuItem { Header = "Leaf" } } };
|
|
var menu = new AtomUIMenu { IsMotionEnabled = false, Width = 320, Items = { first, second } };
|
|
var window = ShowInWindow(menu);
|
|
try
|
|
{
|
|
menu.IsPopupPinnedOpen = true;
|
|
Dispatcher.UIThread.RunJobs();
|
|
second.Open();
|
|
Dispatcher.UIThread.RunJobs();
|
|
first.IsSubMenuOpen.ShouldBeFalse();
|
|
first.IsPopupPinnedOpen.ShouldBeFalse();
|
|
second.IsSubMenuOpen.ShouldBeTrue();
|
|
second.IsPopupPinnedOpen.ShouldBeTrue();
|
|
}
|
|
finally
|
|
{
|
|
menu.IsPopupPinnedOpen = false;
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
|
|
private static AtomUIPopup FindPopup(Control root)
|
|
{
|
|
return root.GetVisualDescendants()
|
|
.OfType<AtomUIPopup>()
|
|
.Single(item => item.Name == "PART_Popup");
|
|
}
|
|
|
|
private static AtomUIWindow ShowInWindow(Control content)
|
|
{
|
|
var overlayPanel = new ScopeAwareOverlayLayerPanel
|
|
{
|
|
Width = 420,
|
|
Height = 240
|
|
};
|
|
overlayPanel.Children.Add(content);
|
|
var visualLayerManager = new VisualLayerManager
|
|
{
|
|
Child = overlayPanel
|
|
};
|
|
var window = new AtomUIWindow
|
|
{
|
|
Width = 420,
|
|
Height = 240,
|
|
Content = visualLayerManager
|
|
};
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
return window;
|
|
}
|
|
}
|