// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Array.h" #include "Containers/UnrealString.h" #include "CoreMinimal.h" #include "Math/UnrealMathSSE.h" #include "PropertyPath.h" #include "StructUtils/InstancedStruct.h" #include "UObject/Field.h" #include "UObject/UnrealType.h" #include "UObject/WeakFieldPtr.h" class IPropertyHandle; class UClass; class UObject; class UStruct; enum class ESequencerKeyMode; /** * Parameters for determining if a property can be keyed. */ struct SEQUENCER_API FCanKeyPropertyParams { /** * Creates new can key property parameters. * @param InObjectClass the class of the object which has the property to be keyed. * @param InPropertyPath path get from the root object to the property to be keyed. */ FCanKeyPropertyParams(const UClass* InObjectClass, const FPropertyPath& InPropertyPath); /** * Creates new can key property parameters. * @param InObjectClass the class of the object which has the property to be keyed. * @param InPropertyHandle a handle to the property to be keyed. */ FCanKeyPropertyParams(const UClass* InObjectClass, const IPropertyHandle& InPropertyHandle); /** The owner struct */ const UStruct* FindPropertyOwner(const FProperty* ForProperty) const; /** The container from which to find setter functions */ const UStruct* FindPropertyContainer(const FProperty* ForProperty) const; /** The class of the object which has the property to be keyed. */ const UClass* ObjectClass; /** A path of properties to get from the root object to the property to be keyed. */ FPropertyPath PropertyPath; }; /** * Parameters for keying a property. */ struct SEQUENCER_API FKeyPropertyParams { /** * Creates new key property parameters for a manually triggered property change. * @param InObjectsToKey an array of the objects who's property will be keyed. * @param InPropertyPath path get from the root object to the property to be keyed. */ FKeyPropertyParams(TArray InObjectsToKey, const FPropertyPath& InPropertyPath, ESequencerKeyMode InKeyMode); /** * Creates new key property parameters from an actual property change notification with a property handle. * @param InObjectsToKey an array of the objects who's property will be keyed. * @param InPropertyHandle a handle to the property to be keyed. */ FKeyPropertyParams(TArray InObjectsToKey, const IPropertyHandle& InPropertyHandle, ESequencerKeyMode InKeyMode); /** An array of the objects who's property will be keyed. */ const TArray ObjectsToKey; /** A path of properties to get from the root object to the property to be keyed. */ FPropertyPath PropertyPath; /** Keyframing params */ const ESequencerKeyMode KeyMode; }; /** * Parameters for the property changed callback. */ class SEQUENCER_API FPropertyChangedParams { public: FPropertyChangedParams(TArray InObjectsThatChanged, const FPropertyPath& InPropertyPath, const FPropertyPath& InStructPathToKey, ESequencerKeyMode InKeyMode); /** * Gets the value of the property that changed. */ template ValueType GetPropertyValue() const { void* ContainerPtr = ObjectsThatChanged[0]; for (int32 i = 0; i < PropertyPath.GetNumProperties(); i++) { const FPropertyInfo& PropertyInfo = PropertyPath.GetPropertyInfo(i); if (const FProperty* Property = PropertyInfo.Property.Get()) { if (const FArrayProperty* ArrayProp = CastField(Property)) { // Sometimes property paths have the array property twice, first with no array index, // then a second so we skip over this property if that's the case int32 ArrayIndex = FMath::Max(0, PropertyInfo.ArrayIndex); if (PropertyInfo.ArrayIndex == INDEX_NONE && i < PropertyPath.GetNumProperties()-1) { const FPropertyInfo& InnerPropertyInfo = PropertyPath.GetPropertyInfo(i+1); const FProperty* InnerProperty = InnerPropertyInfo.Property.Get(); if (InnerProperty && InnerProperty->GetOwner() == ArrayProp) { ArrayIndex = InnerPropertyInfo.ArrayIndex; ++i; } } FScriptArrayHelper ParentArrayHelper(ArrayProp, ArrayProp->ContainerPtrToValuePtr(ContainerPtr)); if (!ParentArrayHelper.IsValidIndex(ArrayIndex)) { return ValueType(); } ContainerPtr = ParentArrayHelper.GetRawPtr(ArrayIndex); } else if (const FStructProperty* StructProp = CastField(Property)) { if (StructProp->Struct == FInstancedStruct::StaticStruct()) { FInstancedStruct* InstancedStruct = Property->ContainerPtrToValuePtr(ContainerPtr); ContainerPtr = InstancedStruct->GetMutableMemory(); } else { ContainerPtr = Property->ContainerPtrToValuePtr(ContainerPtr); } } else { ContainerPtr = Property->ContainerPtrToValuePtr(ContainerPtr); } } } return GetPropertyValueImpl(ContainerPtr, PropertyPath.GetLeafMostProperty()); } /** Gets the property path as a period seperated string of property names. */ FString GetPropertyPathString() const; /** An array of the objects that changed. */ const TArray ObjectsThatChanged; /** A path of properties to get from the root object to the property to be keyed. */ FPropertyPath PropertyPath; /** Represents the path of an inner property which should be keyed for a struct property. If all inner properties should be keyed, this will be empty. */ FPropertyPath StructPathToKey; /** Keyframing params */ const ESequencerKeyMode KeyMode; private: template static ValueType GetPropertyValueImpl(void* Data, const FPropertyInfo& Info) { return *((ValueType*)Data); } }; template<> SEQUENCER_API bool FPropertyChangedParams::GetPropertyValueImpl(void* Data, const FPropertyInfo& Info); template<> SEQUENCER_API UObject* FPropertyChangedParams::GetPropertyValueImpl(void* Data, const FPropertyInfo& Info);