Files
o3de/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
T
Danilo Aimini 6bce0a9a8d LYN-7054 + LYN-7704 | Exit Focus Mode when starting Game Mode, correct painting of Prefab capsules in Outliner. (#5280)
* Add RefreshAllContainerEntities function to ContainerEntityInterface. It refreshes all registered containers so that listeners can refresh their state.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Move Prefab border painting to foreground, and invert foreground painting order. This ensures the Prefab capsules are drawn according to UX.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
2021-11-04 09:52:35 -07:00

214 lines
7.4 KiB
C++

/*
* 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 <AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace AzToolsFramework
{
void ContainerEntitySystemComponent::Activate()
{
AZ::Interface<ContainerEntityInterface>::Register(this);
EditorEntityContextNotificationBus::Handler::BusConnect();
}
void ContainerEntitySystemComponent::Deactivate()
{
EditorEntityContextNotificationBus::Handler::BusDisconnect();
AZ::Interface<ContainerEntityInterface>::Unregister(this);
}
void ContainerEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ContainerEntitySystemComponent, AZ::Component>()->Version(1);
}
}
void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("ContainerEntityService"));
}
ContainerEntityOperationResult ContainerEntitySystemComponent::RegisterEntityAsContainer(AZ::EntityId entityId)
{
if (IsContainer(entityId))
{
return AZ::Failure(AZStd::string(
"ContainerEntitySystemComponent error - trying to register entity as container twice."));
}
m_containers.insert(entityId);
return AZ::Success();
}
ContainerEntityOperationResult ContainerEntitySystemComponent::UnregisterEntityAsContainer(AZ::EntityId entityId)
{
if (!IsContainer(entityId))
{
return AZ::Failure(AZStd::string(
"ContainerEntitySystemComponent error - trying to unregister entity that is not a container."));
}
m_containers.erase(entityId);
return AZ::Success();
}
bool ContainerEntitySystemComponent::IsContainer(AZ::EntityId entityId) const
{
return m_containers.contains(entityId);
}
ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpen(AZ::EntityId entityId, bool open)
{
if (!IsContainer(entityId))
{
return AZ::Failure(AZStd::string(
"ContainerEntitySystemComponent error - cannot set open state of entity that was not registered as container."));
}
if(open)
{
m_openContainers.insert(entityId);
}
else
{
m_openContainers.erase(entityId);
}
ContainerEntityNotificationBus::Broadcast(&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, entityId, open);
return AZ::Success();
}
bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const
{
// Non-container entities behave the same as open containers. This saves the caller an additional check.
if(!m_containers.contains(entityId))
{
return true;
}
// If the entity is a container, return its state.
return m_openContainers.contains(entityId);
}
AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const
{
if (!entityId.IsValid())
{
return entityId;
}
// Return the highest closed container, or the entity if none is found.
AZ::EntityId highestSelectableEntityId = entityId;
// Skip the queried entity, as we only want to check its ancestors.
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
// Go up the hierarchy until you hit the root
while (entityId.IsValid())
{
if (!IsContainerOpen(entityId))
{
// If one of the ancestors is a container and it's closed, keep track of its id.
// We only return of the higher closed container in the hierarchy.
highestSelectableEntityId = entityId;
}
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
}
return highestSelectableEntityId;
}
void ContainerEntitySystemComponent::OnEntityStreamLoadSuccess()
{
// We don't yet support multiple entity contexts, so just use the default.
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
Clear(editorEntityContextId);
}
void ContainerEntitySystemComponent::RefreshAllContainerEntities([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{
for (AZ::EntityId containerEntityId : m_containers)
{
ContainerEntityNotificationBus::Broadcast(
&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, containerEntityId, m_openContainers.contains(containerEntityId));
}
}
ContainerEntityOperationResult ContainerEntitySystemComponent::Clear(AzFramework::EntityContextId entityContextId)
{
// We don't yet support multiple entity contexts, so only clear the default.
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
if (entityContextId != editorEntityContextId)
{
return AZ::Failure(AZStd::string(
"Error in ContainerEntitySystemComponent::Clear - cannot clear non-default Entity Context!"));
}
if (!m_containers.empty())
{
return AZ::Failure(AZStd::string(
"Error in ContainerEntitySystemComponent::Clear - cannot clear container states if entities are still registered!"));
}
m_openContainers.clear();
return AZ::Success();
}
bool ContainerEntitySystemComponent::IsUnderClosedContainerEntity(AZ::EntityId entityId) const
{
if (!entityId.IsValid())
{
return false;
}
// Skip the queried entity, as we only want to check its ancestors.
AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
// Go up the hierarchy until you hit the root.
while (entityId.IsValid())
{
if (!IsContainerOpen(entityId))
{
// One of the ancestors is a container and it's closed.
return true;
}
AZ::EntityId parentId;
AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId);
if (parentId == entityId)
{
// In some circumstances, querying a root level entity with GetParentId will return
// the entity itself instead of an invalid entityId.
break;
}
entityId = parentId;
}
// All ancestors are either regular entities or open containers.
return false;
}
} // namespace AzToolsFramework