Files

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;
}
}