// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MVVMBlueprintFunctionReference.h" #include "MVVMBlueprintPin.h" #include "MVVMBlueprintView.h" #include "Engine/MemberReference.h" #include "UObject/WeakObjectPtrTemplates.h" #include "MVVMBlueprintViewConversionFunction.generated.h" class UK2Node; class UEdGraphPin; class UEdGraph; struct FEdGraphEditAction; /** * A conversion function converts between the source and destiation of a binding. * * Internally that function may be using native C++, K2Nodes, UFunctions, Events, etc. */ UCLASS() class MODELVIEWVIEWMODELBLUEPRINT_API UMVVMBlueprintViewConversionFunction : public UObject { GENERATED_BODY() public: static bool IsValidConversionFunction(const UBlueprint* WidgetBlueprint, const UFunction* Function); static bool IsValidConversionNode(const UBlueprint* WidgetBlueprint, const TSubclassOf Function); public: /** @return the conversion function uses at runtime. The wrapper function if complex or GetFunction is simple. */ const UFunction* GetCompiledFunction(const UClass* SelfContext) const; /** @return the conversion function uses at runtime. The wrapper function if complex or GetFunction is simple. */ FName GetCompiledFunctionName(const UClass* SelfContext) const; /** @return the conversion function. */ UE_DEPRECATED(5.4, "GetConversionFunction that returns a variant is deprecated.") TVariant> GetConversionFunction(const UBlueprint* SelfContext) const; /** @return the conversion function. */ FMVVMBlueprintFunctionReference GetConversionFunction() const; /** Set the function. Generate a Graph. */ void Initialize(UBlueprint* SelfContext, FName GraphName, FMVVMBlueprintFunctionReference Function); /** Set the function. Generate a Graph. */ void InitializeFromFunction(UBlueprint* SelfContext, FName GraphName, const UFunction* Function); // For deprecation void Deprecation_InitializeFromWrapperGraph(UBlueprint* SelfContext, UEdGraph* Graph); // For deprecation void Deprecation_InitializeFromMemberReference(UBlueprint* SelfContext, FName GraphName, FMemberReference MemberReference, const FMVVMBlueprintPropertyPath& Source); // For deprecation void Deprecation_SetWrapperGraphName(UBlueprint* Context, FName GraphName, const FMVVMBlueprintPropertyPath& Source); /** * The conversion is valid. * The function was valid when created but may not be anymore. * It doesn't check if the source and destination are valid. */ bool IsValid(const UBlueprint* SelfContext) const; /** The function has more than one argument and requires a wrapper or it uses a FunctionNode. */ bool NeedsWrapperGraph(const UBlueprint* SelfContext) const; /** The wrapper Graph is generated on load/compile and is not saved. */ bool IsWrapperGraphTransient() const; /** True if the graph is going to be used for an ubergraph page. */ bool IsUbergraphPage() const; const FMVVMBlueprintPropertyPath& GetDestinationPath() const { return DestinationPath; } void SetDestinationPath(FMVVMBlueprintPropertyPath DestinationPath); /** Return the wrapper graph, if it exists. */ UEdGraph* GetWrapperGraph() const { return CachedWrapperGraph; } FName GetWrapperGraphName() const { return GraphName; } /** Return the wrapper node, if it exists. */ UK2Node* GetWrapperNode() const { return CachedWrapperNode; } /** Return latent UUID Node. */ UEdGraphNode* GetLatentNodeUUID() const { return LatentEventNodeUUID; } /** * If needed, create the graph and all the nodes for that graph when compiling. * Returns the existing one, if one was created from GetOrCreateWrapperGraph. */ UEdGraph* GetOrCreateIntermediateWrapperGraph(FKismetCompilerContext& Context); /** If needed, create the graph and all the nodes for that graph. */ UEdGraph* GetOrCreateWrapperGraph(UBlueprint* Blueprint); void RecreateWrapperGraph(UBlueprint* Blueprint); /** * The conversion function is going to be removed from the Blueprint. * Do any cleanup that is needed. */ void RemoveWrapperGraph(UBlueprint* Blueprint); /** * Returns the pin from the graph. * Create the graph and all the nodes for that graph if the graph doesn't exist and it's needed. */ UEdGraphPin* GetOrCreateGraphPin(UBlueprint* Blueprint, const FMVVMBlueprintPinId& PinId); const TArrayView GetPins() const { return SavedPins; } /** */ void SetGraphPin(UBlueprint* Blueprint, const FMVVMBlueprintPinId& PinId, const FMVVMBlueprintPropertyPath& Value); /** Generates SavedPins from the wrapper graph, if it exists. */ void SavePinValues(UBlueprint* Blueprint); /** Keep the orphaned pins. Add the missing pins. */ void UpdatePinValues(UBlueprint* Blueprint); /** Keep the orphaned pins. Add the missing pins. */ bool HasOrphanedPin() const; FSimpleMulticastDelegate OnWrapperGraphModified; virtual void PostLoad() override; private: void HandleGraphChanged(const FEdGraphEditAction& Action, TWeakObjectPtr Context); void HandleUserDefinedPinRenamed(UK2Node* InNode, FName OldPinName, FName NewPinName, TWeakObjectPtr WeakBlueprint); void SetCachedWrapperGraph(UBlueprint* Blueprint, UEdGraph* CachedGraph, UK2Node* CachedNode); UEdGraph* CreateWrapperGraphInternal(FKismetCompilerContext& Context); UEdGraph* CreateWrapperGraphInternal(UBlueprint* Blueprint); bool NeedsWrapperGraphInternal(const UClass* SkeletalSelfContext) const; void LoadPinValuesInternal(UBlueprint* Blueprint); FName GenerateUniqueGraphName() const; void CreateWrapperGraphName(); void Reset(); bool IsConversionFunctionAsyncNode(); private: /** * Destination of the binding, currently only saved when the conversion function uses * async nodes. Async graphs will handle value setting internally rather than using the MVVM subsystem. */ UPROPERTY(VisibleAnywhere, Category = "Viewmodel") FMVVMBlueprintPropertyPath DestinationPath; /** * Conversion reference. It can be simple, complex or a K2Node. * @note The conversion is complex */ UPROPERTY(VisibleAnywhere, Category = "Viewmodel") FMVVMBlueprintFunctionReference ConversionFunction; /** Name of the generated graph if a wrapper is needed. */ UPROPERTY(VisibleAnywhere, Category = "Viewmodel") FName GraphName; /** * The pin that are modified and we saved data. * The data may not be modified. We used the default value of the K2Node in that case. */ UPROPERTY(VisibleAnywhere, Category = "Viewmodel") TArray SavedPins; UPROPERTY(VisibleAnywhere, Category = "Viewmodel") bool bWrapperGraphTransient = true; UPROPERTY(VisibleAnywhere, Category = "Viewmodel") bool bIsUbergraphPage = false; UPROPERTY(Transient, DuplicateTransient) mutable TObjectPtr CachedWrapperGraph; UPROPERTY(Transient, DuplicateTransient) mutable TObjectPtr CachedWrapperNode; /** * Events require a node UUID for the latent manager to handle lantents with */ UPROPERTY(Transient) TObjectPtr LatentEventNodeUUID; FDelegateHandle OnGraphChangedHandle; FDelegateHandle OnUserDefinedPinRenamedHandle; bool bLoadingPins = false; UPROPERTY() FMemberReference FunctionReference_DEPRECATED; UPROPERTY() TSubclassOf FunctionNode_DEPRECATED; };