// Copyright Epic Games, Inc. All Rights Reserved. #include "Bindings/MVVMConversionFunctionHelper.h" #include "BlueprintTypePromotion.h" #include "EngineLogs.h" #include "EdGraph/EdGraph.h" #include "K2Node_PromotableOperator.h" #include "K2Node_VariableGet.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Misc/StringBuilder.h" #include "Components/Widget.h" #include "MVVMBlueprintView.h" #include "MVVMBlueprintViewModelContext.h" #include "MVVMWidgetBlueprintExtension_View.h" #include "MVVMViewModelBase.h" #include "View/MVVMView.h" #include "WidgetBlueprint.h" namespace UE::MVVM::ConversionFunctionHelper { namespace Private { void BuildPropertyPath(TArray& Result, FMVVMBlueprintPropertyPath BasePath, UClass* Class, const UK2Node_VariableGet* CurrentNode) { bool bAddPath = false; const UEdGraphPin* OutputPin = CurrentNode->FindPinByPredicate([](UEdGraphPin* Pin) { return Pin->Direction == EGPD_Output; }); if (OutputPin) { for (const UEdGraphPin* LinkedTo : OutputPin->LinkedTo) { if (const UK2Node_VariableGet* LinkToVariable = Cast(LinkedTo->GetOwningNode())) { BasePath.SetBasePropertyPath(UE::MVVM::FMVVMConstFieldVariant(LinkToVariable->VariableReference.ResolveMember(Class))); BuildPropertyPath(Result, BasePath, Class, LinkToVariable); } else { bAddPath = true; } } } if (bAddPath) { Result.Add(BasePath); } } } //namespace TArray FindAllPropertyPathInGraph(const UEdGraph* Graph, const UMVVMBlueprintView* BlueprintView, UClass* Class) { TArray Result; TArray GetNodes; Graph->GetNodesOfClass(GetNodes); for (const UK2Node_VariableGet* Node : GetNodes) { if (Node->VariableReference.IsSelfContext()) { if (FProperty* Property = Node->VariableReference.ResolveMember(Class)) { const UClass* OwningClass = Class; if (const FObjectProperty* ObjectProperty = CastField(Property)) { OwningClass = ObjectProperty->PropertyClass; } check(OwningClass); FMVVMBlueprintPropertyPath PropertyPath; if (OwningClass->IsChildOf() || OwningClass->IsChildOf()) { PropertyPath.SetWidgetName(Property->GetFName()); } else if (OwningClass->ImplementsInterface(UNotifyFieldValueChanged::StaticClass())) { if (const FMVVMBlueprintViewModelContext* ViewModel = BlueprintView->FindViewModel(Property->GetFName())) { PropertyPath.SetViewModelId(ViewModel->GetViewModelId()); } } if (PropertyPath.IsEmpty()) { continue; } Private::BuildPropertyPath(Result, PropertyPath, Class, Node); } } } return Result; } FName GetWrapperName(const UMVVMBlueprintView* View, const FMVVMBlueprintViewBinding& Binding, bool bSourceToDestination) { TStringBuilder<256> StringBuilder; StringBuilder << TEXT("__"); StringBuilder << Binding.GetFName(View); StringBuilder << (bSourceToDestination ? TEXT("_SourceToDest") : TEXT("_DestToSource")); return FName(StringBuilder.ToString()); } namespace Private { UEdGraph* FindExistingConversionFunctionWrapper(const UWidgetBlueprint* WidgetBlueprint, FName WrapperName) { const TObjectPtr* Result = WidgetBlueprint->FunctionGraphs.FindByPredicate([WrapperName](const UEdGraph* GraphPtr) { return GraphPtr->GetFName() == WrapperName; }); return Result ? Result->Get() : nullptr; } } // namespace UEdGraph* GetGraph(const UWidgetBlueprint* WidgetBlueprint, const FMVVMBlueprintViewBinding& Binding, bool bSourceToDestination) { check(WidgetBlueprint); const UMVVMBlueprintView* View = nullptr; if (UMVVMWidgetBlueprintExtension_View* ExtensionView = UMVVMWidgetBlueprintExtension_View::GetExtension(WidgetBlueprint)) { View = ExtensionView->GetBlueprintView(); } if (View) { const FName WrapperName = GetWrapperName(View, Binding, bSourceToDestination); return Private::FindExistingConversionFunctionWrapper(WidgetBlueprint, WrapperName); } return nullptr; } } //namespace