From d144398a6dd0e89e9b53c04d17f23b246574a70e Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Fri, 13 Mar 2026 16:05:03 -0400 Subject: [PATCH 1/6] Fix the 'Set Double Sided' action in the Editor sample. It couldn't be enabled in the contextual menu due to a missing override. --- Samples~/Editor/CustomAction.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Samples~/Editor/CustomAction.cs b/Samples~/Editor/CustomAction.cs index e976f1317..330afeb01 100644 --- a/Samples~/Editor/CustomAction.cs +++ b/Samples~/Editor/CustomAction.cs @@ -38,9 +38,11 @@ public class MakeFacesDoubleSided : MenuAction /// public override bool enabled { - get { return MeshSelection.selectedFaceCount > 0; } + get { return base.enabled && MeshSelection.selectedFaceCount > 0; } } + protected override bool hasFileMenuEntry => false; + /// /// This action is applicable in Face selection modes. /// From 28882385cb0ace9f1bdc6978233c630df4823f63 Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Fri, 13 Mar 2026 16:26:14 -0400 Subject: [PATCH 2/6] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5186fc1..8934b4b8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - [UUM-133861] Fixed "Look rotation viewing vector is zero" log being spammed when holding shift while using a create tool such as Create Sprite. +- [UUM-133530] Fixed the `Set Double Sided` custom action in the Editor Sample, which was previously remaining disabled. - Fixed warnings related to obsolete API calls with Unity 6.4 and onwards. ## [6.0.9] - 2026-01-30 From 9e40c045ec377521b41b460c326999de7f89384b Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Tue, 17 Mar 2026 11:30:49 -0400 Subject: [PATCH 3/6] Ensure to pass the current status of a MenuAction when there is no options, nor fileMenuEntry associated to it --- Editor/EditorCore/ProBuilderToolsContexts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/EditorCore/ProBuilderToolsContexts.cs b/Editor/EditorCore/ProBuilderToolsContexts.cs index 99cfcc3c0..621ac517f 100644 --- a/Editor/EditorCore/ProBuilderToolsContexts.cs +++ b/Editor/EditorCore/ProBuilderToolsContexts.cs @@ -110,7 +110,7 @@ public override void PopulateMenu(DropdownMenu menu) menu.AppendAction(title, _ => EditorAction.Start(new MenuActionSettings(action, HasPreview(action))), GetStatus(action)); } else - menu.AppendAction(GetMenuTitle(action, title), _ => action.PerformAction()); + menu.AppendAction(GetMenuTitle(action, title), _ => action.PerformAction(), GetStatus(action)); } } From 1e9ca3e247eaab6a02113b551a9878f91b563e6c Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Tue, 17 Mar 2026 15:24:08 -0400 Subject: [PATCH 4/6] Add tests to cover some cases of the contextual menu --- Tests/Editor/Actions/ContextualMenuTests.cs | 192 ++++++++++++++++++ .../Actions/ContextualMenuTests.cs.meta | 2 + 2 files changed, 194 insertions(+) create mode 100644 Tests/Editor/Actions/ContextualMenuTests.cs create mode 100644 Tests/Editor/Actions/ContextualMenuTests.cs.meta diff --git a/Tests/Editor/Actions/ContextualMenuTests.cs b/Tests/Editor/Actions/ContextualMenuTests.cs new file mode 100644 index 000000000..162b773b7 --- /dev/null +++ b/Tests/Editor/Actions/ContextualMenuTests.cs @@ -0,0 +1,192 @@ +using NUnit.Framework; +using UnityEditor; +using UnityEditor.EditorTools; +using UnityEditor.ProBuilder; +using UnityEngine; +using UnityEngine.ProBuilder; +using UnityEngine.UIElements; + + +/// +/// Test the construction of the contextual menu in the Scene View. +/// It doesn't cover the cases where a MenuAction has a file menu entry. +/// +[ProBuilderMenuAction] +public class ConfigurableMenuAction : MenuAction +{ + internal const string actionName = "Action Without File Menu Entry"; + internal static bool userHasFileMenuEntry { get; set; } + internal static SelectMode userSelectMode { get; set; } + internal static bool userEnabled { get; set; } + + public override ToolbarGroup group + { + get { return ToolbarGroup.Geometry; } + } + + public override Texture2D icon => null; + + public override string iconPath => string.Empty; + + public override TooltipContent tooltip => new TooltipContent( + actionName, + @"This action should not have a file menu entry." + ); + + public ConfigurableMenuAction() + { + } + + protected override ActionResult PerformActionImplementation() + { + return ActionResult.Success; + } + + public override SelectMode validSelectModes => userSelectMode; + public override bool enabled => userEnabled; + protected internal override bool hasFileMenuEntry => userHasFileMenuEntry; +} + +public class ContextualMenuTests +{ + // Cases: + // - MenuAction with hasFileMenuEntry = false should show in the Contextual Menu. + // - MenuAction with hasFileMenuEntry = true should not show in the File Menu. + // - MenuAction with validSelectModes not matching the current selection should be disabled. + // - MenuAction with validSelectModes matching the current selection should be enabled. + // - MenuAction with enabled = false should be disabled in the Contextual Menu. + // - MenuAction with enabled = true should be enabled in the Contextual Menu. + + ProBuilderMesh m_PBMesh; + + [SetUp] + public void Setup() + { + m_PBMesh = ShapeFactory.Instantiate(typeof(UnityEngine.ProBuilder.Shapes.Plane)); + } + + public void TearDown() + { + if (m_PBMesh) + Object.DestroyImmediate(m_PBMesh.gameObject); + } + + [Test] + [TestCase(true, ExpectedResult = false)] + [TestCase(false, ExpectedResult = true)] + public bool MenuActionWithoutMenuItem_hasFileMenuEntry(bool hasFileMenuEntry) + { + MeshSelection.SetSelection(m_PBMesh.gameObject); + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ToolManager.SetActiveContext(); + Tools.current = Tool.Move; + ProBuilderEditor.selectMode = SelectMode.Face; + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ConfigurableMenuAction.userHasFileMenuEntry = hasFileMenuEntry; + ConfigurableMenuAction.userSelectMode = SelectMode.Any; + ConfigurableMenuAction.userEnabled = true; + + DropdownMenu menu = new DropdownMenu(); + PositionToolContext ctx = Resources.FindObjectsOfTypeAll()?[0]; + Assume.That(ctx, Is.Not.Null); + + ctx.PopulateMenu(menu); + menu.PrepareForDisplay(null); + DropdownMenuAction foundInMenu = null; + foreach (var t in menu.MenuItems()) + { + if (t is not DropdownMenuAction menuAction) + continue; + + if (menuAction.name == ConfigurableMenuAction.actionName) + { + foundInMenu = menuAction; + break; + } + } + + Assert.That(foundInMenu, Is.Not.Null, "MenuAction should be present in the Contextual Menu regardless of hasFileMenuEntry value."); + return (foundInMenu.status == DropdownMenuAction.Status.Normal); + } + + [Test] + [TestCase(SelectMode.Edge, ExpectedResult = false)] + [TestCase(SelectMode.Face, ExpectedResult = true)] + [TestCase(SelectMode.Vertex, ExpectedResult = false)] + public bool MenuAction_SelectModeSetToFace_EnabledOnlyForFaceSelection(SelectMode mode) + { + MeshSelection.SetSelection(m_PBMesh.gameObject); + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ToolManager.SetActiveContext(); + Tools.current = Tool.Move; + ProBuilderEditor.selectMode = mode; + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ConfigurableMenuAction.userHasFileMenuEntry = false; + ConfigurableMenuAction.userSelectMode = SelectMode.Face; + ConfigurableMenuAction.userEnabled = true; + + DropdownMenu menu = new DropdownMenu(); + PositionToolContext ctx = Resources.FindObjectsOfTypeAll()?[0]; + Assume.That(ctx, Is.Not.Null); + + ctx.PopulateMenu(menu); + menu.PrepareForDisplay(null); + DropdownMenuAction foundInMenu = null; + foreach (var t in menu.MenuItems()) + { + if (t is not DropdownMenuAction menuAction) + continue; + + if (menuAction.name == ConfigurableMenuAction.actionName) + { + foundInMenu = menuAction; + break; + } + } + + // MenuAction is expected to be present in the menu only when the mode matches. + return (foundInMenu != null); + } + + [Test] + [TestCase(true, ExpectedResult = true)] + [TestCase(false, ExpectedResult = false)] + public bool MenuAction_enabledPropertyIsFollowedByMenu(bool enabled) + { + MeshSelection.SetSelection(m_PBMesh.gameObject); + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ToolManager.SetActiveContext(); + Tools.current = Tool.Move; + ProBuilderEditor.selectMode = SelectMode.Face; + ActiveEditorTracker.sharedTracker.ForceRebuild(); + + ConfigurableMenuAction.userHasFileMenuEntry = false; + ConfigurableMenuAction.userSelectMode = SelectMode.Face; + ConfigurableMenuAction.userEnabled = enabled; + + DropdownMenu menu = new DropdownMenu(); + PositionToolContext ctx = Resources.FindObjectsOfTypeAll()?[0]; + Assume.That(ctx, Is.Not.Null); + + ctx.PopulateMenu(menu); + menu.PrepareForDisplay(null); + DropdownMenuAction foundInMenu = null; + foreach (var t in menu.MenuItems()) + { + if (t is not DropdownMenuAction menuAction) + continue; + + if (menuAction.name == ConfigurableMenuAction.actionName) + { + foundInMenu = menuAction; + break; + } + } + return (foundInMenu.status == DropdownMenuAction.Status.Normal); + } +} diff --git a/Tests/Editor/Actions/ContextualMenuTests.cs.meta b/Tests/Editor/Actions/ContextualMenuTests.cs.meta new file mode 100644 index 000000000..46a006097 --- /dev/null +++ b/Tests/Editor/Actions/ContextualMenuTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c2167c99ac2c1f9488142fe2aa87d872 \ No newline at end of file From 92c90fb82d734d13fc3a2896eabb4e18068abe72 Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Tue, 17 Mar 2026 15:29:12 -0400 Subject: [PATCH 5/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index acaf593c1..d935dfd4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [UUM-133861] Fixed "Look rotation viewing vector is zero" log being spammed when holding shift while using a create tool such as Create Sprite. - [UUM-133530] Fixed the `Set Double Sided` custom action in the Editor Sample, which was previously remaining disabled. +- [UUM-133530] Ensured that the context menu respects the value of `MenuAction.enabled`. - [UUM-133526] Material Editor: fixed a warning (`GUI Error: Invalid GUILayout state in MaterialEditor view.`) that was thrown when deleting an extra material slot. - Fixed warnings related to obsolete API calls with Unity 6.4 and onwards. From 7063df012bf904b37cb5816011f843b130c81511 Mon Sep 17 00:00:00 2001 From: Thomas Tu Date: Wed, 18 Mar 2026 10:26:25 -0400 Subject: [PATCH 6/6] Clean up --- Tests/Editor/Actions/ContextualMenuTests.cs | 66 +++++++++------------ 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/Tests/Editor/Actions/ContextualMenuTests.cs b/Tests/Editor/Actions/ContextualMenuTests.cs index 162b773b7..ae28a35c8 100644 --- a/Tests/Editor/Actions/ContextualMenuTests.cs +++ b/Tests/Editor/Actions/ContextualMenuTests.cs @@ -6,56 +6,47 @@ using UnityEngine.ProBuilder; using UnityEngine.UIElements; - /// /// Test the construction of the contextual menu in the Scene View. /// It doesn't cover the cases where a MenuAction has a file menu entry. /// -[ProBuilderMenuAction] -public class ConfigurableMenuAction : MenuAction +public class ContextualMenuTests { - internal const string actionName = "Action Without File Menu Entry"; - internal static bool userHasFileMenuEntry { get; set; } - internal static SelectMode userSelectMode { get; set; } - internal static bool userEnabled { get; set; } - - public override ToolbarGroup group + [ProBuilderMenuAction] + public class ConfigurableMenuAction : MenuAction { - get { return ToolbarGroup.Geometry; } - } + internal const string actionName = "Action Without File Menu Entry"; + internal static bool userHasFileMenuEntry { get; set; } + internal static SelectMode userSelectMode { get; set; } + internal static bool userEnabled { get; set; } - public override Texture2D icon => null; + public override ToolbarGroup group + { + get { return ToolbarGroup.Geometry; } + } - public override string iconPath => string.Empty; + public override Texture2D icon => null; - public override TooltipContent tooltip => new TooltipContent( - actionName, - @"This action should not have a file menu entry." - ); + public override string iconPath => string.Empty; - public ConfigurableMenuAction() - { - } + public override TooltipContent tooltip => new TooltipContent( + actionName, + @"This action should not have a file menu entry." + ); - protected override ActionResult PerformActionImplementation() - { - return ActionResult.Success; - } + public ConfigurableMenuAction() + { + } - public override SelectMode validSelectModes => userSelectMode; - public override bool enabled => userEnabled; - protected internal override bool hasFileMenuEntry => userHasFileMenuEntry; -} + protected override ActionResult PerformActionImplementation() + { + return ActionResult.Success; + } -public class ContextualMenuTests -{ - // Cases: - // - MenuAction with hasFileMenuEntry = false should show in the Contextual Menu. - // - MenuAction with hasFileMenuEntry = true should not show in the File Menu. - // - MenuAction with validSelectModes not matching the current selection should be disabled. - // - MenuAction with validSelectModes matching the current selection should be enabled. - // - MenuAction with enabled = false should be disabled in the Contextual Menu. - // - MenuAction with enabled = true should be enabled in the Contextual Menu. + public override SelectMode validSelectModes => userSelectMode; + public override bool enabled => userEnabled; + protected internal override bool hasFileMenuEntry => userHasFileMenuEntry; + } ProBuilderMesh m_PBMesh; @@ -65,6 +56,7 @@ public void Setup() m_PBMesh = ShapeFactory.Instantiate(typeof(UnityEngine.ProBuilder.Shapes.Plane)); } + [TearDown] public void TearDown() { if (m_PBMesh)