diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.cpp new file mode 100644 index 0000000000..ab8108e064 --- /dev/null +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +#include +#include + +void ContextMenuBottomHandler::Setup() +{ + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); +} + +void ContextMenuBottomHandler::Teardown() +{ + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); +} + +int ContextMenuBottomHandler::GetMenuPosition() const +{ + return aznumeric_cast(AzToolsFramework::EditorContextMenuOrdering::BOTTOM); +} + +void ContextMenuBottomHandler::PopulateEditorGlobalContextMenu( + QMenu* menu, [[maybe_unused]] const AZ::Vector2& point, [[maybe_unused]] int flags) +{ + AzToolsFramework::EntityIdList selected; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + selected, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + + QAction* action = nullptr; + + if (selected.size() > 0) + { + action = menu->addAction(QObject::tr("Open pinned Inspector")); + QObject::connect( + action, &QAction::triggered, action, + [selected] + { + AzToolsFramework::EntityIdSet pinnedEntities(selected.begin(), selected.end()); + AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequests::OpenPinnedInspector, pinnedEntities); + } + ); + + menu->addSeparator(); + } +} diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.h new file mode 100644 index 0000000000..58f43b9d18 --- /dev/null +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ContextMenuHandlers.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +class ContextMenuBottomHandler : private AzToolsFramework::EditorContextMenuBus::Handler +{ +public: + void Setup(); + void Teardown(); + +private: + // EditorContextMenu overrides ... + void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; + int GetMenuPosition() const override; +}; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index b88c7f8d60..23fd128bd2 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -45,17 +45,17 @@ #include #include #include -#include #include #include +#include #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -212,6 +212,8 @@ void SandboxIntegrationManager::Setup() AZ_Assert(m_readOnlyEntityPublicInterface, "SandboxIntegrationManager requires an ReadOnlyEntityPublicInterface instance to be present on Setup()."); AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Handler::BusConnect(); + + m_contextMenuBottomHandler.Setup(); } void SandboxIntegrationManager::SaveSlice(const bool& QuickPushToFirstLevel) @@ -395,6 +397,8 @@ void SandboxIntegrationManager::GetEntitiesInSlices( void SandboxIntegrationManager::Teardown() { + m_contextMenuBottomHandler.Teardown(); + AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Handler::BusDisconnect(); AzFramework::DisplayContextRequestBus::Handler::BusDisconnect(); AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect(); @@ -651,12 +655,14 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con if (selected.size() == 0) { action = menu->addAction(QObject::tr("Create entity")); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_N)); QObject::connect( action, &QAction::triggered, action, [this] { ContextMenu_NewEntity(); - }); + } + ); } // when a single entity is selected, entity is created as its child else if (selected.size() == 1) @@ -667,6 +673,7 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con if (!prefabSystemEnabled || (containerEntityInterface && containerEntityInterface->IsContainerOpen(selectedEntityId) && !selectedEntityIsReadOnly)) { action = menu->addAction(QObject::tr("Create entity")); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_N)); QObject::connect( action, &QAction::triggered, action, [selectedEntityId] @@ -694,33 +701,30 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con AzToolsFramework::SetupAddToLayerMenu(menu, flattenedSelection, [this] { return ContextMenu_NewLayer(); }); SetupSliceContextMenu(menu); - } - if (!selected.empty()) - { - // Don't allow duplication if any of the selected entities are direct desendants of a read-only entity - bool selectionContainsDescendantOfReadOnlyEntity = false; - for (const auto& entityId : selected) + if (!selected.empty()) { - AZ::EntityId parentEntityId; - AZ::TransformBus::EventResult(parentEntityId, entityId, &AZ::TransformBus::Events::GetParentId); - - if (parentEntityId.IsValid() && m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId)) + // Don't allow duplication if any of the selected entities are direct descendants of a read-only entity + bool selectionContainsDescendantOfReadOnlyEntity = false; + for (const auto& entityId : selected) { - selectionContainsDescendantOfReadOnlyEntity = true; - break; + AZ::EntityId parentEntityId; + AZ::TransformBus::EventResult(parentEntityId, entityId, &AZ::TransformBus::Events::GetParentId); + + if (parentEntityId.IsValid() && m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId)) + { + selectionContainsDescendantOfReadOnlyEntity = true; + break; + } } - } - if (!selectionContainsDescendantOfReadOnlyEntity) - { - action = menu->addAction(QObject::tr("Duplicate")); - QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); }); + if (!selectionContainsDescendantOfReadOnlyEntity) + { + action = menu->addAction(QObject::tr("Duplicate")); + QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); }); + } } - } - if (!prefabSystemEnabled) - { action = menu->addAction(QObject::tr("Delete")); QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_DeleteSelected(); }); if (selected.size() == 0) @@ -733,20 +737,14 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con if (selected.size() > 0) { - action = menu->addAction(QObject::tr("Open pinned Inspector")); - QObject::connect(action, &QAction::triggered, action, [this, selected] - { - AzToolsFramework::EntityIdSet pinnedEntities(selected.begin(), selected.end()); - OpenPinnedInspector(pinnedEntities); - }); - if (selected.size() > 0) - { - action = menu->addAction(QObject::tr("Find in Entity Outliner")); - QObject::connect(action, &QAction::triggered, [selected] + action = menu->addAction(QObject::tr("Find in Entity Outliner")); + QObject::connect( + action, &QAction::triggered, + [selected] { - AzToolsFramework::EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnFocusInEntityOutliner, selected); + AzToolsFramework::EditorEntityContextNotificationBus::Broadcast( + &EditorEntityContextNotification::OnFocusInEntityOutliner, selected); }); - } menu->addSeparator(); } } diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index c58f019c85..75841b5014 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -9,6 +9,8 @@ #ifndef CRYINCLUDE_COMPONENTENTITYEDITORPLUGIN_SANDBOXINTEGRATION_H #define CRYINCLUDE_COMPONENTENTITYEDITORPLUGIN_SANDBOXINTEGRATION_H +#include "ContextMenuHandlers.h" + #include #include #include @@ -273,6 +275,8 @@ private: }; private: + ContextMenuBottomHandler m_contextMenuBottomHandler; + AZ::Vector2 m_contextMenuViewPoint; short m_startedUndoRecordingNestingLevel; // used in OnBegin/EndUndo to ensure we only accept undo's we started recording diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake b/Code/Editor/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake index 28f96de862..a4a2d2b266 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake @@ -10,6 +10,8 @@ set(FILES dllmain.cpp ComponentEntityEditorPlugin.h ComponentEntityEditorPlugin.cpp + ContextMenuHandlers.h + ContextMenuHandlers.cpp SandboxIntegration.h SandboxIntegration.cpp UI/QComponentEntityEditorMainWindow.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h index d545c87a06..2bd9004d82 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 8a22cc50b5..dc17a21e4b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -253,6 +253,68 @@ namespace AzToolsFramework } } + // Edit/Inspect/Close Prefab + { + if (selectedEntities.size() == 1) + { + AZ::EntityId selectedEntity = selectedEntities[0]; + + if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity)) + { + if (!s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity)) + { + if (s_prefabPublicInterface->IsOwnedByProceduralPrefabInstance(selectedEntity)) + { + // Inspect Prefab + QAction* editAction = menu->addAction(QObject::tr("Inspect Procedural Prefab")); + editAction->setShortcut(QKeySequence(Qt::Key_Plus)); + editAction->setToolTip(QObject::tr("See the procedural prefab contents in focus mode.")); + + QObject::connect( + editAction, &QAction::triggered, editAction, + [selectedEntity] + { + ContextMenu_EditPrefab(selectedEntity); + } + ); + } + else + { + // Edit Prefab + QAction* editAction = menu->addAction(QObject::tr("Open/Edit Prefab")); + editAction->setShortcut(QKeySequence(Qt::Key_Plus)); + editAction->setToolTip(QObject::tr("Edit the prefab in focus mode.")); + + QObject::connect( + editAction, &QAction::triggered, editAction, + [selectedEntity] + { + ContextMenu_EditPrefab(selectedEntity); + } + ); + } + } + else + { + // Close Prefab + QAction* closeAction = menu->addAction(QObject::tr("Close Prefab")); + closeAction->setShortcut(QKeySequence(Qt::Key_Minus)); + closeAction->setToolTip(QObject::tr("Close focus mode for this prefab and move one level up.")); + + QObject::connect( + closeAction, &QAction::triggered, closeAction, + [] + { + ContextMenu_ClosePrefab(); + } + ); + } + + menu->addSeparator(); + } + } + } + bool itemWasShown = false; // Create Prefab @@ -291,7 +353,8 @@ namespace AzToolsFramework [selectedEntities] { ContextMenu_CreatePrefab(selectedEntities); - }); + } + ); itemWasShown = true; } @@ -299,6 +362,21 @@ namespace AzToolsFramework } } + // Detach Prefab + if (onlySelectedEntityIsClosedPrefabContainer) + { + AZ::EntityId selectedEntityId = selectedEntities.front(); + + QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); + QObject::connect( + detachPrefabAction, &QAction::triggered, detachPrefabAction, + [selectedEntityId] + { + ContextMenu_DetachPrefab(selectedEntityId); + } + ); + } + // Instantiate Prefab if (selectedEntities.size() == 0 || selectedEntities.size() == 1 && !readOnlyEntityInSelection && !onlySelectedEntityIsClosedPrefabContainer) @@ -311,7 +389,8 @@ namespace AzToolsFramework [] { ContextMenu_InstantiatePrefab(); - }); + } + ); // Instantiate Procedural Prefab if (AZ::Prefab::ProceduralPrefabAsset::UseProceduralPrefabs()) @@ -324,7 +403,8 @@ namespace AzToolsFramework [] { ContextMenu_InstantiateProceduralPrefab(); - }); + } + ); } itemWasShown = true; @@ -335,9 +415,7 @@ namespace AzToolsFramework menu->addSeparator(); } - itemWasShown = false; - - // Edit/Save Prefab + // Save Prefab { if (selectedEntities.size() == 1) { @@ -345,52 +423,6 @@ namespace AzToolsFramework if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity)) { - if (!s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity)) - { - if (s_prefabPublicInterface->IsOwnedByProceduralPrefabInstance(selectedEntity)) - { - // Inspect Prefab - QAction* editAction = menu->addAction(QObject::tr("Inspect Procedural Prefab")); - editAction->setShortcut(QKeySequence(Qt::Key_Plus)); - editAction->setToolTip(QObject::tr("See the procedural prefab contents in focus mode.")); - - QObject::connect( - editAction, &QAction::triggered, editAction, - [selectedEntity] - { - ContextMenu_EditPrefab(selectedEntity); - }); - } - else - { - // Edit Prefab - QAction* editAction = menu->addAction(QObject::tr("Open/Edit Prefab")); - editAction->setShortcut(QKeySequence(Qt::Key_Plus)); - editAction->setToolTip(QObject::tr("Edit the prefab in focus mode.")); - - QObject::connect( - editAction, &QAction::triggered, editAction, - [selectedEntity] - { - ContextMenu_EditPrefab(selectedEntity); - }); - } - } - else - { - // Close Prefab - QAction* closeAction = menu->addAction(QObject::tr("Close Prefab")); - closeAction->setShortcut(QKeySequence(Qt::Key_Minus)); - closeAction->setToolTip(QObject::tr("Close focus mode for this prefab and move one level up.")); - - QObject::connect( - closeAction, &QAction::triggered, closeAction, - [] - { - ContextMenu_ClosePrefab(); - }); - } - // Save Prefab AZ::IO::Path prefabFilePath = s_prefabPublicInterface->GetOwningInstancePrefabPath(selectedEntity); auto dirtyOutcome = s_prefabPublicInterface->HasUnsavedChanges(prefabFilePath); @@ -405,17 +437,43 @@ namespace AzToolsFramework [selectedEntity] { ContextMenu_SavePrefab(selectedEntity); - }); - } + } + ); - itemWasShown = true; + menu->addSeparator(); + } } } } - if (itemWasShown) + if (!selectedEntities.empty()) { - menu->addSeparator(); + // Don't allow duplication if any of the selected entities are direct descendants of a read-only entity + bool selectionContainsDescendantOfReadOnlyEntity = false; + for (const auto& entityId : selectedEntities) + { + AZ::EntityId parentEntityId; + AZ::TransformBus::EventResult(parentEntityId, entityId, &AZ::TransformBus::Events::GetParentId); + + if (parentEntityId.IsValid() && m_readOnlyEntityPublicInterface->IsReadOnly(parentEntityId)) + { + selectionContainsDescendantOfReadOnlyEntity = true; + break; + } + } + + if (!selectionContainsDescendantOfReadOnlyEntity) + { + QAction* duplicateAction = menu->addAction(QObject::tr("Duplicate")); + duplicateAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + QObject::connect( + duplicateAction, &QAction::triggered, duplicateAction, + [] + { + ContextMenu_Duplicate(); + } + ); + } } if (!selectedEntities.empty() && @@ -424,27 +482,17 @@ namespace AzToolsFramework !readOnlyEntityInSelection) { QAction* deleteAction = menu->addAction(QObject::tr("Delete")); + deleteAction->setShortcut(QKeySequence(Qt::Key_Delete)); QObject::connect( deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); - }); + } + ); } - // Detach Prefab - if (onlySelectedEntityIsClosedPrefabContainer) - { - AZ::EntityId selectedEntityId = selectedEntities.front(); - - QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); - QObject::connect( - detachPrefabAction, &QAction::triggered, detachPrefabAction, - [selectedEntityId] - { - ContextMenu_DetachPrefab(selectedEntityId); - }); - } + menu->addSeparator(); } void PrefabIntegrationManager::OnEscape() @@ -653,6 +701,12 @@ namespace AzToolsFramework } } + void PrefabIntegrationManager::ContextMenu_Duplicate() + { + bool handled = true; + AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequests::CloneSelection, handled); + } + void PrefabIntegrationManager::ContextMenu_DeleteSelected() { AzToolsFramework::EntityIdList selectedEntityIds; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 0277d7ab24..09ef7f515e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -92,6 +92,7 @@ namespace AzToolsFramework static void ContextMenu_ClosePrefab(); static void ContextMenu_EditPrefab(AZ::EntityId containerEntity); static void ContextMenu_SavePrefab(AZ::EntityId containerEntity); + static void ContextMenu_Duplicate(); static void ContextMenu_DeleteSelected(); static void ContextMenu_DetachPrefab(AZ::EntityId containerEntity);