New infrastructure for property manipulation.
This commit is contained in:
234
Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp
Normal file
234
Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
#include "WingPropHandle.h"
|
||||
#include "WingServer.h"
|
||||
#include "WingActorComponent.h"
|
||||
#include "PropertyEditorModule.h"
|
||||
#include "IDetailTreeNode.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "Components/Widget.h"
|
||||
#include "Components/PanelSlot.h"
|
||||
#include "MaterialGraph/MaterialGraphNode.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
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TSharedRef<IPropertyRowGenerator> WingPropHandle::CreateGenerator()
|
||||
{
|
||||
FPropertyEditorModule& Module = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
||||
FPropertyRowGeneratorArgs Args;
|
||||
Args.bShouldShowHiddenProperties = false;
|
||||
return Module.CreatePropertyRowGenerator(Args);
|
||||
}
|
||||
|
||||
TSharedRef<IPropertyRowGenerator> WingPropHandle::GetGeneratorForObject(UObject* Obj)
|
||||
{
|
||||
for (auto& Pair : Generators)
|
||||
{
|
||||
if (Pair.Key == Obj) return Pair.Value.ToSharedRef();
|
||||
}
|
||||
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
||||
Gen->SetObjects({Obj});
|
||||
Generators.Add({Obj, Gen});
|
||||
return Gen;
|
||||
}
|
||||
|
||||
TSharedRef<IPropertyRowGenerator> WingPropHandle::GetGeneratorForStruct(const UStruct* ScriptStruct, uint8* Data)
|
||||
{
|
||||
for (auto& Pair : Generators)
|
||||
{
|
||||
if (Pair.Key == Data) return Pair.Value.ToSharedRef();
|
||||
}
|
||||
TSharedRef<IPropertyRowGenerator> Gen = CreateGenerator();
|
||||
TSharedPtr<FStructOnScope> Wrapper = MakeShared<FStructOnScope>(ScriptStruct, Data);
|
||||
Gen->SetStructure(Wrapper);
|
||||
Generators.Add({Data, Gen});
|
||||
return Gen;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// All Tree Nodes
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WingPropHandle::AllTreeNodesRecursive(const TSharedRef<IDetailTreeNode>& Node, FlatTree& Out)
|
||||
{
|
||||
if (IsSubObject(Node)) return;
|
||||
if (Node->GetNodeType() == EDetailNodeType::Category)
|
||||
{
|
||||
TArray<TSharedRef<IDetailTreeNode>> Children;
|
||||
Node->GetChildren(Children);
|
||||
for (const TSharedRef<IDetailTreeNode>& Child : Children)
|
||||
{
|
||||
AllTreeNodesRecursive(Child, Out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Out.Add(&*Node);
|
||||
}
|
||||
|
||||
WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(TSharedRef<IPropertyRowGenerator> Generator)
|
||||
{
|
||||
FlatTree Result;
|
||||
for (const TSharedRef<IDetailTreeNode>& Root : Generator->GetRootTreeNodes())
|
||||
{
|
||||
AllTreeNodesRecursive(Root, Result);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AllProperties
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WingPropHandle::Handles WingPropHandle::AllProperties(TSharedRef<IPropertyRowGenerator> Generator, EPropertyFlags Filter)
|
||||
{
|
||||
Handles Result;
|
||||
for (IDetailTreeNode* Node : AllTreeNodes(Generator))
|
||||
{
|
||||
TSharedPtr<IPropertyHandle> Handle = Node->CreatePropertyHandle();
|
||||
if (Handle.IsValid() && Handle->GetProperty())
|
||||
{
|
||||
if (Filter == CPF_None || Handle->GetProperty()->HasAllPropertyFlags(Filter))
|
||||
{
|
||||
Result.Add(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
WingPropHandle::Handles WingPropHandle::AllProperties(UObject* Obj, EPropertyFlags Filter)
|
||||
{
|
||||
if (!Obj) return {};
|
||||
return AllProperties(GetGeneratorForObject(Obj), Filter);
|
||||
}
|
||||
|
||||
WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruct, uint8* Data, EPropertyFlags Filter)
|
||||
{
|
||||
if (!ScriptStruct || !Data) return {};
|
||||
return AllProperties(GetGeneratorForStruct(ScriptStruct, Data), Filter);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Named Property
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(TSharedRef<IPropertyRowGenerator> Generator, FName Name)
|
||||
{
|
||||
for (IDetailTreeNode* Node : AllTreeNodes(Generator))
|
||||
{
|
||||
if (Node->GetNodeName() == Name)
|
||||
return Node->CreatePropertyHandle();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(UObject* Obj, FName Name)
|
||||
{
|
||||
if (!Obj) return nullptr;
|
||||
return NamedProperty(GetGeneratorForObject(Obj), Name);
|
||||
}
|
||||
|
||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name)
|
||||
{
|
||||
if (!ScriptStruct || !Data) return nullptr;
|
||||
return NamedProperty(GetGeneratorForStruct(ScriptStruct, Data), Name);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GetDetails
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable, EPropertyFlags Filter)
|
||||
{
|
||||
if (!Obj) return {};
|
||||
|
||||
// Blueprints: redirect to the generated class CDO.
|
||||
if (UBlueprint* BP = Cast<UBlueprint>(Obj))
|
||||
{
|
||||
if (!BP->GeneratedClass)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName());
|
||||
return {};
|
||||
}
|
||||
Obj = BP->GeneratedClass->GetDefaultObject();
|
||||
}
|
||||
|
||||
// Component references: redirect to the template.
|
||||
if (UWingComponentReference* Ref = Cast<UWingComponentReference>(Obj))
|
||||
{
|
||||
Obj = Mutable ? Ref->GetMutableTemplate() : Ref->GetImmutableTemplate();
|
||||
if (!Obj)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Handles Result = AllProperties(Obj, Filter);
|
||||
|
||||
// Material graph nodes: also collect expression properties.
|
||||
if (UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(Obj))
|
||||
{
|
||||
if (UMaterialExpression* Expr = MatNode->MaterialExpression)
|
||||
{
|
||||
Result.Append(AllProperties(Expr, Filter));
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: hide the Slot property, add slot properties.
|
||||
if (UWidget* Widget = Cast<UWidget>(Obj))
|
||||
{
|
||||
Result.RemoveAll([](const TSharedPtr<IPropertyHandle>& H)
|
||||
{
|
||||
return H->GetProperty()->GetFName() == TEXT("Slot");
|
||||
});
|
||||
if (UPanelSlot* Slot = Widget->Slot)
|
||||
{
|
||||
Result.Append(AllProperties(Slot, Filter));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user