From 44db262a61cdf2f7bd78f8c1781a56a65f588046 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 13 Dec 2023 22:57:12 +0300 Subject: [PATCH 1/3] Change `Menu.Children` and `Items` to reflect on layout order --- osu.Framework/Graphics/UserInterface/Menu.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Graphics/UserInterface/Menu.cs b/osu.Framework/Graphics/UserInterface/Menu.cs index fb6502442c..6413ce946e 100644 --- a/osu.Framework/Graphics/UserInterface/Menu.cs +++ b/osu.Framework/Graphics/UserInterface/Menu.cs @@ -62,7 +62,7 @@ public abstract partial class Menu : CompositeDrawable, IStateful /// /// Gets the item representations contained by this . /// - protected internal IReadOnlyList Children => itemsFlow.Children; + protected internal IEnumerable Children => itemsFlow.Children.OrderBy(c => itemsFlow.GetLayoutPosition(c)); protected readonly Direction Direction; @@ -142,9 +142,9 @@ protected override void LoadComplete() /// /// Gets or sets the s contained within this . /// - public IReadOnlyList Items + public IEnumerable Items { - get => itemsFlow.Select(r => r.Item).ToList(); + get => Children.Select(r => r.Item); set { Clear(); From 8e77426859ed40aff1b055993d9d4a9da1d7d63d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 13 Dec 2023 23:30:27 +0300 Subject: [PATCH 2/3] Fix `Dropdown.Items` relying on dictionary order --- .../Graphics/UserInterface/Dropdown.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Framework/Graphics/UserInterface/Dropdown.cs b/osu.Framework/Graphics/UserInterface/Dropdown.cs index 830bcba12f..18baea92bb 100644 --- a/osu.Framework/Graphics/UserInterface/Dropdown.cs +++ b/osu.Framework/Graphics/UserInterface/Dropdown.cs @@ -60,12 +60,14 @@ public bool AllowNonContiguousMatching protected IEnumerable> MenuItems => itemMap.Values; + private readonly List orderedItems = new List(); + /// /// Enumerate all values in the dropdown. /// public IEnumerable Items { - get => MenuItems.Select(i => i.Value); + get => orderedItems; set { if (boundItemSource != null) @@ -127,7 +129,7 @@ private void addDropdownItem(T value, int? position = null) if (itemMap.ContainsKey(value)) throw new ArgumentException($"The item {value} already exists in this {nameof(Dropdown)}."); - var item = new DropdownMenuItem(value, () => + var menuItem = new DropdownMenuItem(value, () => { if (!Current.Disabled) Current.Value = value; @@ -137,14 +139,20 @@ private void addDropdownItem(T value, int? position = null) // inheritors expect that `virtual GenerateItemText` is only called when this dropdown's BDL has run to completion. if (LoadState >= LoadState.Ready) - item.Text.Value = GenerateItemText(value); + menuItem.Text.Value = GenerateItemText(value); if (position != null) - Menu.Insert(position.Value, item); + { + Menu.Insert(position.Value, menuItem); + orderedItems.Insert(position.Value, value); + } else - Menu.Add(item); + { + Menu.Add(menuItem); + orderedItems.Add(value); + } - itemMap[value] = item; + itemMap[value] = menuItem; } /// @@ -169,6 +177,7 @@ private bool removeDropdownItem(T value) Menu.Remove(item); itemMap.Remove(value); + orderedItems.Remove(value); return true; } @@ -405,7 +414,7 @@ private void ensureItemSelectionIsValid() { if (Current.Value == null || !itemMap.ContainsKey(Current.Value)) { - Current.Value = itemMap.Keys.FirstOrDefault(); + Current.Value = orderedItems.FirstOrDefault(); return; } @@ -442,6 +451,7 @@ public void ClearItems() private void clearItems() { itemMap.Clear(); + orderedItems.Clear(); Menu.Clear(); } From 26dcd4828d159fe80af9531ff2a65256068a8149 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 13 Dec 2023 23:20:22 +0300 Subject: [PATCH 3/3] Update existing usages --- .../Visual/UserInterface/TestSceneClosableMenu.cs | 2 +- .../Visual/UserInterface/TestSceneContextMenu.cs | 2 +- osu.Framework.Tests/Visual/UserInterface/TestSceneDropdown.cs | 4 ++-- .../Visual/UserInterface/TestSceneNestedMenus.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneClosableMenu.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneClosableMenu.cs index 319351f1bc..b38f78204a 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneClosableMenu.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneClosableMenu.cs @@ -118,7 +118,7 @@ public void TestMenuBlocksInputUnderneathIt() bool itemClicked = false; bool actionReceived = false; - AddStep("set item action", () => Menus.GetSubMenu(0).Items[0].Items[0].Action.Value = () => itemClicked = true); + AddStep("set item action", () => Menus.GetSubMenu(0).Items.ElementAt(0).Items[0].Action.Value = () => itemClicked = true); AddStep("add mouse handler", () => Add(new MouseHandlingLayer { Action = () => actionReceived = true, diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneContextMenu.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneContextMenu.cs index 20bd8ac97a..8cc5a826ea 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneContextMenu.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneContextMenu.cs @@ -320,7 +320,7 @@ private void assertMenuOnScreen(bool expected) => AddAssert($"menu {(expected ? return result == expected; }); - private void assertMenuItems(int expectedCount) => AddAssert($"menu contains {expectedCount} item(s)", () => contextMenuContainer.CurrentMenu.Items.Count == expectedCount); + private void assertMenuItems(int expectedCount) => AddAssert($"menu contains {expectedCount} item(s)", () => contextMenuContainer.CurrentMenu.Items.Count() == expectedCount); private partial class BoxWithContextMenu : Box, IHasContextMenu { diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneDropdown.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneDropdown.cs index 1c7d75a780..a928d62991 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneDropdown.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneDropdown.cs @@ -47,7 +47,7 @@ public void TestSelectByUserInteraction() AddStep("click item 2", () => { - InputManager.MoveMouseTo(testDropdown.Menu.Children[2]); + InputManager.MoveMouseTo(testDropdown.Menu.Children.ElementAt(2)); InputManager.Click(MouseButton.Left); }); @@ -176,7 +176,7 @@ public void TestReplaceItems() AddStep("click item 4", () => { - InputManager.MoveMouseTo(testDropdown.Menu.Children[4]); + InputManager.MoveMouseTo(testDropdown.Menu.Children.ElementAt(4)); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneNestedMenus.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneNestedMenus.cs index f310e809cf..761b80f51c 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneNestedMenus.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneNestedMenus.cs @@ -181,7 +181,7 @@ public void TestHoverChange() IReadOnlyList currentItems = null; AddStep("Click item", () => { ClickItem(0, 0); }); - AddStep("Get items", () => { currentItems = Menus.GetSubMenu(1).Items; }); + AddStep("Get items", () => { currentItems = Menus.GetSubMenu(1).Items.ToList(); }); AddAssert("Check open", () => Menus.GetSubMenu(1).State == MenuState.Open); AddStep("Hover item", () => InputManager.MoveMouseTo(Menus.GetSubStructure(0).GetMenuItems()[1]));