From 8ab409e4d257e4d8d1ee12b16437e3069fce5992 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 20 Sep 2021 23:36:41 -0700 Subject: [PATCH] Implemented the PrefabViewportFocusPathHandler class, added a breadcrumb widget to the viewport toolbar to display the currently focused prefab path. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.cpp | 4 +- Code/Editor/ViewportTitleDlg.h | 3 + Code/Editor/ViewportTitleDlg.ui | 29 +++++--- .../Prefab/PrefabFocusHandler.cpp | 68 ++++++++++++++++++- .../Prefab/PrefabFocusHandler.h | 11 +++ .../Prefab/PrefabFocusInterface.h | 9 +++ .../Prefab/PrefabFocusNotificationBus.h | 25 +++++++ .../Prefab/PrefabViewportFocusPathHandler.cpp | 54 +++++++++++++++ .../Prefab/PrefabViewportFocusPathHandler.h | 40 +++++++++++ .../aztoolsframework_files.cmake | 3 + 10 files changed, 231 insertions(+), 15 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 65d6de8944..0c5c45e5c8 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -292,8 +292,6 @@ void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane) ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::OnInitDialog() { - m_ui->m_titleBtn->setText(m_title); - // Add a child parented to us that listens for r_displayInfo changes. auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this); connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo); @@ -314,13 +312,13 @@ void CViewportTitleDlg::OnInitDialog() m_cameraSpeed->setFixedWidth(width); + m_prefabViewportFocusPathHandler.Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton); } ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetTitle(const QString& title) { m_title = title; - m_ui->m_titleBtn->setText(m_title); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index 4a2a454907..dfdf567a39 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -176,6 +177,8 @@ protected: QWidgetAction* m_gridSizeActionWidget = nullptr; QWidgetAction* m_angleSizeActionWidget = nullptr; + AzToolsFramework::Prefab::PrefabViewportFocusPathHandler m_prefabViewportFocusPathHandler; + QScopedPointer m_ui; }; diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index f0679dd2a1..e67f04b68a 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -42,22 +42,25 @@ 0 - + + + + :/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg:/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg + + + + Back + + + + + 0 0 - - Qt::NoContextMenu - - - Static - - - 11 - @@ -129,6 +132,12 @@ + + AzQtComponents::BreadCrumbs + QWidget +
AzQtComponents/Components/Widgets/Breadcrumbs.h
+ 1 +
AzQtComponents::ButtonDivider QWidget diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 2338c8892b..276d76f848 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace AzToolsFramework::Prefab { @@ -23,12 +24,14 @@ namespace AzToolsFramework::Prefab "Instance Entity Mapper Interface could not be found. " "Check that it is being correctly initialized."); + EditorEntityContextNotificationBus::Handler::BusConnect(); AZ::Interface::Register(this); } PrefabFocusHandler::~PrefabFocusHandler() { AZ::Interface::Unregister(this); + EditorEntityContextNotificationBus::Handler::BusDisconnect(); } PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) @@ -55,8 +58,28 @@ namespace AzToolsFramework::Prefab if (!focusedInstance.has_value()) { - return AZ::Failure(AZStd::string( - "Prefab Focus Handler: Couldn't find owning instance of entityId provided.")); + return AZ::Failure(AZStd::string("Prefab Focus Handler: Couldn't find owning instance of entityId provided.")); + } + + if (&m_focusedInstance->get() != &focusedInstance->get()) + { + m_focusedInstance = focusedInstance; + m_focusedTemplateId = focusedInstance->get().GetTemplateId(); + s_focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); + + RefreshInstanceFocusList(); + + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } + + return AZ::Success(); + } + + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex(int index) + { + if (index < 0 || index >= m_instanceFocusVector.size()) + { + return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); } m_focusedInstance = focusedInstance; @@ -68,7 +91,13 @@ namespace AzToolsFramework::Prefab focusModeInterface->SetFocusRoot(focusedInstance->get().GetContainerEntityId()); } + RefreshInstanceFocusList(); + + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } + return AZ::Success(); + } TemplateId PrefabFocusHandler::GetFocusedPrefabTemplateId() @@ -93,4 +122,39 @@ namespace AzToolsFramework::Prefab return instance.has_value() && (&instance->get() == &m_focusedInstance->get()); } + const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath() + { + return m_instanceFocusPath; + } + + void PrefabFocusHandler::OnEntityStreamLoadSuccess() + { + // Focus on the root prefab (AZ::EntityId() will default to it) + FocusOnOwningPrefab(AZ::EntityId()); + } + + void PrefabFocusHandler::RefreshInstanceFocusList() + { + m_instanceFocusVector.clear(); + m_instanceFocusPath.clear(); + + AZStd::list instanceFocusList; + + // Use a support list to easily push front while traversing the prefab hierarchy + InstanceOptionalReference currentInstance = m_focusedInstance; + while (currentInstance.has_value()) + { + instanceFocusList.push_front(currentInstance); + + currentInstance = currentInstance->get().GetParentInstance(); + } + + // Populate internals using the support list + for (auto& instance : instanceFocusList) + { + m_instanceFocusPath.Append(instance->get().GetContainerEntity()->get().GetName()); + m_instanceFocusVector.emplace_back(instance); + } + } + } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index fa7727894d..35ef9aba61 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -21,6 +22,7 @@ namespace AzToolsFramework::Prefab //! Handles Prefab Focus mode, determining which prefab file entity changes will target. class PrefabFocusHandler final : private PrefabFocusInterface + , private EditorEntityContextNotificationBus::Handler { public: AZ_CLASS_ALLOCATOR(PrefabFocusHandler, AZ::SystemAllocator, 0); @@ -30,13 +32,22 @@ namespace AzToolsFramework::Prefab // PrefabFocusInterface override ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; + PrefabFocusOperationResult FocusOnPathIndex(int index) override; TemplateId GetFocusedPrefabTemplateId() override; InstanceOptionalReference GetFocusedPrefabInstance() override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) override; + const AZ::IO::Path& GetPrefabFocusPath() override; + + // EditorEntityContextNotificationBus... + void OnEntityStreamLoadSuccess() override; private: + void RefreshInstanceFocusList(); + InstanceOptionalReference m_focusedInstance; TemplateId m_focusedTemplateId; + AZStd::vector m_instanceFocusVector; + AZ::IO::Path m_instanceFocusPath; InstanceEntityMapperInterface* m_instanceEntityMapperInterface; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 833a5ef7c8..9f695f2bf7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -28,6 +28,10 @@ namespace AzToolsFramework::Prefab //! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on. virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0; + //! Set the focused prefab instance to the instance at position index of the current path. + //! @param index The index of the instance in the current path that we want the prefab system to focus on. + virtual PrefabFocusOperationResult FocusOnPathIndex(int index) = 0; + //! Returns the template id of the instance the prefab system is focusing on. virtual TemplateId GetFocusedPrefabTemplateId() = 0; @@ -38,6 +42,11 @@ namespace AzToolsFramework::Prefab //! @param entityId The entityId of the queried entity. //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) = 0; + + //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. + //! @param entityId The entityId of the queried entity. + //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. + virtual const AZ::IO::Path& GetPrefabFocusPath() = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h new file mode 100644 index 0000000000..5eda6ff2e3 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusNotificationBus.h @@ -0,0 +1,25 @@ +/* + * 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 + +namespace AzToolsFramework::Prefab +{ + class PrefabFocusNotifications : public AZ::EBusTraits + { + public: + virtual ~PrefabFocusNotifications() = default; + + virtual void OnPrefabFocusChanged() = 0; + }; + + using PrefabFocusNotificationBus = AZ::EBus; + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp new file mode 100644 index 0000000000..3ca3ec990f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -0,0 +1,54 @@ +/* + * 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 + +namespace AzToolsFramework::Prefab +{ + PrefabViewportFocusPathHandler::~PrefabViewportFocusPathHandler() + { + // Disconnect from Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusDisconnect(); + } + + void PrefabViewportFocusPathHandler::Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton) + { + // Get reference to the PrefabFocusInterface handler + m_prefabFocusInterface = AZ::Interface::Get(); + if (m_prefabFocusInterface == nullptr) + { + AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabViewportFocusPathHandler construction."); + return; + } + + // Connect to Prefab Focus Notifications + PrefabFocusNotificationBus::Handler::BusConnect(); + + // Initialize Widgets + m_breadcrumbsWidget = breadcrumbsWidget; + m_backButton = backButton; + + m_backButton->setEnabled(false); + + connect( + m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, + [&](const QString&, int linkIndex) + { + m_prefabFocusInterface->FocusOnPathIndex(linkIndex); + } + ); + } + + void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() + { + // Push new Path + m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath().c_str()); + } + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h new file mode 100644 index 0000000000..63e5579c00 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -0,0 +1,40 @@ +/* + * 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 + +#include + +#include +#include + +namespace AzToolsFramework::Prefab +{ + class PrefabFocusInterface; + + class PrefabViewportFocusPathHandler + : public PrefabFocusNotificationBus::Handler + , private QObject + { + public: + ~PrefabViewportFocusPathHandler(); + + void Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); + + // PrefabFocusNotificationBus... + void OnPrefabFocusChanged() override; + + private: + AzQtComponents::BreadCrumbs* m_breadcrumbsWidget = nullptr; + QToolButton* m_backButton = nullptr; + + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + }; +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 88febef8c2..019ae21674 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -635,6 +635,7 @@ set(FILES Prefab/PrefabFocusHandler.h Prefab/PrefabFocusHandler.cpp Prefab/PrefabFocusInterface.h + Prefab/PrefabFocusNotificationBus.h Prefab/PrefabIdTypes.h Prefab/PrefabLoader.h Prefab/PrefabLoader.cpp @@ -733,6 +734,8 @@ set(FILES UI/Prefab/PrefabIntegrationInterface.h UI/Prefab/PrefabUiHandler.h UI/Prefab/PrefabUiHandler.cpp + UI/Prefab/PrefabViewportFocusPathHandler.h + UI/Prefab/PrefabViewportFocusPathHandler.cpp PythonTerminal/ScriptHelpDialog.cpp PythonTerminal/ScriptHelpDialog.h PythonTerminal/ScriptHelpDialog.ui