1383 lines
49 KiB
C++
1383 lines
49 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "PropertyPath.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "EditConditionParser.h"
|
|
|
|
class FCategoryPropertyNode;
|
|
class FComplexPropertyNode;
|
|
class FDetailTreeNode;
|
|
class FEditConditionContext;
|
|
class FEditConditionExpression;
|
|
class FItemPropertyNode;
|
|
class FNotifyHook;
|
|
class FObjectPropertyNode;
|
|
class FPropertyItemValueDataTrackerSlate;
|
|
class FPropertyNode;
|
|
class FPropertyRestriction;
|
|
class FStructurePropertyNode;
|
|
|
|
namespace PropertyEditorPolicy
|
|
{
|
|
class IEditConstPolicy;
|
|
class IArchetypePolicy;
|
|
}
|
|
|
|
DECLARE_LOG_CATEGORY_EXTERN(LogPropertyNode, Log, All);
|
|
|
|
namespace EPropertyNodeFlags
|
|
{
|
|
typedef uint32 Type;
|
|
|
|
inline const Type IsSeen = 1 << 0; /** true if this node can be seen based on current parent expansion. Does not take into account clipping*/
|
|
inline const Type IsSeenDueToFiltering = 1 << 1; /** true if this node has been accepted by the filter*/
|
|
inline const Type IsSeenDueToChildFiltering = 1 << 2; /** true if this node or one of it's children is seen due to filtering. It will then be forced on as well.*/
|
|
inline const Type IsParentSeenDueToFiltering = 1 << 3; /** True if the parent was visible due to filtering*/
|
|
inline const Type IsSeenDueToChildFavorite = 1 << 4; /** True if this node is seen to it having a favorite as a child */
|
|
|
|
inline const Type Expanded = 1 << 5; /** true if this node should display its children*/
|
|
inline const Type CanBeExpanded = 1 << 6; /** true if this node is able to be expanded */
|
|
|
|
inline const Type EditInlineNew = 1 << 7; /** true if the property can be expanded into the property window. */
|
|
|
|
inline const Type SingleSelectOnly = 1 << 8; /** true if only a single object is selected. */
|
|
inline const Type ShowCategories = 1 << 9; /** true if this node should show categories. Different*/
|
|
|
|
inline const Type HasEverBeenExpanded = 1 << 10; /** true if expand has ever been called on this node */
|
|
|
|
inline const Type IsBeingFiltered = 1 << 11; /** true if the node is being filtered. If this is true, seen flags should be checked for visibility. If this is false the node has no filter and is visible */
|
|
|
|
inline const Type IsFavorite = 1 << 12; /** true if this item has been dubbed a favorite by the user */
|
|
|
|
inline const Type NoChildrenDueToCircularReference= 1 << 13; /** true if this node has no children (but normally would) due to circular referencing */
|
|
|
|
inline const Type AutoExpanded = 1 << 14; /** true if this node was autoexpanded due to being filtered */
|
|
inline const Type ShouldShowHiddenProperties = 1 << 15; /** true if this node should all properties not just those with the correct flag(s) to be shown in the editor */
|
|
inline const Type IsAdvanced = 1 << 16; /** true if the property node is advanced (i.e it only shows up in advanced sections) */
|
|
inline const Type IsCustomized = 1 << 17; /** true if this node's visual representation has been customized by the editor */
|
|
|
|
inline const Type RequiresValidation = 1 << 18; /** true if this node could unexpectedly change (array changes, editinlinenew changes) */
|
|
|
|
inline const Type ShouldShowDisableEditOnInstance = 1 << 19; /** true if this node should show child properties marked CPF_DisableEditOnInstance */
|
|
|
|
inline const Type IsReadOnly = 1 << 20; /** true if this node is overridden to appear as read-only */
|
|
|
|
inline const Type SkipChildValidation = 1 << 21; /** true if this node should skip child validation */
|
|
|
|
inline const Type ShowInnerObjectProperties = 1 << 22;
|
|
|
|
inline const Type HasCustomResetToDefault = 1 << 23; /** true if this node's visual representation of reset to default has been customized*/
|
|
|
|
inline const Type IsSparseClassData = 1 << 24; /** true if the property on this node is part of a sparse class data structure */
|
|
|
|
inline const Type ShouldShowInViewport = 1 << 25; /** true if the property should be shown in the viewport context menu */
|
|
|
|
inline const Type ResolveInstanceDataObjects = 1 << 26; /** Object properties will resolve to the instance data objects if they exist */
|
|
|
|
inline const Type SupportsDynamicInstancing = 1 << 27; /** This property could be point to a reference, an instance or null */
|
|
|
|
inline const Type DynamicInstance = 1 << 28; /** This property is pointing to an instance object.
|
|
Convenience and optimization without requiring inspecting the outer of the child Objects
|
|
*/
|
|
|
|
inline const Type NoFlags = 0;
|
|
|
|
};
|
|
|
|
namespace FPropertyNodeConstants
|
|
{
|
|
inline const int32 NoDepthRestrictions = -1;
|
|
|
|
/** Character used to deliminate sub-categories in category path names */
|
|
inline const TCHAR CategoryDelimiterChar = TCHAR( '|' );
|
|
};
|
|
|
|
class FPropertySettings
|
|
{
|
|
public:
|
|
static FPropertySettings& Get();
|
|
bool ShowFriendlyPropertyNames() const { return bShowFriendlyPropertyNames; }
|
|
bool ShowHiddenProperties() const { return bShowHiddenProperties; }
|
|
bool ExpandDistributions() const { return bExpandDistributions; }
|
|
private:
|
|
FPropertySettings();
|
|
private:
|
|
bool bShowFriendlyPropertyNames;
|
|
bool bExpandDistributions;
|
|
bool bShowHiddenProperties;
|
|
};
|
|
|
|
struct FAddressPair
|
|
{
|
|
FAddressPair(const UObject* InObject, uint8* Address, bool bInIsStruct)
|
|
: Object( InObject)
|
|
, ReadAddress( Address )
|
|
, bIsStruct(bInIsStruct)
|
|
{}
|
|
TWeakObjectPtr<const UObject> Object;
|
|
uint8* ReadAddress;
|
|
bool bIsStruct;
|
|
};
|
|
|
|
template<> struct TIsPODType<FAddressPair> { enum { Value = true }; };
|
|
|
|
struct FReadAddressListData
|
|
{
|
|
public:
|
|
FReadAddressListData()
|
|
: bAllValuesTheSame( false )
|
|
, bRequiresCache( true )
|
|
{
|
|
}
|
|
void Add(const UObject* Object, uint8* Address, bool bIsStruct = false)
|
|
{
|
|
ReadAddresses.Add(FAddressPair(Object, Address, bIsStruct));
|
|
}
|
|
|
|
int32 Num() const
|
|
{
|
|
return ReadAddresses.Num();
|
|
}
|
|
|
|
uint8* GetAddress( int32 Index )
|
|
{
|
|
const FAddressPair& Pair = ReadAddresses[Index];
|
|
return (Pair.Object.IsValid() || Pair.bIsStruct) ? Pair.ReadAddress : 0;
|
|
}
|
|
|
|
const UObject* GetObject(int32 Index)
|
|
{
|
|
const FAddressPair& Pair = ReadAddresses[Index];
|
|
return Pair.Object.Get();
|
|
}
|
|
|
|
bool IsValidIndex( int32 Index ) const
|
|
{
|
|
return ReadAddresses.IsValidIndex(Index);
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
ReadAddresses.Reset();
|
|
bAllValuesTheSame = false;
|
|
bRequiresCache = true;
|
|
}
|
|
|
|
bool bAllValuesTheSame;
|
|
bool bRequiresCache;
|
|
private:
|
|
TArray<FAddressPair> ReadAddresses;
|
|
};
|
|
|
|
/**
|
|
* A list of read addresses for a property node which contains the address for the nodes FProperty on each object
|
|
*/
|
|
class FReadAddressList
|
|
{
|
|
friend class FPropertyNode;
|
|
public:
|
|
FReadAddressList()
|
|
: ReadAddressListData(nullptr)
|
|
{}
|
|
|
|
int32 Num() const
|
|
{
|
|
return (ReadAddressListData != nullptr) ? ReadAddressListData->Num() : 0;
|
|
}
|
|
|
|
uint8* GetAddress( int32 Index )
|
|
{
|
|
return ReadAddressListData->GetAddress( Index );
|
|
}
|
|
|
|
const UObject* GetObject(int32 Index)
|
|
{
|
|
return ReadAddressListData->GetObject(Index);
|
|
}
|
|
|
|
bool IsValidIndex( int32 Index ) const
|
|
{
|
|
return ReadAddressListData->IsValidIndex( Index );
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
if (ReadAddressListData != nullptr)
|
|
{
|
|
ReadAddressListData->Reset();
|
|
}
|
|
}
|
|
|
|
private:
|
|
FReadAddressListData* ReadAddressListData;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Parameters for initializing a property node
|
|
*/
|
|
struct FPropertyNodeInitParams
|
|
{
|
|
enum class EIsSparseDataProperty : uint8
|
|
{
|
|
False,
|
|
True,
|
|
Inherit,
|
|
};
|
|
|
|
/** The parent of the property node */
|
|
TSharedPtr<FPropertyNode> ParentNode;
|
|
/** The property that the node observes and modifies*/
|
|
FProperty* Property;
|
|
/** Offset to the property data within either a fixed array or a dynamic array */
|
|
int32 ArrayOffset;
|
|
/** Index of the property in its array parent */
|
|
int32 ArrayIndex;
|
|
/** Whether or not to create any children */
|
|
bool bAllowChildren;
|
|
/** Whether or not to allow hidden properties (ones without CPF_Edit) to be visible */
|
|
bool bForceHiddenPropertyVisibility;
|
|
/** Whether or not to create category nodes (note: this setting is only valid for the root node of a property tree. The setting will propagate to children) */
|
|
bool bCreateCategoryNodes;
|
|
/** Whether or not to create nodes for properties marked CPF_DisableEditOnInstance */
|
|
bool bCreateDisableEditOnInstanceNodes;
|
|
/** Resolve Objects to their IDOs */
|
|
bool bResolveInstanceDataObjects;
|
|
|
|
/** Whether or not this property is sparse data */
|
|
EIsSparseDataProperty IsSparseProperty;
|
|
|
|
FPropertyNodeInitParams()
|
|
: ParentNode(nullptr)
|
|
, Property(nullptr)
|
|
, ArrayOffset(0)
|
|
, ArrayIndex( INDEX_NONE )
|
|
, bAllowChildren( true )
|
|
, bForceHiddenPropertyVisibility( false )
|
|
, bCreateCategoryNodes( true )
|
|
, bCreateDisableEditOnInstanceNodes( true )
|
|
, bResolveInstanceDataObjects(false)
|
|
, IsSparseProperty( EIsSparseDataProperty::Inherit )
|
|
{}
|
|
};
|
|
|
|
/** Describes in which way an array property change has happend. This is used
|
|
for propagation of array property changes to the instances of archetype objects. */
|
|
struct EPropertyArrayChangeType
|
|
{
|
|
enum Type
|
|
{
|
|
/** A value was added to the array */
|
|
Add,
|
|
/** The array was cleared */
|
|
Clear,
|
|
/** A new item has been inserted. */
|
|
Insert,
|
|
/** An item has been deleted */
|
|
Delete,
|
|
/** An item has been duplicated */
|
|
Duplicate,
|
|
/** Two items have been swapped */
|
|
Swap,
|
|
};
|
|
};
|
|
|
|
enum EPropertyDataValidationResult : uint8
|
|
{
|
|
/** The object(s) being viewed are now invalid */
|
|
ObjectInvalid,
|
|
/** Non dynamic array property nodes were added or removed that would require a refresh */
|
|
PropertiesChanged,
|
|
/** An edit inline new value changed, In the tree this rebuilds the nodes, in the details view we don't need to do this */
|
|
EditInlineNewValueChanged,
|
|
/** The size of an array changed (delete,insert,add) */
|
|
ArraySizeChanged,
|
|
/** An internal node's children were rebuilt for some reason */
|
|
ChildrenRebuilt,
|
|
/** All data is valid */
|
|
DataValid,
|
|
};
|
|
|
|
/** Helper class for modifying property values with setters and getters */
|
|
class FPropertyNodeEditStack
|
|
{
|
|
struct FMemoryFrame
|
|
{
|
|
FMemoryFrame() = default;
|
|
FMemoryFrame(const FProperty* InProperty, uint8* InMemory)
|
|
: Property(InProperty)
|
|
, Memory(InMemory)
|
|
{
|
|
}
|
|
/** Property that points to the memory in this frame */
|
|
const FProperty* Property = nullptr;
|
|
/** Property address */
|
|
uint8* Memory = nullptr;
|
|
};
|
|
public:
|
|
|
|
/**
|
|
* Constructs property stack for the specified node
|
|
* InNode Property node to construct the stack for
|
|
* InObj Optional Object instance that contains the property being modified (if not provided the root container pointer will be acquired from the provided node hierarchy)
|
|
*/
|
|
FPropertyNodeEditStack(const FPropertyNode* InNode, const UObject* InObj = nullptr);
|
|
FPropertyNodeEditStack() = default;
|
|
~FPropertyNodeEditStack();
|
|
|
|
FPropertyNodeEditStack& operator = (const FPropertyNodeEditStack& Other) = delete;
|
|
FPropertyNodeEditStack(const FPropertyNodeEditStack& Other) = delete;
|
|
|
|
/**
|
|
* Initializes property stack for the specified node
|
|
* InNode Property node to construct the stack for
|
|
* InObj Object instance that contains the property being modified
|
|
*/
|
|
FPropertyAccess::Result Initialize(const FPropertyNode* InNode, const UObject* InObj);
|
|
|
|
/**
|
|
* Returns the address of the property being modified.
|
|
* If anywhere in the property stack is a property with a setter or getter this will point to a temporarily allocated memory.
|
|
*/
|
|
uint8* GetDirectPropertyAddress()
|
|
{
|
|
return MemoryStack.Last().Memory;
|
|
}
|
|
|
|
/**
|
|
* Commits all modifications to temporarily allocated property values back to the actual member variables using setters and getters where available
|
|
*/
|
|
void CommitChanges();
|
|
|
|
/** Checks if this edit stack is valid */
|
|
bool IsValid() const
|
|
{
|
|
return MemoryStack.Num() > 0;
|
|
}
|
|
|
|
private:
|
|
|
|
FPropertyAccess::Result InitializeInternal(const FPropertyNode* InNode, const UObject* InObj);
|
|
void Cleanup();
|
|
|
|
TArray<FMemoryFrame> MemoryStack;
|
|
};
|
|
|
|
/**
|
|
* The base class for all property nodes
|
|
*/
|
|
class FPropertyNode : public TSharedFromThis<FPropertyNode>
|
|
{
|
|
public:
|
|
|
|
FPropertyNode();
|
|
virtual ~FPropertyNode();
|
|
|
|
/**
|
|
* Init Tree Node internally (used only derived classes to pass through variables that are common to all nodes
|
|
* @param InitParams Parameters for how the node should be initialized
|
|
*/
|
|
void InitNode(const FPropertyNodeInitParams& InitParams);
|
|
|
|
/**
|
|
* Indicates that children of this node should be rebuilt next tick. Some topology changes will require this
|
|
*/
|
|
void RequestRebuildChildren() { bRebuildChildrenRequested = true; }
|
|
|
|
/**
|
|
* Used for rebuilding this nodes children
|
|
*/
|
|
void RebuildChildren();
|
|
|
|
/**
|
|
* Mark this and all children as having been rebuilt.
|
|
*/
|
|
void MarkChildrenAsRebuilt();
|
|
|
|
/**
|
|
* For derived windows to be able to add their nodes to the child array
|
|
*/
|
|
void AddChildNode(TSharedPtr<FPropertyNode> InNode);
|
|
|
|
/**
|
|
* Destroys all child nodes under this node
|
|
*/
|
|
void RemoveAllChildNodes();
|
|
|
|
/**
|
|
* Clears cached read address data
|
|
*/
|
|
void ClearCachedReadAddresses(bool bRecursive = true);
|
|
|
|
/**
|
|
* Interface function to get at the derived FObjectPropertyNode class
|
|
*/
|
|
virtual FObjectPropertyNode* AsObjectNode() { return nullptr; }
|
|
virtual const FObjectPropertyNode* AsObjectNode() const { return nullptr; }
|
|
|
|
/**
|
|
* Interface function to get at the derived FComplexPropertyNode class
|
|
*/
|
|
virtual FComplexPropertyNode* AsComplexNode() { return nullptr; }
|
|
virtual const FComplexPropertyNode* AsComplexNode() const { return nullptr; }
|
|
|
|
/**
|
|
* Interface function to get at the derived FCategoryPropertyNode class
|
|
*/
|
|
virtual FCategoryPropertyNode* AsCategoryNode() { return nullptr; }
|
|
virtual const FCategoryPropertyNode* AsCategoryNode() const { return nullptr; }
|
|
|
|
/**
|
|
* Interface function to get at the derived FItemPropertyNode class
|
|
*/
|
|
virtual FItemPropertyNode* AsItemPropertyNode() { return nullptr; }
|
|
virtual const FItemPropertyNode* AsItemPropertyNode() const { return nullptr; }
|
|
|
|
/**
|
|
* Follows the chain of items upwards until it finds the complex property that houses this item.
|
|
*/
|
|
FComplexPropertyNode* FindComplexParent();
|
|
const FComplexPropertyNode* FindComplexParent() const;
|
|
|
|
/**
|
|
* Follows the chain of items upwards until it finds the object property that houses this item.
|
|
*/
|
|
FObjectPropertyNode* FindObjectItemParent();
|
|
const FObjectPropertyNode* FindObjectItemParent() const;
|
|
|
|
/**
|
|
* Follows the chain of items upwards until it finds the structure property that houses this item.
|
|
*/
|
|
FStructurePropertyNode* FindStructureItemParent();
|
|
const FStructurePropertyNode* FindStructureItemParent() const;
|
|
|
|
/**
|
|
* Follows the top-most object window that contains this property window item.
|
|
*/
|
|
FObjectPropertyNode* FindRootObjectItemParent();
|
|
|
|
/**
|
|
* Used to see if any data has been destroyed from under the property tree. Should only be called during Tick
|
|
*/
|
|
virtual EPropertyDataValidationResult EnsureDataIsValid();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Text
|
|
|
|
/**
|
|
* @param OutText The property formatted in a string
|
|
* @param bAllowAlternateDisplayValue Allow the function to potentially use an alternate form more suitable for display in the UI
|
|
* @param PortFlags Determines how the property's value is accessed. Defaults to PPF_PropertyWindow
|
|
* @return true if the value was retrieved successfully
|
|
*/
|
|
FPropertyAccess::Result GetPropertyValueString(FString& OutString, const bool bAllowAlternateDisplayValue, EPropertyPortFlags PortFlags = PPF_PropertyWindow) const;
|
|
|
|
/**
|
|
* @param OutText The property formatted in text
|
|
* @param bAllowAlternateDisplayValue Allow the function to potentially use an alternate form more suitable for display in the UI
|
|
* @return true if the value was retrieved successfully
|
|
*/
|
|
FPropertyAccess::Result GetPropertyValueText(FText& OutText, const bool bAllowAlternateDisplayValue) const;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//Flags
|
|
bool HasNodeFlags(const EPropertyNodeFlags::Type InTestFlags) const { return (PropertyNodeFlags & InTestFlags) != 0; }
|
|
/**
|
|
* Sets the flags used by the window and the root node
|
|
* @param InFlags - flags to turn on or off
|
|
* @param InOnOff - whether to toggle the bits on or off
|
|
*/
|
|
void SetNodeFlags(const EPropertyNodeFlags::Type InFlags, const bool InOnOff);
|
|
|
|
/**
|
|
* Finds a child of this property node
|
|
*
|
|
* @param InPropertyName The name of the property to find
|
|
* @param bRecurse true if we should recurse into children's children and so on.
|
|
*/
|
|
TSharedPtr<FPropertyNode> FindChildPropertyNode(const FName InPropertyName, bool bRecurse = false);
|
|
|
|
/**
|
|
* Returns the parent node in the hierarchy
|
|
*/
|
|
FPropertyNode* GetParentNode() { return ParentNodeWeakPtr.Pin().Get(); }
|
|
const FPropertyNode* GetParentNode() const { return ParentNodeWeakPtr.Pin().Get(); }
|
|
TSharedPtr<FPropertyNode> GetParentNodeSharedPtr() { return ParentNodeWeakPtr.Pin(); }
|
|
/**
|
|
* Returns the Property this Node represents
|
|
*/
|
|
FProperty* GetProperty() { return Property.Get(); }
|
|
const FProperty* GetProperty() const { return Property.Get(); }
|
|
|
|
/**
|
|
* Accessor functions for internals
|
|
*/
|
|
int32 GetArrayOffset() const { return ArrayOffset; }
|
|
int32 GetArrayIndex() const { return ArrayIndex; }
|
|
|
|
/**
|
|
* Return number of children that survived being filtered
|
|
*/
|
|
int32 GetNumChildNodes() const { return ChildNodes.Num(); }
|
|
|
|
/**
|
|
* Returns the matching Child node
|
|
*/
|
|
TSharedPtr<FPropertyNode>& GetChildNode(const int32 ChildIndex)
|
|
{
|
|
check(ChildNodes[ChildIndex].IsValid());
|
|
return ChildNodes[ChildIndex];
|
|
}
|
|
|
|
/**
|
|
* Returns the matching Child node
|
|
*/
|
|
const TSharedPtr<FPropertyNode>& GetChildNode(const int32 ChildIndex) const
|
|
{
|
|
check(ChildNodes[ChildIndex].IsValid());
|
|
return ChildNodes[ChildIndex];
|
|
}
|
|
|
|
/**
|
|
* Returns the Child node whose ArrayIndex matches the supplied ChildIndex
|
|
*/
|
|
bool GetChildNode(const int32 ChildArrayIndex, TSharedPtr<FPropertyNode>& OutChildNode);
|
|
|
|
/**
|
|
* Returns the Child node whose ArrayIndex matches the supplied ChildIndex
|
|
*/
|
|
bool GetChildNode(const int32 ChildArrayIndex, TSharedPtr<FPropertyNode>& OutChildNode) const;
|
|
|
|
/**
|
|
* Returns whether this window's property is read only or has the CPF_EditConst flag.
|
|
*/
|
|
bool IsPropertyConst() const;
|
|
|
|
/** @return whether this window's property is constant (can't be edited by the user). If bIncludeEditCondition is false, the property is considered editable regardless of the EditCondition result. */
|
|
bool IsEditConst(const bool bIncludeEditCondition = true) const;
|
|
|
|
/**
|
|
* Returns whether this window's property should not be serialized (determined by the CPF_SkipSerialization flag).
|
|
*/
|
|
bool ShouldSkipSerialization() const;
|
|
|
|
/**
|
|
* Gets the full name of this node
|
|
* @param PathPlusIndex - return value with full path of node
|
|
* @param bWithArrayIndex - If True, adds an array index (where appropriate)
|
|
* @param StopParent - Stop at this parent (if any). Does NOT include it in the path
|
|
* @param bIgnoreCategories - Skip over categories
|
|
*/
|
|
virtual bool GetQualifiedName(FString& PathPlusIndex, const bool bWithArrayIndex, const FPropertyNode* StopParent = nullptr, bool bIgnoreCategories = false) const;
|
|
|
|
// The bArrayPropertiesCanDifferInSize flag is an override for array properties which want to display
|
|
// e.g. the "Clear" and "Empty" buttons, even though the array properties may differ in the number of elements.
|
|
bool GetReadAddress(
|
|
bool InRequiresSingleSelection,
|
|
FReadAddressList& OutAddresses,
|
|
bool bComparePropertyContents = true,
|
|
bool bObjectForceCompare = false,
|
|
bool bArrayPropertiesCanDifferInSize = false) const;
|
|
|
|
/**
|
|
* fills in the OutAddresses array with the addresses of all of the available objects.
|
|
* @param OutAddresses Storage array for all of the objects' addresses.
|
|
*/
|
|
bool GetReadAddress(FReadAddressList& OutAddresses) const;
|
|
|
|
/**
|
|
* Fills in the OutValueAddress with the address of the value of all the available objects.
|
|
* If multiple items are selected, this will return a null address unless they are all the same value.
|
|
* @param OutValueAddress The address of the item
|
|
*/
|
|
FPropertyAccess::Result GetSingleReadAddress(uint8*& OutValueAddress) const;
|
|
|
|
/**
|
|
* Fills in the OutObject with the address of the object of all the available objects.
|
|
* If multiple items are selected, this will return a null address unless they are all the same value.
|
|
* @param OutObject The address of the Object
|
|
*/
|
|
FPropertyAccess::Result GetSingleObject(UObject*& OutObject) const;
|
|
|
|
/**
|
|
* Fills in the OutContainer with the address of the container (struct or UObject instance) that owns the property this node represents.
|
|
* @param OutContainer The address of the container instance
|
|
*/
|
|
FPropertyAccess::Result GetSingleEditStack(FPropertyNodeEditStack& OutStack) const;
|
|
|
|
/**
|
|
* Gets read addresses without accessing cached data. Is less efficient but gets the must up to date data
|
|
*/
|
|
virtual bool GetReadAddressUncached(const FPropertyNode& InNode, bool InRequiresSingleSelection, FReadAddressListData* OutAddresses, bool bComparePropertyContents = true, bool bObjectForceCompare = false, bool bArrayPropertiesCanDifferInSize = false) const;
|
|
virtual bool GetReadAddressUncached(const FPropertyNode& InNode, FReadAddressListData& OutAddresses) const;
|
|
|
|
/**
|
|
* Calculates the memory address for the data associated with this item's property. This is typically the value of a FProperty or a UObject address.
|
|
*
|
|
* @param StartAddress the location to use as the starting point for the calculation; typically the address of the object that contains this property.
|
|
* @param bIsSparseData True if StartAddress is pointing to a sidecar structure containing sparse class data, false otherwise
|
|
*
|
|
* @return a pointer to a FProperty value or UObject. (For dynamic arrays, you'd cast this value to an FArray*)
|
|
*/
|
|
virtual uint8* GetValueBaseAddress(uint8* StartAddress, bool bIsSparseData, bool bIsStruct = false) const;
|
|
|
|
/**
|
|
* Calculates the memory address for the data associated with this item's value. For most properties, identical to GetValueBaseAddress. For items corresponding
|
|
* to dynamic array elements, the pointer returned will be the location for that element's data.
|
|
*
|
|
* @param StartAddress the location to use as the starting point for the calculation; typically the address of the object that contains this property.
|
|
* @param bIsSparseData True if StartAddress is pointing to a sidecar structure containing sparse class data, false otherwise
|
|
*
|
|
* @return a pointer to a FProperty value or UObject. (For dynamic arrays, you'd cast this value to whatever type is the Inner for the dynamic array)
|
|
*/
|
|
virtual uint8* GetValueAddress(uint8* StartAddress, bool bIsSparseData, bool bIsStruct = false) const;
|
|
|
|
/**
|
|
* Caclulates the memory address for the starting point of the structure that contains the property this node uses.
|
|
* This will often be Obj but may also point to a sidecar data structure.
|
|
*/
|
|
uint8* GetStartAddressFromObject(const UObject* Obj) const;
|
|
|
|
/**
|
|
* Calculates the memory address for the data associated with this item's property. This is typically the value of a FProperty or a UObject address.
|
|
*
|
|
* @param Obj The object that contains this property; used as the starting point for the calculation
|
|
*
|
|
* @return a pointer to a FProperty value or UObject. (For dynamic arrays, you'd cast this value to an FArray*)
|
|
*/
|
|
uint8* GetValueBaseAddressFromObject(const UObject* Obj) const;
|
|
|
|
/**
|
|
* Calculates the memory address for the data associated with this item's value. For most properties, identical to GetValueBaseAddress. For items corresponding
|
|
* to dynamic array elements, the pointer returned will be the location for that element's data.
|
|
*
|
|
* @param Obj The object that contains this property; used as the starting point for the calculation
|
|
*
|
|
* @return a pointer to a FProperty value or UObject. (For dynamic arrays, you'd cast this value to whatever type is the Inner for the dynamic array)
|
|
*/
|
|
uint8* GetValueAddressFromObject(const UObject* Obj) const;
|
|
|
|
/**
|
|
* Sets the display name override to use instead of the display name
|
|
*/
|
|
virtual void SetDisplayNameOverride(const FText& InDisplayNameOverride) {}
|
|
|
|
/**
|
|
* @return true if the property is mark as a favorite
|
|
*/
|
|
virtual void SetFavorite(bool FavoriteValue) {}
|
|
|
|
/**
|
|
* @return true if the property is mark as a favorite
|
|
*/
|
|
virtual bool IsFavorite() const { return false; }
|
|
|
|
/**
|
|
* @return The formatted display name for the property in this node
|
|
*/
|
|
virtual FText GetDisplayName() const { return FText::GetEmpty(); }
|
|
|
|
/**
|
|
* Sets the tooltip override to use instead of the property tooltip
|
|
*/
|
|
virtual void SetToolTipOverride(const FText& InToolTipOverride) {}
|
|
|
|
/**
|
|
* @return The tooltip for the property in this node
|
|
*/
|
|
virtual FText GetToolTipText() const { return FText::GetEmpty(); }
|
|
|
|
/**
|
|
* If there is a property, sees if it matches. Otherwise sees if the entire parent structure matches
|
|
*/
|
|
bool GetDiffersFromDefault();
|
|
|
|
/**
|
|
* @return The label for displaying a reset to default value
|
|
*/
|
|
FText GetResetToDefaultLabel();
|
|
|
|
/**
|
|
* @return If this property node is associated with a property that can be reordered within an array
|
|
*/
|
|
bool IsReorderable();
|
|
|
|
/**Walks up the hierarchy and return true if any parent node is a favorite*/
|
|
bool IsChildOfFavorite() const;
|
|
|
|
void NotifyPreChange(FProperty* PropertyAboutToChange, FNotifyHook* InNotifyHook);
|
|
void NotifyPreChange(FProperty* PropertyAboutToChange, FNotifyHook* InNotifyHook, const TSet<UObject*>& AffectedInstances);
|
|
void NotifyPreChange(FProperty* PropertyAboutToChange, FNotifyHook* InNotifyHook, TSet<UObject*>&& AffectedInstances);
|
|
|
|
void NotifyPostChange(FPropertyChangedEvent& InPropertyChangedEvent, FNotifyHook* InNotifyHook);
|
|
|
|
DECLARE_EVENT(FPropertyNode, FPropertyChildrenRebuiltEvent);
|
|
FDelegateHandle SetOnRebuildChildren(const FSimpleDelegate& InOnRebuildChildren);
|
|
FPropertyChildrenRebuiltEvent& OnRebuildChildren() { return OnRebuildChildrenEvent; }
|
|
|
|
/**
|
|
* Propagates the property change to all instances of an archetype
|
|
*
|
|
* @param ModifiedObject Object which property has been modified
|
|
* @param NewValue New value of the property
|
|
* @param PreviousValue Value of the property before the modification
|
|
*/
|
|
void PropagatePropertyChange(UObject* ModifiedObject, const TCHAR* NewValue, const FString& PreviousValue);
|
|
|
|
/**
|
|
* Propagates the property change of a container property to all instances of an archetype
|
|
*
|
|
* @param ModifiedObject Object which property has been modified
|
|
* @param OriginalContainerAddr Original address holding the container value before the modification
|
|
* @param ChangeType In which way was the container modified
|
|
* @param Index Index of the modified item
|
|
*/
|
|
void PropagateContainerPropertyChange(UObject* ModifiedObject, const void* OriginalContainerAddr,
|
|
EPropertyArrayChangeType::Type ChangeType, int32 Index, int32 SwapIndex = INDEX_NONE);
|
|
|
|
/**
|
|
* Helper function to centralize logic for duplcating an array entry and ensuring that instanced object references are correctly handled
|
|
*/
|
|
static void DuplicateArrayEntry(FProperty* NodeProperty, FScriptArrayHelper& ArrayHelper, int32 Index);
|
|
|
|
/**
|
|
* Gather the list of all instances that will be affected by a container property change
|
|
*
|
|
* @param ModifiedObject Object which property has been modified
|
|
* @param OriginalContainerAddr Original address holding the container value before the modification
|
|
* @param ChangeType In which way is the container modified
|
|
* @param OutAffectedInstances Instances affected by the property change
|
|
*/
|
|
void GatherInstancesAffectedByContainerPropertyChange(UObject* ModifiedObject, const void* OriginalContainerAddr, EPropertyArrayChangeType::Type ChangeType, TArray<UObject*>& OutAffectedInstances);
|
|
|
|
/**
|
|
* Propagates the property change of a container property to the provided archetype instances
|
|
*
|
|
* @param ModifiedObject Object which property has been modified
|
|
* @param OriginalContainerAddr Original address holding the container value before the modification
|
|
* @param AffectedInstances Instances affected by the property change
|
|
* @param ChangeType In which way was the container modified
|
|
* @param Index Index of the modified item
|
|
*/
|
|
void PropagateContainerPropertyChange(UObject* ModifiedObject, const void* OriginalContainerAddr, const TArray<UObject*>& AffectedInstances,
|
|
EPropertyArrayChangeType::Type ChangeType, int32 Index, int32 SwapIndex = INDEX_NONE);
|
|
|
|
/** Broadcasts when a property value changes */
|
|
DECLARE_EVENT(FPropertyNode, FPropertyValueChangedEvent);
|
|
/** Broadcasts when a property value changes, but additionally includes the property changed event.*/
|
|
DECLARE_MULTICAST_DELEGATE_OneParam(FPropertyValueChangedWithData, const FPropertyChangedEvent&)
|
|
FPropertyValueChangedEvent& OnPropertyValueChanged() { return PropertyValueChangedEvent; }
|
|
FPropertyValueChangedWithData& OnPropertyValueChangedWithData() { return PropertyValueChangedDelegate; }
|
|
|
|
/** Broadcasts when a child of this property changes */
|
|
FPropertyValueChangedEvent& OnChildPropertyValueChanged() { return ChildPropertyValueChangedEvent; }
|
|
FPropertyValueChangedWithData& OnChildPropertyValueChangedWithData() { return ChildPropertyValueChangedDelegate; }
|
|
|
|
/** Broadcasts when a property value changes */
|
|
DECLARE_EVENT(FPropertyNode, FPropertyValuePreChangeEvent);
|
|
FPropertyValuePreChangeEvent& OnPropertyValuePreChange() { return PropertyValuePreChangeEvent; }
|
|
|
|
/** Broadcasts when a child of this property changes */
|
|
FPropertyValuePreChangeEvent& OnChildPropertyValuePreChange() { return ChildPropertyValuePreChangeEvent; }
|
|
|
|
/** Broadcasts when this property is reset to default */
|
|
DECLARE_EVENT(FPropertyNode, FPropertyResetToDefaultEvent);
|
|
FPropertyResetToDefaultEvent& OnPropertyResetToDefault() { return PropertyResetToDefaultEvent; }
|
|
|
|
/**
|
|
* Marks window's seem due to filtering flags
|
|
* @param InFilterStrings - List of strings that must be in the property name in order to display
|
|
* Empty InFilterStrings means display as normal
|
|
* All strings must match in order to be accepted by the filter
|
|
* @param bParentAllowsVisible - is NOT true for an expander that is NOT expanded
|
|
*/
|
|
void FilterNodes(const TArray<FString>& InFilterStrings, const bool bParentSeenDueToFiltering = false);
|
|
|
|
/**
|
|
* Marks windows as visible based on the filter strings or standard visibility
|
|
*
|
|
* @param bParentAllowsVisible - is NOT true for an expander that is NOT expanded
|
|
*/
|
|
void ProcessSeenFlags(const bool bParentAllowsVisible);
|
|
|
|
/**
|
|
* Marks windows as visible based their favorites status
|
|
*/
|
|
void ProcessSeenFlagsForFavorites();
|
|
|
|
/**
|
|
* @return true if this node should be visible in a tree
|
|
*/
|
|
bool IsVisible() const { return HasNodeFlags(EPropertyNodeFlags::IsBeingFiltered) == 0 || HasNodeFlags(EPropertyNodeFlags::IsSeen) || HasNodeFlags(EPropertyNodeFlags::IsSeenDueToChildFiltering); };
|
|
|
|
static TSharedRef< FPropertyPath > CreatePropertyPath(const TSharedRef< FPropertyNode >& PropertyNode)
|
|
{
|
|
TArray< FPropertyInfo > Properties;
|
|
FPropertyNode* CurrentNode = &PropertyNode.Get();
|
|
|
|
if (CurrentNode != nullptr && CurrentNode->AsCategoryNode() != nullptr)
|
|
{
|
|
TSharedRef< FPropertyPath > NewPath = MakeShared<FPropertyPath>();
|
|
return NewPath;
|
|
}
|
|
|
|
while (CurrentNode != nullptr)
|
|
{
|
|
if (CurrentNode->AsItemPropertyNode() != nullptr)
|
|
{
|
|
FPropertyInfo NewPropInfo;
|
|
NewPropInfo.Property = CurrentNode->GetProperty();
|
|
if (!NewPropInfo.Property.IsValid())
|
|
{
|
|
return MakeShared<FPropertyPath>();
|
|
}
|
|
NewPropInfo.ArrayIndex = CurrentNode->GetArrayIndex();
|
|
|
|
Properties.Add(NewPropInfo);
|
|
}
|
|
|
|
CurrentNode = CurrentNode->GetParentNode();
|
|
}
|
|
|
|
TSharedRef< FPropertyPath > NewPath = MakeShared<FPropertyPath>();
|
|
|
|
for (int PropertyIndex = Properties.Num() - 1; PropertyIndex >= 0; --PropertyIndex)
|
|
{
|
|
NewPath->AddProperty(Properties[PropertyIndex]);
|
|
}
|
|
|
|
return NewPath;
|
|
}
|
|
|
|
static TSharedPtr< FPropertyNode > FindPropertyNodeByPath(const TSharedPtr< FPropertyPath > Path, const TSharedRef< FPropertyNode >& StartingNode)
|
|
{
|
|
if (!Path.IsValid() || Path->GetNumProperties() == 0)
|
|
{
|
|
return StartingNode;
|
|
}
|
|
|
|
bool FailedToFindProperty = false;
|
|
TSharedPtr< FPropertyNode > PropertyNode = StartingNode;
|
|
for (int PropertyIndex = 0; PropertyIndex < Path->GetNumProperties() && !FailedToFindProperty; PropertyIndex++)
|
|
{
|
|
FailedToFindProperty = true;
|
|
const FPropertyInfo& PropInfo = Path->GetPropertyInfo(PropertyIndex);
|
|
|
|
TArray< TSharedRef< FPropertyNode > > ChildrenStack;
|
|
ChildrenStack.Push(PropertyNode.ToSharedRef());
|
|
while (ChildrenStack.Num() > 0)
|
|
{
|
|
const TSharedRef< FPropertyNode > CurrentNode = ChildrenStack.Pop();
|
|
|
|
for (int32 ChildIndex = 0; ChildIndex < CurrentNode->GetNumChildNodes(); ++ChildIndex)
|
|
{
|
|
const TSharedPtr< FPropertyNode > ChildNode = CurrentNode->GetChildNode(ChildIndex);
|
|
|
|
if (ChildNode->AsItemPropertyNode() == nullptr)
|
|
{
|
|
ChildrenStack.Add(ChildNode.ToSharedRef());
|
|
}
|
|
else if (ChildNode.IsValid() &&
|
|
ChildNode->GetProperty() == PropInfo.Property.Get() &&
|
|
ChildNode->GetArrayIndex() == PropInfo.ArrayIndex)
|
|
{
|
|
PropertyNode = ChildNode;
|
|
FailedToFindProperty = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FailedToFindProperty)
|
|
{
|
|
PropertyNode = nullptr;
|
|
}
|
|
|
|
return PropertyNode;
|
|
}
|
|
|
|
|
|
static TArray< FPropertyInfo > GetPossibleExtensionsForPath(const TSharedPtr< FPropertyPath > Path, const TSharedRef< FPropertyNode >& StartingNode)
|
|
{
|
|
TArray< FPropertyInfo > PossibleExtensions;
|
|
TSharedPtr< FPropertyNode > PropertyNode = FindPropertyNodeByPath(Path, StartingNode);
|
|
|
|
if (!PropertyNode.IsValid())
|
|
{
|
|
return PossibleExtensions;
|
|
}
|
|
|
|
for (int32 ChildIndex = 0; ChildIndex < PropertyNode->GetNumChildNodes(); ++ChildIndex)
|
|
{
|
|
TSharedPtr< FPropertyNode > CurrentNode = PropertyNode->GetChildNode(ChildIndex);
|
|
|
|
if (CurrentNode.IsValid() && CurrentNode->AsItemPropertyNode() != nullptr)
|
|
{
|
|
FPropertyInfo NewPropInfo;
|
|
NewPropInfo.Property = CurrentNode->GetProperty();
|
|
NewPropInfo.ArrayIndex = CurrentNode->GetArrayIndex();
|
|
|
|
bool AlreadyExists = false;
|
|
for (auto ExtensionIter = PossibleExtensions.CreateConstIterator(); ExtensionIter; ++ExtensionIter)
|
|
{
|
|
if (*ExtensionIter == NewPropInfo)
|
|
{
|
|
AlreadyExists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!AlreadyExists)
|
|
{
|
|
PossibleExtensions.Add(NewPropInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
return PossibleExtensions;
|
|
}
|
|
|
|
static UObject* GetArchetype(const UObject* Object);
|
|
|
|
static void RegisterArchetypePolicy(PropertyEditorPolicy::IArchetypePolicy* ArchetypePolicy);
|
|
static void UnregisterArchetypePolicy(PropertyEditorPolicy::IArchetypePolicy* ArchetypePolicy);
|
|
|
|
static void RegisterEditConstPolicy(PropertyEditorPolicy::IEditConstPolicy* EditConstPolicy);
|
|
static void UnregisterEditConstPolicy(PropertyEditorPolicy::IEditConstPolicy* EditConstPolicy);
|
|
|
|
static bool IsPropertyEditConst(const FEditPropertyChain& PropertyChain, UObject* Object);
|
|
|
|
static bool IsPropertyEditConst(const FProperty* Property, UObject* Object);
|
|
|
|
/**
|
|
* Adds a restriction to the possible values for this property.
|
|
* @param Restriction The restriction being added to this property.
|
|
*/
|
|
virtual void AddRestriction(TSharedRef<const FPropertyRestriction> Restriction);
|
|
|
|
/**
|
|
* Tests if a value is hidden for this property
|
|
* @param Value The value to test for being hidden.
|
|
* @return True if this value is hidden.
|
|
*/
|
|
bool IsHidden(const FString& Value) const
|
|
{
|
|
return IsHidden(Value, nullptr);
|
|
}
|
|
|
|
/**
|
|
* Tests if a value is disabled for this property
|
|
* @param Value The value to test for being disabled.
|
|
* @return True if this value is disabled.
|
|
*/
|
|
bool IsDisabled(const FString& Value) const
|
|
{
|
|
return IsDisabled(Value, nullptr);
|
|
}
|
|
|
|
bool IsRestricted(const FString& Value) const
|
|
{
|
|
return IsHidden(Value) || IsDisabled(Value);
|
|
}
|
|
|
|
/**
|
|
* Tests if a value is hidden for this property.
|
|
* @param Value The value to test for being hidden.
|
|
* @param OutReasons If hidden, the reasons why.
|
|
* @return True if this value is hidden.
|
|
*/
|
|
virtual bool IsHidden(const FString& Value, TArray<FText>* OutReasons) const;
|
|
|
|
/**
|
|
* Tests if a value is disabled for this property.
|
|
* @param Value The value to test for being disabled.
|
|
* @param OutReasons If disabled, the reasons why.
|
|
* @return True if this value is disabled.
|
|
*/
|
|
virtual bool IsDisabled(const FString& Value, TArray<FText>* OutReasons) const;
|
|
|
|
/**
|
|
* Tests if a value is restricted for this property.
|
|
* @param Value The value to test for being restricted.
|
|
* @param OutReasons If restricted, the reasons why.
|
|
* @return True if this value is restricted.
|
|
*/
|
|
bool IsRestricted(const FString& Value, TArray<FText>& OutReasons) const;
|
|
|
|
/**
|
|
* Generates a consistent tooltip describing this restriction for use in the editor.
|
|
* @param Value The value to test for restriction and generate the tooltip from.
|
|
* @param OutTooltip The tooltip describing why this value is restricted.
|
|
* @return True if this value is restricted.
|
|
*/
|
|
virtual bool GenerateRestrictionToolTip(const FString& Value, FText& OutTooltip)const;
|
|
|
|
const TArray<TSharedRef<const FPropertyRestriction>>& GetRestrictions() const
|
|
{
|
|
return Restrictions;
|
|
}
|
|
|
|
FPropertyChangedEvent& FixPropertiesInEvent(FPropertyChangedEvent& Event);
|
|
|
|
/** Set metadata value for 'Key' to 'Value' on this property instance (as opposed to the class) */
|
|
void SetInstanceMetaData(const FName& Key, const FString& Value);
|
|
|
|
/**
|
|
* Get metadata value for 'Key' for this property instance (as opposed to the class)
|
|
*
|
|
* @return Pointer to metadata value; nullptr if Key not found
|
|
*/
|
|
const FString* GetInstanceMetaData(const FName& Key) const;
|
|
|
|
/**
|
|
* Get metadata map for this property instance (as opposed to the class)
|
|
*
|
|
* @return Map ptr containing metadata pairs
|
|
*/
|
|
const TMap<FName, FString>* GetInstanceMetaDataMap() const;
|
|
|
|
bool ParentOrSelfHasMetaData(const FName& MetaDataKey) const;
|
|
|
|
/**
|
|
* Gets the property we should use to read meta-data
|
|
*/
|
|
FProperty* GetMetaDataProperty();
|
|
|
|
/**
|
|
* Invalidates the cached state of this node in all children;
|
|
*/
|
|
void InvalidateCachedState();
|
|
|
|
static void SetupKeyValueNodePair( TSharedPtr<FPropertyNode>& KeyNode, TSharedPtr<FPropertyNode>& ValueNode )
|
|
{
|
|
check( KeyNode.IsValid() && ValueNode.IsValid() );
|
|
check( !KeyNode->PropertyKeyNode.IsValid() && !ValueNode->PropertyKeyNode.IsValid() );
|
|
|
|
ValueNode->PropertyKeyNode = KeyNode;
|
|
}
|
|
|
|
TSharedPtr<FPropertyNode>& GetPropertyKeyNode() { return PropertyKeyNode; }
|
|
|
|
const TSharedPtr<FPropertyNode>& GetPropertyKeyNode() const { return PropertyKeyNode; }
|
|
|
|
/**
|
|
* Gets the default value of the property as string.
|
|
*/
|
|
FString GetDefaultValueAsString(bool bUseDisplayName = true);
|
|
|
|
/**
|
|
* Broadcasts reset to default property changes
|
|
*/
|
|
void BroadcastPropertyResetToDefault();
|
|
|
|
/** @return Whether this property should have an edit condition toggle. */
|
|
bool SupportsEditConditionToggle() const;
|
|
|
|
/** Toggle the current state of the edit condition if this SupportsEditConditionToggle() */
|
|
void ToggleEditConditionState();
|
|
|
|
/** @return Whether the property has a condition which must be met before allowing editing of it's value */
|
|
bool HasEditCondition() const;
|
|
|
|
/** @return Whether the condition has been met to allow editing of this property's value */
|
|
bool IsEditConditionMet() const;
|
|
|
|
/** @return Whether this property derives its visibility from its edit condition */
|
|
bool IsOnlyVisibleWhenEditConditionMet() const;
|
|
|
|
|
|
/**
|
|
* Helper to fetch a list of child property nodes that are expanded
|
|
*/
|
|
void GetExpandedChildPropertyPaths(TSet<FString>& OutExpandedChildPropertyPaths) const;
|
|
|
|
/**
|
|
* Helper to set the expansion state of a list of child property nodes
|
|
*/
|
|
void SetExpandedChildPropertyNodes(const TSet<FString>& InNodesToExpand);
|
|
|
|
/**
|
|
* Helper to fetch a PropertyPath
|
|
*/
|
|
const FString& GetPropertyPath() const { return PropertyPath; }
|
|
|
|
/** Marks this property node as ignoring CPF_InstancedReference */
|
|
void SetIgnoreInstancedReference();
|
|
|
|
/** Queries whether the node would like to ignore CPF_InstancedReference semantics */
|
|
bool IsIgnoringInstancedReference() const;
|
|
|
|
/** Return true if DestroyTree() has been called on this node. */
|
|
bool IsDestroyed() const;
|
|
|
|
/**
|
|
* Sets bIsDestroyed on all nodes within the hierarchy
|
|
*/
|
|
void MarkDestroyedRecursive();
|
|
|
|
TSharedRef<FEditPropertyChain> BuildPropertyChain( FProperty* PropertyAboutToChange ) const;
|
|
|
|
protected:
|
|
TSharedRef<FEditPropertyChain> BuildPropertyChain( FProperty* PropertyAboutToChange, const TSet<UObject*>& InAffectedArchetypeInstances ) const;
|
|
TSharedRef<FEditPropertyChain> BuildPropertyChain( FProperty* PropertyAboutToChange, TSet<UObject*>&& InAffectedArchetypeInstances ) const;
|
|
|
|
void NotifyPreChangeInternal(TSharedRef<FEditPropertyChain> PropertyChain, FProperty* PropertyAboutToChange, FNotifyHook* InNotifyHook);
|
|
|
|
/**
|
|
* Destroys all node within the hierarchy
|
|
*/
|
|
void DestroyTree(const bool bInDestroySelf=true);
|
|
|
|
/**
|
|
* Interface function for Custom Setup of Node (prior to node flags being set)
|
|
*/
|
|
virtual void InitBeforeNodeFlags() {};
|
|
|
|
/**
|
|
* Interface function for Custom expansion Flags. Default is objects and categories which always expand
|
|
*/
|
|
virtual void InitExpansionFlags() { SetNodeFlags(EPropertyNodeFlags::CanBeExpanded, true); };
|
|
|
|
/**
|
|
* Interface function for Creating Child Nodes
|
|
*/
|
|
virtual void InitChildNodes() = 0;
|
|
|
|
/**
|
|
* Does the string compares to ensure this Name is acceptable to the filter that is passed in
|
|
*/
|
|
bool IsFilterAcceptable(const TArray<FString>& InAcceptableNames, const TArray<FString>& InFilterStrings);
|
|
/**
|
|
* Make sure that parent nodes are expanded
|
|
*/
|
|
void ExpandParent( bool bInRecursive );
|
|
|
|
/** @return The property stored at this node, to be passed to Pre/PostEditChange. */
|
|
FProperty* GetStoredProperty() { return nullptr; }
|
|
|
|
bool GetDiffersFromDefault(const uint8* PropertyValueAddress, const uint8* PropertyDefaultAddress, const uint8* DefaultPropertyValueBaseAddress, const FProperty* InProperty, const UObject* TopLevelObject) const;
|
|
bool GetDiffersFromDefaultForObject( FPropertyItemValueDataTrackerSlate& ValueTracker, FProperty* InProperty );
|
|
|
|
enum class EValueAsStringMode
|
|
{
|
|
None,
|
|
UseDisplayName,
|
|
ForDiff,
|
|
};
|
|
FString GetDefaultValueAsString(const uint8* PropertyDefaultAddress, const FProperty* InProperty, EValueAsStringMode Mode, const UObject* TopLevelObject) const;
|
|
FString GetDefaultValueAsStringForObject( FPropertyItemValueDataTrackerSlate& ValueTracker, UObject* InObject, FProperty* InProperty, EValueAsStringMode Mode);
|
|
|
|
/**
|
|
* Helper function to obtain the display name for an enum property
|
|
* @param InEnum The enum whose metadata to pull from
|
|
* @param DisplayName The name of the enum value to adjust
|
|
*
|
|
* @return true if the DisplayName has been changed
|
|
*/
|
|
bool AdjustEnumPropDisplayName(UEnum* InEnum, FString& DisplayName) const;
|
|
|
|
/**
|
|
* Helper function for derived members to be able to
|
|
* broadcast property changed notifications
|
|
*/
|
|
void BroadcastPropertyChangedDelegates();
|
|
|
|
/**
|
|
* Helper function for derived members to be able to
|
|
* broadcast property changed notifications including property changed event data
|
|
*/
|
|
void BroadcastPropertyChangedDelegates(const FPropertyChangedEvent& Event);
|
|
|
|
|
|
/**
|
|
* Helper function for derived members to be able to
|
|
* broadcast property pre-change notifications
|
|
*/
|
|
void BroadcastPropertyPreChangeDelegates();
|
|
|
|
/**
|
|
* Gets a value tracker for the default of this property in the passed in object
|
|
*
|
|
* @param Object The object to get the value for
|
|
* @param ObjIndex The index of the object in the parent property node's object array (for caching)
|
|
*/
|
|
TSharedPtr< FPropertyItemValueDataTrackerSlate > GetValueTracker( UObject* Object, uint32 ObjIndex );
|
|
|
|
/**
|
|
* Updates and caches the current edit const state of this property
|
|
*/
|
|
void UpdateEditConstState();
|
|
|
|
/**
|
|
* Checks to see if the supplied property of a child node requires validation
|
|
* @param InChildProp The property of the child node
|
|
* @return True if the property requires validation, false otherwise
|
|
*/
|
|
static bool DoesChildPropertyRequireValidation(FProperty* InChildProp);
|
|
|
|
protected:
|
|
|
|
static FEditConditionParser EditConditionParser;
|
|
|
|
/**
|
|
* The node that is the parent of this node or nullptr for the root
|
|
*/
|
|
TWeakPtr<FPropertyNode> ParentNodeWeakPtr;
|
|
|
|
/** The property node, if any, that serves as the key value for this node */
|
|
TSharedPtr<FPropertyNode> PropertyKeyNode;
|
|
|
|
/** Cached read addresses for this property node */
|
|
mutable FReadAddressListData CachedReadAddresses;
|
|
|
|
/** List of per object default value trackers associated with this property node */
|
|
TArray< TSharedPtr<FPropertyItemValueDataTrackerSlate> > ObjectDefaultValueTrackers;
|
|
|
|
/** List of all child nodes this node is responsible for */
|
|
TArray< TSharedPtr<FPropertyNode> > ChildNodes;
|
|
|
|
/** Called when this node's children are rebuilt */
|
|
FPropertyChildrenRebuiltEvent OnRebuildChildrenEvent;
|
|
|
|
/** Called when this node's property value is about to change (called during NotifyPreChange) */
|
|
FPropertyValuePreChangeEvent PropertyValuePreChangeEvent;
|
|
|
|
/** Called when a child's property value is about to change */
|
|
FPropertyValuePreChangeEvent ChildPropertyValuePreChangeEvent;
|
|
|
|
/** Called when this node's property value has changed (called during NotifyPostChange) */
|
|
FPropertyValueChangedEvent PropertyValueChangedEvent;
|
|
/** Called when this node's property value has changed with the property changed event data as payload (called during NotifyPostChange) */
|
|
FPropertyValueChangedWithData PropertyValueChangedDelegate;
|
|
|
|
/** Called when a child's property value has changed */
|
|
FPropertyValueChangedEvent ChildPropertyValueChangedEvent;
|
|
/** Called when a child's property value has changed with the property changed event data as payload */
|
|
FPropertyValueChangedWithData ChildPropertyValueChangedDelegate;
|
|
|
|
/** Called when the property is reset to default */
|
|
FPropertyResetToDefaultEvent PropertyResetToDefaultEvent;
|
|
|
|
/** The property being displayed/edited. */
|
|
TWeakFieldPtr<FProperty> Property;
|
|
|
|
/** Offset to the property data within either a fixed array or a dynamic array */
|
|
int32 ArrayOffset;
|
|
|
|
/** The index of the property if it is inside an array, set, or map (internally, we'll use set/map helpers that store element indices in an array) */
|
|
int32 ArrayIndex;
|
|
|
|
/** Safety Value representing Depth in the property tree used to stop diabolical topology cases
|
|
* -1 = No limit on children
|
|
* 0 = No more children are allowed. Do not process child nodes
|
|
* >0 = A limit has been set by the property and will tick down for successive children
|
|
*/
|
|
int32 MaxChildDepthAllowed;
|
|
|
|
/**
|
|
* Used for flags to determine if the node is seen (if not seen and never been created, don't create it on display)
|
|
*/
|
|
EPropertyNodeFlags::Type PropertyNodeFlags;
|
|
|
|
/** If true, children of this node will be rebuilt next tick. */
|
|
bool bRebuildChildrenRequested;
|
|
|
|
/** Set to true when RebuildChildren is called on the node */
|
|
bool bChildrenRebuilt;
|
|
|
|
/** Set to true when we want to ignore CPF_InstancedReference */
|
|
bool bIgnoreInstancedReference;
|
|
|
|
/** If true, DestroyTree() has been called on the node. */
|
|
bool bIsDestroyed = false;
|
|
|
|
/** An array of restrictions limiting this property's potential values in property editors.*/
|
|
TArray<TSharedRef<const FPropertyRestriction>> Restrictions;
|
|
|
|
/** Optional reference to a tree node that is displaying this property */
|
|
TWeakPtr<FDetailTreeNode> TreeNode;
|
|
|
|
/**
|
|
* Stores metadata for this instance of the property (in contrast
|
|
* to regular metadata, which is stored per-class)
|
|
*/
|
|
TMap<FName, FString> InstanceMetaData;
|
|
|
|
/**
|
|
* The property path for this property
|
|
*/
|
|
FString PropertyPath;
|
|
|
|
/** Edit condition expression used to determine if this property editor can modify its property */
|
|
TSharedPtr<FEditConditionExpression> EditConditionExpression;
|
|
TSharedPtr<FEditConditionContext> EditConditionContext;
|
|
|
|
/**
|
|
* Cached state of flags that are expensive to update
|
|
* These update when values are changed in the details panel
|
|
*/
|
|
mutable bool bIsEditConst; // Includes EditCondition state
|
|
mutable bool bIsEditConstWithoutCondition; // Ignores EditCondition state
|
|
mutable bool bUpdateEditConstState;
|
|
mutable int32 UpdateEditConstStateEpoch;
|
|
mutable bool bDiffersFromDefault;
|
|
mutable bool bUpdateDiffersFromDefault;
|
|
mutable int32 UpdateDiffersFromDefaultEpoch;
|
|
};
|
|
|
|
class FComplexPropertyNode : public FPropertyNode
|
|
{
|
|
public:
|
|
|
|
enum EPropertyType
|
|
{
|
|
EPT_Object,
|
|
EPT_StandaloneStructure,
|
|
};
|
|
|
|
FComplexPropertyNode() : FPropertyNode() {}
|
|
virtual ~FComplexPropertyNode() {}
|
|
|
|
virtual FComplexPropertyNode* AsComplexNode() override { return this; }
|
|
virtual const FComplexPropertyNode* AsComplexNode() const override { return this; }
|
|
|
|
virtual FStructurePropertyNode* AsStructureNode() { return nullptr; }
|
|
virtual const FStructurePropertyNode* AsStructureNode() const { return nullptr; }
|
|
|
|
virtual void SetDisplayNameOverride(const FText& InDisplayNameOverride) override;
|
|
virtual FText GetDisplayName() const override;
|
|
|
|
virtual UStruct* GetBaseStructure() = 0;
|
|
virtual const UStruct* GetBaseStructure() const = 0;
|
|
|
|
// Returns the base struct as well as any sidecar data structs
|
|
virtual TArray<UStruct*> GetAllStructures() = 0;
|
|
virtual TArray<const UStruct*> GetAllStructures() const = 0;
|
|
|
|
virtual int32 GetInstancesNum() const = 0;
|
|
virtual uint8* GetMemoryOfInstance(int32 Index) const = 0;
|
|
|
|
/**
|
|
* Returns a pointer to the stored value of InProperty on InParentNode's Index'th instance.
|
|
*/
|
|
virtual uint8* GetValuePtrOfInstance(int32 Index, const FProperty* InProperty, const FPropertyNode* InParentNode) const = 0;
|
|
virtual TWeakObjectPtr<UObject> GetInstanceAsUObject(int32 Index) const = 0;
|
|
virtual EPropertyType GetPropertyType() const = 0;
|
|
|
|
virtual void Disconnect() = 0;
|
|
|
|
/** Generates a single child from the provided property name. Any existing children are destroyed */
|
|
virtual TSharedPtr<FPropertyNode> GenerateSingleChild(FName ChildPropertyName) = 0;
|
|
|
|
private:
|
|
/** Display name to use instead of the fully qualified name */
|
|
FText DisplayNameOverride;
|
|
};
|