Introduce a new Focus Mode API function to retrieve full list of EntityIds that are in focus. (#7159)

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
This commit is contained in:
Danilo Aimini
2022-01-26 08:12:34 -08:00
committed by GitHub
parent ec47c4fdfc
commit 1a7a350880
4 changed files with 135 additions and 0 deletions
@@ -17,6 +17,8 @@
namespace AzToolsFramework
{
using EntityIdList = AZStd::vector<AZ::EntityId>;
//! FocusModeInterface
//! Interface to handle the Editor Focus Mode.
class FocusModeInterface
@@ -36,6 +38,9 @@ namespace AzToolsFramework
//! @return The entity id of the root of the Editor focus, or an invalid entity id if no focus is set.
virtual AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) = 0;
//! Returns a list of the ids of all the entities that are descendants of the focus root.
virtual EntityIdList GetFocusedEntities(AzFramework::EntityContextId entityContextId) = 0;
//! Returns whether the entity id provided is part of the focused sub-tree.
virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
};
@@ -40,10 +40,14 @@ namespace AzToolsFramework
void FocusModeSystemComponent::Activate()
{
AZ::Interface<FocusModeInterface>::Register(this);
EditorEntityInfoNotificationBus::Handler::BusConnect();
Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
}
void FocusModeSystemComponent::Deactivate()
{
Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
EditorEntityInfoNotificationBus::Handler::BusDisconnect();
AZ::Interface<FocusModeInterface>::Unregister(this);
}
@@ -89,6 +93,9 @@ namespace AzToolsFramework
AZ::EntityId previousFocusEntityId = m_focusRoot;
m_focusRoot = entityId;
RefreshFocusedEntityIdList();
FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot);
}
@@ -102,6 +109,11 @@ namespace AzToolsFramework
return m_focusRoot;
}
EntityIdList FocusModeSystemComponent::GetFocusedEntities([[maybe_unused]] AzFramework::EntityContextId entityContextId)
{
return m_focusedEntityIdList;
}
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) const
{
if (m_focusRoot == AZ::EntityId())
@@ -112,4 +124,54 @@ namespace AzToolsFramework
return AzToolsFramework::IsInFocusSubTree(entityId, m_focusRoot);
}
void FocusModeSystemComponent::OnEntityInfoUpdatedAddChildEnd(AZ::EntityId parentId, AZ::EntityId childId)
{
// If the parent's entityId is in the list, add the child.
if (auto iter = AZStd::find(m_focusedEntityIdList.begin(), m_focusedEntityIdList.end(), parentId);
iter != m_focusedEntityIdList.end())
{
m_focusedEntityIdList.push_back(childId);
}
}
void FocusModeSystemComponent::OnEntityInfoUpdatedRemoveChildEnd([[maybe_unused]] AZ::EntityId parentId, AZ::EntityId childId)
{
// If the removed entityId is in the list, remove it.
if (auto iter = AZStd::find(m_focusedEntityIdList.begin(), m_focusedEntityIdList.end(), childId);
iter != m_focusedEntityIdList.end())
{
m_focusedEntityIdList.erase(iter);
}
}
void FocusModeSystemComponent::OnPrefabInstancePropagationEnd()
{
// Can't rely on any of the entities in the list to still exist, refresh the whole thing.
RefreshFocusedEntityIdList();
}
void FocusModeSystemComponent::RefreshFocusedEntityIdList()
{
m_focusedEntityIdList.clear();
AZStd::queue<AZ::EntityId> entityIdQueue;
entityIdQueue.push(m_focusRoot);
while (!entityIdQueue.empty())
{
AZ::EntityId entityId = entityIdQueue.front();
entityIdQueue.pop();
m_focusedEntityIdList.push_back(entityId);
EntityIdList children;
EditorEntityInfoRequestBus::EventResult(children, entityId, &EditorEntityInfoRequestBus::Events::GetChildren);
for (AZ::EntityId childEntityId : children)
{
entityIdQueue.push(childEntityId);
}
}
}
} // namespace AzToolsFramework
@@ -11,7 +11,9 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/Prefab/PrefabPublicNotificationBus.h>
namespace AzToolsFramework
{
@@ -21,6 +23,8 @@ namespace AzToolsFramework
class FocusModeSystemComponent final
: public AZ::Component
, private FocusModeInterface
, private EditorEntityInfoNotificationBus::Handler
, private Prefab::PrefabPublicNotificationBus::Handler
{
public:
AZ_COMPONENT(FocusModeSystemComponent, "{6CE522FE-2057-4794-BD05-61E04BD8EA30}");
@@ -42,10 +46,21 @@ namespace AzToolsFramework
void SetFocusRoot(AZ::EntityId entityId) override;
void ClearFocusRoot(AzFramework::EntityContextId entityContextId) override;
AZ::EntityId GetFocusRoot(AzFramework::EntityContextId entityContextId) override;
EntityIdList GetFocusedEntities(AzFramework::EntityContextId entityContextId) override;
bool IsInFocusSubTree(AZ::EntityId entityId) const override;
// EditorEntityInfoNotificationBus overrides ...
void OnEntityInfoUpdatedAddChildEnd(AZ::EntityId parentId, AZ::EntityId childId) override;
void OnEntityInfoUpdatedRemoveChildEnd(AZ::EntityId parentId, AZ::EntityId childId) override;
// PrefabPublicNotificationBus overrides ...
void OnPrefabInstancePropagationEnd() override;
private:
void RefreshFocusedEntityIdList();
AZ::EntityId m_focusRoot;
EntityIdList m_focusedEntityIdList;
};
} // namespace AzToolsFramework
@@ -7,6 +7,7 @@
*/
#include <Tests/FocusMode/EditorFocusModeFixture.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace UnitTest
{
@@ -30,6 +31,58 @@ namespace UnitTest
EXPECT_EQ(m_focusModeInterface->GetFocusRoot(m_editorEntityContextId), AZ::EntityId());
}
TEST_F(EditorFocusModeFixture, GetFocusedEntitiesBase)
{
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
AzToolsFramework::EntityIdList entities = m_focusModeInterface->GetFocusedEntities(m_editorEntityContextId);
EXPECT_EQ(entities.size(), 5);
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[StreetEntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[CarEntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[Passenger1EntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[SportsCarEntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[Passenger2EntityName]) != entities.end());
}
TEST_F(EditorFocusModeFixture, GetFocusedEntitiesSiblings)
{
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
AzToolsFramework::EntityIdList entities = m_focusModeInterface->GetFocusedEntities(m_editorEntityContextId);
EXPECT_EQ(entities.size(), 2);
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[SportsCarEntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[Passenger2EntityName]) != entities.end());
}
TEST_F(EditorFocusModeFixture, GetFocusedEntitiesAddEntity)
{
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
AZ::EntityId testEntityId = CreateEditorEntity("Test", m_entityMap[Passenger2EntityName]);
AzToolsFramework::EntityIdList entities = m_focusModeInterface->GetFocusedEntities(m_editorEntityContextId);
EXPECT_EQ(entities.size(), 3);
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[SportsCarEntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[Passenger2EntityName]) != entities.end());
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), testEntityId) != entities.end());
}
TEST_F(EditorFocusModeFixture, GetFocusedEntitiesRemoveEntity)
{
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::DeleteEntityAndAllDescendants, m_entityMap[Passenger2EntityName]);
AzToolsFramework::EntityIdList entities = m_focusModeInterface->GetFocusedEntities(m_editorEntityContextId);
EXPECT_EQ(entities.size(), 1);
EXPECT_TRUE(AZStd::find(entities.begin(), entities.end(), m_entityMap[SportsCarEntityName]) != entities.end());
}
TEST_F(EditorFocusModeFixture, IsInFocusSubTreeAncestorsDescendants)
{
// When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't.