EM_Task/UnrealEd/Public/IPropertyAccessEditor.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

203 lines
7.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleInterface.h"
#include "UObject/Field.h"
#include "Misc/Attribute.h"
#include "Features/IModularFeature.h"
#include "UObject/UnrealType.h"
class UBlueprint;
class IPropertyHandle;
class UEdGraph;
class FExtender;
class SWidget;
struct FSlateBrush;
struct FEdGraphPinType;
/** An element in a binding chain */
struct FBindingChainElement
{
FBindingChainElement(FProperty* InProperty, int32 InArrayIndex = INDEX_NONE)
: Field(InProperty), ArrayIndex(InArrayIndex)
{}
FBindingChainElement(UFunction* InFunction)
: Field(InFunction), ArrayIndex(INDEX_NONE)
{}
/** Field that this this chain element refers to */
FFieldVariant Field;
/** Optional array index if this element refers to an array */
int32 ArrayIndex = INDEX_NONE;
};
/**
* Info about a redirector binding.
* Redirector bindings allow
*/
struct FRedirectorBindingInfo
{
FRedirectorBindingInfo(FName InName, const FText& InDescription, UStruct* InStruct)
: Name(InName), Description(InDescription), Struct(InStruct)
{}
/** The name of the binding */
FName Name = NAME_None;
/** Description of the binding, used as tooltip text */
FText Description;
/** The struct that the binding will output */
UStruct* Struct = nullptr;
};
/** Delegate used to generate a new binding function's name */
DECLARE_DELEGATE_RetVal(FString, FOnGenerateBindingName);
/** Delegate used to open a binding (e.g. a function) */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnGotoBinding, FName /*InPropertyName*/);
/** Delegate used to se if we can open a binding (e.g. a function) */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanGotoBinding, FName /*InPropertyName*/);
/** Delegate used to check whether a property can be bound to the property in question */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanBindProperty, FProperty* /*InProperty*/);
/** Delegate used to check whether a function can be bound to the property in question */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanBindFunction, UFunction* /*InFunction*/);
/** Delegate called to see if a class can be bound to */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanBindToClass, UClass* /*InClass*/);
/** Delegate called to see if a subobject can be bound to */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanBindToSubObjectClass, UClass* /*InSubObjectClass*/);
/** Delegate called to add a binding */
DECLARE_DELEGATE_TwoParams(FOnAddBinding, FName /*InPropertyName*/, const TArray<FBindingChainElement>& /*InBindingChain*/);
/** Delegate called to remove a binding */
DECLARE_DELEGATE_OneParam(FOnRemoveBinding, FName /*InPropertyName*/);
/** Delegate called to see if we can remove remove a binding (ie. if it exists) */
DECLARE_DELEGATE_RetVal_OneParam(bool, FOnCanRemoveBinding, FName /*InPropertyName*/);
/** Setup arguments structure for a property binding widget */
struct FPropertyBindingWidgetArgs
{
/** An optional bindable property */
FProperty* Property = nullptr;
/** An optional signature to use to match binding functions */
UFunction* BindableSignature = nullptr;
/** Delegate used to generate a new binding function's name */
FOnGenerateBindingName OnGenerateBindingName;
/** Delegate used to open a bound generated function */
FOnGotoBinding OnGotoBinding;
/** Delegate used to see if we can open a binding (e.g. a function) */
FOnCanGotoBinding OnCanGotoBinding;
/** Delegate used to check whether a property can be bound to the property in question */
FOnCanBindProperty OnCanBindProperty;
/** Delegate used to check whether a function can be bound to the property in question */
FOnCanBindFunction OnCanBindFunction;
/** Delegate called to see if a class can be bound to */
FOnCanBindToClass OnCanBindToClass;
/** Delegate called to see if a subobject can be bound to */
FOnCanBindToSubObjectClass OnCanBindToSubObjectClass;
/** Delegate called to add a binding */
FOnAddBinding OnAddBinding;
/** Delegate called to remove a binding */
FOnRemoveBinding OnRemoveBinding;
/** Delegate called to see if we can remove remove a binding (ie. if it exists) */
FOnCanRemoveBinding OnCanRemoveBinding;
/** The current binding's text label */
TAttribute<FText> CurrentBindingText;
/** The current binding's image */
TAttribute<const FSlateBrush*> CurrentBindingImage;
/** The current binding's color */
TAttribute<FLinearColor> CurrentBindingColor;
/** Menu extender */
TSharedPtr<FExtender> MenuExtender;
/** Whether to generate pure bindings */
bool bGeneratePureBindings = true;
/** Whether to allow array element bindings */
bool bAllowArrayElementBindings = false;
/** Whether to allow new bindings to be made from within the widget's UI */
bool bAllowNewBindings = true;
/** Whether to allow UObject functions as non-leaf nodes */
bool bAllowUObjectFunctions = false;
};
/** Enum describing the result of ResolveLeafProperty */
enum class EPropertyAccessResolveResult
{
/** Resolution of the path failed */
Failed,
/** Resolution of the path failed and the property is internal to the initial context */
SucceededInternal,
/** Resolution of the path failed and the property is external to the initial context (i.e. uses an object/redirector indirection) */
SucceededExternal,
};
/** Enum describing property compatibility */
enum class EPropertyAccessCompatibility
{
// Properties are incompatible
Incompatible,
// Properties are directly compatible
Compatible,
// Properties can be copied with a simple type promotion
Promotable,
};
/** Editor support for property access system */
class IPropertyAccessEditor: public IModularFeature
{
public:
virtual ~IPropertyAccessEditor() {}
/**
* Make a property binding widget.
* @param InBlueprint The blueprint that the binding will exist within
* @param InArgs Optional arguments for the widget
* @return a new binding widget
*/
virtual TSharedRef<SWidget> MakePropertyBindingWidget(UBlueprint* InBlueprint, const FPropertyBindingWidgetArgs& InArgs = FPropertyBindingWidgetArgs()) const = 0;
/** Resolve a property path to a structure, returning the leaf property and array index if any. @return true if resolution succeeded */
virtual EPropertyAccessResolveResult ResolveLeafProperty(const UStruct* InStruct, TArrayView<FString> InPath, FProperty*& OutProperty, int32& OutArrayIndex) const = 0;
// Get the compatibility of the two supplied properties. Ordering matters for promotion (A->B).
virtual EPropertyAccessCompatibility GetPropertyCompatibility(const FProperty* InPropertyA, const FProperty* InPropertyB) const = 0;
// Get the compatibility of the two supplied pin types. Ordering matters for promotion (A->B).
virtual EPropertyAccessCompatibility GetPinTypeCompatibility(const FEdGraphPinType& InPinTypeA, const FEdGraphPinType& InPinTypeB) const = 0;
// Makes a string path from a binding chain
virtual void MakeStringPath(const TArray<FBindingChainElement>& InBindingChain, TArray<FString>& OutStringPath) const = 0;
};