Merge branch 'development' of https://github.com/o3de/o3de into TerrainMaterialsFix

This commit is contained in:
Sergey Pereslavtsev
2022-02-04 20:23:36 +00:00
684 changed files with 225383 additions and 9547 deletions
@@ -295,7 +295,7 @@ namespace AzToolsFramework
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
{
@@ -19,45 +19,69 @@
namespace AzToolsFramework
{
namespace Prefab
{
//! A RootAliasPath can be used to store an alias path that starts from the Prefab EOS root instance.
//! The root instance itself is included in the path. These can be used as Instance handles across systems
//! that do not have visibility over InstanceOptionalReferences, or that need to store Instance handles
//! for longer than just the span of a function without the risk of them going out of scope.
using RootAliasPath = AliasPath;
}
class PrefabEditorEntityOwnershipInterface
{
public:
AZ_RTTI(PrefabEditorEntityOwnershipInterface,"{38E764BA-A089-49F3-848F-46018822CE2E}");
AZ_RTTI(PrefabEditorEntityOwnershipInterface, "{38E764BA-A089-49F3-848F-46018822CE2E}");
//! Returns whether the system has a root instance assigned.
//! @return True if a root prefab is assigned, false otherwise.
virtual bool IsRootPrefabAssigned() const = 0;
//! Returns an optional reference to the root prefab instance.
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
//! Returns the template id for the root prefab instance.
virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;
//! Creates a prefab instance with the provided entities and nestedPrefabInstances.
//! /param entities The entities to put under the new prefab.
//! /param nestedPrefabInstances The nested prefab instances to put under the new prefab.
//! /param filePath The filepath corresponding to the prefab file to be created.
//! /param instanceToParentUnder The instance the newly created prefab instance is parented under.
//! /return The optional reference to the prefab created.
//! @param entities The entities to put under the new prefab.
//! @param nestedPrefabInstances The nested prefab instances to put under the new prefab.
//! @param filePath The filepath corresponding to the prefab file to be created.
//! @param instanceToParentUnder The instance the newly created prefab instance is parented under.
//! @return The optional reference to the prefab created.
virtual Prefab::InstanceOptionalReference CreatePrefab(
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;
//! Instantiate the prefab file provided.
//! /param filePath The filepath for the prefab file the instance should be created from.
//! /param instanceToParentUnder The instance the newly instantiated prefab instance is parented under.
//! /return The optional reference to the prefab instance.
//! @param filePath The filepath for the prefab file the instance should be created from.
//! @param instanceToParentUnder The instance the newly instantiated prefab instance is parented under.
//! @return The optional reference to the prefab instance.
virtual Prefab::InstanceOptionalReference InstantiatePrefab(
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0;
virtual void StartPlayInEditor() = 0;
virtual void StopPlayInEditor() = 0;
//! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
//! /return The vector of Assets generated by Prefab processing
//! @return The vector of Assets generated by Prefab processing
virtual const Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer::SpawnableAssets& GetPlayInEditorAssetData() const = 0;
virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
virtual void StartPlayInEditor() = 0;
virtual void StopPlayInEditor() = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;
//! Returns the reference to the instance corresponding to the RootAliasPath provided.
//! @param rootAliasPath The RootAliasPath to be queried.
//! @return A reference to the instance if valid, AZStd::nullopt otherwise.
virtual Prefab::InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(Prefab::RootAliasPath rootAliasPath) const = 0;
virtual bool IsRootPrefabAssigned() const = 0;
//! Allows to iterate through all instances referenced in the path, from the root down.
//! @param rootAliasPath The RootAliasPath to iterate through. If invalid, callback will not be called.
//! @param callback The function to call on each instance. If it returns true, it prevents the rest of the path from being called.
//! @return True if the iteration was halted by a callback returning true, false otherwise. Also returns false if the path is invalid.
virtual bool GetInstancesInRootAliasPath(
Prefab::RootAliasPath rootAliasPath, const AZStd::function<bool(const Prefab::InstanceOptionalReference)>& callback) const = 0;
};
}
@@ -510,6 +510,70 @@ namespace AzToolsFramework
m_playInEditorData.m_isEnabled = false;
}
bool PrefabEditorEntityOwnershipService::IsValidRootAliasPath(Prefab::RootAliasPath rootAliasPath) const
{
return GetInstanceReferenceFromRootAliasPath(rootAliasPath) != AZStd::nullopt;
}
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetInstanceReferenceFromRootAliasPath(
Prefab::RootAliasPath rootAliasPath) const
{
Prefab::InstanceOptionalReference instance = *m_rootInstance;
for (const auto& pathElement : rootAliasPath)
{
if (pathElement.Native() == rootAliasPath.begin()->Native())
{
// If the root is not the root Instance, the rootAliasPath is invalid.
if (pathElement.Native() != instance->get().GetInstanceAlias())
{
return Prefab::InstanceOptionalReference();
}
}
else
{
// If the instance alias can't be found, the rootAliasPath is invalid.
instance = instance->get().FindNestedInstance(pathElement.Native());
if (!instance.has_value())
{
return Prefab::InstanceOptionalReference();
}
}
}
return instance;
}
bool PrefabEditorEntityOwnershipService::GetInstancesInRootAliasPath(
Prefab::RootAliasPath rootAliasPath, const AZStd::function<bool(const Prefab::InstanceOptionalReference)>& callback) const
{
if (!IsValidRootAliasPath(rootAliasPath))
{
return false;
}
Prefab::InstanceOptionalReference instance;
for (const auto& pathElement : rootAliasPath)
{
if (!instance.has_value())
{
instance = *m_rootInstance;
}
else
{
instance = instance->get().FindNestedInstance(pathElement.Native());
}
if(callback(instance))
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
// Slice Buses implementation with Assert(false), this will exist only during Slice->Prefab
// development to pinpoint and replace specific calls to Slice system
@@ -169,11 +169,17 @@ namespace AzToolsFramework
void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) override;
bool IsRootPrefabAssigned() const override;
Prefab::InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(Prefab::RootAliasPath rootAliasPath) const override;
bool GetInstancesInRootAliasPath(
Prefab::RootAliasPath rootAliasPath, const AZStd::function<bool(const Prefab::InstanceOptionalReference)>& callback) const override;
protected:
AZ::SliceComponent::SliceInstanceAddress GetOwningSlice() override;
private:
bool IsValidRootAliasPath(Prefab::RootAliasPath rootAliasPath) const;
struct PlayInEditorData
{
AzToolsFramework::Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer m_assetsCache;
@@ -177,7 +177,6 @@ namespace AzToolsFramework
AZStd::pair<Instance*, AZ::EntityId> GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath);
AZStd::pair<const Instance*, AZ::EntityId> GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath) const;
/**
* Gets the aliases of all the nested instances, which are sourced by the template with the given id.
*
@@ -11,7 +11,6 @@
#include <AzToolsFramework/Commands/SelectionCommand.h>
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Entity/ReadOnly/ReadOnlyEntityInterface.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
@@ -97,9 +96,9 @@ namespace AzToolsFramework::Prefab
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities);
}
// Edit Prefab
// Add undo element
{
auto editUndo = aznew PrefabFocusUndo("Edit Prefab");
auto editUndo = aznew PrefabFocusUndo("Focus Prefab");
editUndo->Capture(entityId);
editUndo->SetParent(undoBatch.GetUndoBatch());
FocusOnPrefabInstanceOwningEntityId(entityId);
@@ -112,15 +111,24 @@ namespace AzToolsFramework::Prefab
[[maybe_unused]] AzFramework::EntityContextId entityContextId)
{
// If only one instance is in the hierarchy, this operation is invalid
size_t hierarchySize = m_instanceFocusHierarchy.size();
if (hierarchySize <= 1)
if (m_rootAliasFocusPathLength <= 1)
{
return AZ::Failure(
AZStd::string("Prefab Focus Handler: Could not complete FocusOnParentOfFocusedPrefab operation while focusing on the root."));
return AZ::Failure(AZStd::string(
"Prefab Focus Handler: Could not complete FocusOnParentOfFocusedPrefab operation while focusing on the root."));
}
RootAliasPath parentPath = m_rootAliasFocusPath;
parentPath.RemoveFilename();
// Retrieve parent of currently focused prefab.
InstanceOptionalReference parentInstance = GetReferenceFromContainerEntityId(m_instanceFocusHierarchy[hierarchySize - 2]);
InstanceOptionalReference parentInstance = GetInstanceReference(parentPath);
// If only one instance is in the hierarchy, this operation is invalid
if (!parentInstance.has_value())
{
return AZ::Failure(AZStd::string(
"Prefab Focus Handler: Could not retrieve parent of current focus in FocusOnParentOfFocusedPrefab."));
}
// Use container entity of parent Instance for focus operations.
AZ::EntityId entityId = parentInstance->get().GetContainerEntityId();
@@ -136,9 +144,9 @@ namespace AzToolsFramework::Prefab
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities);
}
// Edit Prefab
// Add undo element
{
auto editUndo = aznew PrefabFocusUndo("Edit Prefab");
auto editUndo = aznew PrefabFocusUndo("Focus Prefab");
editUndo->Capture(entityId);
editUndo->SetParent(undoBatch.GetUndoBatch());
FocusOnPrefabInstanceOwningEntityId(entityId);
@@ -149,12 +157,31 @@ namespace AzToolsFramework::Prefab
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index)
{
if (index < 0 || index >= m_instanceFocusHierarchy.size())
if (index < 0 || index >= m_rootAliasFocusPathLength)
{
return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex."));
}
InstanceOptionalReference focusedInstance = GetReferenceFromContainerEntityId(m_instanceFocusHierarchy[index]);
int i = 0;
RootAliasPath indexedPath;
for (const auto& pathElement : m_rootAliasFocusPath)
{
indexedPath.Append(pathElement);
if (i == index)
{
break;
}
++i;
}
InstanceOptionalReference focusedInstance = GetInstanceReference(indexedPath);
if (!focusedInstance.has_value())
{
return AZ::Failure(AZStd::string::format("Prefab Focus Handler: Could not retrieve instance at index %i.", index));
}
return FocusOnOwningPrefab(focusedInstance->get().GetContainerEntityId());
}
@@ -192,13 +219,14 @@ namespace AzToolsFramework::Prefab
}
// Close all container entities in the old path.
CloseInstanceContainers(m_instanceFocusHierarchy);
SetInstanceContainersOpenState(m_rootAliasFocusPath, false);
AZ::EntityId previousContainerEntityId = m_focusedInstanceContainerEntityId;
const RootAliasPath previousContainerRootAliasPath = m_rootAliasFocusPath;
const InstanceOptionalConstReference previousFocusedInstance = GetInstanceReference(previousContainerRootAliasPath);
// Do not store the container for the root instance, use an invalid EntityId instead.
m_focusedInstanceContainerEntityId = focusedInstance->get().GetParentInstance().has_value() ? focusedInstance->get().GetContainerEntityId() : AZ::EntityId();
m_rootAliasFocusPath = focusedInstance->get().GetAbsoluteInstanceAliasPath();
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
m_rootAliasFocusPathLength = aznumeric_cast<int>(AZStd::distance(m_rootAliasFocusPath.begin(), m_rootAliasFocusPath.end()));
// Focus on the descendants of the container entity in the Editor, if the interface is initialized.
if (m_focusModeInterface)
@@ -214,15 +242,22 @@ namespace AzToolsFramework::Prefab
// Refresh the read-only cache, if the interface is initialized.
if (m_readOnlyEntityQueryInterface)
{
m_readOnlyEntityQueryInterface->RefreshReadOnlyState({ previousContainerEntityId, m_focusedInstanceContainerEntityId });
EntityIdList containerEntities;
if (previousFocusedInstance.has_value())
{
containerEntities.push_back(previousFocusedInstance->get().GetContainerEntityId());
}
containerEntities.push_back(focusedInstance->get().GetContainerEntityId());
m_readOnlyEntityQueryInterface->RefreshReadOnlyState(containerEntities);
}
// Refresh path variables.
RefreshInstanceFocusList();
RefreshInstanceFocusPath();
// Open all container entities in the new path.
OpenInstanceContainers(m_instanceFocusHierarchy);
SetInstanceContainersOpenState(m_rootAliasFocusPath, true);
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
@@ -237,17 +272,12 @@ namespace AzToolsFramework::Prefab
InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance(
[[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{
return GetReferenceFromContainerEntityId(m_focusedInstanceContainerEntityId);
return GetInstanceReference(m_rootAliasFocusPath);
}
AZ::EntityId PrefabFocusHandler::GetFocusedPrefabContainerEntityId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{
if (m_focusedInstanceContainerEntityId.IsValid())
{
return m_focusedInstanceContainerEntityId;
}
if (auto instance = GetReferenceFromContainerEntityId(m_focusedInstanceContainerEntityId); instance.has_value())
if (const InstanceOptionalConstReference instance = GetInstanceReference(m_rootAliasFocusPath); instance.has_value())
{
return instance->get().GetContainerEntityId();
}
@@ -262,19 +292,13 @@ namespace AzToolsFramework::Prefab
return false;
}
InstanceOptionalReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
const InstanceOptionalConstReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
if (!instance.has_value())
{
return false;
}
// If this is owned by the root instance, that corresponds to an invalid m_focusedInstanceContainerEntityId.
if (!instance->get().GetParentInstance().has_value())
{
return !m_focusedInstanceContainerEntityId.IsValid();
}
return (instance->get().GetContainerEntityId() == m_focusedInstanceContainerEntityId);
return (instance->get().GetAbsoluteInstanceAliasPath() == m_rootAliasFocusPath);
}
bool PrefabFocusHandler::IsOwningPrefabInFocusHierarchy(AZ::EntityId entityId) const
@@ -284,18 +308,10 @@ namespace AzToolsFramework::Prefab
return false;
}
// If the focus is on the root, m_focusedInstanceContainerEntityId will be the invalid id.
// In those case all entities are in the focus hierarchy and should return true.
if (!m_focusedInstanceContainerEntityId.IsValid())
{
return true;
}
InstanceOptionalReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
InstanceOptionalConstReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
while (instance.has_value())
{
if (instance->get().GetContainerEntityId() == m_focusedInstanceContainerEntityId)
if (instance->get().GetAbsoluteInstanceAliasPath() == m_rootAliasFocusPath)
{
return true;
}
@@ -308,40 +324,47 @@ namespace AzToolsFramework::Prefab
const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{
return m_instanceFocusPath;
return m_filenameFocusPath;
}
const int PrefabFocusHandler::GetPrefabFocusPathLength([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{
return aznumeric_cast<int>(m_instanceFocusHierarchy.size());
return m_rootAliasFocusPathLength;
}
void PrefabFocusHandler::OnContextReset()
{
// Clear the old focus vector
m_instanceFocusHierarchy.clear();
// Focus on the root prefab (AZ::EntityId() will default to it)
FocusOnPrefabInstanceOwningEntityId(AZ::EntityId());
}
void PrefabFocusHandler::OnEntityInfoUpdatedName(AZ::EntityId entityId, [[maybe_unused]]const AZStd::string& name)
{
// Determine if the entityId is the container for any of the instances in the vector.
auto result = AZStd::find_if(
m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end(),
[&, entityId](const AZ::EntityId& containerEntityId)
{
InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId);
return (instance->get().GetContainerEntityId() == entityId);
}
);
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (result != m_instanceFocusHierarchy.end())
if (prefabEditorEntityOwnershipInterface)
{
// Refresh the path and notify changes.
RefreshInstanceFocusPath();
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
// Determine if the entityId is the container for any of the instances in the vector.
bool match = prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath(
m_rootAliasFocusPath,
[&](const Prefab::InstanceOptionalReference instance)
{
if (instance->get().GetContainerEntityId() == entityId)
{
return true;
}
return false;
}
);
if (match)
{
// Refresh the path and notify changes.
RefreshInstanceFocusPath();
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
}
}
}
@@ -354,108 +377,81 @@ namespace AzToolsFramework::Prefab
void PrefabFocusHandler::OnPrefabTemplateDirtyFlagUpdated(TemplateId templateId, [[maybe_unused]] bool status)
{
// Determine if the templateId matches any of the instances in the vector.
auto result = AZStd::find_if(
m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end(),
[&, templateId](const AZ::EntityId& containerEntityId)
{
InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId);
return (instance->get().GetTemplateId() == templateId);
}
);
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (result != m_instanceFocusHierarchy.end())
if (prefabEditorEntityOwnershipInterface)
{
// Refresh the path and notify changes.
RefreshInstanceFocusPath();
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
}
}
// Determine if the templateId matches any of the instances in the vector.
bool match = prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath(
m_rootAliasFocusPath,
[&](const Prefab::InstanceOptionalReference instance)
{
if (instance->get().GetTemplateId() == templateId)
{
return true;
}
void PrefabFocusHandler::RefreshInstanceFocusList()
{
m_instanceFocusHierarchy.clear();
return false;
}
);
AZStd::list<InstanceOptionalReference> instanceFocusList;
InstanceOptionalReference currentInstance = GetReferenceFromContainerEntityId(m_focusedInstanceContainerEntityId);
while (currentInstance.has_value())
{
if (currentInstance->get().GetParentInstance().has_value())
if (match)
{
m_instanceFocusHierarchy.emplace_back(currentInstance->get().GetContainerEntityId());
// Refresh the path and notify changes.
RefreshInstanceFocusPath();
PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged);
}
else
{
m_instanceFocusHierarchy.emplace_back(AZ::EntityId());
}
currentInstance = currentInstance->get().GetParentInstance();
}
// Invert the vector, since we need the top instance to be at index 0.
AZStd::reverse(m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end());
}
void PrefabFocusHandler::RefreshInstanceFocusPath()
{
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
m_instanceFocusPath.clear();
size_t index = 0;
size_t maxIndex = m_instanceFocusHierarchy.size() - 1;
for (const AZ::EntityId& containerEntityId : m_instanceFocusHierarchy)
{
InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId);
if (instance.has_value())
{
AZStd::string prefabName;
if (index < maxIndex)
{
// Get the filename without the extension (stem).
prefabName = instance->get().GetTemplateSourcePath().Stem().Native();
}
else
{
// Get the full filename.
prefabName = instance->get().GetTemplateSourcePath().Filename().Native();
}
if (prefabSystemComponentInterface->IsTemplateDirty(instance->get().GetTemplateId()))
{
prefabName += "*";
}
m_instanceFocusPath.Append(prefabName);
}
++index;
}
}
void PrefabFocusHandler::OpenInstanceContainers(const AZStd::vector<AZ::EntityId>& instances) const
{
// If this is called outside the Editor, this interface won't be initialized.
if (!m_containerEntityInterface)
{
return;
}
m_filenameFocusPath.clear();
for (const AZ::EntityId& containerEntityId : instances)
{
InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId);
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
PrefabSystemComponentInterface* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
if (instance.has_value())
{
m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), true);
}
if (prefabEditorEntityOwnershipInterface && prefabSystemComponentInterface)
{
int i = 0;
prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath(
m_rootAliasFocusPath,
[&](const Prefab::InstanceOptionalReference instance)
{
if (instance.has_value())
{
AZStd::string prefabName;
if (i == m_rootAliasFocusPathLength - 1)
{
// Get the full filename.
prefabName = instance->get().GetTemplateSourcePath().Filename().Native();
}
else
{
// Get the filename without the extension (stem).
prefabName = instance->get().GetTemplateSourcePath().Stem().Native();
}
if (prefabSystemComponentInterface->IsTemplateDirty(instance->get().GetTemplateId()))
{
prefabName += "*";
}
m_filenameFocusPath.Append(prefabName);
}
++i;
return false;
}
);
}
}
void PrefabFocusHandler::CloseInstanceContainers(const AZStd::vector<AZ::EntityId>& instances) const
void PrefabFocusHandler::SetInstanceContainersOpenState(const RootAliasPath& rootAliasPath, bool openState) const
{
// If this is called outside the Editor, this interface won't be initialized.
if (!m_containerEntityInterface)
@@ -463,33 +459,34 @@ namespace AzToolsFramework::Prefab
return;
}
for (const AZ::EntityId& containerEntityId : instances)
{
InstanceOptionalReference instance = GetReferenceFromContainerEntityId(containerEntityId);
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (instance.has_value())
{
m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), false);
}
if (prefabEditorEntityOwnershipInterface)
{
prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath(
rootAliasPath,
[&](const Prefab::InstanceOptionalReference instance)
{
m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), openState);
return false;
}
);
}
}
InstanceOptionalReference PrefabFocusHandler::GetReferenceFromContainerEntityId(AZ::EntityId containerEntityId) const
InstanceOptionalReference PrefabFocusHandler::GetInstanceReference(RootAliasPath rootAliasPath) const
{
if (!containerEntityId.IsValid())
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (prefabEditorEntityOwnershipInterface)
{
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (!prefabEditorEntityOwnershipInterface)
{
return AZStd::nullopt;
}
return prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
return prefabEditorEntityOwnershipInterface->GetInstanceReferenceFromRootAliasPath(rootAliasPath);
}
return m_instanceEntityMapperInterface->FindOwningInstance(containerEntityId);
return AZStd::nullopt;
}
} // namespace AzToolsFramework::Prefab
@@ -12,6 +12,7 @@
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
@@ -28,6 +29,7 @@ namespace AzToolsFramework
namespace AzToolsFramework::Prefab
{
class InstanceEntityMapperInterface;
class PrefabSystemComponentInterface;
//! Handles Prefab Focus mode, determining which prefab file entity changes will target.
class PrefabFocusHandler final
@@ -73,23 +75,20 @@ namespace AzToolsFramework::Prefab
private:
PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance);
void RefreshInstanceFocusList();
void RefreshInstanceFocusPath();
void OpenInstanceContainers(const AZStd::vector<AZ::EntityId>& instances) const;
void CloseInstanceContainers(const AZStd::vector<AZ::EntityId>& instances) const;
void SetInstanceContainersOpenState(const RootAliasPath& rootAliasPath, bool openState) const;
InstanceOptionalReference GetReferenceFromContainerEntityId(AZ::EntityId containerEntityId) const;
InstanceOptionalReference GetInstanceReference(RootAliasPath rootAliasPath) const;
//! The EntityId of the prefab container entity for the instance the editor is currently focusing on.
AZ::EntityId m_focusedInstanceContainerEntityId = AZ::EntityId();
//! The alias path for the instance the editor is currently focusing on, starting from the root instance.
RootAliasPath m_rootAliasFocusPath = RootAliasPath();
//! The templateId of the focused instance.
TemplateId m_focusedTemplateId;
//! The list of instances going from the root (index 0) to the focused instance,
//! referenced by their prefab container's EntityId.
AZStd::vector<AZ::EntityId> m_instanceFocusHierarchy;
//! A path containing the filenames of the instances in the focus hierarchy, separated with a /.
AZ::IO::Path m_instanceFocusPath;
AZ::IO::Path m_filenameFocusPath;
//! The length of the current focus path. Stored to simplify internal checks.
int m_rootAliasFocusPathLength = 0;
ContainerEntityInterface* m_containerEntityInterface = nullptr;
FocusModeInterface* m_focusModeInterface = nullptr;
@@ -815,7 +815,8 @@ namespace AzToolsFramework
if (templateRef.has_value())
{
return templateRef->get().IsDirty();
return !templateRef->get().IsProcedural() && // all procedural prefabs are read-only
templateRef->get().IsDirty();
}
return false;
@@ -349,7 +349,7 @@ namespace AzToolsFramework
return false;
}
StatementPrototype stmt("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=:1;");
StatementPrototype stmt("SELECT COUNT(*) FROM sqlite_schema WHERE type='table' AND name=:1;");
Statement* execute = stmt.Prepare(m_db); // execute now belongs to stmt and will die when stmt leaves scope.
if (!execute->Prepared())
{
@@ -501,7 +501,7 @@ namespace AzToolsFramework
// https://www.sqlite.org/c3ref/prepare.html ^^^^^^^^^
int res = sqlite3_prepare_v2(db, m_parentPrototype->GetSqlText().c_str(), (int)m_parentPrototype->GetSqlText().length() + 1, &m_statement, NULL);
AZ_Assert(res == SQLITE_OK, "Statement::PrepareFirstTime: failed! %s ( prototype is '%s'). Error code returned is %d.", sqlite3_errmsg(db), m_parentPrototype->GetSqlText().c_str(), res);
return ((res == SQLITE_OK)&&(m_statement));
}
@@ -703,7 +703,7 @@ namespace AzToolsFramework
int res = sqlite3_clear_bindings(m_statement);
AZ_Assert(res == SQLITE_OK, "Statement::sqlite3_clear_bindings: failed!");
return (res == SQLITE_OK);
}
int Statement::GetNamedParamIdx(const char* name)
@@ -783,6 +783,7 @@ namespace AzToolsFramework
}
EBUS_EVENT(ToolsApplicationEvents::Bus, InvalidatePropertyDisplay, Refresh_EntireTree);
ToolsApplicationRequests::Bus::Broadcast(&ToolsApplicationRequests::Bus::Events::AddDirtyEntity, GetEntityId());
}
void ScriptEditorComponent::LoadProperties()
@@ -306,41 +306,37 @@ namespace AzToolsFramework
{
// Only show the close icon if the prefab is expanded.
// This allows the prefab container to be opened if it was collapsed during propagation.
if (!isExpanded)
if (isExpanded)
{
return;
}
// Use the same color as the background.
QColor backgroundColor = m_backgroundColor;
if (isSelected)
{
backgroundColor = m_backgroundSelectedColor;
}
else if (isHovered)
{
backgroundColor = m_backgroundHoverColor;
}
// Use the same color as the background.
QColor backgroundColor = m_backgroundColor;
if (isSelected)
{
backgroundColor = m_backgroundSelectedColor;
}
else if (isHovered)
{
backgroundColor = m_backgroundHoverColor;
}
// Paint a rect to cover up the expander.
QRect rect = QRect(0, 0, 16, 16);
rect.translate(option.rect.topLeft() + offset);
painter->fillRect(rect, backgroundColor);
// Paint a rect to cover up the expander.
QRect rect = QRect(0, 0, 16, 16);
rect.translate(option.rect.topLeft() + offset);
painter->fillRect(rect, backgroundColor);
// Paint the icon.
QIcon closeIcon = QIcon(m_prefabEditCloseIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, closeIcon.pixmap(iconSize));
// Paint the icon.
QIcon closeIcon = QIcon(m_prefabEditCloseIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, closeIcon.pixmap(iconSize));
}
}
else
{
// Only show the edit icon on hover.
if (!isHovered)
if (isHovered)
{
return;
QIcon openIcon = QIcon(m_prefabEditOpenIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, openIcon.pixmap(iconSize));
}
QIcon openIcon = QIcon(m_prefabEditOpenIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, openIcon.pixmap(iconSize));
}
painter->restore();
@@ -122,7 +122,7 @@ namespace AzToolsFramework
EditorInteractionSystemViewportSelectionRequestBus::Event(
GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler,
[](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
[](const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
});
@@ -90,6 +90,61 @@ namespace UnitTest
return AZStd::string(keyText.toUtf8().data());
}
bool ViewportSettingsTestImpl::GridSnappingEnabled() const
{
return m_gridSnapping;
}
float ViewportSettingsTestImpl::GridSize() const
{
return m_gridSize;
}
bool ViewportSettingsTestImpl::ShowGrid() const
{
return false;
}
bool ViewportSettingsTestImpl::AngleSnappingEnabled() const
{
return m_angularSnapping;
}
float ViewportSettingsTestImpl::AngleStep() const
{
return m_angularStep;
}
float ViewportSettingsTestImpl::ManipulatorLineBoundWidth() const
{
return 0.1f;
}
float ViewportSettingsTestImpl::ManipulatorCircleBoundWidth() const
{
return 0.1f;
}
bool ViewportSettingsTestImpl::StickySelectEnabled() const
{
return m_stickySelect;
}
bool ViewportSettingsTestImpl::IconsVisible() const
{
return m_iconsVisible;
}
bool ViewportSettingsTestImpl::HelpersVisible() const
{
return m_helpersVisible;
}
AZ::Vector3 ViewportSettingsTestImpl::DefaultEditorCameraPosition() const
{
return {};
}
bool TestWidget::eventFilter(QObject* watched, QEvent* event)
{
AZ_UNUSED(watched);
@@ -91,6 +91,43 @@ namespace UnitTest
/// @param modifiers Optional keyboard modifiers to include during the wheel events, defaults to Qt::NoModifier
AZStd::string QtKeyToAzString(Qt::Key key, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
//! Test implementation of the ViewportSettingsRequestBus.
//! @note Can be used to customize viewport settings during test execution.
class ViewportSettingsTestImpl : public AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler
{
public:
void Connect(const AzFramework::ViewportId viewportId)
{
AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(viewportId);
}
void Disconnect()
{
AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusDisconnect();
}
// ViewportSettingsRequestBus overrides ...
bool GridSnappingEnabled() const override;
float GridSize() const override;
bool ShowGrid() const override;
bool AngleSnappingEnabled() const override;
float AngleStep() const override;
float ManipulatorLineBoundWidth() const override;
float ManipulatorCircleBoundWidth() const override;
bool StickySelectEnabled() const override;
AZ::Vector3 DefaultEditorCameraPosition() const override;
bool IconsVisible() const override;
bool HelpersVisible() const override;
float m_gridSize = 1.0f;
float m_angularStep = 0.0f;
bool m_gridSnapping = false;
bool m_angularSnapping = false;
bool m_stickySelect = true;
bool m_iconsVisible = true;
bool m_helpersVisible = true;
};
/// Test widget to store QActions generated by EditorTransformComponentSelection.
class TestWidget : public QWidget
{
@@ -207,7 +244,7 @@ namespace UnitTest
m_editorActions.Connect();
const auto viewportHandlerBuilder =
[this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[this](const AzToolsFramework::EditorVisibleEntityDataCacheInterface* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
// create the default viewport (handles ComponentMode)
@@ -0,0 +1,27 @@
/*
* 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 <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
#include <gmock/gmock.h>
namespace UnitTest
{
class MockEditorViewportIconDisplayInterface : public AZ::Interface<AzToolsFramework::EditorViewportIconDisplayInterface>::Registrar
{
public:
virtual ~MockEditorViewportIconDisplayInterface() = default;
//! AzToolsFramework::EditorViewportIconDisplayInterface overrides ...
MOCK_METHOD1(DrawIcon, void(const DrawParameters&));
MOCK_METHOD1(GetOrLoadIconForPath, IconId(AZStd::string_view path));
MOCK_METHOD1(GetIconLoadStatus, IconLoadStatus(IconId icon));
};
} // namespace UnitTest
@@ -0,0 +1,37 @@
/*
* 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 <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <gmock/gmock.h>
namespace UnitTest
{
class MockEditorVisibleEntityDataCacheInterface : public AzToolsFramework::EditorVisibleEntityDataCacheInterface
{
using ComponentEntityAccentType = AzToolsFramework::Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
public:
virtual ~MockEditorVisibleEntityDataCacheInterface() = default;
// AzToolsFramework::EditorVisibleEntityDataCacheInterface overrides ...
MOCK_CONST_METHOD0(VisibleEntityDataCount, size_t());
MOCK_CONST_METHOD1(GetVisibleEntityPosition, AZ::Vector3(size_t));
MOCK_CONST_METHOD1(GetVisibleEntityTransform, const AZ::Transform&(size_t));
MOCK_CONST_METHOD1(GetVisibleEntityId, AZ::EntityId(size_t));
MOCK_CONST_METHOD1(GetVisibleEntityAccent, ComponentEntityAccentType(size_t));
MOCK_CONST_METHOD1(IsVisibleEntityLocked, bool(size_t));
MOCK_CONST_METHOD1(IsVisibleEntityVisible, bool(size_t));
MOCK_CONST_METHOD1(IsVisibleEntitySelected, bool(size_t));
MOCK_CONST_METHOD1(IsVisibleEntityIconHidden, bool(size_t));
MOCK_CONST_METHOD1(IsVisibleEntityIndividuallySelectableInViewport, bool(size_t));
MOCK_CONST_METHOD1(GetVisibleEntityIndexFromId, AZStd::optional<size_t>(AZ::EntityId entityId));
};
} // namespace UnitTest
@@ -0,0 +1,29 @@
/*
* 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 <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <gmock/gmock.h>
namespace UnitTest
{
class MockFocusModeInterface : public AZ::Interface<AzToolsFramework::FocusModeInterface>::Registrar
{
public:
virtual ~MockFocusModeInterface() = default;
// AzToolsFramework::FocusModeInterface overrides ...
MOCK_METHOD1(SetFocusRoot, void(AZ::EntityId entityId));
MOCK_METHOD1(ClearFocusRoot, void(AzFramework::EntityContextId entityContextId));
MOCK_METHOD1(GetFocusRoot, AZ::EntityId(AzFramework::EntityContextId entityContextId));
MOCK_METHOD1(GetFocusedEntities, AzToolsFramework::EntityIdList(AzFramework::EntityContextId entityContextId));
MOCK_CONST_METHOD1(IsInFocusSubTree, bool(AZ::EntityId entityId));
};
} // namespace UnitTest
@@ -21,9 +21,8 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0)
EditorDefaultSelection::EditorDefaultSelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
: m_phantomWidget(nullptr)
, m_entityDataCache(entityDataCache)
, m_viewportEditorModeTracker(viewportEditorModeTracker)
, m_componentModeCollection(viewportEditorModeTracker)
{
@@ -27,7 +27,8 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_DECL
//! @cond
EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
EditorDefaultSelection(
const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
EditorDefaultSelection(const EditorDefaultSelection&) = delete;
EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete;
virtual ~EditorDefaultSelection();
@@ -85,10 +86,8 @@ namespace AzToolsFramework
QWidget m_phantomWidget; //!< The phantom widget responsible for holding QActions while in ComponentMode.
QWidget* m_phantomOverrideWidget = nullptr; //!< It's possible to override the phantom widget in special circumstances (eg testing).
ComponentModeFramework::ComponentModeCollection m_componentModeCollection; //!< Handles all active ComponentMode types.
AZStd::unique_ptr<EditorTransformComponentSelection> m_transformComponentSelection =
nullptr; //!< Viewport selection (responsible for
//!< manipulators and transform modifications).
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Reference to cached visible EntityData.
//! Viewport selection (responsible for manipulators and transform modifications).
AZStd::unique_ptr<EditorTransformComponentSelection> m_transformComponentSelection = nullptr;
//! Mapping between passed ActionOverride (AddActionOverride) and allocated QAction.
struct ActionOverrideMapping
@@ -112,7 +111,7 @@ namespace AzToolsFramework
AZStd::shared_ptr<AzToolsFramework::ManipulatorManager> m_manipulatorManager; //!< The default manipulator manager.
ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes.
//! Tracker for activating/deactivating viewport editor modes.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr;
};
} // namespace AzToolsFramework
@@ -159,7 +159,7 @@ namespace AzToolsFramework
return false;
}
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCacheInterface* entityDataCache)
: m_entityDataCache(entityDataCache)
{
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
@@ -344,9 +344,19 @@ namespace AzToolsFramework
continue;
}
int iconTextureId = 0;
EditorEntityIconComponentRequestBus::EventResult(
iconTextureId, entityId, &EditorEntityIconComponentRequests::GetEntityIconTextureId);
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
const AZ::Vector3 entityCameraVector = entityPosition - cameraState.m_position;
if (const float directionFromCamera = entityCameraVector.Dot(cameraState.m_forward); directionFromCamera < 0.0f)
{
continue;
}
const float distanceFromCamera = entityCameraVector.GetLength();
if (distanceFromCamera < cameraState.m_nearClip)
{
continue;
}
using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
const AZ::Color iconHighlight = [this, entityCacheIndex]()
@@ -364,13 +374,13 @@ namespace AzToolsFramework
return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
}();
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
const float distanceFromCamera = cameraState.m_position.GetDistance(entityPosition);
const float iconSize = GetIconSize(distanceFromCamera);
int iconTextureId = 0;
EditorEntityIconComponentRequestBus::EventResult(
iconTextureId, entityId, &EditorEntityIconComponentRequestBus::Events::GetEntityIconTextureId);
editorViewportIconDisplay->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition,
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace,
AZ::Vector2{ iconSize, iconSize } });
editorViewportIconDisplay->DrawIcon(EditorViewportIconDisplayInterface::DrawParameters{
viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition,
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace, AZ::Vector2(GetIconSize(distanceFromCamera)) });
}
}
}
@@ -24,7 +24,7 @@ namespace AzFramework
namespace AzToolsFramework
{
class EditorVisibleEntityDataCache;
class EditorVisibleEntityDataCacheInterface;
class FocusModeInterface;
namespace ViewportInteraction
@@ -64,7 +64,7 @@ namespace AzToolsFramework
//! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to
//! efficiently read entity data without resorting to EBus calls.
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache);
explicit EditorHelpers(const EditorVisibleEntityDataCacheInterface* entityDataCache);
EditorHelpers(const EditorHelpers&) = delete;
EditorHelpers& operator=(const EditorHelpers&) = delete;
~EditorHelpers() = default;
@@ -103,7 +103,7 @@ namespace AzToolsFramework
AZStd::unique_ptr<InvalidClicks> m_invalidClicks; //!< Display for invalid click behavior.
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
const EditorVisibleEntityDataCacheInterface* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality.
};
@@ -84,7 +84,7 @@ namespace AzToolsFramework
void EditorInteractionSystemComponent::SetDefaultHandler()
{
SetHandler(
[](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
[](const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<EditorDefaultSelection>(entityDataCache, viewportEditorModeTracker);
});
@@ -16,7 +16,7 @@
namespace AzToolsFramework
{
class EditorVisibleEntityDataCache;
class EditorVisibleEntityDataCacheInterface;
class ViewportEditorModeTrackerInterface;
//! Bus to handle all mouse events originating from the viewport.
@@ -34,7 +34,7 @@ namespace AzToolsFramework
//! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface.
using ViewportSelectionRequestsBuilderFn = AZStd::function<AZStd::unique_ptr<ViewportInteraction::InternalViewportSelectionRequests>(
const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>;
const EditorVisibleEntityDataCacheInterface*, ViewportEditorModeTrackerInterface*)>;
//! Interface for system component implementing the ViewportSelectionRequests interface.
//! This interface also includes a setter to set a custom handler also implementing
@@ -17,7 +17,7 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0)
EditorPickEntitySelection::EditorPickEntitySelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
: m_editorHelpers(AZStd::make_unique<EditorHelpers>(entityDataCache))
, m_viewportEditorModeTracker(viewportEditorModeTracker)
{
@@ -13,6 +13,7 @@
namespace AzToolsFramework
{
class EditorVisibleEntityDataCacheInterface;
class ViewportEditorModeTrackerInterface;
//! Viewport interaction that will handle assigning an entity in the viewport to
@@ -23,7 +24,7 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_DECL
EditorPickEntitySelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
const EditorVisibleEntityDataCacheInterface* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
~EditorPickEntitySelection();
private:
@@ -35,6 +36,7 @@ namespace AzToolsFramework
AZStd::unique_ptr<EditorHelpers> m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc).
AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any).
AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes.
//! Tracker for activating/deactivating viewport editor modes.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr;
};
} // namespace AzToolsFramework
@@ -381,7 +381,7 @@ namespace AzToolsFramework
EntityIdContainer& selectedEntityIdsBeforeBoxSelect,
EntityIdContainer& potentialSelectedEntityIds,
EntityIdContainer& potentialDeselectedEntityIds,
const EditorVisibleEntityDataCache& entityDataCache,
const EditorVisibleEntityDataCacheInterface& entityDataCache,
const int viewportId,
const ViewportInteraction::KeyboardModifiers currentKeyboardModifiers,
const ViewportInteraction::KeyboardModifiers& previousKeyboardModifiers)
@@ -958,7 +958,7 @@ namespace AzToolsFramework
// (useful in the context of drawing when we only care about entities we can see)
// note: return the index if it is selectable, nullopt otherwise
static AZStd::optional<size_t> SelectableInVisibleViewportCache(
const EditorVisibleEntityDataCache& entityDataCache, const AZ::EntityId entityId)
const EditorVisibleEntityDataCacheInterface& entityDataCache, const AZ::EntityId entityId)
{
if (auto entityIndex = entityDataCache.GetVisibleEntityIndexFromId(entityId))
{
@@ -1002,7 +1002,7 @@ namespace AzToolsFramework
}
}
EditorTransformComponentSelection::EditorTransformComponentSelection(const EditorVisibleEntityDataCache* entityDataCache)
EditorTransformComponentSelection::EditorTransformComponentSelection(const EditorVisibleEntityDataCacheInterface* entityDataCache)
: m_entityDataCache(entityDataCache)
{
const AzFramework::EntityContextId entityContextId = GetEntityContextId();
@@ -34,7 +34,7 @@
namespace AzToolsFramework
{
class EditorVisibleEntityDataCache;
class EditorVisibleEntityDataCacheInterface;
using EntityIdSet = AZStd::unordered_set<AZ::EntityId>; //!< Alias for unordered_set of EntityIds.
@@ -167,7 +167,7 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_DECL
EditorTransformComponentSelection() = default;
explicit EditorTransformComponentSelection(const EditorVisibleEntityDataCache* entityDataCache);
explicit EditorTransformComponentSelection(const EditorVisibleEntityDataCacheInterface* entityDataCache);
EditorTransformComponentSelection(const EditorTransformComponentSelection&) = delete;
EditorTransformComponentSelection& operator=(const EditorTransformComponentSelection&) = delete;
virtual ~EditorTransformComponentSelection();
@@ -325,10 +325,8 @@ namespace AzToolsFramework
AZ::EntityId m_currentEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display.
AZ::EntityId m_editorCameraComponentEntityId; //!< The EditorCameraComponent EntityId if it is set.
EntityIdSet m_selectedEntityIds; //!< Represents the current entities in the selection.
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< A cache of packed EntityData that can be
//!< iterated over efficiently without the need
//!< to make individual EBus calls.
//! A cache of packed EntityData that can be iterated over efficiently without the need to make individual EBus calls.
const EditorVisibleEntityDataCacheInterface* m_entityDataCache = nullptr;
AZStd::unique_ptr<EditorHelpers> m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc).
EntityIdManipulators m_entityIdManipulators; //!< Mapping from a Manipulator to potentially many EntityIds.
@@ -20,10 +20,36 @@
namespace AzToolsFramework
{
//! Read-only interface for EditorVisibleEntityDataCache to be used by systems that want to efficiently
//! query the state of visible entities in the viewport.
class EditorVisibleEntityDataCacheInterface
{
using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
public:
virtual ~EditorVisibleEntityDataCacheInterface() = default;
virtual size_t VisibleEntityDataCount() const = 0;
virtual AZ::Vector3 GetVisibleEntityPosition(size_t index) const = 0;
virtual const AZ::Transform& GetVisibleEntityTransform(size_t index) const = 0;
virtual AZ::EntityId GetVisibleEntityId(size_t index) const = 0;
virtual ComponentEntityAccentType GetVisibleEntityAccent(size_t index) const = 0;
virtual bool IsVisibleEntityLocked(size_t index) const = 0;
virtual bool IsVisibleEntityVisible(size_t index) const = 0;
virtual bool IsVisibleEntitySelected(size_t index) const = 0;
virtual bool IsVisibleEntityIconHidden(size_t index) const = 0;
//! Returns true if the entity is individually selectable (none of its ancestors are a closed container entity).
//! @note It may still be desirable to be able to 'click' an entity that is a descendant of a closed container
//! to select the container itself, not the individual entity.
virtual bool IsVisibleEntityIndividuallySelectableInViewport(size_t index) const = 0;
virtual AZStd::optional<size_t> GetVisibleEntityIndexFromId(AZ::EntityId entityId) const = 0;
};
//! A cache of packed EntityData that can be iterated over efficiently without
//! the need to make individual EBus calls
class EditorVisibleEntityDataCache
: private EditorEntityVisibilityNotificationBus::Router
: public EditorVisibleEntityDataCacheInterface
, private EditorEntityVisibilityNotificationBus::Router
, private EditorEntityLockComponentNotificationBus::Router
, private AZ::TransformNotificationBus::Router
, private EditorComponentSelectionNotificationsBus::Router
@@ -45,22 +71,18 @@ namespace AzToolsFramework
void CalculateVisibleEntityDatas(const AzFramework::ViewportInfo& viewportInfo);
//! EditorVisibleEntityDataCache interface
size_t VisibleEntityDataCount() const;
AZ::Vector3 GetVisibleEntityPosition(size_t index) const;
const AZ::Transform& GetVisibleEntityTransform(size_t index) const;
AZ::EntityId GetVisibleEntityId(size_t index) const;
ComponentEntityAccentType GetVisibleEntityAccent(size_t index) const;
bool IsVisibleEntityLocked(size_t index) const;
bool IsVisibleEntityVisible(size_t index) const;
bool IsVisibleEntitySelected(size_t index) const;
bool IsVisibleEntityIconHidden(size_t index) const;
//! Returns true if the entity is individually selectable (none of its ancestors are a closed container entity).
//! @note It may still be desirable to be able to 'click' an entity that is a descendant of a closed container
//! to select the container itself, not the individual entity.
bool IsVisibleEntityIndividuallySelectableInViewport(size_t index) const;
AZStd::optional<size_t> GetVisibleEntityIndexFromId(AZ::EntityId entityId) const;
//! EditorVisibleEntityDataCacheInterface overrides ...
size_t VisibleEntityDataCount() const override;
AZ::Vector3 GetVisibleEntityPosition(size_t index) const override;
const AZ::Transform& GetVisibleEntityTransform(size_t index) const override;
AZ::EntityId GetVisibleEntityId(size_t index) const override;
ComponentEntityAccentType GetVisibleEntityAccent(size_t index) const override;
bool IsVisibleEntityLocked(size_t index) const override;
bool IsVisibleEntityVisible(size_t index) const override;
bool IsVisibleEntitySelected(size_t index) const override;
bool IsVisibleEntityIconHidden(size_t index) const override;
bool IsVisibleEntityIndividuallySelectableInViewport(size_t index) const override;
AZStd::optional<size_t> GetVisibleEntityIndexFromId(AZ::EntityId entityId) const override;
void AddEntityIds(const EntityIdList& entityIds);
@@ -9,6 +9,9 @@
set(FILES
UnitTest/AzToolsFrameworkTestHelpers.cpp
UnitTest/AzToolsFrameworkTestHelpers.h
UnitTest/Mocks/MockFocusModeInterface.h
UnitTest/Mocks/MockEditorVisibleEntityDataCacheInterface.h
UnitTest/Mocks/MockEditorViewportIconDisplayInterface.h
UnitTest/ToolsTestApplication.cpp
UnitTest/ToolsTestApplication.h
)
@@ -265,7 +265,7 @@ namespace UnitTest
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[](const AzToolsFramework::EditorVisibleEntityDataCacheInterface* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
@@ -0,0 +1,116 @@
/*
* 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 <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/UnitTest/TestDebugDisplayRequests.h>
#include <AzFramework/Viewport/CameraState.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/UnitTest/Mocks/MockEditorViewportIconDisplayInterface.h>
#include <AzToolsFramework/UnitTest/Mocks/MockEditorVisibleEntityDataCacheInterface.h>
#include <AzToolsFramework/UnitTest/Mocks/MockFocusModeInterface.h>
#include <AzToolsFramework/ViewportSelection/EditorHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
namespace UnitTest
{
class EditorViewportIconFixture : public AllocatorsTestFixture
{
public:
inline static constexpr AzFramework::ViewportId TestViewportId = 2468;
void SetUp() override
{
AllocatorsTestFixture::SetUp();
m_focusModeMock = AZStd::make_unique<::testing::NiceMock<MockFocusModeInterface>>();
m_editorViewportIconDisplayMock = AZStd::make_unique<::testing::NiceMock<MockEditorViewportIconDisplayInterface>>();
m_entityVisibleEntityDataCacheMock = AZStd::make_unique<::testing::NiceMock<MockEditorVisibleEntityDataCacheInterface>>();
m_editorHelpers = AZStd::make_unique<AzToolsFramework::EditorHelpers>(m_entityVisibleEntityDataCacheMock.get());
m_viewportSettings = AZStd::make_unique<ViewportSettingsTestImpl>();
m_viewportSettings->Connect(TestViewportId);
m_viewportSettings->m_helpersVisible = false;
m_viewportSettings->m_iconsVisible = true;
m_cameraState = AzFramework::CreateDefaultCamera(AZ::Transform::CreateIdentity(), AZ::Vector2(1024.0f, 768.0f));
using ::testing::_;
using ::testing::Return;
ON_CALL(*m_entityVisibleEntityDataCacheMock, VisibleEntityDataCount()).WillByDefault(Return(1));
ON_CALL(*m_entityVisibleEntityDataCacheMock, GetVisibleEntityId(_)).WillByDefault(Return(AZ::EntityId()));
ON_CALL(*m_entityVisibleEntityDataCacheMock, IsVisibleEntityIconHidden(_)).WillByDefault(Return(false));
ON_CALL(*m_entityVisibleEntityDataCacheMock, IsVisibleEntityVisible(_)).WillByDefault(Return(true));
ON_CALL(*m_focusModeMock, IsInFocusSubTree(_)).WillByDefault(Return(true));
}
void TearDown() override
{
m_viewportSettings->Disconnect();
m_viewportSettings.reset();
m_editorHelpers.reset();
m_entityVisibleEntityDataCacheMock.reset();
m_editorViewportIconDisplayMock.reset();
m_focusModeMock.reset();
AllocatorsTestFixture::TearDown();
}
AZStd::unique_ptr<ViewportSettingsTestImpl> m_viewportSettings;
AZStd::unique_ptr<AzToolsFramework::EditorHelpers> m_editorHelpers;
AZStd::unique_ptr<::testing::NiceMock<MockFocusModeInterface>> m_focusModeMock;
AZStd::unique_ptr<::testing::NiceMock<MockEditorVisibleEntityDataCacheInterface>> m_entityVisibleEntityDataCacheMock;
AZStd::unique_ptr<::testing::NiceMock<MockEditorViewportIconDisplayInterface>> m_editorViewportIconDisplayMock;
AzFramework::CameraState m_cameraState;
};
TEST_F(EditorViewportIconFixture, ViewportIconsAreNotDisplayedWhenInBetweenCameraAndNearClipPlane)
{
NullDebugDisplayRequests nullDebugDisplayRequests;
const auto insideNearClip = m_cameraState.m_nearClip * 0.5f;
using ::testing::_;
using ::testing::Return;
// given
// entity position (where icon will be drawn) is in between near clip plane and camera position
ON_CALL(*m_entityVisibleEntityDataCacheMock, GetVisibleEntityPosition(_))
.WillByDefault(Return(AZ::Vector3(0.0f, insideNearClip, 0.0f)));
EXPECT_CALL(*m_editorViewportIconDisplayMock, DrawIcon(_)).Times(0);
// when
m_editorHelpers->DisplayHelpers(
AzFramework::ViewportInfo{ TestViewportId }, m_cameraState, nullDebugDisplayRequests,
[](AZ::EntityId)
{
return true;
});
}
TEST_F(EditorViewportIconFixture, ViewportIconsAreNotDisplayedWhenBehindCamera)
{
NullDebugDisplayRequests nullDebugDisplayRequests;
using ::testing::_;
using ::testing::Return;
// given
// entity position (where icon will be drawn) behind the camera position
ON_CALL(*m_entityVisibleEntityDataCacheMock, GetVisibleEntityPosition(_)).WillByDefault(Return(AZ::Vector3(0.0f, -1.0f, 0.0f)));
EXPECT_CALL(*m_editorViewportIconDisplayMock, DrawIcon(_)).Times(0);
// when
m_editorHelpers->DisplayHelpers(
AzFramework::ViewportInfo{ TestViewportId }, m_cameraState, nullDebugDisplayRequests,
[](AZ::EntityId)
{
return true;
});
}
} // namespace UnitTest
@@ -41,6 +41,11 @@ namespace UnitTest
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
AzToolsFramework::EntityList{ m_entityMap[Passenger1EntityName], m_entityMap[Passenger2EntityName], m_entityMap[CityEntityName] });
// Initialize Prefab EOS Interface
AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
ASSERT_TRUE(prefabEditorEntityOwnershipInterface);
// Create a car prefab from the passenger1 entity. The container entity will be created as part of the process.
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> carInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger1EntityName] }, {}, "test/car");
@@ -59,11 +64,14 @@ namespace UnitTest
ASSERT_TRUE(streetInstance);
m_instanceMap[StreetEntityName] = streetInstance.get();
// Create a city prefab that nests the street instances created above and the city entity. The container entity will be created as part of the process.
m_rootInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap[CityEntityName] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city");
ASSERT_TRUE(m_rootInstance);
m_instanceMap[CityEntityName] = m_rootInstance.get();
// Use the Prefab EOS root instance as the City instance. This will ensure functions that go through the EOS work in these tests too.
m_rootInstance = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
ASSERT_TRUE(m_rootInstance.has_value());
m_rootInstance->get().AddEntity(*m_entityMap[CityEntityName]);
m_rootInstance->get().AddInstance(AZStd::move(streetInstance));
m_instanceMap[CityEntityName] = &m_rootInstance->get();
}
void SetUpEditorFixtureImpl() override
@@ -84,7 +92,7 @@ namespace UnitTest
void TearDownEditorFixtureImpl() override
{
m_rootInstance.release();
m_rootInstance->get().Reset();
PrefabTestFixture::TearDownEditorFixtureImpl();
}
@@ -92,7 +100,7 @@ namespace UnitTest
AZStd::unordered_map<AZStd::string, AZ::Entity*> m_entityMap;
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_rootInstance;
InstanceOptionalReference m_rootInstance;
PrefabFocusInterface* m_prefabFocusInterface = nullptr;
PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
@@ -106,9 +114,7 @@ namespace UnitTest
inline static const char* Passenger2EntityName = "Passenger2";
};
// Test was disabled because the implementation of GetFocusedPrefabInstance now relies on the Prefab EOS,
// which is not used by our test environment. This can be restored once Instance handles are implemented.
TEST_F(PrefabFocusTests, DISABLED_PrefabFocus_FocusOnOwningPrefab_RootContainer)
TEST_F(PrefabFocusTests, FocusOnOwningPrefabRootContainer)
{
// Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
{
@@ -123,9 +129,7 @@ namespace UnitTest
}
}
// Test was disabled because the implementation of GetFocusedPrefabInstance now relies on the Prefab EOS,
// which is not used by our test environment. This can be restored once Instance handles are implemented.
TEST_F(PrefabFocusTests, DISABLED_PrefabFocus_FocusOnOwningPrefab_RootEntity)
TEST_F(PrefabFocusTests, FocusOnOwningPrefabRootEntity)
{
// Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
{
@@ -140,7 +144,7 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedContainer)
TEST_F(PrefabFocusTests, FocusOnOwningPrefabNestedContainer)
{
// Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
{
@@ -154,7 +158,7 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedEntity)
TEST_F(PrefabFocusTests, FocusOnOwningPrefabNestedEntity)
{
// Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
{
@@ -168,7 +172,7 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_Clear)
TEST_F(PrefabFocusTests, FocusOnOwningPrefabClear)
{
// Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
{
@@ -188,7 +192,32 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Content)
TEST_F(PrefabFocusTests, FocusOnParentOfFocusedPrefabLeaf)
{
// Call FocusOnParentOfFocusedPrefab on a leaf instance and verify the parent is focused correctly.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId());
m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(m_editorEntityContextId);
EXPECT_EQ(
&m_prefabFocusInterface->GetFocusedPrefabInstance(m_editorEntityContextId)->get(),
m_instanceMap[StreetEntityName]
);
}
}
TEST_F(PrefabFocusTests, FocusOnParentOfFocusedPrefabRoot)
{
// Call FocusOnParentOfFocusedPrefab on the root instance and verify the operation fails.
{
m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId());
auto outcome = m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(m_editorEntityContextId);
EXPECT_FALSE(outcome.IsSuccess());
}
}
TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedContent)
{
// Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
{
@@ -199,7 +228,7 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_AncestorsDescendants)
TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedAncestorsDescendants)
{
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
{
@@ -213,7 +242,7 @@ namespace UnitTest
}
}
TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Siblings)
TEST_F(PrefabFocusTests, IsOwningPrefabBeingFocusedSiblings)
{
// Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
{
@@ -573,7 +573,7 @@ namespace UnitTest
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[](const AzToolsFramework::EditorVisibleEntityDataCacheInterface* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
@@ -591,7 +591,7 @@ namespace UnitTest
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[](const AzToolsFramework::EditorVisibleEntityDataCacheInterface* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
@@ -599,7 +599,7 @@ namespace UnitTest
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[](const AzToolsFramework::EditorVisibleEntityDataCacheInterface* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorDefaultSelection>(entityDataCache, viewportEditorModeTracker);
@@ -24,6 +24,7 @@ set(FILES
ComponentModeTests.cpp
EditorTransformComponentSelectionTests.cpp
EditorVertexSelectionTests.cpp
EditorViewportIconTests.cpp
Entity/EditorEntityContextComponentTests.cpp
Entity/EditorEntityHelpersTests.cpp
Entity/EditorEntitySearchComponentTests.cpp