2338 lines
86 KiB
C++
2338 lines
86 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SBlueprintPalette.h"
|
|
|
|
#include "AnimStateConduitNode.h"
|
|
#include "AnimationBlendSpaceSampleGraph.h"
|
|
#include "AnimationGraph.h"
|
|
#include "AnimationStateGraph.h"
|
|
#include "AnimationStateMachineGraph.h"
|
|
#include "AnimationCustomTransitionGraph.h"
|
|
#include "AnimationStateMachineSchema.h"
|
|
#include "AnimationTransitionGraph.h"
|
|
#include "AssetRegistry/AssetData.h"
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
|
#include "AssetRegistry/IAssetRegistry.h"
|
|
#include "AssetToolsModule.h"
|
|
#include "BlendSpaceGraph.h"
|
|
#include "BlueprintActionMenuItem.h"
|
|
#include "BlueprintActionMenuUtils.h"
|
|
#include "BlueprintDragDropMenuItem.h"
|
|
#include "BlueprintEditor.h"
|
|
#include "BlueprintEditorSettings.h"
|
|
#include "BlueprintNamespaceUtilities.h"
|
|
#include "BlueprintNodeSpawner.h"
|
|
#include "BlueprintPaletteFavorites.h"
|
|
#include "Components/ActorComponent.h"
|
|
#include "Components/TimelineComponent.h"
|
|
#include "Containers/Array.h"
|
|
#include "Containers/EnumAsByte.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "CoreGlobals.h"
|
|
#include "Delegates/Delegate.h"
|
|
#include "Dialogs/Dialogs.h"
|
|
#include "EdGraph/EdGraph.h"
|
|
#include "EdGraph/EdGraphNode.h"
|
|
#include "EdGraph/EdGraphPin.h"
|
|
#include "EdGraph/EdGraphSchema.h"
|
|
#include "EdGraphNode_Comment.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "EdGraphSchema_K2_Actions.h"
|
|
#include "Engine/Blueprint.h"
|
|
#include "Engine/MemberReference.h"
|
|
#include "Engine/SCS_Node.h"
|
|
#include "Engine/SimpleConstructionScript.h"
|
|
#include "FieldNotifyToggle.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "Framework/SlateDelegates.h"
|
|
#include "GenericPlatform/GenericApplication.h"
|
|
#include "HAL/Platform.h"
|
|
#include "IAssetTools.h"
|
|
#include "IDocumentation.h"
|
|
#include "Internationalization/Culture.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "INotifyFieldValueChanged.h"
|
|
#include "K2Node.h"
|
|
#include "K2Node_CallFunction.h"
|
|
#include "K2Node_Variable.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "Kismet2/ComponentEditorUtils.h"
|
|
#include "Kismet2/Kismet2NameValidators.h"
|
|
#include "Layout/Children.h"
|
|
#include "Layout/ChildrenBase.h"
|
|
#include "Layout/Margin.h"
|
|
#include "Layout/Visibility.h"
|
|
#include "Math/Color.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "Misc/PackageName.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "SBlueprintFavoritesPalette.h"
|
|
#include "SBlueprintLibraryPalette.h"
|
|
#include "SGraphActionMenu.h"
|
|
#include "SMyBlueprint.h"
|
|
#include "SPinTypeSelector.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "SlateOptMacros.h"
|
|
#include "SlotBase.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Styling/CoreStyle.h"
|
|
#include "Styling/ISlateStyle.h"
|
|
#include "Styling/SlateColor.h"
|
|
#include "Styling/SlateTypes.h"
|
|
#include "Styling/StyleDefaults.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Templates/SubclassOf.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "TutorialMetaData.h"
|
|
#include "Types/ISlateMetaData.h"
|
|
#include "UObject/Class.h"
|
|
#include "UObject/Field.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/ObjectMacros.h"
|
|
#include "UObject/ObjectPtr.h"
|
|
#include "UObject/Package.h"
|
|
#include "UObject/Script.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "UObject/UnrealNames.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "UObject/WeakFieldPtr.h"
|
|
#include "UObject/WeakObjectPtr.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
#include "WidgetBlueprintEditorUtils.h"
|
|
#include "Widgets/IToolTip.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Widgets/Layout/SBorder.h"
|
|
#include "Widgets/Layout/SSplitter.h"
|
|
#include "Widgets/SBoxPanel.h"
|
|
#include "Widgets/SOverlay.h"
|
|
#include "Widgets/SToolTip.h"
|
|
#include "Widgets/SWidget.h"
|
|
#include "Widgets/Text/SInlineEditableTextBlock.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
|
|
class FDragDropEvent;
|
|
struct FGeometry;
|
|
struct FSlateBrush;
|
|
|
|
#define LOCTEXT_NAMESPACE "BlueprintPalette"
|
|
|
|
/*******************************************************************************
|
|
* Static File Helpers
|
|
*******************************************************************************/
|
|
|
|
/** namespace'd to avoid collisions during unified builds */
|
|
namespace BlueprintPalette
|
|
{
|
|
static FString const ConfigSection("BlueprintEditor.Palette");
|
|
static FString const FavoritesHeightConfigKey("FavoritesHeightRatio");
|
|
static FString const LibraryHeightConfigKey("LibraryHeightRatio");
|
|
}
|
|
|
|
/**
|
|
* A helper method intended for constructing tooltips on palette items
|
|
* associated with specific blueprint variables (gets a string representing the
|
|
* specified variable's type)
|
|
*
|
|
* @param VarScope The struct that owns the variable in question.
|
|
* @param VarName The name of the variable you want the type of.
|
|
* @param Detailed If true the returned string includes SubCategoryObject
|
|
* @return A string representing the variable's type (empty if the variable couldn't be found).
|
|
*/
|
|
static FString GetVarType(UStruct* VarScope, FName VarName, bool bUseObjToolTip, bool bDetailed = false)
|
|
{
|
|
FString VarDesc;
|
|
|
|
if (VarScope)
|
|
{
|
|
if (FProperty* Property = FindFProperty<FProperty>(VarScope, VarName))
|
|
{
|
|
// If it is an object property, see if we can get a nice class description instead of just the name
|
|
FObjectProperty* ObjProp = CastField<FObjectProperty>(Property);
|
|
if (bUseObjToolTip && ObjProp && ObjProp->PropertyClass)
|
|
{
|
|
VarDesc = ObjProp->PropertyClass->GetToolTipText(GetDefault<UBlueprintEditorSettings>()->bShowShortTooltips).ToString();
|
|
}
|
|
|
|
// Name of type
|
|
if (VarDesc.Len() == 0)
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
FEdGraphPinType PinType;
|
|
if (K2Schema->ConvertPropertyToPinType(Property, PinType)) // use schema to get the color
|
|
{
|
|
VarDesc = UEdGraphSchema_K2::TypeToText(PinType).ToString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return VarDesc;
|
|
}
|
|
|
|
/**
|
|
* Util function that helps construct a tooltip for a specific variable action
|
|
* (attempts to grab the variable's "tooltip" metadata).
|
|
*
|
|
* @param InBlueprint The blueprint that the palette is associated.
|
|
* @param VarClass The class that owns the variable.
|
|
* @param VarName The variable you want a tooltip for.
|
|
* @return A string from the variable's "tooltip" metadata (empty if the variable wasn't found, or it didn't have the metadata).
|
|
*/
|
|
static FString GetVarTooltip(UBlueprint* InBlueprint, UClass* VarClass, FName VarName)
|
|
{
|
|
FString ResultTooltip;
|
|
if (VarClass)
|
|
{
|
|
|
|
if (FProperty* Property = FindFProperty<FProperty>(VarClass, VarName))
|
|
{
|
|
// discover if the variable property is a non blueprint user variable
|
|
UClass* SourceClass = Property->GetOwnerClass();
|
|
if( SourceClass && SourceClass->ClassGeneratedBy == nullptr )
|
|
{
|
|
ResultTooltip = Property->GetToolTipText().ToString();
|
|
}
|
|
else
|
|
{
|
|
const UBlueprint* SourceBlueprint = SourceClass ? Cast<UBlueprint>(SourceClass->ClassGeneratedBy) : nullptr;
|
|
FBlueprintEditorUtils::GetBlueprintVariableMetaData(SourceBlueprint ? SourceBlueprint : InBlueprint, VarName, nullptr, TEXT("tooltip"), ResultTooltip);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ResultTooltip;
|
|
}
|
|
|
|
/**
|
|
* A utility function intended to aid the construction of a specific blueprint
|
|
* palette item (specifically FEdGraphSchemaAction_K2Graph palette items). Based
|
|
* off of the sub-graph's type, this gets an icon representing said sub-graph.
|
|
*
|
|
* @param ActionIn The FEdGraphSchemaAction_K2Graph action that the palette item represents.
|
|
* @param BlueprintIn The blueprint currently being edited (that the action is for).
|
|
* @param IconOut An icon denoting the sub-graph's type.
|
|
* @param ColorOut An output color, further denoting the specified action.
|
|
* @param ToolTipOut The tooltip to display when the icon is hovered over (describing the sub-graph type).
|
|
*/
|
|
static void GetSubGraphIcon(FEdGraphSchemaAction_K2Graph const* const ActionIn, UBlueprint const* BlueprintIn, FSlateBrush const*& IconOut, FSlateColor& ColorOut, FText& ToolTipOut)
|
|
{
|
|
check(BlueprintIn);
|
|
|
|
switch (ActionIn->GraphType)
|
|
{
|
|
case EEdGraphSchemaAction_K2Graph::Graph:
|
|
{
|
|
if (ActionIn->EdGraph)
|
|
{
|
|
IconOut = FBlueprintEditor::GetGlyphForGraph(ActionIn->EdGraph);
|
|
}
|
|
else
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.EventGraph_16x"));
|
|
}
|
|
|
|
ToolTipOut = LOCTEXT("EventGraph_ToolTip", "Event Graph");
|
|
}
|
|
break;
|
|
case EEdGraphSchemaAction_K2Graph::Subgraph:
|
|
{
|
|
if (Cast<UAnimationStateMachineGraph>(ActionIn->EdGraph))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.StateMachine_16x") );
|
|
ToolTipOut = LOCTEXT("AnimationStateMachineGraph_ToolTip", "Animation State Machine");
|
|
}
|
|
else if (Cast<UAnimationStateGraph>(ActionIn->EdGraph))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.State_16x") );
|
|
ToolTipOut = LOCTEXT("AnimationState_ToolTip", "Animation State");
|
|
}
|
|
else if (Cast<UAnimationTransitionGraph>(ActionIn->EdGraph))
|
|
{
|
|
UAnimStateConduitNode* EdGraphOuter = Cast<UAnimStateConduitNode>(ActionIn->EdGraph->GetOuter());
|
|
if (EdGraphOuter)
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.Conduit_16x"));
|
|
ToolTipOut = LOCTEXT("ConduitGraph_ToolTip", "Conduit");
|
|
}
|
|
else
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.Rule_16x"));
|
|
ToolTipOut = LOCTEXT("AnimationTransitionGraph_ToolTip", "Animation Transition Rule");
|
|
}
|
|
}
|
|
else if (Cast<UBlendSpaceGraph>(ActionIn->EdGraph))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("BlendSpace.Graph") );
|
|
ToolTipOut = LOCTEXT("BlendSpace_ToolTip", "BlendSpace");
|
|
}
|
|
else if (Cast<UAnimationBlendSpaceSampleGraph>(ActionIn->EdGraph))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("BlendSpace.SampleGraph") );
|
|
ToolTipOut = LOCTEXT("BlendSpaceSample_ToolTip", "BlendSpace Sample");
|
|
}
|
|
else if (Cast<UAnimationCustomTransitionGraph>(ActionIn->EdGraph))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.SubGraph_16x"));
|
|
ToolTipOut = LOCTEXT("CustomBlendGraph_ToolTip", "Custom Blend");
|
|
}
|
|
else
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.SubGraph_16x") );
|
|
ToolTipOut = LOCTEXT("EventSubgraph_ToolTip", "Event Subgraph");
|
|
}
|
|
}
|
|
break;
|
|
case EEdGraphSchemaAction_K2Graph::Macro:
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.Macro_16x"));
|
|
if ( ActionIn->EdGraph == nullptr )
|
|
{
|
|
ToolTipOut = LOCTEXT("PotentialOverride_Tooltip", "Potential Override");
|
|
}
|
|
else
|
|
{
|
|
// Need to see if this is a function overriding something in the parent, or
|
|
;
|
|
if (UFunction* OverrideFunc = FindUField<UFunction>(BlueprintIn->ParentClass, ActionIn->FuncName))
|
|
{
|
|
ToolTipOut = LOCTEXT("Override_Tooltip", "Override");
|
|
}
|
|
else
|
|
{
|
|
ToolTipOut = LOCTEXT("Macro_Tooltip", "Macro");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EEdGraphSchemaAction_K2Graph::Interface:
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.InterfaceFunction_16x"));
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("InterfaceName"), FText::FromName(ActionIn->FuncName));
|
|
ToolTipOut = FText::Format(LOCTEXT("FunctionFromInterface_Tooltip", "Function (from Interface '{InterfaceName}')"), Args);
|
|
if (UFunction* OverrideFunc = FindUField<UFunction>(BlueprintIn->SkeletonGeneratedClass, ActionIn->FuncName))
|
|
{
|
|
if (UEdGraphSchema_K2::FunctionCanBePlacedAsEvent(OverrideFunc))
|
|
{
|
|
ToolTipOut = FText::Format(LOCTEXT("EventFromInterface_Tooltip", "Event (from Interface '{InterfaceName}')"), Args);
|
|
ColorOut = FLinearColor::Yellow;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EEdGraphSchemaAction_K2Graph::Function:
|
|
{
|
|
if (ActionIn->EdGraph == nullptr)
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.PotentialOverrideFunction_16x"));
|
|
ToolTipOut = LOCTEXT("PotentialOverride_Tooltip", "Potential Override");
|
|
}
|
|
else
|
|
{
|
|
if (ActionIn->EdGraph->IsA(UAnimationGraph::StaticClass()))
|
|
{
|
|
IconOut = FAppStyle::GetBrush(TEXT("GraphEditor.Animation_16x"));
|
|
}
|
|
else if (UFunction* OverrideFunc = FindUField<UFunction>(BlueprintIn->ParentClass, ActionIn->FuncName))
|
|
{
|
|
const bool bIsPureFunction = OverrideFunc && OverrideFunc->HasAnyFunctionFlags(FUNC_BlueprintPure);
|
|
IconOut = FAppStyle::GetBrush(bIsPureFunction ? TEXT("GraphEditor.OverridePureFunction_16x") : TEXT("GraphEditor.OverrideFunction_16x"));
|
|
ToolTipOut = LOCTEXT("Override_Tooltip", "Override");
|
|
}
|
|
else
|
|
{
|
|
UFunction* Function = FindUField<UFunction>(BlueprintIn->SkeletonGeneratedClass, ActionIn->FuncName);
|
|
const bool bIsPureFunction = Function && Function->HasAnyFunctionFlags(FUNC_BlueprintPure);
|
|
|
|
IconOut = FAppStyle::GetBrush(bIsPureFunction ? TEXT("GraphEditor.PureFunction_16x") : TEXT("GraphEditor.Function_16x"));
|
|
if (ActionIn->EdGraph->IsA(UAnimationGraph::StaticClass()))
|
|
{
|
|
ToolTipOut = LOCTEXT("AnimationGraph_Tooltip", "Animation Graph");
|
|
}
|
|
else
|
|
{
|
|
ToolTipOut = LOCTEXT("Function_Tooltip", "Function");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A utility function intended to aid the construction of a specific blueprint
|
|
* palette item. This looks at the item's associated action, and based off its
|
|
* type, retrieves an icon, color and tooltip for the slate widget.
|
|
*
|
|
* @param ActionIn The action associated with the palette item you want an icon for.
|
|
* @param BlueprintIn The blueprint currently being edited (that the action is for).
|
|
* @param BrushOut An output of the icon, best representing the specified action.
|
|
* @param ColorOut An output color, further denoting the specified action.
|
|
* @param ToolTipOut An output tooltip, best describing the specified action type.
|
|
*/
|
|
static void GetPaletteItemIcon(TSharedPtr<FEdGraphSchemaAction> ActionIn, UBlueprint const* BlueprintIn, FSlateBrush const*& BrushOut, FSlateColor& ColorOut, FText& ToolTipOut, FString& DocLinkOut, FString& DocExcerptOut, FSlateBrush const*& SecondaryBrushOut, FSlateColor& SecondaryColorOut)
|
|
{
|
|
// Default to tooltip based on action supplied
|
|
ToolTipOut = ActionIn->GetTooltipDescription().IsEmpty() ? ActionIn->GetMenuDescription() : ActionIn->GetTooltipDescription();
|
|
|
|
if (ActionIn->GetTypeId() == FBlueprintActionMenuItem::StaticGetTypeId())
|
|
{
|
|
FBlueprintActionMenuItem* NodeSpawnerAction = (FBlueprintActionMenuItem*)ActionIn.Get();
|
|
BrushOut = NodeSpawnerAction->GetMenuIcon(ColorOut);
|
|
|
|
TSubclassOf<UEdGraphNode> VarNodeClass = NodeSpawnerAction->GetRawAction()->NodeClass;
|
|
// if the node is a variable getter or setter, use the variable icon instead, because maps need two brushes
|
|
if (*VarNodeClass && VarNodeClass->IsChildOf(UK2Node_Variable::StaticClass()))
|
|
{
|
|
const UK2Node_Variable* TemplateNode = Cast<UK2Node_Variable>(NodeSpawnerAction->GetRawAction()->GetTemplateNode());
|
|
FProperty* Property = TemplateNode->GetPropertyForVariable();
|
|
BrushOut = FBlueprintEditor::GetVarIconAndColorFromProperty(Property, ColorOut, SecondaryBrushOut, SecondaryColorOut);
|
|
}
|
|
}
|
|
else if (ActionIn->GetTypeId() == FBlueprintDragDropMenuItem::StaticGetTypeId())
|
|
{
|
|
FBlueprintDragDropMenuItem* DragDropAction = (FBlueprintDragDropMenuItem*)ActionIn.Get();
|
|
BrushOut = DragDropAction->GetMenuIcon(ColorOut);
|
|
}
|
|
// for backwards compatibility:
|
|
else if (UK2Node const* const NodeTemplate = FBlueprintActionMenuUtils::ExtractNodeTemplateFromAction(ActionIn))
|
|
{
|
|
// If the node wants to create tooltip text, use that instead, because its probably more detailed
|
|
FText NodeToolTipText = NodeTemplate->GetTooltipText();
|
|
if (!NodeToolTipText.IsEmpty())
|
|
{
|
|
ToolTipOut = NodeToolTipText;
|
|
}
|
|
|
|
// Ask node for a palette icon
|
|
FLinearColor IconLinearColor = FLinearColor::White;
|
|
BrushOut = NodeTemplate->GetIconAndTint(IconLinearColor).GetOptionalIcon();
|
|
ColorOut = IconLinearColor;
|
|
}
|
|
// for MyBlueprint tab specific actions:
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Graph const* GraphAction = (FEdGraphSchemaAction_K2Graph const*)ActionIn.Get();
|
|
GetSubGraphIcon(GraphAction, BlueprintIn, BrushOut, ColorOut, ToolTipOut);
|
|
}
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)ActionIn.Get();
|
|
|
|
BrushOut = FAppStyle::GetBrush(TEXT("GraphEditor.Delegate_16x"));
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("EventDispatcherName"), FText::FromName(DelegateAction->GetDelegateName()));
|
|
ToolTipOut = FText::Format(LOCTEXT("Delegate_Tooltip", "Event Dispatcher '{EventDispatcherName}'"), Args);
|
|
}
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)ActionIn.Get();
|
|
|
|
UClass* VarClass = VarAction->GetVariableClass();
|
|
BrushOut = FBlueprintEditor::GetVarIconAndColor(VarClass, VarAction->GetVariableName(), ColorOut, SecondaryBrushOut, SecondaryColorOut);
|
|
ToolTipOut = FText::FromString(GetVarType(VarClass, VarAction->GetVariableName(), true, true));
|
|
|
|
DocLinkOut = TEXT("Shared/Editor/Blueprint/VariableTypes");
|
|
DocExcerptOut = GetVarType(VarClass, VarAction->GetVariableName(), false, false);
|
|
}
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2LocalVar* LocalVarAction = (FEdGraphSchemaAction_K2LocalVar*)ActionIn.Get();
|
|
|
|
UStruct* VarScope = CastChecked<UStruct>(LocalVarAction->GetVariableScope());
|
|
BrushOut = FBlueprintEditor::GetVarIconAndColor(VarScope, LocalVarAction->GetVariableName(), ColorOut, SecondaryBrushOut, SecondaryColorOut);
|
|
ToolTipOut = FText::FromString(GetVarType(VarScope, LocalVarAction->GetVariableName(), true));
|
|
|
|
DocLinkOut = TEXT("Shared/Editor/Blueprint/VariableTypes");
|
|
DocExcerptOut = GetVarType(VarScope, LocalVarAction->GetVariableName(), false);
|
|
}
|
|
else if (ActionIn->IsA(FEdGraphSchemaAction_BlueprintVariableBase::StaticGetTypeId()))
|
|
{
|
|
FEdGraphSchemaAction_BlueprintVariableBase* BPVarAction = (FEdGraphSchemaAction_BlueprintVariableBase*)(ActionIn.Get());
|
|
const FEdGraphPinType PinType = BPVarAction->GetPinType();
|
|
|
|
BrushOut = FBlueprintEditor::GetVarIconAndColorFromPinType(PinType, ColorOut, SecondaryBrushOut, SecondaryColorOut);
|
|
ToolTipOut = FText::FromString(UEdGraphSchema_K2::TypeToText(PinType).ToString());
|
|
|
|
DocLinkOut = TEXT("Shared/Editor/Blueprint/VariableTypes");
|
|
DocExcerptOut = UEdGraphSchema_K2::TypeToText(PinType).ToString();
|
|
}
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Enum::StaticGetTypeId())
|
|
{
|
|
BrushOut = FAppStyle::GetBrush(TEXT("GraphEditor.EnumGlyph"));
|
|
ToolTipOut = LOCTEXT("Enum_Tooltip", "Enum Asset");
|
|
}
|
|
else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Struct::StaticGetTypeId())
|
|
{
|
|
BrushOut = FAppStyle::GetBrush(TEXT("GraphEditor.StructGlyph"));
|
|
ToolTipOut = LOCTEXT("Struct_Tooltip", "Struct Asset");
|
|
}
|
|
else
|
|
{
|
|
BrushOut = ActionIn->GetPaletteIcon();
|
|
const FText ActionToolTip = ActionIn->GetPaletteToolTip();
|
|
if(!ActionToolTip.IsEmpty())
|
|
{
|
|
ToolTipOut = ActionToolTip;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Takes the existing tooltip and concats a path id (for the specified action)
|
|
* to the end.
|
|
*
|
|
* @param ActionIn The action you want to show the path for.
|
|
* @param OldToolTip The tooltip that you're replacing (we fold it into the new one)/
|
|
* @return The newly created tooltip (now with the action's path tacked on the bottom).
|
|
*/
|
|
static TSharedRef<IToolTip> ConstructToolTipWithActionPath(TSharedPtr<FEdGraphSchemaAction> ActionIn, TSharedPtr<IToolTip> OldToolTip)
|
|
{
|
|
TSharedRef<IToolTip> NewToolTip = OldToolTip.ToSharedRef();
|
|
if (!ActionIn)
|
|
{
|
|
return NewToolTip;
|
|
}
|
|
|
|
FFavoritedBlueprintPaletteItem ActionItem(*ActionIn);
|
|
if (ActionItem.IsValid())
|
|
{
|
|
static FTextBlockStyle PathStyle = FTextBlockStyle()
|
|
.SetFont(FCoreStyle::GetDefaultFontStyle("Regular", 8))
|
|
.SetColorAndOpacity(FLinearColor(0.4f, 0.4f, 0.4f));
|
|
|
|
NewToolTip = SNew(SToolTip)
|
|
|
|
// Emulate text-only tool-tip styling that SToolTip uses when no custom content is supplied. We want node tool-tips to
|
|
// be styled just like text-only tool-tips
|
|
.BorderImage( FCoreStyle::Get().GetBrush("ToolTip.BrightBackground") )
|
|
.TextMargin(FMargin(11.0f))
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
[
|
|
OldToolTip->GetContentWidget()
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.HAlign(EHorizontalAlignment::HAlign_Right)
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle( FAppStyle::Get(), "Documentation.SDocumentationTooltip")
|
|
.Text(FText::FromString(ActionItem.ToString()))
|
|
//.TextStyle(&PathStyle)
|
|
]
|
|
];
|
|
}
|
|
|
|
return NewToolTip;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* FBlueprintPaletteItemRenameUtils
|
|
*******************************************************************************/
|
|
|
|
/** A set of utilities to aid SBlueprintPaletteItem when the user attempts to rename one. */
|
|
struct FBlueprintPaletteItemRenameUtils
|
|
{
|
|
private:
|
|
static bool VerifyNewAssetName(UObject* Object, const FText& InNewText, FText& OutErrorMessage)
|
|
{
|
|
if (!Object)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Object->GetName() == InNewText.ToString())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
TArray<FAssetData> AssetData;
|
|
FAssetRegistryModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
|
AssetToolsModule.Get().GetAssetsByPath(FName(*FPaths::GetPath(Object->GetOutermost()->GetPathName())), AssetData);
|
|
|
|
if(!FFileHelper::IsFilenameValidForSaving(InNewText.ToString(), OutErrorMessage) || !FName(*InNewText.ToString()).IsValidObjectName( OutErrorMessage ))
|
|
{
|
|
return false;
|
|
}
|
|
else if( InNewText.ToString().Len() >= NAME_SIZE )
|
|
{
|
|
OutErrorMessage = FText::Format(LOCTEXT("RenameFailed_NameTooLong", "Names must have fewer than {0} characters!"), NAME_SIZE);
|
|
}
|
|
else
|
|
{
|
|
// Check to see if the name conflicts
|
|
for ( const FAssetData& AssetInfo : AssetData)
|
|
{
|
|
if(AssetInfo.AssetName.ToString() == InNewText.ToString())
|
|
{
|
|
OutErrorMessage = LOCTEXT("RenameFailed_AlreadyInUse", "Asset name already in use!");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void CommitNewAssetName(UObject* Object, FBlueprintEditor* BlueprintEditor, const FText& NewText)
|
|
{
|
|
if (Object && BlueprintEditor)
|
|
{
|
|
if(Object->GetName() != NewText.ToString())
|
|
{
|
|
TArray<FAssetRenameData> AssetsAndNames;
|
|
const FString PackagePath = FPackageName::GetLongPackagePath(Object->GetOutermost()->GetName());
|
|
new(AssetsAndNames) FAssetRenameData(Object, PackagePath, NewText.ToString());
|
|
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
|
AssetToolsModule.Get().RenameAssetsWithDialog(AssetsAndNames);
|
|
}
|
|
|
|
TSharedPtr<SMyBlueprint> MyBlueprint = BlueprintEditor->GetMyBlueprintWidget();
|
|
if (MyBlueprint.IsValid())
|
|
{
|
|
MyBlueprint->SelectItemByName(FName(*Object->GetPathName()));
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Determines whether the enum node, associated with the selected action,
|
|
* can be renamed with the specified text.
|
|
*
|
|
* @param InNewText The text you want to verify.
|
|
* @param OutErrorMessage Text explaining why the associated node couldn't be renamed (if the return value is false).
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @return True if it is ok to rename the associated node with the given string (false if not).
|
|
*/
|
|
static bool VerifyNewEnumName(const FText& InNewText, FText& OutErrorMessage, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
// Should never make it here with anything but an enum action
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Enum::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2Enum* EnumAction = (FEdGraphSchemaAction_K2Enum*)ActionPtr.Pin().Get();
|
|
|
|
return VerifyNewAssetName(EnumAction ? EnumAction->Enum : nullptr, InNewText, OutErrorMessage);
|
|
}
|
|
|
|
/**
|
|
* Take the verified text and renames the enum node associated with the
|
|
* selected action.
|
|
*
|
|
* @param NewText The new (verified) text to rename the node with.
|
|
* @param InTextCommit A value denoting how the text was entered.
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @param BlueprintEditorPtr A pointer to the blueprint editor that the palette belongs to.
|
|
*/
|
|
static void CommitNewEnumName(const FText& NewText, ETextCommit::Type InTextCommit, TWeakPtr<FEdGraphSchemaAction> ActionPtr, TWeakPtr<FBlueprintEditor> BlueprintEditorPtr)
|
|
{
|
|
// Should never make it here with anything but an enum action
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Enum::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2Enum* EnumAction = (FEdGraphSchemaAction_K2Enum*)ActionPtr.Pin().Get();
|
|
|
|
if(EnumAction->Enum->GetName() != NewText.ToString())
|
|
{
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
|
TArray<FAssetRenameData> AssetsAndNames;
|
|
const FString PackagePath = FPackageName::GetLongPackagePath(EnumAction->Enum->GetOutermost()->GetName());
|
|
new(AssetsAndNames) FAssetRenameData(EnumAction->Enum, PackagePath, NewText.ToString());
|
|
|
|
BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->SelectItemByName(FName("ConstructionScript"));
|
|
|
|
AssetToolsModule.Get().RenameAssetsWithDialog(AssetsAndNames);
|
|
}
|
|
|
|
BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->SelectItemByName(FName(*EnumAction->Enum->GetPathName()));
|
|
}
|
|
|
|
/**
|
|
* Determines whether the struct node, associated with the selected action,
|
|
* can be renamed with the specified text.
|
|
*
|
|
* @param InNewText The text you want to verify.
|
|
* @param OutErrorMessage Text explaining why the associated node couldn't be renamed (if the return value is false).
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @return True if it is ok to rename the associated node with the given string (false if not).
|
|
*/
|
|
static bool VerifyNewStructName(const FText& InNewText, FText& OutErrorMessage, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
// Should never make it here with anything but a struct action
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Struct::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2Struct* Action = (FEdGraphSchemaAction_K2Struct*)ActionPtr.Pin().Get();
|
|
|
|
return VerifyNewAssetName(Action ? Action->Struct : nullptr, InNewText, OutErrorMessage);
|
|
}
|
|
|
|
/**
|
|
* Determines whether the event node, associated with the selected action,
|
|
* can be renamed with the specified text.
|
|
*
|
|
* @param InNewText The text you want to verify.
|
|
* @param OutErrorMessage Text explaining why the associated node couldn't be renamed (if the return value is false).
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @return True if it is ok to rename the associated node with the given string (false if not).
|
|
*/
|
|
static bool VerifyNewEventName(const FText& InNewText, FText& OutErrorMessage, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
bool bIsNameValid = false;
|
|
OutErrorMessage = LOCTEXT("RenameFailed_NodeRename", "Cannot rename associated node!");
|
|
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId());
|
|
FEdGraphSchemaAction_K2Event* EventAction = (FEdGraphSchemaAction_K2Event*)ActionPtr.Pin().Get();
|
|
|
|
UK2Node* AssociatedNode = EventAction->NodeTemplate;
|
|
if (AssociatedNode && AssociatedNode->GetCanRenameNode())
|
|
{
|
|
TSharedPtr<INameValidatorInterface> NodeNameValidator = FNameValidatorFactory::MakeValidator(AssociatedNode);
|
|
bIsNameValid = (NodeNameValidator->IsValid(InNewText.ToString(), true) == EValidatorResult::Ok);
|
|
}
|
|
return bIsNameValid;
|
|
}
|
|
|
|
/**
|
|
* Take the verified text and renames the struct node associated with the
|
|
* selected action.
|
|
*
|
|
* @param NewText The new (verified) text to rename the node with.
|
|
* @param InTextCommit A value denoting how the text was entered.
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @param BlueprintEditorPtr A pointer to the blueprint editor that the palette belongs to.
|
|
*/
|
|
static void CommitNewStructName(const FText& NewText, ETextCommit::Type InTextCommit, TWeakPtr<FEdGraphSchemaAction> ActionPtr, TWeakPtr<FBlueprintEditor> BlueprintEditorPtr)
|
|
{
|
|
// Should never make it here with anything but a struct action
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Struct::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2Struct* Action = (FEdGraphSchemaAction_K2Struct*)ActionPtr.Pin().Get();
|
|
|
|
CommitNewAssetName(Action ? Action->Struct : nullptr, BlueprintEditorPtr.Pin().Get(), NewText);
|
|
}
|
|
|
|
/**
|
|
* Take the verified text and renames the event node associated with the
|
|
* selected action.
|
|
*
|
|
* @param NewText The new (verified) text to rename the node with.
|
|
* @param InTextCommit A value denoting how the text was entered.
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
*/
|
|
static void CommitNewEventName(const FText& NewText, ETextCommit::Type InTextCommit, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2Event* EventAction = (FEdGraphSchemaAction_K2Event*)ActionPtr.Pin().Get();
|
|
if (EventAction->NodeTemplate)
|
|
{
|
|
EventAction->NodeTemplate->OnRenameNode(NewText.ToString());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines whether the target node, associated with the selected action,
|
|
* can be renamed with the specified text.
|
|
*
|
|
* @param InNewText The text you want to verify.
|
|
* @param OutErrorMessage Text explaining why the associated node couldn't be renamed (if the return value is false).
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
* @return True if it is ok to rename the associated node with the given string (false if not).
|
|
*/
|
|
static bool VerifyNewTargetNodeName(const FText& InNewText, FText& OutErrorMessage, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
|
|
bool bIsNameValid = false;
|
|
OutErrorMessage = LOCTEXT("RenameFailed_NodeRename", "Cannot rename associated node!");
|
|
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId());
|
|
FEdGraphSchemaAction_K2TargetNode* TargetNodeAction = (FEdGraphSchemaAction_K2TargetNode*)ActionPtr.Pin().Get();
|
|
|
|
UK2Node* AssociatedNode = TargetNodeAction->NodeTemplate;
|
|
if (AssociatedNode && AssociatedNode->GetCanRenameNode())
|
|
{
|
|
TSharedPtr<INameValidatorInterface> NodeNameValidator = FNameValidatorFactory::MakeValidator(AssociatedNode);
|
|
bIsNameValid = (NodeNameValidator->IsValid(InNewText.ToString(), true) == EValidatorResult::Ok);
|
|
}
|
|
return bIsNameValid;
|
|
}
|
|
|
|
/**
|
|
* Take the verified text and renames the target node associated with the
|
|
* selected action.
|
|
*
|
|
* @param NewText The new (verified) text to rename the node with.
|
|
* @param InTextCommit A value denoting how the text was entered.
|
|
* @param ActionPtr The selected action that the calling palette item represents.
|
|
*/
|
|
static void CommitNewTargetNodeName(const FText& NewText, ETextCommit::Type InTextCommit, TWeakPtr<FEdGraphSchemaAction> ActionPtr)
|
|
{
|
|
check(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId());
|
|
|
|
FEdGraphSchemaAction_K2TargetNode* TargetNodeAction = (FEdGraphSchemaAction_K2TargetNode*)ActionPtr.Pin().Get();
|
|
if (TargetNodeAction->NodeTemplate)
|
|
{
|
|
TargetNodeAction->NodeTemplate->OnRenameNode(NewText.ToString());
|
|
}
|
|
}
|
|
};
|
|
|
|
/*******************************************************************************
|
|
* SPinTypeSelectorHelper
|
|
*******************************************************************************/
|
|
DECLARE_DELEGATE_OneParam(FOnPinTypeChanged, const FEdGraphPinType&)
|
|
|
|
class SPinTypeSelectorHelper : public SCompoundWidget
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS( SPinTypeSelectorHelper ) {}
|
|
SLATE_ATTRIBUTE(bool, ReadOnly)
|
|
SLATE_EVENT(FOnPinTypeChanged, OnTypeChanged)
|
|
SLATE_END_ARGS()
|
|
|
|
void Construct(const FArguments& InArgs, TWeakPtr<FEdGraphSchemaAction_BlueprintVariableBase> InAction, UBlueprint* InBlueprint, TWeakPtr<FBlueprintEditor> InBlueprintEditor)
|
|
{
|
|
BlueprintObj = InBlueprint;
|
|
BlueprintEditorPtr = InBlueprintEditor;
|
|
ActionPtr = InAction;
|
|
VariableProperty = nullptr;
|
|
if (ActionPtr.IsValid())
|
|
{
|
|
VariableProperty = ActionPtr.Pin()->GetProperty();
|
|
}
|
|
|
|
ConstructInternal(InArgs);
|
|
}
|
|
|
|
private:
|
|
|
|
void ConstructInternal(const FArguments& InArgs)
|
|
{
|
|
OnTypeChanged = InArgs._OnTypeChanged;
|
|
|
|
TArray<TSharedPtr<IPinTypeSelectorFilter>> CustomPinTypeFilters;
|
|
if (BlueprintEditorPtr.IsValid())
|
|
{
|
|
BlueprintEditorPtr.Pin()->GetPinTypeSelectorFilters(CustomPinTypeFilters);
|
|
}
|
|
|
|
const UEdGraphSchema* Schema = GetDefault<UEdGraphSchema_K2>();
|
|
if (BlueprintEditorPtr.IsValid())
|
|
{
|
|
if (BlueprintEditorPtr.Pin()->GetFocusedGraph())
|
|
{
|
|
Schema = BlueprintEditorPtr.Pin()->GetFocusedGraph()->GetSchema();
|
|
}
|
|
else
|
|
{
|
|
Schema = BlueprintEditorPtr.Pin()->GetDefaultSchema().GetDefaultObject();
|
|
}
|
|
}
|
|
|
|
const bool bIsDelegate = ActionPtr.IsValid() && ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId();
|
|
|
|
// You cannot change the type of multicast delegates in blueprints
|
|
if(!bIsDelegate)
|
|
{
|
|
this->ChildSlot
|
|
[
|
|
SNew(SPinTypeSelector, FGetPinTypeTree::CreateUObject(GetDefault<UEdGraphSchema_K2>(), &UEdGraphSchema_K2::GetVariableTypeTree))
|
|
.ReadOnly(InArgs._ReadOnly)
|
|
.Schema(Schema)
|
|
.SchemaAction(ActionPtr)
|
|
.TargetPinType(this, &SPinTypeSelectorHelper::OnGetVarType)
|
|
.OnPinTypeChanged(this, &SPinTypeSelectorHelper::OnVarTypeChanged)
|
|
.TypeTreeFilter(ETypeTreeFilter::None)
|
|
.SelectorType(BlueprintEditorPtr.IsValid() ? SPinTypeSelector::ESelectorType::Partial : SPinTypeSelector::ESelectorType::None)
|
|
.CustomFilters(CustomPinTypeFilters)
|
|
];
|
|
}
|
|
}
|
|
|
|
FEdGraphPinType OnGetVarType() const
|
|
{
|
|
if (FProperty* VarProp = const_cast<FProperty*>(VariableProperty.Get()))
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
FEdGraphPinType Type;
|
|
K2Schema->ConvertPropertyToPinType(VarProp, Type);
|
|
return Type;
|
|
}
|
|
else if(ActionPtr.IsValid())
|
|
{
|
|
return ActionPtr.Pin()->GetPinType();
|
|
}
|
|
return FEdGraphPinType();
|
|
}
|
|
|
|
void OnVarTypeChanged(const FEdGraphPinType& InNewPinType)
|
|
{
|
|
if (FBlueprintEditorUtils::IsPinTypeValid(InNewPinType))
|
|
{
|
|
TSharedPtr<FBlueprintEditor> BlueprintEditor = BlueprintEditorPtr.Pin();
|
|
|
|
if (FProperty* VarProp = VariableProperty.Get())
|
|
{
|
|
FName VarName = VarProp->GetFName();
|
|
|
|
if (VarName != NAME_None)
|
|
{
|
|
if (BlueprintEditor.IsValid())
|
|
{
|
|
// Set the MyBP tab's last pin type used as this, for adding lots of variables of the same type
|
|
BlueprintEditor->GetMyBlueprintWidget()->GetLastPinTypeUsed() = InNewPinType;
|
|
}
|
|
|
|
if (UFunction* LocalVariableScope = VarProp->GetOwner<UFunction>())
|
|
{
|
|
FBlueprintEditorUtils::ChangeLocalVariableType(BlueprintObj, LocalVariableScope, VarName, InNewPinType);
|
|
}
|
|
else
|
|
{
|
|
FBlueprintEditorUtils::ChangeMemberVariableType(BlueprintObj, VarName, InNewPinType);
|
|
}
|
|
}
|
|
}
|
|
else if(ActionPtr.IsValid())
|
|
{
|
|
if (BlueprintEditor.IsValid())
|
|
{
|
|
// Set the MyBP tab's last pin type used as this, for adding lots of variables of the same type
|
|
BlueprintEditor->GetMyBlueprintWidget()->GetLastPinTypeUsed() = InNewPinType;
|
|
}
|
|
|
|
ActionPtr.Pin()->ChangeVariableType(InNewPinType);
|
|
}
|
|
|
|
// Auto-import the underlying type object's default namespace set into the current editor context.
|
|
const UObject* PinSubCategoryObject = InNewPinType.PinSubCategoryObject.Get();
|
|
if (PinSubCategoryObject && BlueprintEditor.IsValid())
|
|
{
|
|
FBlueprintEditor::FImportNamespaceExParameters Params;
|
|
FBlueprintNamespaceUtilities::GetDefaultImportsForObject(PinSubCategoryObject, Params.NamespacesToImport);
|
|
BlueprintEditor->ImportNamespaceEx(Params);
|
|
}
|
|
}
|
|
|
|
if (OnTypeChanged.IsBound())
|
|
{
|
|
OnTypeChanged.Execute(InNewPinType);
|
|
}
|
|
}
|
|
|
|
private:
|
|
/** The action that the owning palette entry represents */
|
|
TWeakPtr<FEdGraphSchemaAction_BlueprintVariableBase> ActionPtr;
|
|
|
|
/** Pointer back to the blueprint that is being displayed: */
|
|
UBlueprint* BlueprintObj;
|
|
|
|
/** Pointer back to the blueprint editor that owns this, optional because of diff and merge views: */
|
|
TWeakPtr<FBlueprintEditor> BlueprintEditorPtr;
|
|
|
|
/** Variable Property to change the type of */
|
|
TWeakFieldPtr<FProperty> VariableProperty;
|
|
|
|
/** Event when type has changed */
|
|
FOnPinTypeChanged OnTypeChanged;
|
|
};
|
|
|
|
/*******************************************************************************
|
|
* SPaletteItemVisibilityToggle
|
|
*******************************************************************************/
|
|
|
|
class SPaletteItemVisibilityToggle : public SCompoundWidget
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS( SPaletteItemVisibilityToggle ) {}
|
|
SLATE_END_ARGS()
|
|
|
|
/**
|
|
* Constructs a visibility-toggle widget (for variable actions only, so that
|
|
* the user can modify the variable's "edit-on-instance" state).
|
|
*
|
|
* @param InArgs A set of slate arguments, defined above.
|
|
* @param ActionPtrIn The FEdGraphSchemaAction that the parent item represents.
|
|
* @param BlueprintEdPtrIn A pointer to the blueprint editor that the palette belongs to.
|
|
*/
|
|
void Construct(const FArguments& InArgs, TWeakPtr<FEdGraphSchemaAction> ActionPtrIn, TWeakPtr<FBlueprintEditor> InBlueprintEditor, UBlueprint* InBlueprint)
|
|
{
|
|
ActionPtr = ActionPtrIn;
|
|
BlueprintEditorPtr = InBlueprintEditor;
|
|
BlueprintObj = InBlueprint;
|
|
TSharedPtr<FEdGraphSchemaAction> PaletteAction = ActionPtrIn.Pin();
|
|
|
|
bool bShouldHaveAVisibilityToggle = false;
|
|
if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FProperty* VariableProp = StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(PaletteAction)->GetProperty();
|
|
FObjectProperty* VariableObjProp = CastField<FObjectProperty>(VariableProp);
|
|
|
|
UStruct* VarSourceScope = (VariableProp ? CastChecked<UStruct>(VariableProp->GetOwner<UObject>()) : nullptr);
|
|
const bool bIsBlueprintVariable = (VarSourceScope == BlueprintObj->SkeletonGeneratedClass);
|
|
const bool bIsComponentVar = (VariableObjProp && VariableObjProp->PropertyClass && VariableObjProp->PropertyClass->IsChildOf(UActorComponent::StaticClass()));
|
|
bShouldHaveAVisibilityToggle = bIsBlueprintVariable && (!bIsComponentVar || FBlueprintEditorUtils::IsVariableCreatedByBlueprint(BlueprintObj, VariableObjProp));
|
|
}
|
|
|
|
this->ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.Padding(0.0f)
|
|
.BorderImage(FStyleDefaults::GetNoBrush())
|
|
.Visibility(bShouldHaveAVisibilityToggle ? EVisibility::Visible : EVisibility::Collapsed)
|
|
//.ForegroundColor(this, &SPaletteItemVisibilityToggle::GetVisibilityToggleColor)
|
|
[
|
|
SNew(SCheckBox)
|
|
.ToolTipText(this, &SPaletteItemVisibilityToggle::GetVisibilityToggleToolTip)
|
|
.OnCheckStateChanged(this, &SPaletteItemVisibilityToggle::OnVisibilityToggleFlipped)
|
|
.IsChecked(this, &SPaletteItemVisibilityToggle::GetVisibilityToggleState)
|
|
.Style(FAppStyle::Get(), "TransparentCheckBox")
|
|
[
|
|
SNew(SImage)
|
|
.Image(this, &SPaletteItemVisibilityToggle::GetVisibilityIcon)
|
|
.ColorAndOpacity(FSlateColor::UseForeground())
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* Used by this visibility-toggle widget to see if the property represented
|
|
* by this item is visible outside of Kismet.
|
|
*
|
|
* @return ECheckBoxState::Checked if the property is visible, false if not (or if the property wasn't found)
|
|
*/
|
|
ECheckBoxState GetVisibilityToggleState() const
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction> PaletteAction = ActionPtr.Pin();
|
|
if ( PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId() )
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction_K2Var> VarAction = StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(PaletteAction);
|
|
if (FProperty* VariableProperty = VarAction->GetProperty())
|
|
{
|
|
return VariableProperty->HasAnyPropertyFlags(CPF_DisableEditOnInstance) ? ECheckBoxState::Unchecked : ECheckBoxState::Checked;
|
|
}
|
|
}
|
|
|
|
return ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
/**
|
|
* Used by this visibility-toggle widget when the user makes a change to the
|
|
* checkbox (modifies the property represented by this item by flipping its
|
|
* edit-on-instance flag).
|
|
*
|
|
* @param InNewState The new state that the user set the checkbox to.
|
|
*/
|
|
void OnVisibilityToggleFlipped(ECheckBoxState InNewState)
|
|
{
|
|
if( !BlueprintEditorPtr.IsValid() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
TSharedPtr<FEdGraphSchemaAction> PaletteAction = ActionPtr.Pin();
|
|
if ( PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId() )
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction_K2Var> VarAction = StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(PaletteAction);
|
|
|
|
// Toggle the flag on the blueprint's version of the variable description, based on state
|
|
const bool bVariableIsExposed = ( InNewState == ECheckBoxState::Checked );
|
|
|
|
FBlueprintEditorUtils::SetBlueprintOnlyEditableFlag(BlueprintObj, VarAction->GetVariableName(), !bVariableIsExposed);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by this visibility-toggle widget to convey the visibility of the
|
|
* property represented by this item.
|
|
*
|
|
* @return A image representing the variable's "edit-on-instance" state.
|
|
*/
|
|
const FSlateBrush* GetVisibilityIcon() const
|
|
{
|
|
return GetVisibilityToggleState() == ECheckBoxState::Checked ?
|
|
FAppStyle::GetBrush( "Kismet.VariableList.ExposeForInstance" ) :
|
|
FAppStyle::GetBrush( "Kismet.VariableList.HideForInstance" );
|
|
}
|
|
|
|
/**
|
|
* Used by this visibility-toggle widget to convey the visibility of the
|
|
* property represented by this item (as well as the status of the
|
|
* variable's tooltip).
|
|
*
|
|
* @return A color denoting the item's visibility and tootip status.
|
|
*/
|
|
FSlateColor GetVisibilityToggleColor() const
|
|
{
|
|
if ( GetVisibilityToggleState() != ECheckBoxState::Checked )
|
|
{
|
|
return FSlateColor::UseForeground();
|
|
}
|
|
else
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction_K2Var> VarAction = StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(ActionPtr.Pin());
|
|
|
|
FString Result;
|
|
FBlueprintEditorUtils::GetBlueprintVariableMetaData(BlueprintObj, VarAction->GetVariableName(), nullptr, TEXT("tooltip"), Result);
|
|
|
|
if ( !Result.IsEmpty() )
|
|
{
|
|
static const FName TooltipExistsColor("Colors.AccentGreen");
|
|
return FAppStyle::Get().GetSlateColor(TooltipExistsColor);
|
|
}
|
|
else
|
|
{
|
|
static const FName TooltipDoesntExistColor("Colors.AccentYellow");
|
|
return FAppStyle::Get().GetSlateColor(TooltipDoesntExistColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by this visibility-toggle widget to supply the toggle with a tooltip
|
|
* representing the "edit-on-instance" state of the variable represented by
|
|
* this item.
|
|
*
|
|
* @return Tooltip text for this toggle.
|
|
*/
|
|
FText GetVisibilityToggleToolTip() const
|
|
{
|
|
FText ToolTipText = FText::GetEmpty();
|
|
if ( GetVisibilityToggleState() != ECheckBoxState::Checked )
|
|
{
|
|
ToolTipText = LOCTEXT("VariablePrivacy_not_public_Tooltip", "Variable is not public and will not be editable on an instance of this Blueprint.");
|
|
}
|
|
else
|
|
{
|
|
ToolTipText = LOCTEXT("VariablePrivacy_is_public_Tooltip", "Variable is public and is editable on each instance of this Blueprint.");
|
|
}
|
|
return ToolTipText;
|
|
}
|
|
|
|
private:
|
|
/** The action that the owning palette entry represents */
|
|
TWeakPtr<FEdGraphSchemaAction> ActionPtr;
|
|
|
|
/** Pointer back to the blueprint editor that owns this, optional because of diff and merge views: */
|
|
TWeakPtr<FBlueprintEditor> BlueprintEditorPtr;
|
|
|
|
/** Pointer back to the blueprint that is being diplayed: */
|
|
UBlueprint* BlueprintObj;
|
|
};
|
|
|
|
/*******************************************************************************
|
|
* SBlueprintPaletteItem Public Interface
|
|
*******************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActionData* const InCreateData, TWeakPtr<FBlueprintEditor> InBlueprintEditor)
|
|
{
|
|
Construct(InArgs, InCreateData, InBlueprintEditor.Pin()->GetBlueprintObj(), InBlueprintEditor);
|
|
}
|
|
|
|
void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActionData* const InCreateData, UBlueprint* InBlueprint)
|
|
{
|
|
Construct( InArgs, InCreateData, InBlueprint, TWeakPtr<FBlueprintEditor>() );
|
|
}
|
|
|
|
void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetForActionData* const InCreateData, UBlueprint* InBlueprint, TWeakPtr<FBlueprintEditor> InBlueprintEditor)
|
|
{
|
|
check(InCreateData->Action.IsValid());
|
|
check(InBlueprint);
|
|
|
|
Blueprint = InBlueprint;
|
|
|
|
bShowClassInTooltip = InArgs._ShowClassInTooltip;
|
|
|
|
TSharedPtr<FEdGraphSchemaAction> GraphAction = InCreateData->Action;
|
|
ActionPtr = InCreateData->Action;
|
|
BlueprintEditorPtr = InBlueprintEditor;
|
|
|
|
const bool bIsFullyReadOnly = !InBlueprintEditor.IsValid() || InCreateData->bIsReadOnly;
|
|
|
|
TWeakPtr<FEdGraphSchemaAction> WeakGraphAction = GraphAction;
|
|
auto IsReadOnlyLambda = [WeakGraphAction, InBlueprintEditor, bIsFullyReadOnly]()
|
|
{
|
|
if(WeakGraphAction.IsValid() && InBlueprintEditor.IsValid())
|
|
{
|
|
return bIsFullyReadOnly || FBlueprintEditorUtils::IsPaletteActionReadOnly(WeakGraphAction.Pin(), InBlueprintEditor.Pin());
|
|
}
|
|
|
|
return bIsFullyReadOnly;
|
|
};
|
|
|
|
// We differentiate enabled/read-only state here to not dim icons out unnecessarily, which in some situations
|
|
// (like the right-click palette menu) is confusing to users.
|
|
auto IsEditingEnabledLambda = [InBlueprintEditor]()
|
|
{
|
|
if(InBlueprintEditor.IsValid())
|
|
{
|
|
return InBlueprintEditor.Pin()->InEditingMode();
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
TAttribute<bool> bIsReadOnly = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda(IsReadOnlyLambda));
|
|
TAttribute<bool> bIsEditingEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda(IsEditingEnabledLambda));
|
|
|
|
// construct the icon widget
|
|
FSlateBrush const* IconBrush = FAppStyle::GetBrush(TEXT("NoBrush"));
|
|
FSlateBrush const* SecondaryBrush = FAppStyle::GetBrush(TEXT("NoBrush"));
|
|
FSlateColor IconColor = FSlateColor::UseForeground();
|
|
FSlateColor SecondaryIconColor = FSlateColor::UseForeground();
|
|
FText IconToolTip = GraphAction->GetTooltipDescription();
|
|
FString IconDocLink, IconDocExcerpt;
|
|
GetPaletteItemIcon(GraphAction, Blueprint, IconBrush, IconColor, IconToolTip, IconDocLink, IconDocExcerpt, SecondaryBrush, SecondaryIconColor);
|
|
TSharedRef<SWidget> IconWidget = CreateIconWidget(IconToolTip, IconBrush, IconColor, IconDocLink, IconDocExcerpt, SecondaryBrush, SecondaryIconColor);
|
|
IconWidget->SetEnabled(bIsEditingEnabled);
|
|
|
|
UBlueprintEditorSettings* Settings = GetMutableDefault<UBlueprintEditorSettings>();
|
|
|
|
// Enum representing the access specifier of this function or variable
|
|
enum class EAccessSpecifier : uint8
|
|
{
|
|
None = 0,
|
|
Private = 1,
|
|
Protected = 2,
|
|
Public = 3
|
|
};
|
|
|
|
// We should only bother checking for access if the setting is on and this is not an animation graph
|
|
const bool bShouldCheckForAccessSpec = Settings->bShowAccessSpecifier;
|
|
|
|
EAccessSpecifier ActionAccessSpecifier = EAccessSpecifier::None;
|
|
|
|
// Setup a meta tag for this node
|
|
FTutorialMetaData TagMeta("PaletteItem");
|
|
if( ActionPtr.IsValid() )
|
|
{
|
|
TagMeta.Tag = *FString::Printf(TEXT("PaletteItem,%s,%d"), *GraphAction->GetMenuDescription().ToString(), GraphAction->GetSectionID());
|
|
TagMeta.FriendlyName = GraphAction->GetMenuDescription().ToString();
|
|
}
|
|
// construct the text widget
|
|
TSharedRef<SWidget> NameSlotWidget = CreateTextSlotWidget(InCreateData, bIsReadOnly );
|
|
|
|
// Will set the icon of this property to be a Pin Type selector.
|
|
auto GenerateVariableSettings = [&](TSharedPtr<FEdGraphSchemaAction_BlueprintVariableBase> Action)
|
|
{
|
|
FProperty* VariableProp = nullptr;
|
|
if (Action.IsValid())
|
|
{
|
|
VariableProp = Action->GetProperty();
|
|
}
|
|
if (VariableProp)
|
|
{
|
|
if (bShouldCheckForAccessSpec)
|
|
{
|
|
if (VariableProp->GetBoolMetaData(FBlueprintMetadata::MD_Private))
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Private;
|
|
}
|
|
else if (VariableProp->GetBoolMetaData(FBlueprintMetadata::MD_Protected))
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Protected;
|
|
}
|
|
else
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Public;
|
|
}
|
|
}
|
|
|
|
if (FBlueprintEditorUtils::IsVariableCreatedByBlueprint(Blueprint, VariableProp) || VariableProp->GetOwner<UFunction>())
|
|
{
|
|
const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
|
|
IconWidget = SNew(SPinTypeSelectorHelper, Action, Blueprint, BlueprintEditorPtr)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
.ReadOnly_Lambda([this]() {return !IsHovered(); });
|
|
}
|
|
}
|
|
};
|
|
|
|
// For Variables and Local Variables, we will convert the icon widget into a pin type selector.
|
|
if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
GenerateVariableSettings(StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(GraphAction));
|
|
}
|
|
else if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
GenerateVariableSettings(StaticCastSharedPtr<FEdGraphSchemaAction_K2LocalVar>(GraphAction));
|
|
}
|
|
else if (GraphAction->IsA(FEdGraphSchemaAction_BlueprintVariableBase::StaticGetTypeId()))
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Private;
|
|
const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
|
|
IconWidget = SNew(SPinTypeSelectorHelper, StaticCastSharedPtr<FEdGraphSchemaAction_BlueprintVariableBase>(GraphAction), Blueprint, BlueprintEditorPtr)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
.ReadOnly_Lambda([this]() {return !IsHovered(); })
|
|
.OnTypeChanged_Lambda([this](const FEdGraphPinType& NewPinType) { BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->Refresh(); });
|
|
}
|
|
|
|
// Determine the access level of this action if it is a function graph or for interface events
|
|
else if (bShouldCheckForAccessSpec && GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
UFunction* FunctionToCheck = nullptr;
|
|
|
|
if (FEdGraphSchemaAction_K2Graph* FuncGraphAction = (FEdGraphSchemaAction_K2Graph*)(GraphAction.Get()))
|
|
{
|
|
FunctionToCheck = FindUField<UFunction>(Blueprint->SkeletonGeneratedClass, FuncGraphAction->FuncName);
|
|
|
|
// Handle override/interface functions
|
|
if(!FunctionToCheck)
|
|
{
|
|
FBlueprintEditorUtils::GetOverrideFunctionClass(Blueprint, FuncGraphAction->FuncName, &FunctionToCheck);
|
|
}
|
|
}
|
|
|
|
// If we have found a function that matches this action name, then grab it's access specifier
|
|
if (FunctionToCheck)
|
|
{
|
|
if (FunctionToCheck->HasAnyFunctionFlags(FUNC_Protected))
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Protected;
|
|
}
|
|
else if (FunctionToCheck->HasAnyFunctionFlags(FUNC_Private))
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Private;
|
|
}
|
|
else
|
|
{
|
|
ActionAccessSpecifier = EAccessSpecifier::Public;
|
|
}
|
|
}
|
|
}
|
|
|
|
FText AccessModifierText = FText::GetEmpty();
|
|
|
|
switch (ActionAccessSpecifier)
|
|
{
|
|
case EAccessSpecifier::Public:
|
|
{
|
|
AccessModifierText = LOCTEXT("AccessModifierPublic", "public");
|
|
}
|
|
break;
|
|
case EAccessSpecifier::Protected:
|
|
{
|
|
AccessModifierText = LOCTEXT("AccessModifierProtected", "protected");
|
|
}
|
|
break;
|
|
case EAccessSpecifier::Private:
|
|
{
|
|
AccessModifierText = LOCTEXT("AccessModifierPrivate", "private");
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Calculate a color so that the text gets brighter the more accessible the action is
|
|
const bool AccessSpecifierEnabled = (ActionAccessSpecifier != EAccessSpecifier::None) && bShouldCheckForAccessSpec;
|
|
|
|
// Create the widget with an icon
|
|
TSharedRef<SHorizontalBox> ActionBox = SNew(SHorizontalBox)
|
|
.AddMetaData<FTutorialMetaData>(TagMeta);
|
|
|
|
|
|
auto CreateAccessSpecifierLambda = [&ActionBox, &AccessSpecifierEnabled, &AccessModifierText, &ActionAccessSpecifier]() {
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.MaxWidth(50.f)
|
|
.FillWidth(AccessSpecifierEnabled ? 0.4f : 0.0f)
|
|
.Padding(FMargin(/* horizontal */ AccessSpecifierEnabled ? 6.0f : 0.0f, /* vertical */ 0.0f))
|
|
.VAlign(VAlign_Center)
|
|
.HAlign(HAlign_Right)
|
|
[
|
|
SNew(STextBlock)
|
|
// Will only display text if we have a modifier level
|
|
.IsEnabled(AccessSpecifierEnabled)
|
|
.Text(AccessModifierText)
|
|
.ColorAndOpacity(FSlateColor::UseSubduedForeground())
|
|
// Bold if public
|
|
.TextStyle(FAppStyle::Get(), ActionAccessSpecifier == EAccessSpecifier::Public ? "BlueprintEditor.AccessModifier.Public" : "BlueprintEditor.AccessModifier.Default")
|
|
];
|
|
};
|
|
|
|
|
|
if (GraphAction->IsA(FEdGraphSchemaAction_BlueprintVariableBase::StaticGetTypeId()))
|
|
{
|
|
|
|
|
|
if (ActionAccessSpecifier != EAccessSpecifier::None && GraphAction->GetTypeId() != FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
CreateAccessSpecifierLambda();
|
|
}
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.FillWidth(0.6f)
|
|
.VAlign(VAlign_Center)
|
|
.Padding(3.0f, 0.0f)
|
|
[
|
|
NameSlotWidget
|
|
];
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.FillWidth(0.4f)
|
|
.HAlign(HAlign_Left)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
IconWidget
|
|
];
|
|
|
|
if (InBlueprint && FBlueprintEditorUtils::ImplementsInterface(InBlueprint, true, UNotifyFieldValueChanged::StaticClass()) && GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(6.0f, 0.0f, 3.0f, 0.0f))
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SPaletteItemVarFieldNotifyToggle, ActionPtr, InBlueprintEditor, InBlueprint)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
];
|
|
}
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(6.0f, 0.0f, 3.0f, 0.0f))
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SPaletteItemVisibilityToggle, ActionPtr, InBlueprintEditor, InBlueprint)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
];
|
|
|
|
|
|
if (TSharedPtr<FEdGraphSchemaAction> Action = ActionPtr.Pin())
|
|
{
|
|
if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
if (const FProperty* Property = StaticCastSharedPtr<FEdGraphSchemaAction_K2Var>(GraphAction)->GetProperty())
|
|
{
|
|
bool bIsOptional = false;
|
|
if (FWidgetBlueprintEditorUtils::IsBindWidgetProperty(Property, bIsOptional))
|
|
{
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(6.0f, 0.0f, 3.0f, 0.0f))
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FAppStyle::Get().GetBrush("MainFrame.AddCodeToProject"))
|
|
.IsEnabled(!bIsOptional) // make grey to differentiate between optional and required
|
|
.ToolTipText(bIsOptional
|
|
? LOCTEXT("CppBindWidgetOptionalTooltip", "Widget marked with BindWidgetOptional in native.")
|
|
: LOCTEXT("CppBindWidgetTooltip", "Widget marked with BindWidget in native."))
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(0.0f, 0.0f, 3.0f, 0.0f))
|
|
.HAlign(HAlign_Left)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SPaletteItemVisibilityToggle, ActionPtr, InBlueprintEditor, InBlueprint)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
];
|
|
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
IconWidget
|
|
];
|
|
|
|
// Only add an access specifier if we have one
|
|
if (ActionAccessSpecifier != EAccessSpecifier::None)
|
|
{
|
|
CreateAccessSpecifierLambda();
|
|
}
|
|
|
|
ActionBox.Get().AddSlot()
|
|
.FillWidth(1.f)
|
|
.VAlign(VAlign_Center)
|
|
.Padding(/* horizontal */ 3.0f, /* vertical */ 3.0f)
|
|
[
|
|
NameSlotWidget
|
|
];
|
|
|
|
if (TSharedPtr<FEdGraphSchemaAction> Action = ActionPtr.Pin())
|
|
{
|
|
if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
if (TSharedPtr<FEdGraphSchemaAction_K2Graph> ActionK2Graph = StaticCastSharedPtr<FEdGraphSchemaAction_K2Graph>(Action))
|
|
{
|
|
if (InBlueprint && FBlueprintEditorUtils::ImplementsInterface(InBlueprint, true, UNotifyFieldValueChanged::StaticClass()) && ActionK2Graph->GraphType == EEdGraphSchemaAction_K2Graph::Function)
|
|
{
|
|
ActionBox.Get().AddSlot()
|
|
.AutoWidth()
|
|
.Padding(FMargin(6.0f, 0.0f, 3.0f, 0.0f))
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SPaletteItemFunctionFieldNotifyToggle, ActionPtr, InBlueprintEditor, InBlueprint)
|
|
.IsEnabled(bIsEditingEnabled)
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now, create the actual widget
|
|
ChildSlot
|
|
[
|
|
ActionBox
|
|
];
|
|
}
|
|
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void SBlueprintPaletteItem::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
|
{
|
|
if (BlueprintEditorPtr.IsValid())
|
|
{
|
|
SGraphPaletteItem::OnDragEnter(MyGeometry, DragDropEvent);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* SBlueprintPaletteItem Private Methods
|
|
*******************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
TSharedRef<SWidget> SBlueprintPaletteItem::CreateTextSlotWidget(FCreateWidgetForActionData* const InCreateData, TAttribute<bool> bIsReadOnlyIn)
|
|
{
|
|
FName const ActionTypeId = InCreateData->Action->GetTypeId();
|
|
|
|
FOnVerifyTextChanged OnVerifyTextChanged;
|
|
FOnTextCommitted OnTextCommitted;
|
|
|
|
// enums have different rules for renaming that exist outside the bounds of other items.
|
|
if (ActionTypeId == FEdGraphSchemaAction_K2Enum::StaticGetTypeId())
|
|
{
|
|
OnVerifyTextChanged.BindStatic(&FBlueprintPaletteItemRenameUtils::VerifyNewEnumName, ActionPtr);
|
|
OnTextCommitted.BindStatic(&FBlueprintPaletteItemRenameUtils::CommitNewEnumName, ActionPtr, BlueprintEditorPtr);
|
|
}
|
|
else if (ActionTypeId == FEdGraphSchemaAction_K2Struct::StaticGetTypeId())
|
|
{
|
|
OnVerifyTextChanged.BindStatic(&FBlueprintPaletteItemRenameUtils::VerifyNewStructName, ActionPtr );
|
|
OnTextCommitted.BindStatic(&FBlueprintPaletteItemRenameUtils::CommitNewStructName, ActionPtr, BlueprintEditorPtr);
|
|
}
|
|
else if (ActionTypeId == FEdGraphSchemaAction_K2Event::StaticGetTypeId())
|
|
{
|
|
OnVerifyTextChanged.BindStatic(&FBlueprintPaletteItemRenameUtils::VerifyNewEventName, ActionPtr);
|
|
OnTextCommitted.BindStatic(&FBlueprintPaletteItemRenameUtils::CommitNewEventName, ActionPtr);
|
|
}
|
|
else if (ActionTypeId == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId())
|
|
{
|
|
OnVerifyTextChanged.BindStatic(&FBlueprintPaletteItemRenameUtils::VerifyNewTargetNodeName, ActionPtr);
|
|
OnTextCommitted.BindStatic(&FBlueprintPaletteItemRenameUtils::CommitNewTargetNodeName, ActionPtr);
|
|
}
|
|
else
|
|
{
|
|
// default to our own rename methods
|
|
OnVerifyTextChanged.BindSP(this, &SBlueprintPaletteItem::OnNameTextVerifyChanged);
|
|
OnTextCommitted.BindSP(this, &SBlueprintPaletteItem::OnNameTextCommitted);
|
|
}
|
|
|
|
// Copy the mouse delegate binding if we want it
|
|
if( InCreateData->bHandleMouseButtonDown )
|
|
{
|
|
MouseButtonDownDelegate = InCreateData->MouseButtonDownDelegate;
|
|
}
|
|
|
|
TSharedPtr<SToolTip> ToolTipWidget = ConstructToolTipWidget();
|
|
|
|
TSharedPtr<SOverlay> DisplayWidget;
|
|
TSharedPtr<SInlineEditableTextBlock> EditableTextElement;
|
|
SAssignNew(DisplayWidget, SOverlay)
|
|
+SOverlay::Slot()
|
|
[
|
|
SAssignNew(EditableTextElement, SInlineEditableTextBlock)
|
|
.Text(this, &SBlueprintPaletteItem::GetDisplayText)
|
|
.HighlightText(InCreateData->HighlightText)
|
|
.ToolTip(ToolTipWidget)
|
|
.OnVerifyTextChanged(OnVerifyTextChanged)
|
|
.OnTextCommitted(OnTextCommitted)
|
|
.IsSelected(InCreateData->IsRowSelectedDelegate)
|
|
.IsReadOnly(bIsReadOnlyIn)
|
|
];
|
|
InlineRenameWidget = EditableTextElement.ToSharedRef();
|
|
|
|
InCreateData->OnRenameRequest->BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);
|
|
|
|
if (GetDefault<UBlueprintEditorSettings>()->bShowActionMenuItemSignatures && ActionPtr.IsValid())
|
|
{
|
|
check(InlineRenameWidget.IsValid());
|
|
TSharedPtr<IToolTip> ExistingToolTip = InlineRenameWidget->GetToolTip();
|
|
|
|
DisplayWidget->AddSlot(0)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.Visibility(EVisibility::Visible)
|
|
.ToolTip(ConstructToolTipWithActionPath(ActionPtr.Pin(), ExistingToolTip))
|
|
];
|
|
}
|
|
|
|
return DisplayWidget.ToSharedRef();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
FText SBlueprintPaletteItem::GetDisplayText() const
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
if (MenuDescriptionCache.IsOutOfDate(K2Schema))
|
|
{
|
|
TSharedPtr< FEdGraphSchemaAction > GraphAction = ActionPtr.Pin();
|
|
if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Enum::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Enum* EnumAction = (FEdGraphSchemaAction_K2Enum*)GraphAction.Get();
|
|
FText DisplayText = FText::FromString(EnumAction->Enum->GetName());
|
|
MenuDescriptionCache.SetCachedText(DisplayText, K2Schema);
|
|
}
|
|
else if (GraphAction->GetTypeId() == FEdGraphSchemaAction_K2Struct::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Struct* StructAction = (FEdGraphSchemaAction_K2Struct*)GraphAction.Get();
|
|
FText DisplayText = StructAction->Struct ? FText::FromString(StructAction->Struct->GetName()) : FText::FromString(TEXT("None"));
|
|
MenuDescriptionCache.SetCachedText(DisplayText, K2Schema);
|
|
}
|
|
else
|
|
{
|
|
MenuDescriptionCache.SetCachedText(ActionPtr.Pin()->GetMenuDescription(), K2Schema);
|
|
}
|
|
}
|
|
|
|
return MenuDescriptionCache;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool SBlueprintPaletteItem::OnNameTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage)
|
|
{
|
|
FString TextAsString = InNewText.ToString();
|
|
|
|
FName OriginalName;
|
|
|
|
UStruct* ValidationScope = nullptr;
|
|
|
|
const UEdGraphSchema* Schema = nullptr;
|
|
|
|
// Check if certain action names are unchanged.
|
|
if (ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)ActionPtr.Pin().Get();
|
|
OriginalName = (VarAction->GetVariableName());
|
|
|
|
UClass* VarClass = VarAction->GetVariableClass();
|
|
if (VarClass)
|
|
{
|
|
UBlueprint* BlueprintObj = UBlueprint::GetBlueprintFromClass(VarClass);
|
|
TArray<UEdGraph*> Graphs;
|
|
BlueprintObj->GetAllGraphs(Graphs);
|
|
if (Graphs.Num() > 0)
|
|
{
|
|
Schema = Graphs[0]->GetSchema();
|
|
}
|
|
}
|
|
}
|
|
else if (ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2LocalVar* LocalVarAction = (FEdGraphSchemaAction_K2LocalVar*)ActionPtr.Pin().Get();
|
|
OriginalName = (LocalVarAction->GetVariableName());
|
|
|
|
ValidationScope = CastChecked<UStruct>(LocalVarAction->GetVariableScope());
|
|
|
|
UClass* VarClass = LocalVarAction->GetVariableClass();
|
|
if (VarClass)
|
|
{
|
|
UBlueprint* BlueprintObj = UBlueprint::GetBlueprintFromClass(VarClass);
|
|
TArray<UEdGraph*> Graphs;
|
|
BlueprintObj->GetAllGraphs(Graphs);
|
|
if (Graphs.Num() > 0)
|
|
{
|
|
Schema = Graphs[0]->GetSchema();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UEdGraph* Graph = nullptr;
|
|
|
|
if(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)ActionPtr.Pin().Get();
|
|
Graph = GraphAction->EdGraph;
|
|
}
|
|
else if(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)ActionPtr.Pin().Get();
|
|
Graph = DelegateAction->EdGraph;
|
|
}
|
|
|
|
if (Graph)
|
|
{
|
|
OriginalName = Graph->GetFName();
|
|
Schema = Graph->GetSchema();
|
|
}
|
|
}
|
|
|
|
UBlueprint* BlueprintObj = BlueprintEditorPtr.Pin()->GetBlueprintObj();
|
|
check(BlueprintObj);
|
|
|
|
if (BlueprintObj->SimpleConstructionScript)
|
|
{
|
|
for (USCS_Node* Node : BlueprintObj->SimpleConstructionScript->GetAllNodes())
|
|
{
|
|
if (Node && Node->GetVariableName() == OriginalName && !FComponentEditorUtils::IsValidVariableNameString(Node->ComponentTemplate, InNewText.ToString()))
|
|
{
|
|
OutErrorMessage = LOCTEXT("RenameFailed_NotValid", "This name is reserved for engine use.");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OriginalName.IsNone() && ActionPtr.Pin()->IsA(FEdGraphSchemaAction_BlueprintVariableBase::StaticGetTypeId()))
|
|
{
|
|
FEdGraphSchemaAction_BlueprintVariableBase* BPVar = (FEdGraphSchemaAction_BlueprintVariableBase*)ActionPtr.Pin().Get();
|
|
return BPVar->IsValidName(FName(TextAsString), OutErrorMessage);
|
|
}
|
|
else
|
|
{
|
|
TSharedPtr<INameValidatorInterface> NameValidator = nullptr;
|
|
if (Schema)
|
|
{
|
|
NameValidator = Schema->GetNameValidator(BlueprintObj, OriginalName, ValidationScope, ActionPtr.Pin()->GetTypeId());
|
|
}
|
|
|
|
if (NameValidator.IsValid())
|
|
{
|
|
EValidatorResult ValidatorResult = NameValidator->IsValid(TextAsString);
|
|
switch (ValidatorResult)
|
|
{
|
|
case EValidatorResult::Ok:
|
|
case EValidatorResult::ExistingName:
|
|
// These are fine, don't need to surface to the user, the rename can 'proceed' even if the name is the existing one
|
|
break;
|
|
default:
|
|
OutErrorMessage = INameValidatorInterface::GetErrorText(TextAsString, ValidatorResult);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return OutErrorMessage.IsEmpty();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void SBlueprintPaletteItem::OnNameTextCommitted(const FText& NewText, ETextCommit::Type InTextCommit)
|
|
{
|
|
const FString NewNameString = NewText.ToString();
|
|
const FName NewName = *NewNameString;
|
|
|
|
if(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)ActionPtr.Pin().Get();
|
|
|
|
UEdGraph* Graph = GraphAction->EdGraph;
|
|
if (Graph && (Graph->bAllowDeletion || Graph->bAllowRenaming))
|
|
{
|
|
if (GraphAction->EdGraph)
|
|
{
|
|
if (const UEdGraphSchema* GraphSchema = GraphAction->EdGraph->GetSchema())
|
|
{
|
|
FGraphDisplayInfo DisplayInfo;
|
|
GraphSchema->GetGraphDisplayInformation(*GraphAction->EdGraph, DisplayInfo);
|
|
|
|
// Check if the name is unchanged
|
|
if (NewText.EqualTo(DisplayInfo.PlainName))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GraphSchema->TryRenameGraph(Graph, *NewText.ToString()))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
FBPVariableDescription* RepNotifyVar = FBlueprintEditorUtils::GetVariableFromOnRepFunction(Blueprint, GraphAction->FuncName);
|
|
if (RepNotifyVar)
|
|
{
|
|
FSuppressableWarningDialog::FSetupInfo Info(LOCTEXT("RenameRepNotifyMessage", "This function is linked to a RepNotify variable. Renaming it will still allow the variable to be replicated, but this function will not be called. Do you wish to proceed?"),
|
|
LOCTEXT("RenameRepNotifyTitle", "Rename RepNotify Function?"), TEXT("RenameRepNotifyWarning"));
|
|
Info.ConfirmText = LOCTEXT("Confirm", "Confirm");
|
|
Info.CancelText = LOCTEXT("Cancel", "Cancel");
|
|
|
|
if (FSuppressableWarningDialog(Info).ShowModal() == FSuppressableWarningDialog::Cancel)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Make sure we aren't renaming the graph into something that already exists
|
|
UEdGraph* ExistingGraph = FindObject<UEdGraph>(Graph->GetOuter(), *NewNameString );
|
|
if (ExistingGraph == nullptr || ExistingGraph == Graph)
|
|
{
|
|
const FScopedTransaction Transaction( LOCTEXT( "Rename Function", "Rename Function" ) );
|
|
|
|
if (RepNotifyVar)
|
|
{
|
|
if (const UEdGraphSchema_K2* K2Schema = Cast<UEdGraphSchema_K2>(Graph->GetSchema()))
|
|
{
|
|
Graph->Modify();
|
|
// make function editable
|
|
// reconfigure the graph as if it were user created
|
|
int32 ExtraFunctionFlags = (FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public);
|
|
if (BPTYPE_FunctionLibrary == Blueprint->BlueprintType)
|
|
{
|
|
ExtraFunctionFlags |= FUNC_Static;
|
|
}
|
|
if (BPTYPE_Const == Blueprint->BlueprintType)
|
|
{
|
|
ExtraFunctionFlags |= FUNC_Const;
|
|
}
|
|
K2Schema->MarkFunctionEntryAsEditable(Graph, true);
|
|
K2Schema->AddExtraFunctionFlags(Graph, ExtraFunctionFlags);
|
|
|
|
Blueprint->Modify();
|
|
RepNotifyVar->RepNotifyFunc = NAME_None;
|
|
}
|
|
}
|
|
|
|
FBlueprintEditorUtils::RenameGraph(Graph, NewNameString );
|
|
}
|
|
}
|
|
}
|
|
else if(ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)ActionPtr.Pin().Get();
|
|
|
|
UEdGraph* Graph = DelegateAction->EdGraph;
|
|
if (Graph && (Graph->bAllowDeletion || Graph->bAllowRenaming))
|
|
{
|
|
if (const UEdGraphSchema* GraphSchema = Graph->GetSchema())
|
|
{
|
|
FGraphDisplayInfo DisplayInfo;
|
|
GraphSchema->GetGraphDisplayInformation(*Graph, DisplayInfo);
|
|
|
|
// Check if the name is unchanged
|
|
if (NewText.EqualTo(DisplayInfo.PlainName))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Make sure we aren't renaming the graph into something that already exists
|
|
UEdGraph* ExistingGraph = FindObject<UEdGraph>(Graph->GetOuter(), *NewNameString );
|
|
if (ExistingGraph == nullptr || ExistingGraph == Graph)
|
|
{
|
|
const FScopedTransaction Transaction( LOCTEXT( "Rename Delegate", "Rename Event Dispatcher" ) );
|
|
const FName OldName = Graph->GetFName();
|
|
|
|
UBlueprint* BlueprintObj = BlueprintEditorPtr.Pin()->GetBlueprintObj();
|
|
FBlueprintEditorUtils::RenameMemberVariable(BlueprintObj, OldName, NewName);
|
|
}
|
|
}
|
|
}
|
|
else if (ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)ActionPtr.Pin().Get();
|
|
|
|
// Check if the name is unchanged
|
|
if (NewName.IsEqual(VarAction->GetVariableName(), ENameCase::CaseSensitive))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FScopedTransaction Transaction( LOCTEXT( "RenameVariable", "Rename Variable" ) );
|
|
|
|
BlueprintEditorPtr.Pin()->GetBlueprintObj()->Modify();
|
|
|
|
// Double check we're not renaming a timeline disguised as a variable
|
|
bool bIsTimeline = false;
|
|
if (FProperty* VariableProperty = VarAction->GetProperty())
|
|
{
|
|
// Don't allow removal of timeline properties - you need to remove the timeline node for that
|
|
FObjectProperty* ObjProperty = CastField<FObjectProperty>(VariableProperty);
|
|
if (ObjProperty && ObjProperty->PropertyClass == UTimelineComponent::StaticClass())
|
|
{
|
|
bIsTimeline = true;
|
|
}
|
|
}
|
|
|
|
// Rename as a timeline if required
|
|
if (bIsTimeline)
|
|
{
|
|
FBlueprintEditorUtils::RenameTimeline(BlueprintEditorPtr.Pin()->GetBlueprintObj(), VarAction->GetVariableName(), NewName);
|
|
}
|
|
else
|
|
{
|
|
FBlueprintEditorUtils::RenameMemberVariable(BlueprintEditorPtr.Pin()->GetBlueprintObj(), VarAction->GetVariableName(), NewName);
|
|
}
|
|
}
|
|
else if (ActionPtr.Pin()->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2LocalVar* LocalVarAction = (FEdGraphSchemaAction_K2LocalVar*)ActionPtr.Pin().Get();
|
|
|
|
// Check if the name is unchanged
|
|
if (NewName.IsEqual(LocalVarAction->GetVariableName(), ENameCase::CaseSensitive))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FScopedTransaction Transaction( LOCTEXT( "RenameVariable", "Rename Variable" ) );
|
|
|
|
BlueprintEditorPtr.Pin()->GetBlueprintObj()->Modify();
|
|
|
|
FBlueprintEditorUtils::RenameLocalVariable(BlueprintEditorPtr.Pin()->GetBlueprintObj(), CastChecked<UStruct>(LocalVarAction->GetVariableScope()), LocalVarAction->GetVariableName(), NewName);
|
|
}
|
|
else if (ActionPtr.Pin()->IsA(FEdGraphSchemaAction_BlueprintVariableBase::StaticGetTypeId()))
|
|
{
|
|
FEdGraphSchemaAction_BlueprintVariableBase* BPVarAction = (FEdGraphSchemaAction_BlueprintVariableBase*)ActionPtr.Pin().Get();
|
|
|
|
// Check if the name is unchanged
|
|
if (NewName.IsEqual(BPVarAction->GetVariableName(), ENameCase::CaseSensitive))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FScopedTransaction Transaction( LOCTEXT( "RenameVariable", "Rename Variable" ) );
|
|
BlueprintEditorPtr.Pin()->GetBlueprintObj()->Modify();
|
|
|
|
BPVarAction->RenameVariable(NewName);
|
|
BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->Refresh();
|
|
}
|
|
BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->SelectItemByName(NewName, ESelectInfo::OnMouseClick);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
FText SBlueprintPaletteItem::GetToolTipText() const
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction> PaletteAction = ActionPtr.Pin();
|
|
|
|
FText ToolTipText;
|
|
FText ClassDisplayName;
|
|
|
|
if (PaletteAction.IsValid())
|
|
{
|
|
// Default tooltip is taken from the action
|
|
ToolTipText = PaletteAction->GetTooltipDescription().IsEmpty() ? PaletteAction->GetMenuDescription() : PaletteAction->GetTooltipDescription();
|
|
|
|
if(PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2AddComponent::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2AddComponent* AddCompAction = (FEdGraphSchemaAction_K2AddComponent*)PaletteAction.Get();
|
|
// Show component-specific tooltip
|
|
UClass* ComponentClass = *(AddCompAction->ComponentClass);
|
|
if (ComponentClass)
|
|
{
|
|
ToolTipText = ComponentClass->GetToolTipText();
|
|
}
|
|
}
|
|
else if (UK2Node const* const NodeTemplate = FBlueprintActionMenuUtils::ExtractNodeTemplateFromAction(*PaletteAction))
|
|
{
|
|
// If the node wants to create tooltip text, use that instead, because its probably more detailed
|
|
FText NodeToolTipText = NodeTemplate->GetTooltipText();
|
|
if (!NodeToolTipText.IsEmpty())
|
|
{
|
|
ToolTipText = NodeToolTipText;
|
|
}
|
|
|
|
if (UK2Node_CallFunction const* CallFuncNode = Cast<UK2Node_CallFunction const>(NodeTemplate))
|
|
{
|
|
if(UClass* ParentClass = CallFuncNode->FunctionReference.GetMemberParentClass(CallFuncNode->GetBlueprintClassFromNode()))
|
|
{
|
|
UBlueprint* BlueprintObj = UBlueprint::GetBlueprintFromClass(ParentClass);
|
|
if (BlueprintObj == nullptr)
|
|
{
|
|
ClassDisplayName = ParentClass->GetDisplayNameText();
|
|
}
|
|
else if (!BlueprintObj->HasAnyFlags(RF_Transient))
|
|
{
|
|
ClassDisplayName = FText::FromName(BlueprintObj->GetFName());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)PaletteAction.Get();
|
|
if (GraphAction->EdGraph)
|
|
{
|
|
if (const UEdGraphSchema* GraphSchema = GraphAction->EdGraph->GetSchema())
|
|
{
|
|
FGraphDisplayInfo DisplayInfo;
|
|
GraphSchema->GetGraphDisplayInformation(*(GraphAction->EdGraph), DisplayInfo);
|
|
ToolTipText = DisplayInfo.Tooltip;
|
|
}
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)PaletteAction.Get();
|
|
UClass* VarClass = VarAction->GetVariableClass();
|
|
if (bShowClassInTooltip && VarClass)
|
|
{
|
|
UBlueprint* BlueprintObj = UBlueprint::GetBlueprintFromClass(VarClass);
|
|
ClassDisplayName = (BlueprintObj ? FText::FromName(BlueprintObj->GetFName()) : VarClass->GetDisplayNameText());
|
|
}
|
|
else
|
|
{
|
|
// Use the native display name metadata if we can
|
|
const FProperty* Property = FindFProperty<FProperty>(VarClass, VarAction->GetVariableName());
|
|
if (Property && Property->IsNative())
|
|
{
|
|
ToolTipText = Property->GetDisplayNameText();
|
|
}
|
|
else
|
|
{
|
|
FString Result = GetVarTooltip(Blueprint, VarClass, VarAction->GetVariableName());
|
|
// Only use the variable tooltip if it has been filled out.
|
|
ToolTipText = FText::FromString( !Result.IsEmpty() ? Result : GetVarType(VarClass, VarAction->GetVariableName(), true, true) );
|
|
}
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2LocalVar* LocalVarAction = (FEdGraphSchemaAction_K2LocalVar*)PaletteAction.Get();
|
|
// The variable scope can not be found in intermediate graphs
|
|
UStruct* LocalVarScope = Cast<UStruct>(LocalVarAction->GetVariableScope());
|
|
if(LocalVarScope)
|
|
{
|
|
UClass* VarClass = CastChecked<UClass>(LocalVarAction->GetVariableScope()->GetOuter());
|
|
if (bShowClassInTooltip && (VarClass != nullptr))
|
|
{
|
|
UBlueprint* BlueprintObj = UBlueprint::GetBlueprintFromClass(VarClass);
|
|
ClassDisplayName = (BlueprintObj ? FText::FromName(BlueprintObj->GetFName()) : VarClass->GetDisplayNameText());
|
|
}
|
|
else
|
|
{
|
|
FString Result;
|
|
FBlueprintEditorUtils::GetBlueprintVariableMetaData(Blueprint, LocalVarAction->GetVariableName(), LocalVarScope, TEXT("tooltip"), Result);
|
|
// Only use the variable tooltip if it has been filled out.
|
|
ToolTipText = FText::FromString( !Result.IsEmpty() ? Result : GetVarType(LocalVarScope, LocalVarAction->GetVariableName(), true, true) );
|
|
}
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)PaletteAction.Get();
|
|
|
|
FString Result = GetVarTooltip(Blueprint, DelegateAction->GetDelegateClass(), DelegateAction->GetDelegateName());
|
|
ToolTipText = !Result.IsEmpty() ? FText::FromString(Result) : FText::FromName(DelegateAction->GetDelegateName());
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Enum::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Enum* EnumAction = (FEdGraphSchemaAction_K2Enum*)PaletteAction.Get();
|
|
if (EnumAction->Enum)
|
|
{
|
|
ToolTipText = FText::FromName(EnumAction->Enum->GetFName());
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2TargetNode* TargetNodeAction = (FEdGraphSchemaAction_K2TargetNode*)PaletteAction.Get();
|
|
if (TargetNodeAction->NodeTemplate)
|
|
{
|
|
ToolTipText = TargetNodeAction->NodeTemplate->GetTooltipText();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bShowClassInTooltip && !ClassDisplayName.IsEmpty())
|
|
{
|
|
ToolTipText = FText::Format(LOCTEXT("BlueprintItemClassTooltip", "{0}\nClass: {1}"), ToolTipText, ClassDisplayName);
|
|
}
|
|
|
|
return ToolTipText;
|
|
}
|
|
|
|
TSharedPtr<SToolTip> SBlueprintPaletteItem::ConstructToolTipWidget() const
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction> PaletteAction = ActionPtr.Pin();
|
|
UEdGraphNode const* const NodeTemplate = FBlueprintActionMenuUtils::ExtractNodeTemplateFromAction(PaletteAction);
|
|
|
|
FBlueprintActionMenuItem::FDocExcerptRef DocExcerptRef;
|
|
|
|
if (PaletteAction.IsValid())
|
|
{
|
|
if (NodeTemplate != nullptr)
|
|
{
|
|
// Take rich tooltip from node
|
|
DocExcerptRef.DocLink = NodeTemplate->GetDocumentationLink();
|
|
DocExcerptRef.DocExcerptName = NodeTemplate->GetDocumentationExcerptName();
|
|
|
|
// sometimes, with FBlueprintActionMenuItem's, the NodeTemplate
|
|
// doesn't always reflect the node that will be spawned (some things
|
|
// we don't want to be executed until spawn time, like adding of
|
|
// component templates)... in that case, the
|
|
// FBlueprintActionMenuItem's may have a more specific documentation
|
|
// link of its own (most of the time, it will reflect the NodeTemplate's)
|
|
if ( !DocExcerptRef.IsValid() && (PaletteAction->GetTypeId() == FBlueprintActionMenuItem::StaticGetTypeId()) )
|
|
{
|
|
FBlueprintActionMenuItem* NodeSpawnerAction = (FBlueprintActionMenuItem*)PaletteAction.Get();
|
|
DocExcerptRef = NodeSpawnerAction->GetDocumentationExcerpt();
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)PaletteAction.Get();
|
|
if (GraphAction->EdGraph)
|
|
{
|
|
FGraphDisplayInfo DisplayInfo;
|
|
if (const UEdGraphSchema* GraphSchema = GraphAction->EdGraph->GetSchema())
|
|
{
|
|
GraphSchema->GetGraphDisplayInformation(*(GraphAction->EdGraph), DisplayInfo);
|
|
}
|
|
|
|
DocExcerptRef.DocLink = DisplayInfo.DocLink;
|
|
DocExcerptRef.DocExcerptName = DisplayInfo.DocExcerptName;
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId())
|
|
{
|
|
FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)PaletteAction.Get();
|
|
UClass* VarClass = VarAction->GetVariableClass();
|
|
if (!bShowClassInTooltip || VarClass == nullptr)
|
|
{
|
|
// Don't show big tooltip if we are showing class as well (means we are not in MyBlueprint)
|
|
DocExcerptRef.DocLink = TEXT("Shared/Editors/BlueprintEditor/GraphTypes");
|
|
DocExcerptRef.DocExcerptName = TEXT("Variable");
|
|
}
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId())
|
|
{
|
|
DocExcerptRef.DocLink = TEXT("Shared/Editors/BlueprintEditor/GraphTypes");
|
|
DocExcerptRef.DocExcerptName = TEXT("Event");
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2AddComment::StaticGetTypeId() ||
|
|
PaletteAction->GetTypeId() == FEdGraphSchemaAction_NewStateComment::StaticGetTypeId())
|
|
{
|
|
// Taking tooltip from action is fine
|
|
const UEdGraphNode_Comment* DefaultComment = GetDefault<UEdGraphNode_Comment>();
|
|
DocExcerptRef.DocLink = DefaultComment->GetDocumentationLink();
|
|
DocExcerptRef.DocExcerptName = DefaultComment->GetDocumentationExcerptName();
|
|
}
|
|
else if (PaletteAction->GetTypeId() == FEdGraphSchemaAction_K2LocalVar::StaticGetTypeId())
|
|
{
|
|
// Don't show big tooltip if we are showing class as well (means we are not in MyBlueprint)
|
|
DocExcerptRef.DocLink = TEXT("Shared/Editors/BlueprintEditor/GraphTypes");
|
|
DocExcerptRef.DocExcerptName = TEXT("LocalVariable");
|
|
}
|
|
}
|
|
|
|
// Setup the attribute for dynamically pulling the tooltip
|
|
TAttribute<FText> TextAttribute;
|
|
TextAttribute.Bind(this, &SBlueprintPaletteItem::GetToolTipText);
|
|
|
|
TSharedRef< SToolTip > TooltipWidget = IDocumentation::Get()->CreateToolTip(TextAttribute, nullptr, DocExcerptRef.DocLink, DocExcerptRef.DocExcerptName);
|
|
|
|
// English speakers have no real need to know this exists.
|
|
if ( (NodeTemplate != nullptr) && (FInternationalization::Get().GetCurrentCulture()->GetTwoLetterISOLanguageName() != TEXT("en")) )
|
|
{
|
|
FText NativeNodeName = FText::FromString(NodeTemplate->GetNodeTitle(ENodeTitleType::ListView).BuildSourceString());
|
|
const FTextBlockStyle& SubduedTextStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("Documentation.SDocumentationTooltipSubdued");
|
|
|
|
TSharedPtr<SToolTip> InternationalTooltip;
|
|
TSharedPtr<SVerticalBox> TooltipBody;
|
|
|
|
SAssignNew(InternationalTooltip, SToolTip)
|
|
// Emulate text-only tool-tip styling that SToolTip uses
|
|
// when no custom content is supplied. We want node tool-
|
|
// tips to be styled just like text-only tool-tips
|
|
.BorderImage( FCoreStyle::Get().GetBrush("ToolTip.BrightBackground") )
|
|
.TextMargin(FMargin(11.0f))
|
|
[
|
|
SAssignNew(TooltipBody, SVerticalBox)
|
|
];
|
|
|
|
if (!DocExcerptRef.IsValid())
|
|
{
|
|
auto GetNativeNamePromptVisibility = []()->EVisibility
|
|
{
|
|
FModifierKeysState KeyState = FSlateApplication::Get().GetModifierKeys();
|
|
return KeyState.IsAltDown() ? EVisibility::Collapsed : EVisibility::Visible;
|
|
};
|
|
|
|
TooltipBody->AddSlot()
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle(FAppStyle::Get(), "Documentation.SDocumentationTooltip")
|
|
.Text(NativeNodeName)
|
|
.Visibility_Lambda([GetNativeNamePromptVisibility]()->EVisibility
|
|
{
|
|
return (GetNativeNamePromptVisibility() == EVisibility::Visible) ? EVisibility::Collapsed : EVisibility::Visible;
|
|
})
|
|
];
|
|
|
|
TooltipBody->AddSlot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.Visibility_Lambda(GetNativeNamePromptVisibility)
|
|
+SHorizontalBox::Slot()
|
|
[
|
|
TooltipWidget->GetContentWidget()
|
|
]
|
|
];
|
|
|
|
TooltipBody->AddSlot()
|
|
.AutoHeight()
|
|
.HAlign(HAlign_Center)
|
|
.Padding(0.f, 8.f, 0.f, 0.f)
|
|
[
|
|
|
|
SNew(STextBlock)
|
|
.Text( LOCTEXT("NativeNodeName", "hold (Alt) for native node name") )
|
|
.TextStyle(&SubduedTextStyle)
|
|
.Visibility_Lambda(GetNativeNamePromptVisibility)
|
|
];
|
|
}
|
|
else
|
|
{
|
|
auto GetNativeNodeNameVisibility = []()->EVisibility
|
|
{
|
|
FModifierKeysState KeyState = FSlateApplication::Get().GetModifierKeys();
|
|
return KeyState.IsAltDown() && KeyState.IsControlDown() ? EVisibility::Visible : EVisibility::Collapsed;
|
|
};
|
|
|
|
// give the "advanced" tooltip a header
|
|
TooltipBody->AddSlot()
|
|
.AutoHeight()
|
|
.HAlign(HAlign_Right)
|
|
.Padding(0.f, 0.f, 0.f, 8.f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle(&SubduedTextStyle)
|
|
.Text(LOCTEXT("NativeNodeNameLabel", "Native Node Name: "))
|
|
.Visibility_Lambda(GetNativeNodeNameVisibility)
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.TextStyle(&SubduedTextStyle)
|
|
.Text(NativeNodeName)
|
|
.Visibility_Lambda(GetNativeNodeNameVisibility)
|
|
]
|
|
];
|
|
|
|
TooltipBody->AddSlot()
|
|
[
|
|
TooltipWidget->GetContentWidget()
|
|
];
|
|
}
|
|
|
|
return InternationalTooltip;
|
|
}
|
|
return TooltipWidget;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* SBlueprintPalette
|
|
*******************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
void SBlueprintPalette::Construct(const FArguments& InArgs, TWeakPtr<FBlueprintEditor> InBlueprintEditor)
|
|
{
|
|
const float NumProgressFrames = 2.0f;
|
|
const float SecondsToWaitBeforeShowingProgressDialog = 0.25f;
|
|
|
|
FScopedSlowTask SlowTask(NumProgressFrames, LOCTEXT("ConstructingPaletteTabContent", "Initializing Palette..."));
|
|
SlowTask.MakeDialogDelayed(SecondsToWaitBeforeShowingProgressDialog);
|
|
|
|
float FavoritesHeightRatio = 0.33f;
|
|
GConfig->GetFloat(*BlueprintPalette::ConfigSection, *BlueprintPalette::FavoritesHeightConfigKey, FavoritesHeightRatio, GEditorPerProjectIni);
|
|
float LibraryHeightRatio = 1.f - FavoritesHeightRatio;
|
|
GConfig->GetFloat(*BlueprintPalette::ConfigSection, *BlueprintPalette::LibraryHeightConfigKey, LibraryHeightRatio, GEditorPerProjectIni);
|
|
|
|
bool bUseLegacyLayout = false;
|
|
GConfig->GetBool(*BlueprintPalette::ConfigSection, TEXT("bUseLegacyLayout"), bUseLegacyLayout, GEditorIni);
|
|
|
|
SlowTask.EnterProgressFrame();
|
|
TSharedRef<SWidget> FavoritesContent = SNew(SBlueprintFavoritesPalette, InBlueprintEditor);
|
|
|
|
SlowTask.EnterProgressFrame();
|
|
TSharedRef<SWidget> LibraryContent = SNew(SBlueprintLibraryPalette, InBlueprintEditor)
|
|
.UseLegacyLayout(bUseLegacyLayout);
|
|
|
|
if (bUseLegacyLayout)
|
|
{
|
|
LibraryWrapper = LibraryContent;
|
|
|
|
this->ChildSlot
|
|
[
|
|
LibraryContent
|
|
];
|
|
}
|
|
else
|
|
{
|
|
LibraryContent->AddMetadata<FTagMetaData>(MakeShared<FTagMetaData>(TEXT("BlueprintPaletteLibrary")));
|
|
FavoritesContent->AddMetadata<FTagMetaData>(MakeShared<FTagMetaData>(TEXT("BlueprintPaletteFavorites")));
|
|
|
|
this->ChildSlot
|
|
[
|
|
SAssignNew(PaletteSplitter, SSplitter)
|
|
.Orientation(Orient_Vertical)
|
|
.OnSplitterFinishedResizing(this, &SBlueprintPalette::OnSplitterResized)
|
|
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("FullBlueprintPalette")))
|
|
|
|
+ SSplitter::Slot()
|
|
.Value(FavoritesHeightRatio)
|
|
[
|
|
FavoritesContent
|
|
]
|
|
|
|
+ SSplitter::Slot()
|
|
.Value(LibraryHeightRatio)
|
|
[
|
|
LibraryContent
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void SBlueprintPalette::OnSplitterResized() const
|
|
{
|
|
FChildren const* const SplitterChildren = PaletteSplitter->GetChildren();
|
|
for (int32 SlotIndex = 0; SlotIndex < SplitterChildren->Num(); ++SlotIndex)
|
|
{
|
|
SSplitter::FSlot const& SplitterSlot = PaletteSplitter->SlotAt(SlotIndex);
|
|
|
|
if (SplitterSlot.GetWidget() == FavoritesWrapper)
|
|
{
|
|
GConfig->SetFloat(*BlueprintPalette::ConfigSection, *BlueprintPalette::FavoritesHeightConfigKey, SplitterSlot.GetSizeValue(), GEditorPerProjectIni);
|
|
}
|
|
else if (SplitterSlot.GetWidget() == LibraryWrapper)
|
|
{
|
|
GConfig->SetFloat(*BlueprintPalette::ConfigSection, *BlueprintPalette::LibraryHeightConfigKey, SplitterSlot.GetSizeValue(), GEditorPerProjectIni);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|