Working on better handling of property setters

This commit is contained in:
2026-03-23 00:18:12 -04:00
parent f38630ea08
commit 2a064f3666
10 changed files with 105 additions and 25 deletions

Binary file not shown.

View File

@@ -15,6 +15,9 @@
#include "AnimationGraph.h" #include "AnimationGraph.h"
#include "AnimationGraphSchema.h" #include "AnimationGraphSchema.h"
#include "AnimationStateMachineSchema.h" #include "AnimationStateMachineSchema.h"
#include "WingWidgets.h"
#include "WidgetBlueprint.h"
#include "Blueprint/WidgetTree.h"
#include "Blueprint_Dump.generated.h" #include "Blueprint_Dump.generated.h"
@@ -96,6 +99,13 @@ public:
} }
} }
// Widget Tree
if (UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(BP))
{
UWingServer::Print(TEXT("\nWidget Tree:\n"));
WingWidgets::PrintWidgetTree(WidgetBP->WidgetTree->RootWidget, 1);
}
// Event Dispatchers // Event Dispatchers
if (!BP->DelegateSignatureGraphs.IsEmpty()) if (!BP->DelegateSignatureGraphs.IsEmpty())
{ {

View File

@@ -14,6 +14,9 @@
#include "MaterialGraph/MaterialGraphNode.h" #include "MaterialGraph/MaterialGraphNode.h"
#include "IMaterialEditor.h" #include "IMaterialEditor.h"
#include "Engine/LevelScriptBlueprint.h" #include "Engine/LevelScriptBlueprint.h"
#include "WidgetBlueprint.h"
#include "Blueprint/WidgetTree.h"
#include "Components/Widget.h"
#include "Subsystems/AssetEditorSubsystem.h" #include "Subsystems/AssetEditorSubsystem.h"
WingFetcher::WalkFunc WingFetcher::GetWalker(const FString& Step) WingFetcher::WalkFunc WingFetcher::GetWalker(const FString& Step)
@@ -22,6 +25,7 @@ WingFetcher::WalkFunc WingFetcher::GetWalker(const FString& Step)
if (Step.Equals(TEXT("node"), ESearchCase::IgnoreCase)) return &WingFetcher::Node; if (Step.Equals(TEXT("node"), ESearchCase::IgnoreCase)) return &WingFetcher::Node;
if (Step.Equals(TEXT("pin"), ESearchCase::IgnoreCase)) return &WingFetcher::Pin; if (Step.Equals(TEXT("pin"), ESearchCase::IgnoreCase)) return &WingFetcher::Pin;
if (Step.Equals(TEXT("component"), ESearchCase::IgnoreCase)) return &WingFetcher::Component; if (Step.Equals(TEXT("component"), ESearchCase::IgnoreCase)) return &WingFetcher::Component;
if (Step.Equals(TEXT("widget"), ESearchCase::IgnoreCase)) return &WingFetcher::Widget;
if (Step.Equals(TEXT("levelblueprint"), ESearchCase::IgnoreCase)) return &WingFetcher::LevelBlueprint; if (Step.Equals(TEXT("levelblueprint"), ESearchCase::IgnoreCase)) return &WingFetcher::LevelBlueprint;
return nullptr; return nullptr;
} }
@@ -312,6 +316,23 @@ WingFetcher& WingFetcher::Component(const FString& Value)
return *this; return *this;
} }
WingFetcher& WingFetcher::Widget(const FString& Value)
{
if (bError) return *this;
UWidgetBlueprint* WidgetBP = ::Cast<UWidgetBlueprint>(Obj);
if (!WidgetBP)
return TypeMismatch(TEXT("widget"), TEXT("WidgetBlueprint"));
TArray<UWidget*> AllWidgets;
WidgetBP->WidgetTree->GetAllWidgets(AllWidgets);
UWidget* Found = WingUtils::FindExactlyOneNamed(Value, AllWidgets, TEXT("Widget"));
if (!Found) return SetError();
SetObj(Found);
return *this;
}
WingFetcher& WingFetcher::LevelBlueprint(const FString& Value) WingFetcher& WingFetcher::LevelBlueprint(const FString& Value)
{ {
if (bError) return *this; if (bError) return *this;

View File

@@ -29,11 +29,14 @@ FString FWingProperty::GetCategory()
FString FWingProperty::GetText() const FString FWingProperty::GetText() const
{ {
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
if (IsPinTypeProperty(Prop)) if (IsPinTypeProperty(Prop))
return UWingTypes::TypeToText(*static_cast<FEdGraphPinType*>(ValuePtr)); {
FEdGraphPinType PinType;
Prop->GetValue_InContainer(Container, &PinType);
return UWingTypes::TypeToText(PinType);
}
FString Result; FString Result;
Prop->ExportTextItem_Direct(Result, ValuePtr, nullptr, nullptr, PPF_None); Prop->ExportTextItem_InContainer(Result, Container, nullptr, nullptr, PPF_None);
return Result; return Result;
} }
@@ -49,15 +52,18 @@ FString FWingProperty::GetTruncatedText(int32 MaxLen) const
bool FWingProperty::SetText(const FString &Value) bool FWingProperty::SetText(const FString &Value)
{ {
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
// Notify that we're modifying the containing object. // Notify that we're modifying the containing object.
if (Prop->GetOwnerClass()) if (Prop->GetOwnerClass())
UWingServer::AddTouchedObject(static_cast<UObject*>(Container)); UWingServer::AddTouchedObject(static_cast<UObject*>(Container));
// Pin types get parsed by UWingTypes. // Pin types get parsed by UWingTypes.
if (IsPinTypeProperty(Prop)) if (IsPinTypeProperty(Prop))
return UWingTypes::TextToType(Value, *static_cast<FEdGraphPinType*>(ValuePtr)); {
FEdGraphPinType PinType;
if (!UWingTypes::TextToType(Value, PinType)) return false;
Prop->SetValue_InContainer(Container, &PinType);
return true;
}
// Byte Enum types. // Byte Enum types.
if (FByteProperty* ByteProp = CastField<FByteProperty>(Prop)) if (FByteProperty* ByteProp = CastField<FByteProperty>(Prop))
@@ -66,22 +72,27 @@ bool FWingProperty::SetText(const FString &Value)
{ {
int64 EnumValue; int64 EnumValue;
if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false; if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false;
ByteProp->SetPropertyValue(ValuePtr, (uint8)EnumValue); uint8 ByteValue = (uint8)EnumValue;
Prop->SetValue_InContainer(Container, &ByteValue);
return true; return true;
} }
} }
// Regular Enum types. // Regular Enum types.
// TODO: This doesn't use an incontainer setter, which means it
// doesn't call property setters.
if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Prop)) if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Prop))
{ {
int64 EnumValue; int64 EnumValue;
if (!WingUtils::StringToEnum(EnumProp->GetEnum(), Value, EnumValue)) return false; if (!WingUtils::StringToEnum(EnumProp->GetEnum(), Value, EnumValue)) return false;
EnumProp->GetUnderlyingProperty()->SetIntPropertyValue(ValuePtr, EnumValue); FNumericProperty* Underlying = EnumProp->GetUnderlyingProperty();
void* ValuePtr = Underlying->ContainerPtrToValuePtr<void>(Container);
Underlying->SetIntPropertyValue(ValuePtr, EnumValue);
return true; return true;
} }
// Non-enum properties use ImportText // Non-enum properties use ImportText
const TCHAR* Result = Prop->ImportText_Direct(*Value, ValuePtr, nullptr, PPF_None); const TCHAR* Result = Prop->ImportText_InContainer(*Value, Container, nullptr, PPF_None);
if (!Result) if (!Result)
{ {
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"),

View File

@@ -271,7 +271,12 @@ FString WingUtils::FormatName(const FBPInterfaceDescription &IFace)
FString WingUtils::FormatName(const FWingActorComponent &Comp) FString WingUtils::FormatName(const FWingActorComponent &Comp)
{ {
return Comp.GetName(); return SanitizeName(Comp.GetName());
}
FString WingUtils::FormatName(const UWidget *Widget)
{
return SanitizeName(Widget->GetName());
} }
// ============================================================ // ============================================================

View File

@@ -0,0 +1,26 @@
#include "WingWidgets.h"
#include "WingServer.h"
#include "WingUtils.h"
#include "Blueprint/WidgetTree.h"
#include "Components/Widget.h"
#include "Components/PanelWidget.h"
#include "Components/PanelSlot.h"
void WingWidgets::PrintWidgetTree(UWidget* Widget, int32 Depth)
{
FString Indent = FString::ChrN(Depth * 2, TEXT(' '));
if (Widget == nullptr)
{
UWingServer::Printf(TEXT("%s[null]\n"), *Indent);
return;
}
FString TypeName = WingUtils::FormatName(Widget->GetClass());
FString WidgetName = WingUtils::FormatName(Widget);
UWingServer::Printf(TEXT("%s%s %s\n"), *Indent, *TypeName, *WidgetName);
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
{
for (UPanelSlot* Slot : Panel->GetSlots())
PrintWidgetTree(Slot->Content, Depth + 1);
}
}

View File

@@ -52,6 +52,7 @@ public:
WingFetcher& Node(const FString& Value); WingFetcher& Node(const FString& Value);
WingFetcher& Pin(const FString& Value); WingFetcher& Pin(const FString& Value);
WingFetcher& Component(const FString& Value); WingFetcher& Component(const FString& Value);
WingFetcher& Widget(const FString& Value);
WingFetcher& LevelBlueprint(const FString& Value); WingFetcher& LevelBlueprint(const FString& Value);
// Return true if there haven't been any errors. // Return true if there haven't been any errors.

View File

@@ -28,6 +28,7 @@ class UTexture;
class UScriptStruct; class UScriptStruct;
class UEnum; class UEnum;
class USCS_Node; class USCS_Node;
class UWidget;
struct FMemberReference; struct FMemberReference;
struct FBPVariableDescription; struct FBPVariableDescription;
struct FUserPinInfo; struct FUserPinInfo;
@@ -79,6 +80,7 @@ public:
static FString FormatName(const FUserPinInfo &Pin); static FString FormatName(const FUserPinInfo &Pin);
static FString FormatName(const FBPInterfaceDescription &IFace); static FString FormatName(const FBPInterfaceDescription &IFace);
static FString FormatName(const FWingActorComponent &Comp); static FString FormatName(const FWingActorComponent &Comp);
static FString FormatName(const UWidget *Widget);
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
// Identifies // Identifies
@@ -112,7 +114,7 @@ public:
return Result; return Result;
} }
template<typename T> template<typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
static TArray<T*> FindAllNamed(const FString &Name, TArray<T> &Array) static TArray<T*> FindAllNamed(const FString &Name, TArray<T> &Array)
{ {
TArray<T*> Result; TArray<T*> Result;
@@ -130,7 +132,7 @@ public:
return Result; return Result;
} }
template<typename T> template<typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
static T* FindExactlyOneNamed(const FString &Name, TArray<T> &Array, const TCHAR *Kind) static T* FindExactlyOneNamed(const FString &Name, TArray<T> &Array, const TCHAR *Kind)
{ {
int Count = 0; int Count = 0;
@@ -140,16 +142,6 @@ public:
return Result; return Result;
} }
template<typename T>
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T*> &Array, const TCHAR *Kind)
{
for (T* Elt: Array) if (Identifies(Name, Elt))
{
return CheckExactlyNoneNamed(1, Kind, Name);
}
return true;
}
template<typename T> template<typename T>
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T> &Array, const TCHAR *Kind) static bool FindExactlyNoneNamed(const FString &Name, const TArray<T> &Array, const TCHAR *Kind)
{ {

View File

@@ -0,0 +1,13 @@
#pragma once
#include "CoreMinimal.h"
class UWidgetTree;
class UWidget;
// Utility functions for widget blueprint manipulation.
class WingWidgets
{
public:
static void PrintWidgetTree(UWidget* Widget, int32 Depth);
};

View File

@@ -33,7 +33,8 @@ public class UEWingman : ModuleRules
"Slate", "Slate",
"SlateCore", "SlateCore",
"ToolMenus", "ToolMenus",
"UMG" "UMG",
"UMGEditor"
}); });
} }
} }