786 lines
24 KiB
C++
786 lines
24 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "NiagaraNodeSelect.h"
|
|
|
|
#include "EditorFontGlyphs.h"
|
|
#include "FindInBlueprintManager.h"
|
|
#include "NiagaraEditorStyle.h"
|
|
#include "NiagaraEditorUtilities.h"
|
|
#include "NiagaraHlslTranslator.h"
|
|
#include "EdGraph/EdGraphPin.h"
|
|
#include "Widgets/SNiagaraPinTypeSelector.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Layout/SSpacer.h"
|
|
#include "Widgets/Layout/SSeparator.h"
|
|
#include "IContentBrowserSingleton.h"
|
|
#include "ContentBrowserModule.h"
|
|
#include "Engine/UserDefinedEnum.h"
|
|
#include "Subsystems/AssetEditorSubsystem.h"
|
|
#include "Editor/EditorEngine.h"
|
|
#include "Editor.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(NiagaraNodeSelect)
|
|
|
|
#define LOCTEXT_NAMESPACE "NiagaraNodeSelect"
|
|
|
|
UNiagaraNodeSelect::UNiagaraNodeSelect()
|
|
{
|
|
}
|
|
|
|
void UNiagaraNodeSelect::ChangeValuePinType(int32 Index, FNiagaraTypeDefinition Type)
|
|
{
|
|
if(Index < 0 || Index >= OutputVars.Num())
|
|
{
|
|
UE_LOG(LogNiagaraEditor, Error, TEXT("Tried assigning type %s to index %i. Out of bounds."), *Type.GetName(), Index);
|
|
return;
|
|
}
|
|
|
|
// swap output variables at the same location
|
|
TSet<FName> OutputNames;
|
|
for (const FNiagaraVariable& Output : OutputVars)
|
|
{
|
|
OutputNames.Add(Output.GetName());
|
|
}
|
|
FName OutputName = FNiagaraUtilities::GetUniqueName(Type.GetFName(), OutputNames);
|
|
|
|
OutputVars.RemoveAt(Index);
|
|
OutputVars.EmplaceAt(Index, FNiagaraVariable(Type, OutputName));
|
|
|
|
for(UEdGraphPin* ValuePin : GetOptionPins(Index))
|
|
{
|
|
if(ValuePin->LinkedTo.Num() > 0 && !UEdGraphSchema_Niagara::IsPinWildcard(ValuePin))
|
|
{
|
|
ValuePin->bOrphanedPin = true;
|
|
}
|
|
}
|
|
|
|
if(UEdGraphPin* OutputPin = GetPinByPersistentGuid(OutputVarGuids[Index]))
|
|
{
|
|
if(OutputPin->LinkedTo.Num() > 0 && !UEdGraphSchema_Niagara::IsPinWildcard(OutputPin))
|
|
{
|
|
OutputPin->bOrphanedPin = true;
|
|
}
|
|
}
|
|
|
|
ReallocatePins(true);
|
|
}
|
|
|
|
void UNiagaraNodeSelect::ChangeSelectorPinType(FNiagaraTypeDefinition Type)
|
|
{
|
|
SelectorPinType = Type;
|
|
|
|
UEdGraphPin* SelectorPin = GetSelectorPin();
|
|
|
|
if(OutputVars.Num() == 0)
|
|
{
|
|
AddOutput(FNiagaraTypeDefinition::GetWildcardDef(), FNiagaraTypeDefinition::GetWildcardDef().GetFName());
|
|
ReallocatePins();
|
|
return;
|
|
}
|
|
// ensure we have at least a minimum amount of entries if we change to integer mode
|
|
const int32 MinimumEntries = 2;
|
|
if (SelectorPinType.IsSameBaseDefinition(FNiagaraTypeDefinition::GetIntDef()) && NumOptionsPerVariable < MinimumEntries)
|
|
{
|
|
NumOptionsPerVariable = MinimumEntries;
|
|
}
|
|
|
|
// if this is a wildcard, we don't want to orphan it
|
|
if(SelectorPin->LinkedTo.Num() > 0 && !UEdGraphSchema_Niagara::IsPinWildcard(SelectorPin))
|
|
{
|
|
SelectorPin->bOrphanedPin = true;
|
|
}
|
|
|
|
ReallocatePins(true);
|
|
}
|
|
|
|
UEdGraphPin* UNiagaraNodeSelect::GetSelectorPin() const
|
|
{
|
|
return GetPinByPersistentGuid(SelectorPinGuid);
|
|
}
|
|
|
|
TArray<UEdGraphPin*> UNiagaraNodeSelect::GetOptionPins(int32 Index) const
|
|
{
|
|
TArray<UEdGraphPin*> OptionPins;
|
|
TArray<UEdGraphPin*> InputPins;
|
|
|
|
GetInputPins(InputPins);
|
|
|
|
if (Index < 0 || Index >= OutputVars.Num())
|
|
{
|
|
UE_LOG(LogNiagaraEditor, Error, TEXT("Tried retrieving option pins for index index %i. Out of bounds."), Index);
|
|
return OptionPins;
|
|
}
|
|
|
|
// add all input pins that aren't the selector pin to the option pins array
|
|
for(int32 PinIndex = Index; PinIndex < NumOptionsPerVariable * OutputVars.Num(); PinIndex += OutputVars.Num())
|
|
{
|
|
UEdGraphPin* Pin = InputPins[PinIndex];
|
|
if (Pin->PersistentGuid != SelectorPinGuid && Pin->bOrphanedPin == false)
|
|
{
|
|
OptionPins.Add(Pin);
|
|
}
|
|
}
|
|
|
|
if (NumOptionsPerVariable != OptionPins.Num())
|
|
{
|
|
UE_LOG(LogNiagaraEditor, Error, TEXT("Could not retrieve %i option pins for output pin %i. Retrieved %i pins instead."), NumOptionsPerVariable, Index, OptionPins.Num());
|
|
return {};
|
|
}
|
|
|
|
return OptionPins;
|
|
}
|
|
|
|
TArray<UEdGraphPin*> UNiagaraNodeSelect::GetValuePins(int32 Index) const
|
|
{
|
|
TArray<UEdGraphPin*> ValuePins = GetOptionPins(Index);
|
|
ValuePins.Add(GetPinByPersistentGuid(OutputVarGuids[Index]));
|
|
|
|
return ValuePins;
|
|
}
|
|
|
|
UEdGraphPin* UNiagaraNodeSelect::GetOutputPin(const FNiagaraVariable& Variable) const
|
|
{
|
|
int32 Index = OutputVars.Find(Variable);
|
|
|
|
if(Index != INDEX_NONE)
|
|
{
|
|
return GetPinByPersistentGuid(OutputVarGuids[Index]);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void UNiagaraNodeSelect::AddIntegerInputPin()
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("AddIntegerPinTransaction", "Added integer input pin to select node"));
|
|
|
|
this->Modify();
|
|
|
|
NumOptionsPerVariable++;
|
|
ReallocatePins();
|
|
}
|
|
|
|
void UNiagaraNodeSelect::RemoveIntegerInputPin()
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("RemoveIntegerPinTransaction", "Removed integer input pin from select node"));
|
|
|
|
this->Modify();
|
|
|
|
NumOptionsPerVariable = FMath::Max(2, --NumOptionsPerVariable);
|
|
ReallocatePins();
|
|
}
|
|
|
|
FText UNiagaraNodeSelect::GetTooltipText() const
|
|
{
|
|
return LOCTEXT("SelectTooltipText", "Select takes multiple inputs and passes through the one chosen by the selector");
|
|
}
|
|
|
|
FText UNiagaraNodeSelect::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
return LOCTEXT("SelectNodeTitle", "Select");
|
|
}
|
|
|
|
void UNiagaraNodeSelect::AddPinSearchMetaDataInfo(const UEdGraphPin* Pin, TArray<FSearchTagDataPair>& OutTaggedMetaData) const
|
|
{
|
|
Super::AddPinSearchMetaDataInfo(Pin, OutTaggedMetaData);
|
|
|
|
UEnum* Enum = SelectorPinType.GetEnum();
|
|
|
|
if (Enum != nullptr && Enum->IsNative())
|
|
{
|
|
// Allow native enum switch pins to be searchable by C++ enum name
|
|
OutTaggedMetaData.Add(FSearchTagDataPair(FFindInBlueprintSearchTags::FiB_NativeName, FText::FromString(Enum->GetName())));
|
|
}
|
|
}
|
|
|
|
void UNiagaraNodeSelect::AllocateDefaultPins()
|
|
{
|
|
const UEdGraphSchema_Niagara* Schema = GetDefault<UEdGraphSchema_Niagara>();
|
|
|
|
// in case der selector type became invalid, we change it back to wildcard here.
|
|
// this can happen if the underlying ustruct, for example an enum, has been deleted
|
|
if(!SelectorPinType.IsValid())
|
|
{
|
|
SelectorPinType = FNiagaraTypeDefinition::GetWildcardDef();
|
|
}
|
|
|
|
TArray<int32> OptionValues = GetOptionValues();
|
|
NumOptionsPerVariable = OptionValues.Num();
|
|
|
|
for(int32 OptionIndex = 0; OptionIndex < OptionValues.Num(); OptionIndex++)
|
|
{
|
|
for(const FNiagaraVariable& Variable : OutputVars)
|
|
{
|
|
AddOptionPin(Variable, OptionValues[OptionIndex]);
|
|
}
|
|
}
|
|
|
|
// create the selector pin
|
|
UEdGraphPin* SelectorPin = CreatePin(EGPD_Input, Schema->TypeDefinitionToPinType(SelectorPinType), GetSelectorPinName());
|
|
SelectorPin->PersistentGuid = SelectorPinGuid;
|
|
UNiagaraNode::SetPinDefaultToTypeDefaultIfUnset(SelectorPin);
|
|
|
|
// create all output variable pins
|
|
for (int32 Index = 0; Index < OutputVars.Num(); Index++)
|
|
{
|
|
UEdGraphPin* OutputPin = CreatePin(EGPD_Output, Schema->TypeDefinitionToPinType(OutputVars[Index].GetType()), OutputVars[Index].GetName());
|
|
OutputPin->PersistentGuid = OutputVarGuids[Index];
|
|
}
|
|
|
|
// create the add pin
|
|
CreateAddPin(EGPD_Output);
|
|
}
|
|
|
|
FLinearColor UNiagaraNodeSelect::GetNodeTitleColor() const
|
|
{
|
|
return FLinearColor(0.3f, 0.3f, 0.7f);
|
|
}
|
|
|
|
FSlateIcon UNiagaraNodeSelect::GetIconAndTint(FLinearColor& OutColor) const
|
|
{
|
|
static FSlateIcon Icon(FAppStyle::GetAppStyleSetName(), "GraphEditor.Switch_16x");
|
|
return Icon;
|
|
}
|
|
|
|
void UNiagaraNodeSelect::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const
|
|
{
|
|
Super::GetPinHoverText(Pin, HoverTextOut);
|
|
|
|
if(OutputVarGuids.Contains(Pin.PersistentGuid))
|
|
{
|
|
HoverTextOut = TEXT("The value of this pin is chosen by the selector pin.\n") + HoverTextOut;
|
|
}
|
|
else if(Pin.PersistentGuid == SelectorPinGuid)
|
|
{
|
|
HoverTextOut = TEXT("Based on the value of this pin one of the input pins gets selected for the output.\n") + HoverTextOut;
|
|
}
|
|
}
|
|
|
|
void UNiagaraNodeSelect::PostLoad()
|
|
{
|
|
Super::PostLoad();
|
|
|
|
// we assume something changed externally if the input pins are outdated; i.e. the assigned enum changed or value order changed
|
|
AttemptUpdatePins();
|
|
}
|
|
|
|
void UNiagaraNodeSelect::GetNodeContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
|
|
{
|
|
Super::GetNodeContextMenuActions(Menu, Context);
|
|
|
|
if (SelectorPinType.IsEnum() && SelectorPinType.GetEnum())
|
|
{
|
|
FToolMenuSection& Section = Menu->FindOrAddSection("Node");
|
|
|
|
Section.AddMenuEntry(
|
|
"BrowseToEnum",
|
|
FText::Format(LOCTEXT("BrowseToEnumLabel", "Browse to {0}"), FText::FromString(SelectorPinType.GetEnum()->GetName())),
|
|
LOCTEXT("BrowseToEnumTooltip", "Browses to the enum in the content browser."),
|
|
FSlateIcon(),
|
|
FUIAction(FExecuteAction::CreateLambda([this]()
|
|
{
|
|
FContentBrowserModule& Module = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
|
|
Module.Get().SyncBrowserToAssets({ FAssetData(SelectorPinType.GetEnum()) });
|
|
}), FCanExecuteAction::CreateLambda([this]()
|
|
{
|
|
return Cast<UUserDefinedEnum>(SelectorPinType.GetEnum()) != nullptr;
|
|
})));
|
|
|
|
Section.AddMenuEntry(
|
|
"OpenEnum",
|
|
FText::Format(LOCTEXT("OpenEnumLabel", "Open {0}"), FText::FromString(SelectorPinType.GetEnum()->GetName())),
|
|
LOCTEXT("OpenEnumTooltip", "Opens up the enum asset."),
|
|
FSlateIcon(),
|
|
FUIAction(FExecuteAction::CreateLambda([this]()
|
|
{
|
|
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(SelectorPinType.GetEnum());
|
|
}), FCanExecuteAction::CreateLambda([this]()
|
|
{
|
|
return Cast<UUserDefinedEnum>(SelectorPinType.GetEnum()) != nullptr;
|
|
})));
|
|
}
|
|
}
|
|
|
|
void UNiagaraNodeSelect::Compile(FTranslator* Translator, TArray<int32>& Outputs) const
|
|
{
|
|
const UEdGraphPin* SelectorPin = GetSelectorPin();
|
|
|
|
if(!SelectorPinType.IsValid())
|
|
{
|
|
Translator->Warning(LOCTEXT("SelectNodePinSelectorTypeInvalid", "Select node selector pin should have a valid type."), this, nullptr);
|
|
}
|
|
|
|
const int32 OutputVarCount = OutputVars.Num();
|
|
TArray<int32> ConnectedOutputVarIndices;
|
|
TArray<FNiagaraVariable> ConnectedOutputVars;
|
|
ConnectedOutputVarIndices.Reserve(OutputVarCount);
|
|
ConnectedOutputVars.Reserve(OutputVarCount);
|
|
for (int32 OutputVarIndex = 0; OutputVarIndex < OutputVarCount; ++OutputVarIndex)
|
|
{
|
|
const FNiagaraVariable& OutputVar = OutputVars[OutputVarIndex];
|
|
const UEdGraphPin* OutputPin = GetOutputPin(OutputVar);
|
|
if (OutputPin && !OutputPin->LinkedTo.IsEmpty())
|
|
{
|
|
ConnectedOutputVarIndices.Add(OutputVarIndex);
|
|
ConnectedOutputVars.Add(OutputVar);
|
|
}
|
|
}
|
|
|
|
for (const FNiagaraVariable& Variable : ConnectedOutputVars)
|
|
{
|
|
if(!Variable.GetType().IsValid())
|
|
{
|
|
Translator->Warning(FText::Format(LOCTEXT("SelectNodePinOutputTypeInvalid", "Select node output pin should have a valid type. {0} is invalid."), FText::FromName(Variable.GetName())), this, nullptr);
|
|
}
|
|
}
|
|
|
|
int32 Selection = Translator->CompileInputPin(SelectorPin);
|
|
|
|
// a map from selector value to compiled option pins (i.e.: for selector value 0 all pins that should be case "if 0" get their compiled index added under key 0)
|
|
TMap<int32, TArray<int32>> OptionValues;
|
|
OptionValues.Reserve(NumOptionsPerVariable);
|
|
|
|
TArray<int32> SelectorValues = GetOptionValues();
|
|
|
|
if(SelectorValues.Num() != NumOptionsPerVariable)
|
|
{
|
|
Translator->Error(FText::Format(LOCTEXT("SelectNodePinCountMismatch", "Select node should have {0} cases. {1} found."),
|
|
FText::FromString(FString::FromInt(NumOptionsPerVariable)), FText::FromString(FString::FromInt(SelectorValues.Num()))), this, nullptr);
|
|
return;
|
|
}
|
|
|
|
// initialize every selector value so we can access the array values
|
|
for (int32 Index = 0; Index < SelectorValues.Num(); Index++)
|
|
{
|
|
OptionValues.Add(SelectorValues[Index]);
|
|
}
|
|
|
|
for (const FNiagaraVariable& OutputVar : ConnectedOutputVars)
|
|
{
|
|
const UEdGraphPin* OutputPin = GetOutputPin(OutputVar);
|
|
const FNiagaraTypeDefinition OutputPinType = UEdGraphSchema_Niagara::PinToTypeDefinition(OutputPin);
|
|
|
|
if(OutputVar.GetType() != OutputPinType)
|
|
{
|
|
Translator->Error(FText::Format(LOCTEXT("PinTypeOutputVarTypeMismatch", "Internal output variable type {0} does not match pin type {1}. Please refresh node."),
|
|
FText::FromString(OutputVar.GetType().GetName()), FText::FromString(OutputPinType.GetName())),
|
|
this, OutputPin);
|
|
}
|
|
else if (UEdGraphSchema_Niagara::IsPinWildcard(OutputPin))
|
|
{
|
|
Translator->Error(FText::Format(LOCTEXT("PinTypeOutputWildcard", "Wildcard types are intended to be placeholders and replaced by real types. Please resolve type for {0}."),
|
|
FText::FromString(OutputVar.GetName().ToString())),
|
|
this, OutputPin);
|
|
}
|
|
}
|
|
|
|
for (int32 SelectorValueIndex = 0; SelectorValueIndex < NumOptionsPerVariable; SelectorValueIndex++)
|
|
{
|
|
for (int32 OutputVarIndex : ConnectedOutputVarIndices)
|
|
{
|
|
TArray<UEdGraphPin*> OptionPins = GetOptionPins(OutputVarIndex);
|
|
int32 CodeChunkIndex = Translator->CompileInputPin(OptionPins[SelectorValueIndex]);
|
|
OptionValues[SelectorValues[SelectorValueIndex]].Add(CodeChunkIndex);
|
|
}
|
|
}
|
|
|
|
TArray<int32> SelectOutputs;
|
|
Translator->Select(this, Selection, ConnectedOutputVars, OptionValues, SelectOutputs);
|
|
|
|
// remap the compiled outputs based on list of connected outputs
|
|
Outputs.Init(INDEX_NONE, OutputVarCount);
|
|
for (int32 ConnectedVarIndex = 0; ConnectedVarIndex < ConnectedOutputVars.Num(); ++ConnectedVarIndex)
|
|
{
|
|
Outputs[ConnectedOutputVarIndices[ConnectedVarIndex]] = SelectOutputs[ConnectedVarIndex];
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::AllowExternalPinTypeChanges(const UEdGraphPin* InGraphPin) const
|
|
{
|
|
// only allow pin type changes from UI for selector and output pins
|
|
if(InGraphPin == GetSelectorPin() || Super::AllowExternalPinTypeChanges(InGraphPin))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNiagaraNodeSelect::PinTypeChanged(UEdGraphPin* InGraphPin)
|
|
{
|
|
int32 PinIndex = GetPinIndex(InGraphPin);
|
|
if (PinIndex == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const UEdGraphSchema_Niagara* Schema = CastChecked<UEdGraphSchema_Niagara>(GetSchema());
|
|
check(Schema);
|
|
|
|
Super::PinTypeChanged(InGraphPin);
|
|
}
|
|
|
|
void UNiagaraNodeSelect::AddWidgetsToOutputBox(TSharedPtr<SVerticalBox> OutputBox)
|
|
{
|
|
OutputBox->AddSlot()
|
|
[
|
|
SNew(SSpacer)
|
|
];
|
|
|
|
TAttribute<EVisibility> AddVisibilityAttribute;
|
|
TAttribute<EVisibility> RemoveVisibilityAttribute;
|
|
AddVisibilityAttribute.BindUObject(this, &UNiagaraNodeSelect::ShowAddIntegerButton);
|
|
RemoveVisibilityAttribute.BindUObject(this, &UNiagaraNodeSelect::ShowRemoveIntegerButton);
|
|
|
|
OutputBox->AddSlot()
|
|
.Padding(4.f, 5.f)
|
|
.AutoHeight()
|
|
.HAlign(HAlign_Right)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
[
|
|
SNew(SButton)
|
|
.Visibility(RemoveVisibilityAttribute)
|
|
.ButtonStyle(FAppStyle::Get(), "HoverHintOnly")
|
|
.ToolTipText(GetIntegerRemoveButtonTooltipText())
|
|
.OnPressed(FSimpleDelegate::CreateUObject(this, &UNiagaraNodeSelect::RemoveIntegerInputPin))
|
|
[
|
|
SNew(SImage)
|
|
.ColorAndOpacity(FLinearColor(0.7f, 0.7f, 0.7f, 0.9f))
|
|
.Image(FNiagaraEditorStyle::Get().GetBrush("NiagaraEditor.Module.RemovePin"))
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
[
|
|
SNew(SButton)
|
|
.Visibility(AddVisibilityAttribute)
|
|
.ButtonStyle(FAppStyle::Get(), "HoverHintOnly")
|
|
.ToolTipText(GetIntegerAddButtonTooltipText())
|
|
.OnPressed(FSimpleDelegate::CreateUObject(this, &UNiagaraNodeSelect::AddIntegerInputPin))
|
|
[
|
|
SNew(SImage)
|
|
.ColorAndOpacity(FLinearColor(0.7f, 0.7f, 0.7f, 0.9f))
|
|
.Image(FNiagaraEditorStyle::Get().GetBrush("NiagaraEditor.Module.AddPin"))
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
void UNiagaraNodeSelect::AddWidgetsToInputBox(TSharedPtr<SVerticalBox> InputBox)
|
|
{
|
|
// make sure we maintain our case labels and separators
|
|
Super::AddWidgetsToInputBox(InputBox);
|
|
|
|
// we only want to add a separator before the selector pin if we actually have at least 1 variable
|
|
if (OutputVars.Num() < 1 || NumOptionsPerVariable < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
InputBox->InsertSlot(OutputVars.Num() * NumOptionsPerVariable + 2 * NumOptionsPerVariable)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SSeparator)
|
|
];
|
|
}
|
|
|
|
void UNiagaraNodeSelect::GetWildcardPinHoverConnectionTextAddition(const UEdGraphPin* WildcardPin, const UEdGraphPin* OtherPin, ECanCreateConnectionResponse ConnectionResponse, FString& OutString) const
|
|
{
|
|
if(ConnectionResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW)
|
|
{
|
|
if (WildcardPin && WildcardPin->PersistentGuid.IsValid() && WildcardPin->PersistentGuid == SelectorPinGuid)
|
|
{
|
|
OutString += TEXT("\nThis wildcard pin only supports bool, integer or enum types.");
|
|
}
|
|
else
|
|
{
|
|
OutString += TEXT("\nThis wildcard pin only supports simple types (no numerics or data interfaces).");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::CanRemovePin(const UEdGraphPin* Pin) const
|
|
{
|
|
return Super::CanRemovePin(Pin);
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::CanMovePin(const UEdGraphPin* Pin, int32 DirectionToMove) const
|
|
{
|
|
auto FindPredicate = [=](const FGuid& Guid) { return Guid == Pin->PersistentGuid; };
|
|
int32 FoundIndex = OutputVarGuids.IndexOfByPredicate(FindPredicate);
|
|
if (FoundIndex != INDEX_NONE && OutputVars.IsValidIndex(FoundIndex + DirectionToMove))
|
|
{
|
|
return Pin->Direction == EGPD_Output && Pin->bOrphanedPin == false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNiagaraNodeSelect::MoveDynamicPin(UEdGraphPin* Pin, int32 DirectionToMove)
|
|
{
|
|
auto FindPredicate = [=](const FGuid& Guid) { return Guid == Pin->PersistentGuid; };
|
|
int32 FoundIndex = OutputVarGuids.IndexOfByPredicate(FindPredicate);
|
|
if (FoundIndex != INDEX_NONE && OutputVars.IsValidIndex(FoundIndex + DirectionToMove))
|
|
{
|
|
this->Modify();
|
|
|
|
FNiagaraVariable TmpVar = OutputVars[FoundIndex];
|
|
OutputVars[FoundIndex] = OutputVars[FoundIndex + DirectionToMove];
|
|
OutputVars[FoundIndex + DirectionToMove] = TmpVar;
|
|
|
|
FGuid TmpGuid = OutputVarGuids[FoundIndex];
|
|
OutputVarGuids[FoundIndex] = OutputVarGuids[FoundIndex + DirectionToMove];
|
|
OutputVarGuids[FoundIndex + DirectionToMove] = TmpGuid;
|
|
|
|
ReallocatePins();
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::CanRenamePin(const UEdGraphPin* Pin) const
|
|
{
|
|
return Super::CanRenamePin(Pin) && Pin->Direction == EGPD_Output && Pin->bOrphanedPin == false && !UEdGraphSchema_Niagara::IsPinWildcard(Pin);
|
|
}
|
|
|
|
FString UNiagaraNodeSelect::GetInputCaseName(int32 Case) const
|
|
{
|
|
if( FNiagaraTypeDefinition::GetBoolDef().IsSameBaseDefinition(SelectorPinType))
|
|
{
|
|
if(Case == 0)
|
|
{
|
|
return TEXT("False");
|
|
}
|
|
if (Case == 1)
|
|
{
|
|
return TEXT("True");
|
|
}
|
|
}
|
|
else if ( FNiagaraTypeDefinition::GetIntDef().IsSameBaseDefinition(SelectorPinType))
|
|
{
|
|
return FString::FromInt(Case);
|
|
}
|
|
else if(SelectorPinType.IsEnum() && SelectorPinType.GetEnum())
|
|
{
|
|
UEnum* Enum = SelectorPinType.GetEnum();
|
|
// the display name is subject to localization and some automatic prettification. To avoid the localization aspect, we retrieve the source string of the text
|
|
// which is essentially the still prettified non-localized base text. We have to keep it this way for backwards compatibility until we can do a full upgrade pass.
|
|
// Same in StaticSwitch @todo
|
|
FText EnumDisplayText = Enum->GetDisplayNameTextByValue(Case);
|
|
return *FTextInspector::GetSourceString(EnumDisplayText);
|
|
}
|
|
|
|
return TEXT("");
|
|
}
|
|
|
|
void UNiagaraNodeSelect::BuildParameterMapHistory(FNiagaraParameterMapHistoryBuilder& OutHistory, bool bRecursive, bool bFilterForCompilation) const
|
|
{
|
|
UNiagaraNode::BuildParameterMapHistory(OutHistory, bRecursive, bFilterForCompilation);
|
|
}
|
|
|
|
void UNiagaraNodeSelect::PreChange(const UUserDefinedEnum* Changed, FEnumEditorUtils::EEnumEditorChangeInfo ChangedType)
|
|
{
|
|
// do nothing here
|
|
}
|
|
|
|
void UNiagaraNodeSelect::PostChange(const UUserDefinedEnum* Changed, FEnumEditorUtils::EEnumEditorChangeInfo ChangedType)
|
|
{
|
|
if (SelectorPinType.GetEnum() == Changed)
|
|
{
|
|
RefreshFromExternalChanges();
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::AllowNiagaraTypeForPinTypeChange(const FNiagaraTypeDefinition& InType, UEdGraphPin* Pin) const
|
|
{
|
|
// if it's the selector pin, check for integer types and connections
|
|
if(Pin == GetSelectorPin())
|
|
{
|
|
return InType.IsIndexType();
|
|
}
|
|
// else, it's a value pin. We have to treat all value pins as a single entity
|
|
else
|
|
{
|
|
return Super::AllowNiagaraTypeForPinTypeChange(InType, Pin);
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::OnNewPinTypeRequested(UEdGraphPin* PinToChange, FNiagaraTypeDefinition NewType)
|
|
{
|
|
PinToChange->Modify();
|
|
PinToChange->ResetDefaultValue();
|
|
|
|
if (PinToChange == GetSelectorPin())
|
|
{
|
|
SelectorPinType = NewType;
|
|
this->ChangeSelectorPinType(NewType);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if(OutputVarGuids.Contains(PinToChange->PersistentGuid))
|
|
{
|
|
return Super::OnNewPinTypeRequested(PinToChange, NewType);
|
|
}
|
|
else if(UEdGraphSchema_Niagara::IsPinWildcard(PinToChange))
|
|
{
|
|
// we don't reallocate to maintain pin connections, and instead just change pin types
|
|
int32 OutputIndex = INDEX_NONE;
|
|
|
|
TArray<UEdGraphPin*> InputPins;
|
|
GetInputPins(InputPins);
|
|
|
|
InputPins.RemoveAll([](UEdGraphPin* Pin)
|
|
{
|
|
return Pin->bOrphanedPin;
|
|
});
|
|
|
|
for(int32 Idx = 0; Idx < OutputVars.Num(); Idx++)
|
|
{
|
|
TArray<UEdGraphPin*> OptionPins = GetOptionPins(Idx);
|
|
if(OptionPins.Contains(PinToChange))
|
|
{
|
|
OutputIndex = Idx;
|
|
}
|
|
}
|
|
|
|
TSet<FName> OutputNames;
|
|
for (const FNiagaraVariable& Output : OutputVars)
|
|
{
|
|
OutputNames.Add(Output.GetName());
|
|
}
|
|
|
|
FName VariableAfterTypeChangeName = FNiagaraUtilities::GetUniqueName(NewType.GetFName(), OutputNames);
|
|
FNiagaraVariable OldVariable(OutputVars[OutputIndex].GetType(), OutputVars[OutputIndex].GetType().GetFName());
|
|
FNiagaraVariable TmpVar(NewType, VariableAfterTypeChangeName);
|
|
|
|
int32 Value = INDEX_NONE;
|
|
TArray<int32> OptionValues = GetOptionValues();
|
|
for(int32 OptionIndex = 0; OptionIndex < OptionValues.Num(); OptionIndex++)
|
|
{
|
|
FString CandidateNameForValue = GetOptionPinName(OldVariable, OptionValues[OptionIndex]).ToString();
|
|
if(CandidateNameForValue.Equals(PinToChange->GetName()))
|
|
{
|
|
Value = OptionValues[OptionIndex];
|
|
}
|
|
}
|
|
|
|
if (OutputIndex != INDEX_NONE && Value != INDEX_NONE)
|
|
{
|
|
PinToChange->PinName = GetOptionPinName(TmpVar, Value);
|
|
UEdGraphPin* OutputPin = GetPinByPersistentGuid(OutputVarGuids[OutputIndex]);
|
|
|
|
return Super::OnNewPinTypeRequested(OutputPin, NewType);
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UNiagaraNodeSelect::PostInitProperties()
|
|
{
|
|
Super::PostInitProperties();
|
|
|
|
if (!SelectorPinGuid.IsValid())
|
|
{
|
|
SelectorPinGuid = FGuid::NewGuid();
|
|
}
|
|
|
|
OutputVarGuids.Reserve(OutputVars.Num());
|
|
|
|
for (int32 OutputIndex = 0; OutputIndex < OutputVars.Num(); OutputIndex++)
|
|
{
|
|
if(!OutputVarGuids[OutputIndex].IsValid())
|
|
{
|
|
OutputVarGuids[OutputIndex] = FGuid::NewGuid();
|
|
}
|
|
}
|
|
|
|
for (int32 OutputIndex = 0; OutputIndex < OutputVars.Num(); OutputIndex++)
|
|
{
|
|
if (!OutputVars[OutputIndex].GetType().IsValid())
|
|
{
|
|
OutputVars[OutputIndex] = FNiagaraVariable(FNiagaraTypeDefinition::GetWildcardDef(), FName(TEXT("Wildcard Output") + FString::FromInt(OutputIndex)));
|
|
}
|
|
}
|
|
|
|
if (!SelectorPinType.IsValid())
|
|
{
|
|
SelectorPinType = FNiagaraTypeDefinition::GetWildcardDef();
|
|
}
|
|
}
|
|
|
|
bool UNiagaraNodeSelect::IsPinStatic(const UEdGraphPin* Pin) const
|
|
{
|
|
return Pin->PersistentGuid.IsValid() && (Pin->PersistentGuid == SelectorPinGuid || OutputVarGuids.Contains(Pin->PersistentGuid));
|
|
}
|
|
|
|
TArray<int32> UNiagaraNodeSelect::GetOptionValues() const
|
|
{
|
|
TArray<int32> SelectorValues;
|
|
|
|
if(FNiagaraTypeDefinition::GetBoolDef().IsSameBaseDefinition(SelectorPinType))
|
|
{
|
|
SelectorValues = { 1, 0 };
|
|
}
|
|
else if(FNiagaraTypeDefinition::GetIntDef().IsSameBaseDefinition(SelectorPinType))
|
|
{
|
|
int32 NewOptionsCount = FMath::Max(2, NumOptionsPerVariable);
|
|
SelectorValues.Reserve(NewOptionsCount);
|
|
for(int32 Index = 0; Index < NewOptionsCount; Index++)
|
|
{
|
|
SelectorValues.Add(Index);
|
|
}
|
|
}
|
|
else if(SelectorPinType.IsEnum() && SelectorPinType.IsValid() && SelectorPinType.GetEnum())
|
|
{
|
|
UEnum* Enum = SelectorPinType.GetEnum();
|
|
const int32 TotalEnumEntryCount = Enum->NumEnums() - 1;
|
|
if (TotalEnumEntryCount > 0)
|
|
{
|
|
SelectorValues.Reserve(TotalEnumEntryCount);
|
|
int32 ValidEnumEntryCount = 0;
|
|
for (int32 EnumIndex = 0; EnumIndex < TotalEnumEntryCount; EnumIndex++)
|
|
{
|
|
if(FNiagaraEditorUtilities::IsEnumIndexVisible(Enum, EnumIndex))
|
|
{
|
|
ValidEnumEntryCount++;
|
|
SelectorValues.Add(static_cast<int32>(Enum->GetValueByIndex(EnumIndex)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return SelectorValues;
|
|
}
|
|
|
|
FName UNiagaraNodeSelect::GetSelectorPinName() const
|
|
{
|
|
return FName(TEXT("Selector"));
|
|
}
|
|
|
|
FText UNiagaraNodeSelect::GetIntegerAddButtonTooltipText() const
|
|
{
|
|
return LOCTEXT("IntegerAddButtonTooltip", "Add a new input pin");
|
|
}
|
|
|
|
FText UNiagaraNodeSelect::GetIntegerRemoveButtonTooltipText() const
|
|
{
|
|
return LOCTEXT("IntegerRemoveButtonTooltip", "Remove the input pin with the highest index");
|
|
}
|
|
|
|
EVisibility UNiagaraNodeSelect::ShowAddIntegerButton() const
|
|
{
|
|
return SelectorPinType.IsSameBaseDefinition(FNiagaraTypeDefinition::GetIntDef()) ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility UNiagaraNodeSelect::ShowRemoveIntegerButton() const
|
|
{
|
|
return SelectorPinType.IsSameBaseDefinition(FNiagaraTypeDefinition::GetIntDef()) && NumOptionsPerVariable > 2 ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|