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