using System.Reflection; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Threading; using Shouldly; using Xunit; using AtomUINavMenu = AtomUI.Desktop.Controls.NavMenu; using AtomUIWindow = AtomUI.Desktop.Controls.Window; namespace AtomUI.Desktop.Controls.Tests.NavMenu; public class NavMenuPinnedOpenTests { static NavMenuPinnedOpenTests() { AvaloniaTestApp.EnsureInitialized(); } [Fact] public void Popup_Pin_Opens_First_Expandable_Item_And_Rejects_Close_Requests() { var parent = new NavMenuNode { Header = "Components" }; parent.Children.Add(new NavMenuNode { Header = "Button" }); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(parent); var window = ShowInWindow(menu); try { var parentContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); parentContainer.IsPopupPinnedOpen.ShouldBeTrue(); parentContainer.IsSubMenuOpen.ShouldBeTrue(); parentContainer.Popup.ShouldNotBeNull(); parentContainer.Popup.IsPopupPinnedOpen.ShouldBeTrue(); parentContainer.Popup.IsOpen.ShouldBeTrue(); menu.Close(); parentContainer.Close(); parentContainer.SetCurrentValue(NavMenuItem.IsSubMenuOpenProperty, false); Dispatcher.UIThread.RunJobs(); parentContainer.IsSubMenuOpen.ShouldBeTrue(); parentContainer.Popup.IsOpen.ShouldBeTrue(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } [Fact] public void Popup_Pin_Closes_For_Detach_And_Reopens_After_Reattach() { var parent = new NavMenuNode { Header = "Components" }; parent.Children.Add(new NavMenuNode { Header = "Button" }); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(parent); var window = ShowInWindow(menu); try { var parentContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); var popup = parentContainer.Popup.ShouldNotBeNull(); var windowContent = window.Content; window.Content = null; Dispatcher.UIThread.RunJobs(); parentContainer.IsPopupPinnedOpen.ShouldBeFalse(); parentContainer.IsSubMenuOpen.ShouldBeFalse(); popup.IsPopupPinnedOpen.ShouldBeFalse(); popup.IsOpen.ShouldBeFalse(); window.Content = windowContent; Dispatcher.UIThread.RunJobs(); parentContainer.IsPopupPinnedOpen.ShouldBeTrue(); parentContainer.IsSubMenuOpen.ShouldBeTrue(); popup.IsOpen.ShouldBeTrue(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } [Fact] public void Popup_Pin_Releases_Removed_Container_And_Transfers_To_Next_Item() { var first = new NavMenuNode { Header = "Components" }; first.Children.Add(new NavMenuNode { Header = "Button" }); var second = new NavMenuNode { Header = "Resources" }; second.Children.Add(new NavMenuNode { Header = "Icons" }); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(first); menu.Items.Add(second); var window = ShowInWindow(menu); try { var firstContainer = menu.ContainerFromItem(first).ShouldBeOfType(); menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); var firstPopup = firstContainer.Popup.ShouldNotBeNull(); menu.Items.Remove(first); Dispatcher.UIThread.RunJobs(); window.UpdateLayout(); firstContainer.OwnerMenu.ShouldBeNull(); firstContainer.IsPopupPinnedOpen.ShouldBeFalse(); firstPopup.IsPopupPinnedOpen.ShouldBeFalse(); firstPopup.IsOpen.ShouldBeFalse(); var secondContainer = menu.ContainerFromItem(second).ShouldBeOfType(); secondContainer.IsPopupPinnedOpen.ShouldBeTrue(); secondContainer.IsSubMenuOpen.ShouldBeTrue(); secondContainer.Popup.ShouldNotBeNull(); secondContainer.Popup.IsOpen.ShouldBeTrue(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } [Fact] public void Popup_Pin_Extends_To_The_Active_Nested_Submenu_Chain() { var child = new NavMenuNode { Header = "Inputs" }; child.Children.Add(new NavMenuNode { Header = "Button" }); var parent = new NavMenuNode { Header = "Components" }; parent.Children.Add(child); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(parent); var window = ShowInWindow(menu); try { menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); window.UpdateLayout(); var parentContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); var childContainer = parentContainer.ContainerFromItem(child).ShouldBeOfType(); childContainer.Open(); Dispatcher.UIThread.RunJobs(); parentContainer.IsPopupPinnedOpen.ShouldBeTrue(); childContainer.IsPopupPinnedOpen.ShouldBeTrue(); childContainer.Popup.ShouldNotBeNull(); childContainer.Popup.IsPopupPinnedOpen.ShouldBeTrue(); childContainer.Popup.IsOpen.ShouldBeTrue(); childContainer.Close(); childContainer.SetCurrentValue(NavMenuItem.IsSubMenuOpenProperty, false); Dispatcher.UIThread.RunJobs(); childContainer.IsSubMenuOpen.ShouldBeTrue(); childContainer.Popup.IsOpen.ShouldBeTrue(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } [Fact] public void Popup_Pin_Closes_For_Mode_Replacement_And_Reopens_In_Popup_Mode() { var parent = new NavMenuNode { Header = "Components" }; parent.Children.Add(new NavMenuNode { Header = "Button" }); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(parent); var window = ShowInWindow(menu); try { var parentContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); var popup = parentContainer.Popup.ShouldNotBeNull(); menu.Mode = NavMenuMode.Inline; Dispatcher.UIThread.RunJobs(); menu.IsPopupPinnedOpen.ShouldBeTrue(); parentContainer.IsPopupPinnedOpen.ShouldBeFalse(); parentContainer.IsSubMenuOpen.ShouldBeFalse(); popup.IsPopupPinnedOpen.ShouldBeFalse(); popup.IsOpen.ShouldBeFalse(); menu.Mode = NavMenuMode.Vertical; Dispatcher.UIThread.RunJobs(); var reopenedContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); reopenedContainer.IsPopupPinnedOpen.ShouldBeTrue(); reopenedContainer.IsSubMenuOpen.ShouldBeTrue(); reopenedContainer.Popup.ShouldNotBeNull(); reopenedContainer.Popup.IsOpen.ShouldBeTrue(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } [Fact] public void Popup_Unpin_Leaves_Submenu_Open_And_Restores_Normal_Close() { var parent = new NavMenuNode { Header = "Components" }; parent.Children.Add(new NavMenuNode { Header = "Button" }); var menu = new AtomUINavMenu { Mode = NavMenuMode.Vertical, IsMotionEnabled = false, ShouldUseOverlayPopup = true }; menu.Items.Add(parent); var window = ShowInWindow(menu); try { var parentContainer = menu.ContainerFromItem(parent).ShouldBeOfType(); menu.IsPopupPinnedOpen = true; Dispatcher.UIThread.RunJobs(); var popup = parentContainer.Popup.ShouldNotBeNull(); menu.IsPopupPinnedOpen = false; Dispatcher.UIThread.RunJobs(); parentContainer.IsPopupPinnedOpen.ShouldBeFalse(); popup.IsPopupPinnedOpen.ShouldBeFalse(); parentContainer.IsSubMenuOpen.ShouldBeTrue(); popup.IsOpen.ShouldBeTrue(); menu.Close(); Dispatcher.UIThread.RunJobs(); parentContainer.IsSubMenuOpen.ShouldBeFalse(); popup.IsOpen.ShouldBeFalse(); } finally { window.Close(); Dispatcher.UIThread.RunJobs(); } } private static AtomUIWindow ShowInWindow(Control content) { var visualLayerManager = new VisualLayerManager { Child = content }; var property = typeof(VisualLayerManager).GetProperty( "EnablePopupOverlayLayer", BindingFlags.Instance | BindingFlags.NonPublic); property.ShouldNotBeNull(); property.SetValue(visualLayerManager, true); var window = new AtomUIWindow { Width = 420, Height = 300, Content = visualLayerManager }; window.Show(); Dispatcher.UIThread.RunJobs(); return window; } }