diff --git a/CHANGELOG.md b/CHANGELOG.md index 031560715..163731815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,12 @@ 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. +<<<<<<< bugfix/sample-menuaction-disabled +- [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-133531] Fixed component icons in Light theme. +>>>>>>> master - [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. diff --git a/Editor/EditorCore/ProBuilderToolsContexts.cs b/Editor/EditorCore/ProBuilderToolsContexts.cs index 1f7d5b34d..49ab65d23 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)); } } 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. /// diff --git a/Tests/Editor/Actions/ContextualMenuTests.cs b/Tests/Editor/Actions/ContextualMenuTests.cs new file mode 100644 index 000000000..ae28a35c8 --- /dev/null +++ b/Tests/Editor/Actions/ContextualMenuTests.cs @@ -0,0 +1,184 @@ +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. +/// +public class ContextualMenuTests +{ + [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; + } + + ProBuilderMesh m_PBMesh; + + [SetUp] + public void Setup() + { + m_PBMesh = ShapeFactory.Instantiate(typeof(UnityEngine.ProBuilder.Shapes.Plane)); + } + + [TearDown] + 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