Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into mnaumov/2372
This commit is contained in:
@@ -600,8 +600,8 @@ namespace AzToolsFramework
|
||||
* Open 3D Engine Internal use only.
|
||||
*
|
||||
* Run a specific redo command separate from the undo/redo system.
|
||||
* In many cases before a modifcation on an entity takes place, it is first packaged into
|
||||
* undo/redo commands. Running the modification's redo command separete from the undo/redo
|
||||
* In many cases before a modification on an entity takes place, it is first packaged into
|
||||
* undo/redo commands. Running the modification's redo command separate from the undo/redo
|
||||
* system simulates its execution, and avoids some code duplication.
|
||||
*/
|
||||
virtual void RunRedoSeparately(UndoSystem::URSequencePoint* redoCommand) = 0;
|
||||
@@ -841,9 +841,6 @@ namespace AzToolsFramework
|
||||
*/
|
||||
virtual AZStd::string GetComponentIconPath(const AZ::Uuid& /*componentType*/, AZ::Crc32 /*componentIconAttrib*/, AZ::Component* /*component*/) { return AZStd::string(); }
|
||||
|
||||
/// Resource Selector hook, returns a path for a resource.
|
||||
virtual AZStd::string SelectResource(const AZStd::string& /*resourceType*/, const AZStd::string& /*previousValue*/) { return AZStd::string(); }
|
||||
|
||||
/**
|
||||
* Calculate the navigation 2D radius in units of an agent given its Navigation Type Name
|
||||
* @param angentTypeName the name that identifies the agent navigation type
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/RTTI/TypeInfoSimple.h>
|
||||
|
||||
#include <QRect>
|
||||
#include <QKeySequence>
|
||||
|
||||
@@ -1781,5 +1781,4 @@ namespace AzToolsFramework
|
||||
{
|
||||
appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Tool;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/RTTI/TypeInfoSimple.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
+5
-15
@@ -46,7 +46,6 @@ namespace AzToolsFramework
|
||||
|
||||
bool InstanceToTemplatePropagator::GenerateDomForEntity(PrefabDom& generatedEntityDom, const AZ::Entity& entity)
|
||||
{
|
||||
//grab the owning instance so we can use the entityIdMapper in settings
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entity.GetId());
|
||||
|
||||
if (!owningInstance)
|
||||
@@ -54,19 +53,8 @@ namespace AzToolsFramework
|
||||
AZ_Error("Prefab", false, "Entity does not belong to an instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetStoringInstance(owningInstance->get());
|
||||
|
||||
//create settings so that the serialized entity dom undergoes mapping from entity id to entity alias
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
|
||||
//generate PrefabDom using Json serialization system
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Store(
|
||||
generatedEntityDom, generatedEntityDom.GetAllocator(), entity, settings);
|
||||
|
||||
return result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success;
|
||||
return PrefabDomUtils::StoreEntityInPrefabDomFormat(entity, owningInstance->get(), generatedEntityDom);
|
||||
}
|
||||
|
||||
bool InstanceToTemplatePropagator::GenerateDomForInstance(PrefabDom& generatedInstanceDom, const Prefab::Instance& instance)
|
||||
@@ -185,8 +173,10 @@ namespace AzToolsFramework
|
||||
else
|
||||
{
|
||||
AZ_Error(
|
||||
"Prefab", result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip,
|
||||
"Some of the patches are not successfully applied.");
|
||||
"Prefab",
|
||||
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Skipped) &&
|
||||
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip),
|
||||
"Some of the patches were not successfully applied.");
|
||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
|
||||
return true;
|
||||
|
||||
@@ -196,7 +196,8 @@ namespace AzToolsFramework
|
||||
m_sourceTemplateId, m_targetTemplateId);
|
||||
return false;
|
||||
}
|
||||
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip)
|
||||
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip ||
|
||||
applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Skipped)
|
||||
{
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
|
||||
@@ -26,6 +26,30 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace PrefabDomUtils
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
AZ::JsonSerializationResult::ResultCode JsonIssueReporter(AZStd::string& scratchBuffer,
|
||||
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
if (result.GetProcessing() == JSR::Processing::Halted)
|
||||
{
|
||||
scratchBuffer.append(message.begin(), message.end());
|
||||
scratchBuffer.append("\n Reason: ");
|
||||
result.AppendToString(scratchBuffer, path);
|
||||
scratchBuffer.append(".");
|
||||
AZ_Warning("Prefab Serialization", false, "%s", scratchBuffer.c_str());
|
||||
|
||||
scratchBuffer.clear();
|
||||
|
||||
return JSR::ResultCode(result.GetTask(), JSR::Outcomes::Skipped);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
PrefabDomValueReference FindPrefabDomValue(PrefabDomValue& parentValue, const char* valueName)
|
||||
{
|
||||
PrefabDomValue::MemberIterator valueIterator = parentValue.FindMember(valueName);
|
||||
@@ -48,7 +72,7 @@ namespace AzToolsFramework
|
||||
return valueIterator->value;
|
||||
}
|
||||
|
||||
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreInstanceFlags flags)
|
||||
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreFlags flags)
|
||||
{
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetStoringInstance(instance);
|
||||
@@ -59,17 +83,27 @@ namespace AzToolsFramework
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
settings.m_metadata.Add(&entityIdMapper);
|
||||
|
||||
if ((flags & StoreInstanceFlags::StripDefaultValues) != StoreInstanceFlags::StripDefaultValues)
|
||||
if ((flags & StoreFlags::StripDefaultValues) != StoreFlags::StripDefaultValues)
|
||||
{
|
||||
settings.m_keepDefaults = true;
|
||||
}
|
||||
|
||||
if ((flags & StoreInstanceFlags::StoreLinkIds) != StoreInstanceFlags::None)
|
||||
if ((flags & StoreFlags::StoreLinkIds) != StoreFlags::None)
|
||||
{
|
||||
LinkIdMetadata linkIdMetadata;
|
||||
settings.m_metadata.Add(&linkIdMetadata);
|
||||
}
|
||||
|
||||
AZStd::string scratchBuffer;
|
||||
auto issueReportingCallback = [&scratchBuffer]
|
||||
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
{
|
||||
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
|
||||
};
|
||||
|
||||
settings.m_reporting = AZStd::move(issueReportingCallback);
|
||||
|
||||
AZ::JsonSerializationResult::ResultCode result =
|
||||
AZ::JsonSerialization::Store(prefabDom, prefabDom.GetAllocator(), instance, settings);
|
||||
|
||||
@@ -86,7 +120,38 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags)
|
||||
bool StoreEntityInPrefabDomFormat(const AZ::Entity& entity, Instance& owningInstance, PrefabDom& prefabDom, StoreFlags flags)
|
||||
{
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetStoringInstance(owningInstance);
|
||||
|
||||
//create settings so that the serialized entity dom undergoes mapping from entity id to entity alias
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
|
||||
if ((flags & StoreFlags::StripDefaultValues) != StoreFlags::StripDefaultValues)
|
||||
{
|
||||
settings.m_keepDefaults = true;
|
||||
}
|
||||
|
||||
AZStd::string scratchBuffer;
|
||||
auto issueReportingCallback = [&scratchBuffer]
|
||||
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
{
|
||||
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
|
||||
};
|
||||
|
||||
settings.m_reporting = AZStd::move(issueReportingCallback);
|
||||
|
||||
//generate PrefabDom using Json serialization system
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Store(
|
||||
prefabDom, prefabDom.GetAllocator(), entity, settings);
|
||||
|
||||
return result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success;
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(Instance& instance, const PrefabDom& prefabDom, LoadFlags flags)
|
||||
{
|
||||
// When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will
|
||||
// be released and reloaded once the entities are built up again. By suspending asset release temporarily the asset reload
|
||||
@@ -95,7 +160,7 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetLoadingInstance(instance);
|
||||
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
|
||||
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
|
||||
{
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
@@ -125,7 +190,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadInstanceFlags flags)
|
||||
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadFlags flags)
|
||||
{
|
||||
// When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will
|
||||
// be released and reloaded once the entities are built up again. By suspending asset release temporarily the asset reload
|
||||
@@ -134,7 +199,7 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetLoadingInstance(instance);
|
||||
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
|
||||
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
|
||||
{
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
@@ -167,7 +232,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadInstanceFlags flags)
|
||||
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadFlags flags)
|
||||
{
|
||||
// When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will
|
||||
// be released and reloaded once the entities are built up again. By suspending asset release temporarily the asset reload
|
||||
@@ -176,7 +241,7 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetLoadingInstance(instance);
|
||||
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
|
||||
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
|
||||
{
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
@@ -246,15 +311,12 @@ namespace AzToolsFramework
|
||||
AZ::JsonSerializationResult::ResultCode ApplyPatches(
|
||||
PrefabDomValue& prefabDomToApplyPatchesOn, PrefabDom::AllocatorType& allocator, const PrefabDomValue& patches)
|
||||
{
|
||||
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
|
||||
AZStd::string scratchBuffer;
|
||||
auto issueReportingCallback = [&scratchBuffer]
|
||||
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
if (result.GetProcessing() == Processing::Halted)
|
||||
{
|
||||
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
|
||||
}
|
||||
return result;
|
||||
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
|
||||
};
|
||||
|
||||
AZ::JsonApplyPatchSettings applyPatchSettings;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace AzToolsFramework
|
||||
PrefabDomValueReference FindPrefabDomValue(PrefabDomValue& parentValue, const char* valueName);
|
||||
PrefabDomValueConstReference FindPrefabDomValue(const PrefabDomValue& parentValue, const char* valueName);
|
||||
|
||||
enum class StoreInstanceFlags : uint8_t
|
||||
enum class StoreFlags : uint8_t
|
||||
{
|
||||
//! No flags used during the call to LoadInstanceFromPrefabDom.
|
||||
None = 0,
|
||||
@@ -51,7 +51,7 @@ namespace AzToolsFramework
|
||||
//! linkIds to instance dom so any nested prefabs will have linkIds correctly set.
|
||||
StoreLinkIds = 1 << 1
|
||||
};
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(StoreInstanceFlags);
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(StoreFlags);
|
||||
|
||||
/**
|
||||
* Stores a valid Prefab Instance within a Prefab Dom. Useful for generating Templates
|
||||
@@ -60,9 +60,21 @@ namespace AzToolsFramework
|
||||
* @param flags Controls behavior such as whether to store default values
|
||||
* @return bool on whether the operation succeeded
|
||||
*/
|
||||
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreInstanceFlags flags = StoreInstanceFlags::None);
|
||||
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreFlags flags = StoreFlags::None);
|
||||
|
||||
enum class LoadInstanceFlags : uint8_t
|
||||
/**
|
||||
* Stores a valid entity in Prefab Dom format.
|
||||
* @param entity The entity to store
|
||||
* @param owningInstance The instance owning the passed in entity.
|
||||
* Used for contextualizing the entity's place in a Prefab hierarchy.
|
||||
* @param prefabDom The prefabDom that will be used to store the entity data
|
||||
* @param flags controls behavior such as whether to store default values
|
||||
* @return bool on whether the operation succeeded
|
||||
*/
|
||||
bool StoreEntityInPrefabDomFormat(const AZ::Entity& entity, Instance& owningInstance, PrefabDom& prefabDom,
|
||||
StoreFlags flags = StoreFlags::None);
|
||||
|
||||
enum class LoadFlags : uint8_t
|
||||
{
|
||||
//! No flags used during the call to LoadInstanceFromPrefabDom.
|
||||
None = 0,
|
||||
@@ -70,7 +82,7 @@ namespace AzToolsFramework
|
||||
//! unique, e.g. when they are duplicates of live entities, this flag will assign them a random new id.
|
||||
AssignRandomEntityId = 1 << 0
|
||||
};
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(LoadInstanceFlags);
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(LoadFlags);
|
||||
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
@@ -80,7 +92,7 @@ namespace AzToolsFramework
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags = LoadInstanceFlags::None);
|
||||
Instance& instance, const PrefabDom& prefabDom, LoadFlags flags = LoadFlags::None);
|
||||
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
@@ -92,7 +104,7 @@ namespace AzToolsFramework
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets,
|
||||
LoadInstanceFlags flags = LoadInstanceFlags::None);
|
||||
LoadFlags flags = LoadFlags::None);
|
||||
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
@@ -105,7 +117,7 @@ namespace AzToolsFramework
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom,
|
||||
LoadInstanceFlags flags = LoadInstanceFlags::None);
|
||||
LoadFlags flags = LoadFlags::None);
|
||||
|
||||
inline PrefabDomPath GetPrefabDomInstancePath(const char* instanceName)
|
||||
{
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
PrefabDom storedPrefabDom(&loadedTemplateDom->get().GetAllocator());
|
||||
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom, PrefabDomUtils::StoreInstanceFlags::StoreLinkIds))
|
||||
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom, PrefabDomUtils::StoreFlags::StoreLinkIds))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -328,7 +328,7 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabDom storedPrefabDom(&savingTemplateDom->get().GetAllocator());
|
||||
if (!PrefabDomUtils::StoreInstanceInPrefabDom(savingPrefabInstance, storedPrefabDom,
|
||||
PrefabDomUtils::StoreInstanceFlags::StripDefaultValues))
|
||||
PrefabDomUtils::StoreFlags::StripDefaultValues))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace AzToolsFramework
|
||||
m_prefabUndoCache.Destroy();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath)
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
{
|
||||
EntityList inputEntityList, topLevelEntities;
|
||||
AZ::EntityId commonRootEntityId;
|
||||
@@ -73,8 +73,6 @@ namespace AzToolsFramework
|
||||
return findCommonRootOutcome;
|
||||
}
|
||||
|
||||
AZ_Assert(absolutePath.IsAbsolute(), "CreatePrefab requires an absolute path for saving the initial prefab file.");
|
||||
|
||||
InstanceOptionalReference instanceToCreate;
|
||||
{
|
||||
// Initialize Undo Batch object
|
||||
@@ -125,7 +123,7 @@ namespace AzToolsFramework
|
||||
PrefabDom linkPatchesCopy;
|
||||
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
|
||||
nestedInstanceLinkPatchesMap.emplace(nestedInstance, AZStd::move(linkPatchesCopy));
|
||||
|
||||
|
||||
RemoveLink(outInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
|
||||
|
||||
instancePtrs.emplace_back(AZStd::move(outInstance));
|
||||
@@ -139,18 +137,20 @@ namespace AzToolsFramework
|
||||
if (!prefabEditorEntityOwnershipInterface)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
|
||||
"(PrefabEditorEntityOwnershipInterface unavailable)."));
|
||||
"(PrefabEditorEntityOwnershipInterface unavailable)."));
|
||||
}
|
||||
|
||||
// Create the Prefab
|
||||
AZ_Assert(filePath.IsAbsolute(), "CreatePrefabInMemory requires an absolute file path.");
|
||||
|
||||
instanceToCreate = prefabEditorEntityOwnershipInterface->CreatePrefab(
|
||||
entities, AZStd::move(instancePtrs), m_prefabLoaderInterface->GenerateRelativePath(absolutePath),
|
||||
entities, AZStd::move(instancePtrs), m_prefabLoaderInterface->GenerateRelativePath(filePath),
|
||||
commonRootEntityOwningInstance);
|
||||
|
||||
if (!instanceToCreate)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
|
||||
"(A null instance is returned)."));
|
||||
"(A null instance is returned)."));
|
||||
}
|
||||
|
||||
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
@@ -218,7 +218,7 @@ namespace AzToolsFramework
|
||||
linkUpdate.Redo();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Create a link between the templates of the newly created instance and the instance it's being parented under.
|
||||
CreateLink(
|
||||
instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
|
||||
@@ -255,18 +255,35 @@ namespace AzToolsFramework
|
||||
|
||||
// Select Container Entity
|
||||
{
|
||||
auto selectionUndo = aznew SelectionCommand({containerEntityId}, "Select Prefab Container Entity");
|
||||
auto selectionUndo = aznew SelectionCommand({ containerEntityId }, "Select Prefab Container Entity");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
|
||||
}
|
||||
}
|
||||
|
||||
// Save Template to file
|
||||
m_prefabLoaderInterface->SaveTemplateToFile(instanceToCreate->get().GetTemplateId(), absolutePath);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInDisk(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
{
|
||||
auto result = CreatePrefabInMemory(entityIds, filePath);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
// Save Template to file
|
||||
auto relativePath = m_prefabLoaderInterface->GenerateRelativePath(filePath);
|
||||
Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
|
||||
if (!m_prefabLoaderInterface->SaveTemplateToFile(templateId, filePath))
|
||||
{
|
||||
AZStd::string_view filePathString(filePath);
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Could not save the newly created prefab to file path %.*s - internal error ",
|
||||
AZ_STRING_ARG(filePathString)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PrefabDom PrefabPublicHandler::ApplyContainerTransformAndGeneratePatch(AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities)
|
||||
{
|
||||
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
|
||||
@@ -301,7 +318,7 @@ namespace AzToolsFramework
|
||||
return AZStd::move(patch);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
|
||||
InstantiatePrefabResult PrefabPublicHandler::InstantiatePrefab(
|
||||
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
|
||||
{
|
||||
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
@@ -347,6 +364,7 @@ namespace AzToolsFramework
|
||||
relativePath.Native().c_str(), instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()));
|
||||
}
|
||||
|
||||
AZ::EntityId containerEntityId;
|
||||
{
|
||||
// Initialize Undo Batch object
|
||||
ScopedUndoBatch undoBatch("Instantiate Prefab");
|
||||
@@ -367,7 +385,7 @@ namespace AzToolsFramework
|
||||
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
|
||||
|
||||
// Create Link with correct container patches
|
||||
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
containerEntityId = instanceToCreate->get().GetContainerEntityId();
|
||||
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
|
||||
AZ_Assert(containerEntity, "Invalid container entity detected in InstantiatePrefab.");
|
||||
|
||||
@@ -394,7 +412,7 @@ namespace AzToolsFramework
|
||||
&AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
return AZ::Success(containerEntityId);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::FindCommonRootOwningInstance(
|
||||
@@ -1727,6 +1745,7 @@ namespace AzToolsFramework
|
||||
|
||||
AliasPath absoluteInstancePath = commonOwningInstance.GetAbsoluteInstanceAliasPath();
|
||||
absoluteInstancePath.Append(newInstanceAlias);
|
||||
absoluteInstancePath.Append(PrefabDomUtils::ContainerEntityName);
|
||||
|
||||
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath);
|
||||
duplicatedEntityIds.push_back(newEntityId);
|
||||
|
||||
@@ -42,8 +42,11 @@ namespace AzToolsFramework
|
||||
void UnregisterPrefabPublicHandlerInterface();
|
||||
|
||||
// PrefabPublicInterface...
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) override;
|
||||
PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult CreatePrefabInDisk(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
PrefabOperationResult CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
|
||||
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace AzToolsFramework
|
||||
namespace Prefab
|
||||
{
|
||||
typedef AZ::Outcome<void, AZStd::string> PrefabOperationResult;
|
||||
typedef AZ::Outcome<AZ::EntityId, AZStd::string> InstantiatePrefabResult;
|
||||
typedef AZ::Outcome<bool, AZStd::string> PrefabRequestResult;
|
||||
typedef AZ::Outcome<AZ::EntityId, AZStd::string> PrefabEntityResult;
|
||||
|
||||
@@ -39,22 +40,34 @@ namespace AzToolsFramework
|
||||
AZ_RTTI(PrefabPublicInterface, "{931AAE9D-C775-4818-9070-A2DA69489CBE}");
|
||||
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided.
|
||||
* Create a prefab out of the entities provided, at the path provided, and save it in disk immediately.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
* @param entityIds The entities that should form the new prefab (along with their descendants).
|
||||
* @param filePath The absolute path for the new prefab file.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) = 0;
|
||||
virtual PrefabOperationResult CreatePrefabInDisk(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
* @param entityIds The entities that should form the new prefab (along with their descendants).
|
||||
* @param filePath The absolute path for the new prefab file.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
* @param filePath The path to the prefab file to instantiate.
|
||||
* @param parent The entity the prefab should be a child of in the transform hierarchy.
|
||||
* @param position The position in world space the prefab should be instantiated in.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
* @return An outcome object with an entityId of the new prefab's container entity;
|
||||
* on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
|
||||
virtual InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
|
||||
|
||||
/**
|
||||
* Saves changes to prefab to disk.
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
/**
|
||||
* The primary purpose of this bus is to facilitate writing automated tests for prefabs.
|
||||
* It calls PrefabPublicInterface internally to talk to the prefab system.
|
||||
* If you would like to integrate prefabs into your system, please call PrefabPublicInterface
|
||||
* directly for better performance.
|
||||
*/
|
||||
class PrefabPublicRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
using Bus = AZ::EBus<PrefabPublicRequests>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~PrefabPublicRequests() = default;
|
||||
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
*/
|
||||
virtual bool CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
*/
|
||||
virtual AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
|
||||
};
|
||||
|
||||
using PrefabPublicRequestBus = AZ::EBus<PrefabPublicRequests>;
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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/Prefab/PrefabPublicRequestHandler.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
void PrefabPublicRequestHandler::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->EBus<PrefabPublicRequestBus>("PrefabPublicRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab")
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Event("CreatePrefabInMemory", &PrefabPublicRequests::CreatePrefabInMemory)
|
||||
->Event("InstantiatePrefab", &PrefabPublicRequests::InstantiatePrefab)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabPublicRequestHandler::Connect()
|
||||
{
|
||||
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
|
||||
AZ_Assert(m_prefabPublicInterface, "PrefabPublicRequestHandler - Could not retrieve instance of PrefabPublicInterface");
|
||||
|
||||
PrefabPublicRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabPublicRequestHandler::Disconnect()
|
||||
{
|
||||
PrefabPublicRequestBus::Handler::BusDisconnect();
|
||||
|
||||
m_prefabPublicInterface = nullptr;
|
||||
}
|
||||
|
||||
bool PrefabPublicRequestHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath)
|
||||
{
|
||||
auto createPrefabOutcome = m_prefabPublicInterface->CreatePrefabInMemory(entityIds, filePath);
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("CreatePrefabInMemory", false,
|
||||
"Failed to create Prefab on file path '%.*s'. Error message: %s.",
|
||||
AZ_STRING_ARG(filePath),
|
||||
createPrefabOutcome.GetError().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::EntityId PrefabPublicRequestHandler::InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
|
||||
{
|
||||
auto instantiatePrefabOutcome = m_prefabPublicInterface->InstantiatePrefab(filePath, parent, position);
|
||||
if (!instantiatePrefabOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("InstantiatePrefab", false,
|
||||
"Failed to instantiate Prefab on file path '%.*s'. Error message: %s.",
|
||||
AZ_STRING_ARG(filePath),
|
||||
instantiatePrefabOutcome.GetError().c_str());
|
||||
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
return instantiatePrefabOutcome.GetValue();
|
||||
}
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicRequestBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabPublicInterface;
|
||||
|
||||
class PrefabPublicRequestHandler final
|
||||
: public PrefabPublicRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabPublicRequestHandler, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(PrefabPublicRequestHandler, "{83FBDDF9-10BE-4373-B1DC-44B47EE4805C}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
bool CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) override;
|
||||
AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
|
||||
private:
|
||||
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
@@ -35,12 +35,14 @@ namespace AzToolsFramework
|
||||
m_instanceUpdateExecutor.RegisterInstanceUpdateExecutorInterface();
|
||||
m_instanceToTemplatePropagator.RegisterInstanceToTemplateInterface();
|
||||
m_prefabPublicHandler.RegisterPrefabPublicHandlerInterface();
|
||||
m_prefabPublicRequestHandler.Connect();
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
m_prefabPublicRequestHandler.Disconnect();
|
||||
m_prefabPublicHandler.UnregisterPrefabPublicHandlerInterface();
|
||||
m_instanceToTemplatePropagator.UnregisterInstanceToTemplateInterface();
|
||||
m_instanceUpdateExecutor.UnregisterInstanceUpdateExecutorInterface();
|
||||
@@ -54,6 +56,7 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
|
||||
PrefabPublicRequestHandler::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
@@ -62,7 +65,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast<AZ::JsonRegistrationContext*>(context);
|
||||
|
||||
if (jsonRegistration)
|
||||
{
|
||||
jsonRegistration->Serializer<JsonInstanceSerializer>()->HandlesType<Instance>();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoader.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
|
||||
@@ -369,6 +370,9 @@ namespace AzToolsFramework
|
||||
|
||||
// Used for updating Templates when Instances are modified
|
||||
InstanceToTemplatePropagator m_instanceToTemplatePropagator;
|
||||
|
||||
// Handler of the public Prefab requests
|
||||
PrefabPublicRequestHandler m_prefabPublicRequestHandler;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -266,8 +266,8 @@ namespace AzToolsFramework
|
||||
|
||||
AZ_Error(
|
||||
"Prefab",
|
||||
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip ||
|
||||
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
||||
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Skipped) &&
|
||||
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip),
|
||||
"Some of the patches are not successfully applied.");
|
||||
|
||||
//remove the link id placed into the instance
|
||||
|
||||
+1
-1
@@ -513,7 +513,7 @@ exportComponent, prefabProcessorContext);
|
||||
// convert Prefab DOM into Prefab Instance.
|
||||
AZStd::unique_ptr<Instance> instance(aznew Instance());
|
||||
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab,
|
||||
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId))
|
||||
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId))
|
||||
{
|
||||
PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
Instance instance;
|
||||
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom, referencedAssets,
|
||||
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
|
||||
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
|
||||
// going to be used to create clones of the entities.
|
||||
{
|
||||
AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
|
||||
|
||||
+40
-1
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : For listing available script commands with their descriptions
|
||||
|
||||
#include "ScriptHelpDialog.h"
|
||||
@@ -23,6 +22,7 @@
|
||||
|
||||
// AzToolsFramework
|
||||
#include <AzToolsFramework/API/EditorPythonConsoleBus.h> // for EditorPythonConsoleInterface
|
||||
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <AzToolsFramework/PythonTerminal/ui_ScriptHelpDialog.h>
|
||||
@@ -313,6 +313,45 @@ namespace AzToolsFramework
|
||||
connect(ui->tableView, &ScriptTableView::doubleClicked, this, &CScriptHelpDialog::OnDoubleClick);
|
||||
}
|
||||
|
||||
CScriptHelpDialog* CScriptHelpDialog::GetInstance()
|
||||
{
|
||||
static CScriptHelpDialog* pInstance = nullptr;
|
||||
if (!pInstance)
|
||||
{
|
||||
QMainWindow* mainWindow = GetMainWindowOfCurrentApplication();
|
||||
if (!mainWindow)
|
||||
{
|
||||
AZ_Assert(false, "Failed to find MainWindow.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget* parentWidget = mainWindow->window()
|
||||
? mainWindow->window()
|
||||
: mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS.
|
||||
pInstance = new CScriptHelpDialog(parentWidget);
|
||||
}
|
||||
return pInstance;
|
||||
}
|
||||
|
||||
QMainWindow* CScriptHelpDialog::GetMainWindowOfCurrentApplication()
|
||||
{
|
||||
QWidget* mainWindowWidget = nullptr;
|
||||
EditorWindowRequestBus::BroadcastResult(mainWindowWidget, &EditorWindowRequests::GetAppMainWindow);
|
||||
if (QMainWindow* mainWindow = qobject_cast<QMainWindow*>(mainWindowWidget))
|
||||
{
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
for (QWidget* topLevelWidget : qApp->topLevelWidgets())
|
||||
{
|
||||
if (QMainWindow* mainWindow = qobject_cast<QMainWindow*>(topLevelWidget))
|
||||
{
|
||||
return mainWindow;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CScriptHelpDialog::OnDoubleClick(const QModelIndex& index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
||||
@@ -132,43 +132,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static CScriptHelpDialog* GetInstance()
|
||||
{
|
||||
static CScriptHelpDialog* pInstance = nullptr;
|
||||
if (!pInstance)
|
||||
{
|
||||
QMainWindow* mainWindow = GetMainWindowOfCurrentApplication();
|
||||
if (!mainWindow)
|
||||
{
|
||||
AZ_Assert(false, "Failed to find MainWindow.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget* parentWidget = mainWindow->window() ? mainWindow->window() : mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS.
|
||||
pInstance = new CScriptHelpDialog(parentWidget);
|
||||
}
|
||||
return pInstance;
|
||||
}
|
||||
|
||||
static CScriptHelpDialog* GetInstance();
|
||||
private Q_SLOTS:
|
||||
void OnDoubleClick(const QModelIndex&);
|
||||
|
||||
private:
|
||||
static QMainWindow* GetMainWindowOfCurrentApplication()
|
||||
{
|
||||
QMainWindow* mainWindow = nullptr;
|
||||
for (QWidget* w : qApp->topLevelWidgets())
|
||||
{
|
||||
mainWindow = qobject_cast<QMainWindow*>(w);
|
||||
if (mainWindow)
|
||||
{
|
||||
return mainWindow;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
explicit CScriptHelpDialog(QWidget* parent = nullptr);
|
||||
static QMainWindow* GetMainWindowOfCurrentApplication();
|
||||
QScopedPointer<Ui::ScriptDialog> ui;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+6
-78
@@ -27,7 +27,7 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
EntityOutlinerTreeView::EntityOutlinerTreeView(QWidget* pParent)
|
||||
: QTreeView(pParent)
|
||||
: AzQtComponents::StyledTreeView(pParent)
|
||||
, m_queuedMouseEvent(nullptr)
|
||||
, m_draggingUnselectedItem(false)
|
||||
{
|
||||
@@ -144,16 +144,12 @@ namespace AzToolsFramework
|
||||
|
||||
if (!selectionModel()->isSelected(index))
|
||||
{
|
||||
startCustomDrag({ index }, supportedActions);
|
||||
StartCustomDrag({ index }, supportedActions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectionModel()->selectedIndexes().empty())
|
||||
{
|
||||
startCustomDrag(selectionModel()->selectedIndexes(), supportedActions);
|
||||
return;
|
||||
}
|
||||
StyledTreeView::startDrag(supportedActions);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::dragMoveEvent(QDragMoveEvent* event)
|
||||
@@ -243,14 +239,14 @@ namespace AzToolsFramework
|
||||
QTreeView::mousePressEvent(&mousePressedEvent);
|
||||
}
|
||||
|
||||
void EntityOutlinerTreeView::startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
|
||||
void EntityOutlinerTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
|
||||
{
|
||||
m_draggingUnselectedItem = true;
|
||||
|
||||
//sort by container entity depth and order in hierarchy for proper drag image and drop order
|
||||
QModelIndexList indexListSorted = indexList;
|
||||
AZStd::unordered_map<AZ::EntityId, AZStd::list<AZ::u64>> locations;
|
||||
for (auto index : indexListSorted)
|
||||
for (const auto& index : indexListSorted)
|
||||
{
|
||||
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
AzToolsFramework::GetEntityLocationInHierarchy(entityId, locations[entityId]);
|
||||
@@ -263,76 +259,8 @@ namespace AzToolsFramework
|
||||
return AZStd::lexicographical_compare(locationsE1.begin(), locationsE1.end(), locationsE2.begin(), locationsE2.end());
|
||||
});
|
||||
|
||||
//get the data for the unselected item(s)
|
||||
QMimeData* mimeData = model()->mimeData(indexListSorted);
|
||||
if (mimeData)
|
||||
{
|
||||
//initiate drag/drop for the item
|
||||
QDrag* drag = new QDrag(this);
|
||||
drag->setPixmap(QPixmap::fromImage(createDragImage(indexListSorted)));
|
||||
drag->setMimeData(mimeData);
|
||||
Qt::DropAction defDropAction = Qt::IgnoreAction;
|
||||
if (defaultDropAction() != Qt::IgnoreAction && (supportedActions & defaultDropAction()))
|
||||
{
|
||||
defDropAction = defaultDropAction();
|
||||
}
|
||||
else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
|
||||
{
|
||||
defDropAction = Qt::CopyAction;
|
||||
}
|
||||
drag->exec(supportedActions, defDropAction);
|
||||
}
|
||||
StyledTreeView::StartCustomDrag(indexListSorted, supportedActions);
|
||||
}
|
||||
|
||||
QImage EntityOutlinerTreeView::createDragImage(const QModelIndexList& indexList)
|
||||
{
|
||||
//generate a drag image of the item icon and text, normally done internally, and inaccessible
|
||||
QRect rect(0, 0, 0, 0);
|
||||
for (auto index : indexList)
|
||||
{
|
||||
if (index.column() != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QRect itemRect = visualRect(index);
|
||||
rect.setHeight(rect.height() + itemRect.height());
|
||||
rect.setWidth(AZStd::GetMax(rect.width(), itemRect.width()));
|
||||
}
|
||||
|
||||
QImage dragImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
QPainter dragPainter(&dragImage);
|
||||
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
dragPainter.fillRect(dragImage.rect(), Qt::transparent);
|
||||
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
dragPainter.setOpacity(0.35f);
|
||||
dragPainter.fillRect(rect, QColor("#222222"));
|
||||
dragPainter.setOpacity(1.0f);
|
||||
|
||||
int imageY = 0;
|
||||
for (auto index : indexList)
|
||||
{
|
||||
if (index.column() != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QRect itemRect = visualRect(index);
|
||||
dragPainter.drawPixmap(QPoint(0, imageY),
|
||||
model()->data(index, Qt::DecorationRole).value<QIcon>().pixmap(QSize(16, 16)));
|
||||
dragPainter.setPen(
|
||||
model()->data(index, Qt::ForegroundRole).value<QBrush>().color());
|
||||
dragPainter.setFont(
|
||||
font());
|
||||
dragPainter.drawText(QRect(20, imageY, rect.width() - 20, rect.height()),
|
||||
model()->data(index, Qt::DisplayRole).value<QString>());
|
||||
imageY += itemRect.height();
|
||||
}
|
||||
|
||||
dragPainter.end();
|
||||
return dragImage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <UI/Outliner/moc_EntityOutlinerTreeView.cpp>
|
||||
|
||||
+4
-5
@@ -14,7 +14,8 @@
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QEvent>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/TreeView.h>
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
@@ -33,7 +34,7 @@ namespace AzToolsFramework
|
||||
//! allow for dragging and dropping of entities from the outliner into the property editor
|
||||
//! of other entities. If the selection updates instantly, this would never be possible.
|
||||
class EntityOutlinerTreeView
|
||||
: public QTreeView
|
||||
: public AzQtComponents::StyledTreeView
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
@@ -68,9 +69,7 @@ namespace AzToolsFramework
|
||||
|
||||
void processQueuedMousePressedEvent(QMouseEvent* event);
|
||||
|
||||
void startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions);
|
||||
|
||||
QImage createDragImage(const QModelIndexList& indexList);
|
||||
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
|
||||
|
||||
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
|
||||
|
||||
|
||||
+4
-4
@@ -256,11 +256,11 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const
|
||||
{
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(sourceFilePath, parentId, position);
|
||||
auto instantiatePrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(sourceFilePath, parentId, position);
|
||||
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
if (!instantiatePrefabOutcome.IsSuccess())
|
||||
{
|
||||
WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError());
|
||||
WarnUserOfError("Prefab Instantiation Error", instantiatePrefabOutcome.GetError());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, prefabFilePath.data());
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefabInDisk(selectedEntities, prefabFilePath.data());
|
||||
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
|
||||
+936
-181
File diff suppressed because it is too large
Load Diff
+68
-2
@@ -19,6 +19,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
#include <AzToolsFramework/Undo/UndoSystem.h>
|
||||
@@ -110,6 +111,7 @@ namespace AzToolsFramework
|
||||
, public EditorInspectorComponentNotificationBus::MultiHandler
|
||||
, private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, private EditorWindowUIRequestBus::Handler
|
||||
{
|
||||
Q_OBJECT;
|
||||
@@ -117,6 +119,23 @@ namespace AzToolsFramework
|
||||
|
||||
AZ_CLASS_ALLOCATOR(EntityPropertyEditor, AZ::SystemAllocator, 0)
|
||||
|
||||
enum class ReorderState
|
||||
{
|
||||
Inactive, // No row widget reordering operation is in progress.
|
||||
DraggingComponent, // User is dragging a component editor.
|
||||
DraggingRowWidget, // User is dragging a row widget around.
|
||||
UsingMenu, // User has the context menu open and may hover over a move up/down operation.
|
||||
MenuOperationInProgress, // User has selected a move/up down menu item.
|
||||
WaitForRedraw, // Wait for rebuild of RPE.
|
||||
HighlightMovedRow // User has moved a row, highlight the new position.
|
||||
};
|
||||
|
||||
enum class DropArea
|
||||
{
|
||||
Above,
|
||||
Below
|
||||
};
|
||||
|
||||
EntityPropertyEditor(QWidget* pParent = NULL, Qt::WindowFlags flags = Qt::WindowFlags(), bool isLevelEntityEditor = false);
|
||||
virtual ~EntityPropertyEditor();
|
||||
|
||||
@@ -151,6 +170,16 @@ namespace AzToolsFramework
|
||||
bool IsLockedToSpecificEntities() const { return !m_overrideSelectedEntityIds.empty(); }
|
||||
|
||||
static bool AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components, const ComponentFilter& filter);
|
||||
|
||||
ReorderState GetReorderState() const;
|
||||
ComponentEditor* GetEditorForCurrentReorderRowWidget() const;
|
||||
PropertyRowWidget* GetReorderRowWidget() const;
|
||||
PropertyRowWidget* GetReorderDropTarget() const;
|
||||
DropArea GetReorderDropArea() const;
|
||||
QPixmap GetReorderRowWidgetImage() const;
|
||||
float GetMoveIndicatorAlpha() const;
|
||||
PropertyRowWidget* GetRowToHighlight();
|
||||
|
||||
Q_SIGNALS:
|
||||
void SelectedEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name);
|
||||
|
||||
@@ -211,6 +240,9 @@ namespace AzToolsFramework
|
||||
void GetSelectedEntities(EntityIdList& selectedEntityIds) override;
|
||||
void SetNewComponentId(AZ::ComponentId componentId) override;
|
||||
|
||||
// TickBus
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
// EditorWindowRequestBus overrides
|
||||
void SetEditorUiEnabled(bool enable) override;
|
||||
|
||||
@@ -253,6 +285,10 @@ namespace AzToolsFramework
|
||||
void ContextMenuActionPullFieldData(AZ::Component* parentComponent, InstanceDataNode* fieldNode);
|
||||
void ContextMenuActionSetDataFlag(InstanceDataNode* node, AZ::DataPatch::Flag flag, bool additive);
|
||||
|
||||
void GenerateRowWidgetIndexMapToChildIndex(PropertyRowWidget* parent, int destIndex);
|
||||
void ContextMenuActionMoveItemUp(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget);
|
||||
void ContextMenuActionMoveItemDown(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget);
|
||||
|
||||
/// Given an InstanceDataNode, calculate a DataPatch address relative to the entity.
|
||||
/// @return true if successful.
|
||||
bool GetEntityDataPatchAddress(const InstanceDataNode* componentFieldNode, AZ::DataPatch::AddressType& dataPatchAddressOut, AZ::EntityId* entityIdOut = nullptr) const;
|
||||
@@ -341,8 +377,6 @@ namespace AzToolsFramework
|
||||
QAction* m_actionToMoveComponentsBottom = nullptr;
|
||||
QAction* m_resetToSliceAction = nullptr;
|
||||
|
||||
bool m_isShowingContextMenu = false;
|
||||
|
||||
void CreateActions();
|
||||
void UpdateActions();
|
||||
|
||||
@@ -390,6 +424,10 @@ namespace AzToolsFramework
|
||||
void ResetToSlice();
|
||||
|
||||
bool DoesOwnFocus() const;
|
||||
AZ::u32 GetHeightOfRowAndVisibleChildren(const PropertyRowWidget* row) const;
|
||||
QRect GetWidgetAndVisibleChildrenGlobalRect(const PropertyRowWidget* widget) const;
|
||||
PropertyRowWidget* GetRowWidgetAtSameLevelAfter(PropertyRowWidget* widget) const;
|
||||
PropertyRowWidget* GetRowWidgetAtSameLevelBefore(PropertyRowWidget* widget) const;
|
||||
QRect GetWidgetGlobalRect(const QWidget* widget) const;
|
||||
bool DoesIntersectWidget(const QRect& globalRect, const QWidget* widget) const;
|
||||
bool DoesIntersectSelectedComponentEditor(const QRect& globalRect) const;
|
||||
@@ -445,6 +483,8 @@ namespace AzToolsFramework
|
||||
bool HandleSelectionEvents(QObject* object, QEvent* event);
|
||||
bool m_selectionEventAccepted;
|
||||
|
||||
bool HandleMenuEvent(QObject* object, QEvent* event);
|
||||
|
||||
// drag and drop events
|
||||
QRect GetInflatedRectFromPoint(const QPoint& point, int radius) const;
|
||||
bool GetComponentsAtDropEventPosition(QDropEvent* event, AZ::Entity::ComponentArrayType& targetComponents);
|
||||
@@ -458,8 +498,12 @@ namespace AzToolsFramework
|
||||
|
||||
ComponentEditor* GetReorderDropTarget(const QRect& globalRect) const;
|
||||
bool ResetDrag(QMouseEvent* event);
|
||||
bool FindAllowedRowWidgetReorderDropTarget(const QPoint& globalPos);
|
||||
bool UpdateRowWidgetDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData);
|
||||
PropertyRowWidget* FindPropertyRowWidgetAt(QPoint globalPos);
|
||||
bool UpdateDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData);
|
||||
bool StartDrag(QMouseEvent* event);
|
||||
void EndRowWidgetReorder();
|
||||
bool HandleDrop(QDropEvent* event);
|
||||
bool HandleDropForComponentTypes(QDropEvent* event);
|
||||
bool HandleDropForComponentAssets(QDropEvent* event);
|
||||
@@ -468,6 +512,8 @@ namespace AzToolsFramework
|
||||
bool CanDropForComponentTypes(const QMimeData* mimeData) const;
|
||||
bool CanDropForComponentAssets(const QMimeData* mimeData) const;
|
||||
bool CanDropForAssetBrowserEntries(const QMimeData* mimeData) const;
|
||||
void SetRowWidgetHighlighted(PropertyRowWidget* rowWidget);
|
||||
|
||||
AZStd::vector<AZ::s32> ExtractComponentEditorIndicesFromMimeData(const QMimeData* mimeData) const;
|
||||
ComponentEditorVector GetComponentEditorsFromIndices(const AZStd::vector<AZ::s32>& indices) const;
|
||||
ComponentEditor* GetComponentEditorsFromIndex(const AZ::s32 index) const;
|
||||
@@ -559,6 +605,8 @@ namespace AzToolsFramework
|
||||
|
||||
QIcon m_emptyIcon;
|
||||
QIcon m_clearIcon;
|
||||
QIcon m_dragIcon;
|
||||
QCursor m_dragCursor;
|
||||
|
||||
QStandardItem* m_comboItems[StatusItems];
|
||||
EntityIdSet m_overrideSelectedEntityIds;
|
||||
@@ -566,6 +614,19 @@ namespace AzToolsFramework
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
bool m_prefabsAreEnabled = false;
|
||||
|
||||
// Reordering row widgets within the RPE.
|
||||
static constexpr float MoveFadeSeconds = 0.5f;
|
||||
|
||||
ReorderState m_currentReorderState = ReorderState::Inactive;
|
||||
ComponentEditor* m_reorderRowWidgetEditor = nullptr;
|
||||
InstanceDataNode* m_nodeToMove = nullptr;
|
||||
PropertyRowWidget* m_reorderRowWidget = nullptr;
|
||||
PropertyRowWidget* m_reorderDropTarget = nullptr;
|
||||
DropArea m_reorderDropArea = DropArea::Above;
|
||||
QPixmap m_reorderRowImage;
|
||||
float m_moveFadeSecondsRemaining;
|
||||
AZStd::vector<int> m_indexMapOfMovedRow;
|
||||
|
||||
// When m_initiatingPropertyChangeNotification is set to true, it means this EntityPropertyEditor is
|
||||
// broadcasting a change to all listeners about a property change for a given entity. This is needed
|
||||
// so that we don't update the values twice for this inspector
|
||||
@@ -573,6 +634,9 @@ namespace AzToolsFramework
|
||||
void ConnectToEntityBuses(const AZ::EntityId& entityId);
|
||||
void DisconnectFromEntityBuses(const AZ::EntityId& entityId);
|
||||
|
||||
void BeginMoveRowWidgetFade();
|
||||
void HighlightMovedRowWidget();
|
||||
|
||||
//! Stores a component id to be focused on next time the UI updates.
|
||||
AZStd::optional<AZ::ComponentId> m_newComponentId;
|
||||
|
||||
@@ -594,6 +658,8 @@ namespace AzToolsFramework
|
||||
|
||||
bool SelectedEntitiesAreFromSameSourceSliceEntity() const;
|
||||
|
||||
void DragStopped();
|
||||
|
||||
AZ::Entity* GetSelectedEntityById(AZ::EntityId& entityId) const;
|
||||
};
|
||||
|
||||
|
||||
+10
-9
@@ -7,8 +7,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "PropertyAudioCtrl.h"
|
||||
#include "PropertyQTConstants.h"
|
||||
#include <UI/PropertyEditor/PropertyAudioCtrl.h>
|
||||
#include <UI/PropertyEditor/PropertyQTConstants.h>
|
||||
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
@@ -34,7 +34,7 @@ namespace AzToolsFramework
|
||||
: QWidget(parent)
|
||||
, m_browseEdit(nullptr)
|
||||
, m_mainLayout(nullptr)
|
||||
, m_propertyType(AudioPropertyType::Invalid)
|
||||
, m_propertyType(AudioPropertyType::NumTypes)
|
||||
{
|
||||
// create the gui
|
||||
m_mainLayout = new QHBoxLayout();
|
||||
@@ -96,7 +96,7 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != AudioPropertyType::Invalid)
|
||||
if (type != AudioPropertyType::NumTypes)
|
||||
{
|
||||
m_propertyType = type;
|
||||
}
|
||||
@@ -136,10 +136,11 @@ namespace AzToolsFramework
|
||||
|
||||
void AudioControlSelectorWidget::OnOpenAudioControlSelector()
|
||||
{
|
||||
AZStd::string resourceResult;
|
||||
AZStd::string resourceType(GetResourceSelectorNameFromType(m_propertyType));
|
||||
AZStd::string currentValue(m_controlName.toStdString().c_str());
|
||||
EditorRequests::Bus::BroadcastResult(resourceResult, &EditorRequests::Bus::Events::SelectResource, resourceType, currentValue);
|
||||
AZStd::string resourceResult;
|
||||
AudioControlSelectorRequestBus::EventResult(
|
||||
resourceResult, m_propertyType,
|
||||
&AudioControlSelectorRequestBus::Events::SelectResource, currentValue);
|
||||
SetControlName(QString(resourceResult.c_str()));
|
||||
}
|
||||
|
||||
@@ -167,12 +168,12 @@ namespace AzToolsFramework
|
||||
{
|
||||
case AudioPropertyType::Trigger:
|
||||
return { "AudioTrigger" };
|
||||
case AudioPropertyType::Rtpc:
|
||||
return { "AudioRTPC" };
|
||||
case AudioPropertyType::Switch:
|
||||
return { "AudioSwitch" };
|
||||
case AudioPropertyType::SwitchState:
|
||||
return { "AudioSwitchState" };
|
||||
case AudioPropertyType::Rtpc:
|
||||
return { "AudioRTPC" };
|
||||
case AudioPropertyType::Environment:
|
||||
return { "AudioEnvironment" };
|
||||
case AudioPropertyType::Preload:
|
||||
|
||||
+21
@@ -29,6 +29,27 @@ class QMimeData;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//=============================================================================
|
||||
// Audio Control Selector Request Bus
|
||||
// For connecting UI proper
|
||||
//=============================================================================
|
||||
class AudioControlSelectorRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
// EBusTraits
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
using BusIdType = AudioPropertyType;
|
||||
|
||||
virtual AZStd::string SelectResource(AZStd::string_view previousValue)
|
||||
{
|
||||
return previousValue;
|
||||
}
|
||||
};
|
||||
|
||||
using AudioControlSelectorRequestBus = AZ::EBus<AudioControlSelectorRequests>;
|
||||
|
||||
//=============================================================================
|
||||
// Audio Control Selector Widget
|
||||
//=============================================================================
|
||||
|
||||
+5
-5
@@ -18,15 +18,15 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//=========================================================================
|
||||
enum class AudioPropertyType
|
||||
enum class AudioPropertyType : AZ::u32
|
||||
{
|
||||
Invalid = 0,
|
||||
Trigger,
|
||||
Trigger = 0,
|
||||
Rtpc,
|
||||
Switch,
|
||||
SwitchState,
|
||||
Rtpc,
|
||||
Environment,
|
||||
Preload,
|
||||
NumTypes,
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
@@ -40,7 +40,7 @@ namespace AzToolsFramework
|
||||
virtual ~CReflectedVarAudioControl() = default;
|
||||
|
||||
AZStd::string m_controlName;
|
||||
AudioPropertyType m_propertyType = AudioPropertyType::Invalid;
|
||||
AudioPropertyType m_propertyType = AudioPropertyType::NumTypes;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
|
||||
+183
-2
@@ -70,7 +70,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_leftAreaContainer = new QWidget(this);
|
||||
m_middleAreaContainer = new QWidget(this);
|
||||
const int minimumControlWidth = 192;
|
||||
const int minimumControlWidth = 142;
|
||||
m_middleAreaContainer->setMinimumWidth(minimumControlWidth);
|
||||
m_mainLayout->addWidget(m_leftAreaContainer, LabelColumnStretch, Qt::AlignLeft);
|
||||
m_mainLayout->addWidget(m_middleAreaContainer, ValueColumnStretch);
|
||||
@@ -368,10 +368,15 @@ namespace AzToolsFramework
|
||||
delete m_containerAddButton;
|
||||
}
|
||||
|
||||
this->unsetCursor();
|
||||
|
||||
if ((m_parentRow) && (m_parentRow->IsContainerEditable()))
|
||||
{
|
||||
if (!m_elementRemoveButton)
|
||||
{
|
||||
QIcon icon = QIcon(QStringLiteral(":/Cursors/Grab_release.svg"));
|
||||
this->setCursor(QCursor(icon.pixmap(16), 5, 2));
|
||||
|
||||
static QIcon s_iconRemove(QStringLiteral(":/stylesheet/img/UI20/delete-16.svg"));
|
||||
m_elementRemoveButton = new QToolButton(this);
|
||||
m_elementRemoveButton->setAutoRaise(true);
|
||||
@@ -570,7 +575,12 @@ namespace AzToolsFramework
|
||||
AZ_Assert(m_selectionEnabled, "Property is not selectable");
|
||||
m_isSelected = selected;
|
||||
m_nameLabel->setProperty("selected", selected);
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::GetSelected()
|
||||
{
|
||||
return m_isSelected;
|
||||
}
|
||||
|
||||
void PropertyRowWidget::SetSelectionEnabled(bool selectionEnabled)
|
||||
{
|
||||
@@ -1395,6 +1405,21 @@ namespace AzToolsFramework
|
||||
return !m_childrenRows.empty();
|
||||
}
|
||||
|
||||
AZ::u32 PropertyRowWidget::GetChildRowCount() const
|
||||
{
|
||||
return static_cast<AZ::u32>(m_childrenRows.size());
|
||||
}
|
||||
|
||||
PropertyRowWidget* PropertyRowWidget::GetChildRowByIndex(AZ::u32 index) const
|
||||
{
|
||||
if (index >= m_childrenRows.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_childrenRows[index];
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::ShouldPreValidatePropertyChange() const
|
||||
{
|
||||
return (m_changeValidators.size() > 0);
|
||||
@@ -1722,6 +1747,162 @@ namespace AzToolsFramework
|
||||
|
||||
return m_parentRow->CanChildrenBeReordered();
|
||||
}
|
||||
|
||||
int PropertyRowWidget::GetIndexInParent() const
|
||||
{
|
||||
if (!GetParentRow())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (AZ::u32 index = 0; index < GetParentRow()->GetChildRowCount(); index++)
|
||||
{
|
||||
if (GetParentRow()->GetChildrenRows()[index] == this)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanMoveUp() const
|
||||
{
|
||||
if (!CanBeReordered())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this != m_parentRow->GetChildRowByIndex(0);
|
||||
}
|
||||
|
||||
bool PropertyRowWidget::CanMoveDown() const
|
||||
{
|
||||
if (!CanBeReordered())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::u32 numChildrenOfParent = m_parentRow->GetChildRowCount();
|
||||
|
||||
return this != m_parentRow->GetChildRowByIndex(numChildrenOfParent - 1);
|
||||
}
|
||||
|
||||
int PropertyRowWidget::GetContainingEditorFrameWidth()
|
||||
{
|
||||
QWidget* parent = parentWidget();
|
||||
|
||||
// Find the first ancestor that can be cast to a QFrame, this will be the RPE.
|
||||
while (!qobject_cast<QFrame*>(parent))
|
||||
{
|
||||
parent = parent->parentWidget();
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The parent of the RPE is the size we want.
|
||||
parent = parent->parentWidget();
|
||||
|
||||
return parent->rect().width();
|
||||
}
|
||||
|
||||
int PropertyRowWidget::GetHeightOfRowAndVisibleChildren()
|
||||
{
|
||||
int height = rect().height();
|
||||
|
||||
if (!GetChildRowCount() || !IsExpanded())
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
for (auto childRow : GetChildrenRows())
|
||||
{
|
||||
height += childRow->GetHeightOfRowAndVisibleChildren();
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
int PropertyRowWidget::DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos)
|
||||
{
|
||||
// Render our image into the given painter.
|
||||
int ystart = ypos;
|
||||
|
||||
render(&painter, QPoint(xpos, ypos));
|
||||
|
||||
if (!GetChildRowCount() || !IsExpanded())
|
||||
{
|
||||
return rect().height();
|
||||
}
|
||||
|
||||
ypos += rect().height();
|
||||
|
||||
// Recursively draw any children.
|
||||
for (auto childRow : GetChildrenRows())
|
||||
{
|
||||
ypos += childRow->DrawDragImageAndVisibleChildrenInto(painter, xpos, ypos);
|
||||
}
|
||||
|
||||
return ypos - ystart;
|
||||
}
|
||||
|
||||
QPixmap PropertyRowWidget::createDragImage(
|
||||
const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType)
|
||||
{
|
||||
// Make the drag box as wide as the containing editor minus a gap each side for the border.
|
||||
static constexpr int ParentEditorBorderSize = 2;
|
||||
int width = GetContainingEditorFrameWidth() - ParentEditorBorderSize * 2;
|
||||
int height = 0;
|
||||
|
||||
if (imageType == DragImageType::IncludeVisibleChildren)
|
||||
{
|
||||
height = GetHeightOfRowAndVisibleChildren();
|
||||
}
|
||||
else
|
||||
{
|
||||
height = rect().height();
|
||||
}
|
||||
|
||||
const auto dpr = devicePixelRatioF();
|
||||
QPixmap dragImage(width * dpr, height * dpr);
|
||||
dragImage.setDevicePixelRatio(dpr);
|
||||
dragImage.fill(Qt::transparent);
|
||||
|
||||
QRect imageRect = QRect(0, 0, width, height);
|
||||
|
||||
QPainter dragPainter(&dragImage);
|
||||
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
dragPainter.fillRect(imageRect, Qt::transparent);
|
||||
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
dragPainter.setOpacity(alpha);
|
||||
dragPainter.fillRect(imageRect, backgroundColor);
|
||||
|
||||
dragPainter.setOpacity(1.0f);
|
||||
|
||||
int marginWidth = (imageRect.width() - rect().width()) / 2 + ParentEditorBorderSize - 1;
|
||||
|
||||
if (imageType == DragImageType::IncludeVisibleChildren)
|
||||
{
|
||||
DrawDragImageAndVisibleChildrenInto(dragPainter, marginWidth, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
render(&dragPainter, QPoint(marginWidth, 0));
|
||||
}
|
||||
|
||||
QPen pen;
|
||||
pen.setColor(QColor(borderColor));
|
||||
pen.setWidth(1);
|
||||
dragPainter.setPen(pen);
|
||||
dragPainter.drawRect(0, 0, imageRect.width() - 1, imageRect.height() - 1);
|
||||
|
||||
dragPainter.end();
|
||||
|
||||
return dragImage;
|
||||
}
|
||||
}
|
||||
|
||||
#include "UI/PropertyEditor/moc_PropertyRowWidget.cpp"
|
||||
|
||||
+21
@@ -45,6 +45,13 @@ namespace AzToolsFramework
|
||||
Q_PROPERTY(bool appendDefaultLabelToName READ GetAppendDefaultLabelToName WRITE AppendDefaultLabelToName)
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PropertyRowWidget, AZ::SystemAllocator, 0)
|
||||
|
||||
enum class DragImageType
|
||||
{
|
||||
SingleRow,
|
||||
IncludeVisibleChildren
|
||||
};
|
||||
|
||||
PropertyRowWidget(QWidget* pParent);
|
||||
virtual ~PropertyRowWidget();
|
||||
|
||||
@@ -86,6 +93,9 @@ namespace AzToolsFramework
|
||||
bool GetAppendDefaultLabelToName();
|
||||
void AppendDefaultLabelToName(bool doAppend);
|
||||
|
||||
AZ::u32 GetChildRowCount() const;
|
||||
PropertyRowWidget* GetChildRowByIndex(AZ::u32 index) const;
|
||||
|
||||
AZStd::vector<PropertyRowWidget*>& GetChildrenRows() { return m_childrenRows; }
|
||||
bool HasChildRows() const;
|
||||
|
||||
@@ -124,6 +134,7 @@ namespace AzToolsFramework
|
||||
|
||||
void SetSelectionEnabled(bool selectionEnabled);
|
||||
void SetSelected(bool selected);
|
||||
bool GetSelected();
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
@@ -152,9 +163,18 @@ namespace AzToolsFramework
|
||||
bool CanChildrenBeReordered() const;
|
||||
bool CanBeReordered() const;
|
||||
|
||||
int GetIndexInParent() const;
|
||||
bool CanMoveUp() const;
|
||||
bool CanMoveDown() const;
|
||||
|
||||
int GetContainingEditorFrameWidth();
|
||||
QPixmap createDragImage(const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType);
|
||||
protected:
|
||||
int CalculateLabelWidth() const;
|
||||
|
||||
int GetHeightOfRowAndVisibleChildren();
|
||||
int DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos);
|
||||
|
||||
bool IsHidden(InstanceDataNode* node) const;
|
||||
|
||||
struct ChangeNotification;
|
||||
@@ -216,6 +236,7 @@ namespace AzToolsFramework
|
||||
bool m_isMultiSizeContainer = false;
|
||||
bool m_isFixedSizeOrSmartPtrContainer = false;
|
||||
bool m_custom = false;
|
||||
bool m_canChildrenBeReordered = false;
|
||||
|
||||
bool m_isSelected = false;
|
||||
bool m_selectionEnabled = false;
|
||||
|
||||
+220
-4
@@ -19,6 +19,7 @@
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
#include <QtWidgets/QScrollArea>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QPainter>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 'QTextFormat::d': class 'QSharedDataPointer<QTextFormatPrivate>' needs to have dll-interface to be used by clients of class 'QTextFormat'
|
||||
#include <QtWidgets/QInputDialog>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
@@ -1343,7 +1344,7 @@ namespace AzToolsFramework
|
||||
|
||||
// calculate the index/offset of the instance data node in the container
|
||||
// (useful for notifying which element in a vector was modified/removed)
|
||||
static size_t CalculateElementIndexInContainer(
|
||||
static int CalculateElementIndexInContainer(
|
||||
InstanceDataNode* node, void* parentInstanceNode,
|
||||
AZ::SerializeContext::IDataContainer* container, AZStd::vector<void*>& nodeInstancesOut)
|
||||
{
|
||||
@@ -1358,7 +1359,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
size_t elementIndex = 0;
|
||||
int elementIndex = 0;
|
||||
void* elementPtr = nodeInstancesOut.empty() ? nullptr : nodeInstancesOut.front();
|
||||
|
||||
// find the index of the element we are about to remove
|
||||
@@ -1429,7 +1430,7 @@ namespace AzToolsFramework
|
||||
|
||||
// if the element being modified exists in a container, calculate
|
||||
// the index to be passed through to PropertyNotify
|
||||
const auto calculateElementIndex = [](InstanceDataNode* node) -> size_t {
|
||||
const auto calculateElementIndex = [](InstanceDataNode* node) -> int {
|
||||
if (InstanceDataNode* parent = node->GetParent())
|
||||
{
|
||||
if (AZ::SerializeContext::IDataContainer* container = parent->GetClassMetadata()->m_container)
|
||||
@@ -1656,6 +1657,221 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Refresh_EntireTree);
|
||||
}
|
||||
|
||||
InstanceDataNode* ReflectedPropertyEditor::FindContainerNodeForNode(InstanceDataNode* node) const
|
||||
{
|
||||
// Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField.
|
||||
InstanceDataNode* pContainerNode = node->GetParent();
|
||||
if (!pContainerNode)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (pContainerNode && !pContainerNode->GetClassMetadata()->m_container)
|
||||
{
|
||||
pContainerNode = pContainerNode->GetParent();
|
||||
node = node->GetParent();
|
||||
}
|
||||
|
||||
// Check for pContainerNode again, can happen if a node is deleted during operation.
|
||||
if (!pContainerNode)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (IsParentAssociativeContainer(pContainerNode) && IsPairContainer(pContainerNode))
|
||||
{
|
||||
// Go up one more level to the associative container, we'll remove the pair from that container
|
||||
pContainerNode = pContainerNode->GetParent();
|
||||
node = node->GetParent();
|
||||
}
|
||||
|
||||
AZ_Assert(
|
||||
pContainerNode, "Failed to locate parent container for element \"%s\" of type %s.",
|
||||
node->GetElementMetadata() ? node->GetElementMetadata()->m_name : node->GetClassMetadata()->m_name,
|
||||
node->GetClassMetadata()->m_typeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
return pContainerNode;
|
||||
}
|
||||
|
||||
InstanceDataNode* ReflectedPropertyEditor::GetNodeAtIndex(int index)
|
||||
{
|
||||
if (index >= m_impl->m_widgetsInDisplayOrder.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GetNodeFromWidget(m_impl->m_widgetsInDisplayOrder[index]);
|
||||
}
|
||||
|
||||
QSet<PropertyRowWidget*> ReflectedPropertyEditor::GetTopLevelWidgets()
|
||||
{
|
||||
return m_impl->getTopLevelWidgets();
|
||||
}
|
||||
|
||||
void ReflectedPropertyEditor::ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int fromIndex, int toIndex)
|
||||
{
|
||||
auto container = containerNode->GetElementMetadata()
|
||||
? containerNode->GetElementMetadata()->m_genericClassInfo->GetClassData()->m_container
|
||||
: nullptr;
|
||||
|
||||
if (fromIndex == toIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!container || container->GetAssociativeContainerInterface())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Uuid typeId = node->GetClassMetadata()->m_typeId;
|
||||
|
||||
if (m_impl->m_ptrNotify)
|
||||
{
|
||||
m_impl->m_ptrNotify->BeforePropertyModified(containerNode);
|
||||
}
|
||||
|
||||
const AZ::SerializeContext::ClassElement* containerClassElement = container->GetElement(container->GetDefaultElementNameCrc());
|
||||
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
// Backup the item we're moving.
|
||||
void* srcElement = nullptr;
|
||||
void* destElement = nullptr;
|
||||
|
||||
int destIndex = -1;
|
||||
int srcIndex = fromIndex;
|
||||
|
||||
srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex);
|
||||
|
||||
void* tmpBuffer = serializeContext->CloneObject(srcElement, typeId);
|
||||
|
||||
// Shuffle all intervening items up (or down).
|
||||
int indexOffset = (toIndex < fromIndex) ? -1 : 1;
|
||||
|
||||
while (destIndex != toIndex - indexOffset)
|
||||
{
|
||||
destIndex = srcIndex;
|
||||
srcIndex += indexOffset;
|
||||
|
||||
destElement = srcElement;
|
||||
|
||||
srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex);
|
||||
|
||||
serializeContext->CloneObjectInplace(destElement, srcElement, typeId);
|
||||
}
|
||||
|
||||
// Now replace the final element with the one backed up previously.
|
||||
destElement = srcElement;
|
||||
|
||||
serializeContext->CloneObjectInplace(destElement, tmpBuffer, typeId);
|
||||
|
||||
if (m_impl->m_ptrNotify)
|
||||
{
|
||||
m_impl->m_ptrNotify->AfterPropertyModified(containerNode);
|
||||
m_impl->m_ptrNotify->SealUndoStack();
|
||||
}
|
||||
|
||||
// Need to refresh any pinned inspectors as well to keep the container state in sync
|
||||
QueueInvalidation(Refresh_Values);
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
|
||||
}
|
||||
|
||||
void ReflectedPropertyEditor::MoveNodeToIndex(InstanceDataNode* node, int index)
|
||||
{
|
||||
InstanceDataNode* pContainerNode = FindContainerNodeForNode(node);
|
||||
|
||||
if (!pContainerNode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
|
||||
|
||||
AZStd::vector<void*> nodeInstancesOut;
|
||||
const int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
|
||||
ChangeNodeIndex(pContainerNode, node, elementIndex, index);
|
||||
}
|
||||
|
||||
void ReflectedPropertyEditor::MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore)
|
||||
{
|
||||
InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove);
|
||||
InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore);
|
||||
|
||||
if (nodeToMove == nodeToMoveBefore)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Can only move nodes within the same parent.
|
||||
if (pContainerNode != pContainerNodeTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
|
||||
|
||||
AZStd::vector<void*> nodeInstancesOut;
|
||||
int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
nodeInstancesOut.clear();
|
||||
int elementIndexTarget =
|
||||
CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
|
||||
if (elementIndex < elementIndexTarget)
|
||||
{
|
||||
elementIndexTarget -= 1;
|
||||
}
|
||||
|
||||
ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget);
|
||||
}
|
||||
|
||||
void ReflectedPropertyEditor::MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore)
|
||||
{
|
||||
InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove);
|
||||
InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore);
|
||||
|
||||
if (nodeToMove == nodeToMoveBefore)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Can only move nodes within the same parent.
|
||||
if (pContainerNode != pContainerNodeTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
|
||||
|
||||
AZStd::vector<void*> nodeInstancesOut;
|
||||
int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
nodeInstancesOut.clear();
|
||||
int elementIndexTarget =
|
||||
CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
|
||||
if (elementIndex > elementIndexTarget)
|
||||
{
|
||||
elementIndexTarget += 1;
|
||||
}
|
||||
|
||||
ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget);
|
||||
}
|
||||
|
||||
int ReflectedPropertyEditor::GetNodeIndexInContainer(InstanceDataNode* node)
|
||||
{
|
||||
InstanceDataNode* pContainerNode = FindContainerNodeForNode(node);
|
||||
|
||||
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
|
||||
|
||||
AZStd::vector<void*> nodeInstancesOut;
|
||||
int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
|
||||
return elementIndex;
|
||||
}
|
||||
|
||||
void ReflectedPropertyEditor::OnPropertyRowRequestContainerRemoveItem(PropertyRowWidget* widget, InstanceDataNode* node)
|
||||
{
|
||||
// Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField.
|
||||
@@ -1690,7 +1906,7 @@ namespace AzToolsFramework
|
||||
|
||||
// the index of the element being removed
|
||||
AZStd::vector<void*> nodeInstancesOut;
|
||||
const size_t elementIndex = CalculateElementIndexInContainer(
|
||||
const int elementIndex = CalculateElementIndexInContainer(
|
||||
node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
|
||||
|
||||
// pass the context as the last parameter to actually delete the related data.
|
||||
|
||||
+10
@@ -155,9 +155,19 @@ namespace AzToolsFramework
|
||||
using VisibilityCallback = AZStd::function<void(InstanceDataNode* node, NodeDisplayVisibility& visibility, bool& checkChildVisibility)>;
|
||||
void SetVisibilityCallback(VisibilityCallback callback);
|
||||
|
||||
void MoveNodeToIndex(InstanceDataNode* node, int index);
|
||||
void MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore);
|
||||
void MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore);
|
||||
|
||||
int GetNodeIndexInContainer(InstanceDataNode* node);
|
||||
InstanceDataNode* GetNodeAtIndex(int index);
|
||||
QSet<PropertyRowWidget*> GetTopLevelWidgets();
|
||||
signals:
|
||||
void OnExpansionContractionDone();
|
||||
private:
|
||||
InstanceDataNode* FindContainerNodeForNode(InstanceDataNode* node) const;
|
||||
void ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int oldIndex, int newIndex);
|
||||
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
class SerializeContext;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
|
||||
@@ -657,6 +657,9 @@ set(FILES
|
||||
Prefab/PrefabPublicHandler.cpp
|
||||
Prefab/PrefabPublicInterface.h
|
||||
Prefab/PrefabPublicNotificationBus.h
|
||||
Prefab/PrefabPublicRequestBus.h
|
||||
Prefab/PrefabPublicRequestHandler.h
|
||||
Prefab/PrefabPublicRequestHandler.cpp
|
||||
Prefab/PrefabUndo.h
|
||||
Prefab/PrefabUndo.cpp
|
||||
Prefab/PrefabUndoCache.cpp
|
||||
|
||||
Reference in New Issue
Block a user