Property manipulation now getting closer
This commit is contained in:
@@ -8,39 +8,10 @@
|
|||||||
#include "Components/PanelSlot.h"
|
#include "Components/PanelSlot.h"
|
||||||
#include "MaterialGraph/MaterialGraphNode.h"
|
#include "MaterialGraph/MaterialGraphNode.h"
|
||||||
#include "Materials/MaterialExpression.h"
|
#include "Materials/MaterialExpression.h"
|
||||||
#include "DetailTreeNode.h"
|
|
||||||
#include "PropertyNode.h"
|
|
||||||
#include "ObjectPropertyNode.h"
|
|
||||||
#include "PropertyNode.h"
|
|
||||||
#include "ObjectPropertyNode.h"
|
|
||||||
#include "ItemPropertyNode.h"
|
|
||||||
#include "CategoryPropertyNode.h"
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// IsSubObject
|
// Get Root
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool WingPropHandle::IsSubObject(const TSharedRef<IDetailTreeNode>& Node)
|
|
||||||
{
|
|
||||||
FDetailTreeNode& DetailNode = static_cast<FDetailTreeNode&>(*Node);
|
|
||||||
TSharedPtr<FPropertyNode> PropNode = DetailNode.GetPropertyNode();
|
|
||||||
if (!PropNode.IsValid()) return false;
|
|
||||||
|
|
||||||
FPropertyNode* Current = PropNode.Get();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Current == nullptr) return false;
|
|
||||||
FPropertyNode *Parent = Current->GetParentNode();
|
|
||||||
if (Current->AsObjectNode()) return (Parent != nullptr);
|
|
||||||
Current = Parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Get Generator
|
|
||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -52,29 +23,66 @@ TSharedRef<IPropertyRowGenerator> WingPropHandle::CreateGenerator()
|
|||||||
return Module.CreatePropertyRowGenerator(Args);
|
return Module.CreatePropertyRowGenerator(Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSharedRef<IPropertyRowGenerator> WingPropHandle::GetGeneratorForObject(UObject* Obj)
|
WingPropHandle::Root& WingPropHandle::GetRootForObject(UObject* Obj)
|
||||||
{
|
{
|
||||||
for (auto& Pair : Generators)
|
for (Root& R : Roots)
|
||||||
{
|
{
|
||||||
if (Pair.Key == Obj) return Pair.Value.ToSharedRef();
|
if (R.Base == (uint8*)Obj) return R;
|
||||||
}
|
}
|
||||||
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
||||||
Gen->SetObjects({Obj});
|
Gen->SetObjects({Obj});
|
||||||
Generators.Add({Obj, Gen});
|
Root& R = Roots.AddDefaulted_GetRef();
|
||||||
return Gen;
|
R.Struct = Obj->GetClass();
|
||||||
|
R.Base = (uint8*)Obj;
|
||||||
|
R.End = R.Base + R.Struct->GetStructureSize();
|
||||||
|
R.Generator = Gen;
|
||||||
|
return R;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSharedRef<IPropertyRowGenerator> WingPropHandle::GetGeneratorForStruct(const UStruct* ScriptStruct, uint8* Data)
|
WingPropHandle::Root& WingPropHandle::GetRootForStruct(const UStruct* ScriptStruct, uint8* Data)
|
||||||
{
|
{
|
||||||
for (auto& Pair : Generators)
|
for (Root& R : Roots)
|
||||||
{
|
{
|
||||||
if (Pair.Key == Data) return Pair.Value.ToSharedRef();
|
if (R.Base == Data) return R;
|
||||||
}
|
}
|
||||||
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
||||||
TSharedPtr<FStructOnScope> Wrapper = MakeShared<FStructOnScope>(ScriptStruct, Data);
|
TSharedPtr<FStructOnScope> Wrapper = MakeShared<FStructOnScope>(ScriptStruct, Data);
|
||||||
Gen->SetStructure(Wrapper);
|
Gen->SetStructure(Wrapper);
|
||||||
Generators.Add({Data, Gen});
|
Root& R = Roots.AddDefaulted_GetRef();
|
||||||
return Gen;
|
R.Struct = ScriptStruct;
|
||||||
|
R.Base = Data;
|
||||||
|
R.End = Data + ScriptStruct->GetStructureSize();
|
||||||
|
R.Generator = Gen;
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IsInsideRootObject
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool WingPropHandle::IsInsideRootObject(const Root& Root, IPropertyHandle& Handle)
|
||||||
|
{
|
||||||
|
// Walk up to the topmost property handle that still has a property.
|
||||||
|
// Keep the shared pointers alive so the raw pointer stays valid.
|
||||||
|
TSharedPtr<IPropertyHandle> Held;
|
||||||
|
IPropertyHandle* Top = &Handle;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
TSharedPtr<IPropertyHandle> Parent = Top->GetParentHandle();
|
||||||
|
if (!Parent.IsValid() || !Parent->GetProperty()) break;
|
||||||
|
Held = Parent;
|
||||||
|
Top = Held.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the address of the topmost property's data.
|
||||||
|
void* Addr = nullptr;
|
||||||
|
if (Top->GetValueData(Addr) != FPropertyAccess::Success || !Addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8* DataPtr = (uint8*)Addr;
|
||||||
|
return DataPtr >= Root.Base && DataPtr < Root.End;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -85,7 +93,6 @@ TSharedRef<IPropertyRowGenerator> WingPropHandle::GetGeneratorForStruct(const US
|
|||||||
|
|
||||||
void WingPropHandle::AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& Node, FlatTree& Out)
|
void WingPropHandle::AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& Node, FlatTree& Out)
|
||||||
{
|
{
|
||||||
if (IsSubObject(Node)) return;
|
|
||||||
if (Node->GetNodeType() == EDetailNodeType::Category)
|
if (Node->GetNodeType() == EDetailNodeType::Category)
|
||||||
{
|
{
|
||||||
TArray<TSharedRef<IDetailTreeNode>> Children;
|
TArray<TSharedRef<IDetailTreeNode>> Children;
|
||||||
@@ -100,12 +107,12 @@ void WingPropHandle::AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& No
|
|||||||
Out.Add(&*Node);
|
Out.Add(&*Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(TSharedRef<IPropertyRowGenerator> Generator)
|
WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(Root& Root)
|
||||||
{
|
{
|
||||||
FlatTree Result;
|
FlatTree Result;
|
||||||
for (const TSharedRef<IDetailTreeNode>& Root : Generator->GetRootTreeNodes())
|
for (const TSharedRef<IDetailTreeNode>& TreeRoot : Root.Generator->GetRootTreeNodes())
|
||||||
{
|
{
|
||||||
AllTreeNodesRecursive(Root, Result);
|
AllTreeNodesRecursive(TreeRoot, Result);
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@@ -116,33 +123,34 @@ WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(TSharedRef<IPropertyRowGen
|
|||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
WingPropHandle::Handles WingPropHandle::AllProperties(TSharedRef<IPropertyRowGenerator> Generator, EPropertyFlags Filter)
|
WingPropHandle::Handles WingPropHandle::AllProperties(Root& Root, EPropertyFlags Filter)
|
||||||
{
|
{
|
||||||
Handles Result;
|
Handles Result;
|
||||||
for (IDetailTreeNode* Node : AllTreeNodes(Generator))
|
for (IDetailTreeNode* Node : AllTreeNodes(Root))
|
||||||
{
|
{
|
||||||
TSharedPtr<IPropertyHandle> Handle = Node->CreatePropertyHandle();
|
TSharedPtr<IPropertyHandle> Handle = Node->CreatePropertyHandle();
|
||||||
if (Handle.IsValid() && Handle->GetProperty())
|
if (Handle.IsValid() && Handle->GetProperty())
|
||||||
{
|
{
|
||||||
if (Filter == CPF_None || Handle->GetProperty()->HasAllPropertyFlags(Filter))
|
if (Filter != CPF_None && !Handle->GetProperty()->HasAllPropertyFlags(Filter))
|
||||||
{
|
continue;
|
||||||
|
if (!IsInsideRootObject(Root, *Handle))
|
||||||
|
continue;
|
||||||
Result.Add(Handle);
|
Result.Add(Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
WingPropHandle::Handles WingPropHandle::AllProperties(UObject* Obj, EPropertyFlags Filter)
|
WingPropHandle::Handles WingPropHandle::AllProperties(UObject* Obj, EPropertyFlags Filter)
|
||||||
{
|
{
|
||||||
if (!Obj) return {};
|
if (!Obj) return {};
|
||||||
return AllProperties(GetGeneratorForObject(Obj), Filter);
|
return AllProperties(GetRootForObject(Obj), Filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruct, uint8* Data, EPropertyFlags Filter)
|
WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruct, uint8* Data, EPropertyFlags Filter)
|
||||||
{
|
{
|
||||||
if (!ScriptStruct || !Data) return {};
|
if (!ScriptStruct || !Data) return {};
|
||||||
return AllProperties(GetGeneratorForStruct(ScriptStruct, Data), Filter);
|
return AllProperties(GetRootForStruct(ScriptStruct, Data), Filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -151,12 +159,14 @@ WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruc
|
|||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(TSharedRef<IPropertyRowGenerator> Generator, FName Name)
|
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(Root& Root, FName Name)
|
||||||
{
|
{
|
||||||
for (IDetailTreeNode* Node : AllTreeNodes(Generator))
|
for (IDetailTreeNode* Node : AllTreeNodes(Root))
|
||||||
{
|
{
|
||||||
if (Node->GetNodeName() == Name)
|
if (Node->GetNodeName() != Name) continue;
|
||||||
return Node->CreatePropertyHandle();
|
TSharedPtr<IPropertyHandle> Handle = Node->CreatePropertyHandle();
|
||||||
|
if (Handle.IsValid() && IsInsideRootObject(Root, *Handle))
|
||||||
|
return Handle;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -164,13 +174,13 @@ TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(TSharedRef<IPropertyRo
|
|||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(UObject* Obj, FName Name)
|
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(UObject* Obj, FName Name)
|
||||||
{
|
{
|
||||||
if (!Obj) return nullptr;
|
if (!Obj) return nullptr;
|
||||||
return NamedProperty(GetGeneratorForObject(Obj), Name);
|
return NamedProperty(GetRootForObject(Obj), Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name)
|
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name)
|
||||||
{
|
{
|
||||||
if (!ScriptStruct || !Data) return nullptr;
|
if (!ScriptStruct || !Data) return nullptr;
|
||||||
return NamedProperty(GetGeneratorForStruct(ScriptStruct, Data), Name);
|
return NamedProperty(GetRootForStruct(ScriptStruct, Data), Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -231,4 +241,3 @@ WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable, E
|
|||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,18 +44,23 @@ public:
|
|||||||
TSharedPtr<IPropertyHandle> NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name);
|
TSharedPtr<IPropertyHandle> NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TArray<TPair<void*, TSharedPtr<IPropertyRowGenerator>>> Generators;
|
struct Root
|
||||||
|
{
|
||||||
|
const UStruct* Struct = nullptr;
|
||||||
|
uint8* Base = nullptr;
|
||||||
|
uint8* End = nullptr;
|
||||||
|
TSharedPtr<IPropertyRowGenerator> Generator;
|
||||||
|
};
|
||||||
|
|
||||||
// Check whether a detail tree node's property comes from a sub-object.
|
static bool IsInsideRootObject(const Root& Root, IPropertyHandle& Handle);
|
||||||
static bool IsSubObject(const TSharedRef<IDetailTreeNode>& Node);
|
TArray<Root> Roots;
|
||||||
|
|
||||||
static TSharedRef<IPropertyRowGenerator> CreateGenerator();
|
static TSharedRef<IPropertyRowGenerator> CreateGenerator();
|
||||||
TSharedRef<IPropertyRowGenerator> GetGeneratorForObject(UObject* Obj);
|
Root& GetRootForObject(UObject* Obj);
|
||||||
TSharedRef<IPropertyRowGenerator> GetGeneratorForStruct(const UStruct* ScriptStruct, uint8* Data);
|
Root& GetRootForStruct(const UStruct* ScriptStruct, uint8* Data);
|
||||||
|
|
||||||
static void AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& Node, FlatTree& Out);
|
static void AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& Node, FlatTree& Out);
|
||||||
static FlatTree AllTreeNodes(TSharedRef<IPropertyRowGenerator> Generator);
|
static FlatTree AllTreeNodes(Root& Root);
|
||||||
|
|
||||||
Handles AllProperties(TSharedRef<IPropertyRowGenerator> Generator, EPropertyFlags Filter);
|
Handles AllProperties(Root& Root, EPropertyFlags Filter);
|
||||||
static TSharedPtr<IPropertyHandle> NamedProperty(TSharedRef<IPropertyRowGenerator> Generator, FName Name);
|
static TSharedPtr<IPropertyHandle> NamedProperty(Root& Root, FName Name);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ public class UEWingman : ModuleRules
|
|||||||
{
|
{
|
||||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
// Needed for debug dump of FPropertyNode tree (private headers)
|
|
||||||
PrivateIncludePaths.Add(System.IO.Path.Combine(EngineDirectory, "Source/Editor/PropertyEditor/Private"));
|
|
||||||
|
|
||||||
|
|
||||||
PublicDependencyModuleNames.AddRange(new string[]
|
PublicDependencyModuleNames.AddRange(new string[]
|
||||||
|
|||||||
Reference in New Issue
Block a user