diff --git a/Content/Testing/WB_Test.uasset b/Content/Testing/WB_Test.uasset index 06107175..ad5d476d 100644 --- a/Content/Testing/WB_Test.uasset +++ b/Content/Testing/WB_Test.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa22b0edc55f4fd1bbf9a39dad11345b262b02b4c0c301851f2ab6bb3b744027 -size 22727 +oid sha256:1dca259b72ad5ac75be4009daab1861cd55439cf1825d8f4e7b7c25c7aea468d +size 24321 diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h index 1aed6a7a..dd127ac1 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -15,6 +15,9 @@ #include "AnimationGraph.h" #include "AnimationGraphSchema.h" #include "AnimationStateMachineSchema.h" +#include "WingWidgets.h" +#include "WidgetBlueprint.h" +#include "Blueprint/WidgetTree.h" #include "Blueprint_Dump.generated.h" @@ -96,6 +99,13 @@ public: } } + // Widget Tree + if (UWidgetBlueprint* WidgetBP = Cast(BP)) + { + UWingServer::Print(TEXT("\nWidget Tree:\n")); + WingWidgets::PrintWidgetTree(WidgetBP->WidgetTree->RootWidget, 1); + } + // Event Dispatchers if (!BP->DelegateSignatureGraphs.IsEmpty()) { diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp index 2b0deb64..cb61d835 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp @@ -14,6 +14,9 @@ #include "MaterialGraph/MaterialGraphNode.h" #include "IMaterialEditor.h" #include "Engine/LevelScriptBlueprint.h" +#include "WidgetBlueprint.h" +#include "Blueprint/WidgetTree.h" +#include "Components/Widget.h" #include "Subsystems/AssetEditorSubsystem.h" 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("pin"), ESearchCase::IgnoreCase)) return &WingFetcher::Pin; 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; return nullptr; } @@ -312,6 +316,23 @@ WingFetcher& WingFetcher::Component(const FString& Value) return *this; } +WingFetcher& WingFetcher::Widget(const FString& Value) +{ + if (bError) return *this; + + UWidgetBlueprint* WidgetBP = ::Cast(Obj); + if (!WidgetBP) + return TypeMismatch(TEXT("widget"), TEXT("WidgetBlueprint")); + + TArray 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) { if (bError) return *this; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp index 3b4dd8f4..8684e863 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp @@ -29,11 +29,14 @@ FString FWingProperty::GetCategory() FString FWingProperty::GetText() const { - void* ValuePtr = Prop->ContainerPtrToValuePtr(Container); if (IsPinTypeProperty(Prop)) - return UWingTypes::TypeToText(*static_cast(ValuePtr)); + { + FEdGraphPinType PinType; + Prop->GetValue_InContainer(Container, &PinType); + return UWingTypes::TypeToText(PinType); + } FString Result; - Prop->ExportTextItem_Direct(Result, ValuePtr, nullptr, nullptr, PPF_None); + Prop->ExportTextItem_InContainer(Result, Container, nullptr, nullptr, PPF_None); return Result; } @@ -49,15 +52,18 @@ FString FWingProperty::GetTruncatedText(int32 MaxLen) const bool FWingProperty::SetText(const FString &Value) { - void* ValuePtr = Prop->ContainerPtrToValuePtr(Container); - // Notify that we're modifying the containing object. if (Prop->GetOwnerClass()) UWingServer::AddTouchedObject(static_cast(Container)); // Pin types get parsed by UWingTypes. if (IsPinTypeProperty(Prop)) - return UWingTypes::TextToType(Value, *static_cast(ValuePtr)); + { + FEdGraphPinType PinType; + if (!UWingTypes::TextToType(Value, PinType)) return false; + Prop->SetValue_InContainer(Container, &PinType); + return true; + } // Byte Enum types. if (FByteProperty* ByteProp = CastField(Prop)) @@ -66,22 +72,27 @@ bool FWingProperty::SetText(const FString &Value) { int64 EnumValue; if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false; - ByteProp->SetPropertyValue(ValuePtr, (uint8)EnumValue); + uint8 ByteValue = (uint8)EnumValue; + Prop->SetValue_InContainer(Container, &ByteValue); return true; } } // Regular Enum types. + // TODO: This doesn't use an incontainer setter, which means it + // doesn't call property setters. if (FEnumProperty* EnumProp = CastField(Prop)) { int64 EnumValue; if (!WingUtils::StringToEnum(EnumProp->GetEnum(), Value, EnumValue)) return false; - EnumProp->GetUnderlyingProperty()->SetIntPropertyValue(ValuePtr, EnumValue); + FNumericProperty* Underlying = EnumProp->GetUnderlyingProperty(); + void* ValuePtr = Underlying->ContainerPtrToValuePtr(Container); + Underlying->SetIntPropertyValue(ValuePtr, EnumValue); return true; } // 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) { UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp index 746132d6..64a40857 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp @@ -271,7 +271,12 @@ FString WingUtils::FormatName(const FBPInterfaceDescription &IFace) FString WingUtils::FormatName(const FWingActorComponent &Comp) { - return Comp.GetName(); + return SanitizeName(Comp.GetName()); +} + +FString WingUtils::FormatName(const UWidget *Widget) +{ + return SanitizeName(Widget->GetName()); } // ============================================================ diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp new file mode 100644 index 00000000..005a530e --- /dev/null +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp @@ -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(Widget)) + { + for (UPanelSlot* Slot : Panel->GetSlots()) + PrintWidgetTree(Slot->Content, Depth + 1); + } +} diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h index 9e108730..723cdaa3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h @@ -52,6 +52,7 @@ public: WingFetcher& Node(const FString& Value); WingFetcher& Pin(const FString& Value); WingFetcher& Component(const FString& Value); + WingFetcher& Widget(const FString& Value); WingFetcher& LevelBlueprint(const FString& Value); // Return true if there haven't been any errors. diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index 144c7737..952658f4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -28,6 +28,7 @@ class UTexture; class UScriptStruct; class UEnum; class USCS_Node; +class UWidget; struct FMemberReference; struct FBPVariableDescription; struct FUserPinInfo; @@ -79,6 +80,7 @@ public: static FString FormatName(const FUserPinInfo &Pin); static FString FormatName(const FBPInterfaceDescription &IFace); static FString FormatName(const FWingActorComponent &Comp); + static FString FormatName(const UWidget *Widget); //////////////////////////////////////////////////////// // Identifies @@ -112,7 +114,7 @@ public: return Result; } - template + template>> static TArray FindAllNamed(const FString &Name, TArray &Array) { TArray Result; @@ -130,7 +132,7 @@ public: return Result; } - template + template>> static T* FindExactlyOneNamed(const FString &Name, TArray &Array, const TCHAR *Kind) { int Count = 0; @@ -140,16 +142,6 @@ public: return Result; } - template - static bool FindExactlyNoneNamed(const FString &Name, const TArray &Array, const TCHAR *Kind) - { - for (T* Elt: Array) if (Identifies(Name, Elt)) - { - return CheckExactlyNoneNamed(1, Kind, Name); - } - return true; - } - template static bool FindExactlyNoneNamed(const FString &Name, const TArray &Array, const TCHAR *Kind) { diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h b/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h new file mode 100644 index 00000000..a4587126 --- /dev/null +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h @@ -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); +}; diff --git a/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs b/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs index b42cdca5..3946e0fa 100644 --- a/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs +++ b/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs @@ -33,7 +33,8 @@ public class UEWingman : ModuleRules "Slate", "SlateCore", "ToolMenus", - "UMG" + "UMG", + "UMGEditor" }); } }