diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index b53c2a9a4..42e3a6c5d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -308,6 +308,56 @@ bool UFlowNode::CanUserAddOutput() const return K2_CanUserAddOutput(); } +bool UFlowNode::CanUserInsertInput(const FName& TargetPinName) const +{ + return K2_CanUserInsertInput(TargetPinName); +} + +bool UFlowNode::CanUserInsertOutput(const FName& TargetPinName) const +{ + return K2_CanUserInsertOutput(TargetPinName); +} + +void UFlowNode::AddUserInput(const FName& PinName, uint8 PinIndex) +{ + if (InputPins.IsValidIndex(PinIndex)) + { + InputPins.Insert(PinName, PinIndex); + } + else + { + InputPins.Add(PinName); + } + + // update remaining pins + RenumberUserPins(InputPins, PinIndex); +} + +void UFlowNode::AddUserOutput(const FName& PinName, uint8 PinIndex) +{ + if (OutputPins.IsValidIndex(PinIndex)) + { + OutputPins.Insert(PinName, PinIndex); + } + else + { + OutputPins.Add(PinName); + } + + // update remaining pins + RenumberUserPins(OutputPins, PinIndex); +} + +bool UFlowNode::CanUserRemoveInput(const FName& PinName) const +{ + return K2_CanUserRemoveInput(PinName); +} + +bool UFlowNode::CanUserRemoveOutput(const FName& PinName) const +{ + return K2_CanUserRemoveOutput(PinName); +} + void UFlowNode::RemoveUserInput(const FName& PinName) { Modify(); @@ -324,16 +374,7 @@ void UFlowNode::RemoveUserInput(const FName& PinName) } // update remaining pins - if (RemovedPinIndex > INDEX_NONE) - { - for (int32 i = RemovedPinIndex; i < InputPins.Num(); ++i) - { - if (InputPins[i].PinName.ToString().IsNumeric()) - { - InputPins[i].PinName = *FString::FromInt(i); - } - } - } + RenumberUserPins(InputPins, RemovedPinIndex); } void UFlowNode::RemoveUserOutput(const FName& PinName) @@ -352,13 +393,18 @@ void UFlowNode::RemoveUserOutput(const FName& PinName) } // update remaining pins - if (RemovedPinIndex > INDEX_NONE) + RenumberUserPins(OutputPins, RemovedPinIndex); +} + +void UFlowNode::RenumberUserPins(TArray& PinArray, int32 StartPinIndex) +{ + if (StartPinIndex > INDEX_NONE) { - for (int32 i = RemovedPinIndex; i < OutputPins.Num(); ++i) + for (int32 i = StartPinIndex; i < PinArray.Num(); ++i) { - if (OutputPins[i].PinName.ToString().IsNumeric()) + if (PinArray[i].PinName.ToString().IsNumeric()) { - OutputPins[i].PinName = *FString::FromInt(i); + PinArray[i].PinName = *FString::FromInt(i); } } } diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp index ca16183b3..362b49998 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -22,6 +22,13 @@ UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitiali AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } +#if WITH_EDITOR +bool UFlowNode_ExecutionMultiGate::CanUserRemoveOutput(const FName& PinName) const +{ + return OutputPins.Num() > 2; +} +#endif + void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName) { if (PinName == DefaultInputPin.PinName) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index 4dc8509ea..d828aef27 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -17,6 +17,13 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } +#if WITH_EDITOR +bool UFlowNode_ExecutionSequence::CanUserRemoveOutput(const FName& PinName) const +{ + return OutputPins.Num() > 2; +} +#endif + void UFlowNode_ExecutionSequence::ExecuteInput(const FName& PinName) { if (bSavePinExecutionState) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp index 94630d48c..062693753 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp @@ -15,6 +15,13 @@ UFlowNode_LogicalAND::UFlowNode_LogicalAND(const FObjectInitializer& ObjectIniti SetNumberedInputPins(0, 1); } +#if WITH_EDITOR +bool UFlowNode_LogicalAND::CanUserRemoveInput(const FName& PinName) const +{ + return InputPins.Num() > 2; +} +#endif + void UFlowNode_LogicalAND::ExecuteInput(const FName& PinName) { ExecutedInputNames.Add(PinName); diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp index 04f965b74..130577d67 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp @@ -20,6 +20,23 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial InputPins.Add(FFlowPin(TEXT("Disable"), TEXT("Disabling resets Execution Count"))); } +#if WITH_EDITOR +bool UFlowNode_LogicalOR::CanUserInsertInput(const FName& TargetPinName) const +{ + return TargetPinName != TEXT("Enable") && TargetPinName != TEXT("Disable"); +} + +bool UFlowNode_LogicalOR::CanUserRemoveInput(const FName& PinName) const +{ + if (PinName == TEXT("Enable") || PinName == TEXT("Disable")) + { + return false; + } + + return CountNumberedInputs() > 2; +} +#endif + void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) { if (PinName == TEXT("Enable")) diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 0857485cb..32003bdd0 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -139,6 +139,16 @@ class FLOW_API UFlowNode virtual bool CanUserAddInput() const; virtual bool CanUserAddOutput() const; + // Check if user can insert new pin before or after TargetPinName + virtual bool CanUserInsertInput(const FName& TargetPinName) const; + virtual bool CanUserInsertOutput(const FName& TargetPinName) const; + + void AddUserInput(const FName& PinName, uint8 PinIndex); + void AddUserOutput(const FName& PinName, uint8 PinIndex); + + virtual bool CanUserRemoveInput(const FName& PinName) const; + virtual bool CanUserRemoveOutput(const FName& PinName) const; + void RemoveUserInput(const FName& PinName); void RemoveUserOutput(const FName& PinName); @@ -146,6 +156,9 @@ class FLOW_API UFlowNode // TODO (gtaylor) The data pins feature is under construction bool DoesInputWildcardPinAcceptArray(const UEdGraphPin* Pin) const { return true; } bool DoesOutputWildcardPinAcceptContainer(const UEdGraphPin* Pin) const { return true; } + +private: + void RenumberUserPins(TArray& PinArray, int32 StartPinIndex); #endif protected: @@ -155,6 +168,18 @@ class FLOW_API UFlowNode UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Add Output")) bool K2_CanUserAddOutput() const; + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Insert Input", ToolTip = "Check if user can insert new pin before or after TargetPinName")) + bool K2_CanUserInsertInput(const FName& TargetPinName) const; + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Insert Output", ToolTip = "Check if user can insert new pin before or after TargetPinName")) + bool K2_CanUserInsertOutput(const FName& TargetPinName) const; + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Remove Input")) + bool K2_CanUserRemoveInput(const FName& PinName) const; + + UFUNCTION(BlueprintImplementableEvent, Category = "FlowNode", meta = (DisplayName = "Can User Remove Output")) + bool K2_CanUserRemoveOutput(const FName& PinName) const; + ////////////////////////////////////////////////////////////////////////// // Connections to other nodes diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index 262529cbc..8b96f7ad3 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -34,6 +34,8 @@ class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode public: #if WITH_EDITOR virtual bool CanUserAddOutput() const override { return true; } + virtual bool CanUserInsertOutput(const FName& TargetPinName) const override { return true; } + virtual bool CanUserRemoveOutput(const FName& PinName) const override; #endif protected: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index 73c081755..b5309ed2d 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -32,6 +32,8 @@ class FLOW_API UFlowNode_ExecutionSequence final : public UFlowNode public: #if WITH_EDITOR virtual bool CanUserAddOutput() const override { return true; } + virtual bool CanUserInsertOutput(const FName& TargetPinName) const override { return true; } + virtual bool CanUserRemoveOutput(const FName& PinName) const override; #endif protected: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h index 6296d07e1..2219fbb6b 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h @@ -21,6 +21,8 @@ class FLOW_API UFlowNode_LogicalAND final : public UFlowNode #if WITH_EDITOR public: virtual bool CanUserAddInput() const override { return true; } + virtual bool CanUserInsertInput(const FName& TargetPinName) const override { return true; } + virtual bool CanUserRemoveInput(const FName& PinName) const override; #endif protected: diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h index 70ea21e82..d6ab03da8 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h @@ -30,6 +30,8 @@ class FLOW_API UFlowNode_LogicalOR final : public UFlowNode #if WITH_EDITOR public: virtual bool CanUserAddInput() const override { return true; } + virtual bool CanUserInsertInput(const FName& TargetPinName) const override; + virtual bool CanUserRemoveInput(const FName& PinName) const override; #endif protected: diff --git a/Source/FlowEditor/Private/FlowEditorCommands.cpp b/Source/FlowEditor/Private/FlowEditorCommands.cpp index 8e681edec..8dacd9d52 100644 --- a/Source/FlowEditor/Private/FlowEditorCommands.cpp +++ b/Source/FlowEditor/Private/FlowEditorCommands.cpp @@ -38,6 +38,8 @@ void FFlowGraphCommands::RegisterCommands() UI_COMMAND(AddInput, "Add Input", "Adds an input to the node", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(AddOutput, "Add Output", "Adds an output to the node", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(InsertPinBefore, "Insert Pin Before", "Inserts a pin before selected pin", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(InsertPinAfter, "Insert Pin After", "Inserts a pin after selected pin", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(RemovePin, "Remove Pin", "Removes a pin from the node", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(AddPinBreakpoint, "Add Pin Breakpoint", "Adds a breakpoint to the pin", EUserInterfaceActionType::Button, FInputChord()); diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 19066bd05..5bd8bed03 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -125,6 +125,14 @@ void SFlowGraphEditor::BindGraphCommands() FExecuteAction::CreateSP(this, &SFlowGraphEditor::AddOutput), FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanAddOutput)); + CommandList->MapAction(FlowGraphCommands.InsertPinBefore, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::InsertPin, EPinInsertPosition::Before), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanInsertPin)); + + CommandList->MapAction(FlowGraphCommands.InsertPinAfter, + FExecuteAction::CreateSP(this, &SFlowGraphEditor::InsertPin, EPinInsertPosition::After), + FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanInsertPin)); + CommandList->MapAction(FlowGraphCommands.RemovePin, FExecuteAction::CreateSP(this, &SFlowGraphEditor::RemovePin), FCanExecuteAction::CreateSP(this, &SFlowGraphEditor::CanRemovePin)); @@ -1097,6 +1105,40 @@ bool SFlowGraphEditor::CanAddOutput() const return false; } +void SFlowGraphEditor::InsertPin(EPinInsertPosition Position) +{ + if (UEdGraphPin* SelectedPin = GetGraphPinForMenu()) + { + if (UFlowGraphNode* SelectedNode = Cast(SelectedPin->GetOwningNode())) + { + SelectedNode->InsertInstancePin(SelectedPin, SelectedPin->Direction, Position); + } + } +} + +bool SFlowGraphEditor::CanInsertPin() +{ + if (CanEdit() && GetSelectedFlowNodes().Num() == 1) + { + if (const UEdGraphPin* Pin = GetGraphPinForMenu()) + { + if (const UFlowGraphNode* GraphNode = Cast(Pin->GetOwningNode())) + { + if (Pin->Direction == EGPD_Input) + { + return GraphNode->CanUserInsertInput(Pin); + } + else + { + return GraphNode->CanUserInsertOutput(Pin); + } + } + } + } + + return false; +} + void SFlowGraphEditor::RemovePin() { if (UEdGraphPin* SelectedPin = GetGraphPinForMenu()) @@ -1415,12 +1457,13 @@ bool SFlowGraphEditor::CanTogglePinBreakpoint() void SFlowGraphEditor::SetSignalMode(const EFlowSignalMode Mode) const { + const FScopedTransaction Transaction(LOCTEXT("SetSignalMode", "Set Signal Mode")); + for (UFlowGraphNode* SelectedNode : GetSelectedFlowNodes()) { SelectedNode->SetSignalMode(Mode); } - FlowAsset->Modify(); } bool SFlowGraphEditor::CanSetSignalMode(const EFlowSignalMode Mode) const diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 8edd89c8d..74952466f 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -87,7 +87,7 @@ void UFlowGraphNode::PostLoad() SubscribeToExternalChanges(); } - RebuildPinArraysOnLoad(); + RebuildPinArrays(); } void UFlowGraphNode::PostDuplicate(bool bDuplicateForPIE) @@ -467,9 +467,15 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra { { FToolMenuSection& Section = Menu->AddSection("FlowGraphPinActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions")); - if (Context->Pin->LinkedTo.Num() > 0) + if (Context->Pin->Direction == EGPD_Input && CanUserInsertInput(Context->Pin)) { - Section.AddMenuEntry(GraphCommands.BreakPinLinks); + Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); + Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); + } + else if (Context->Pin->Direction == EGPD_Output && CanUserInsertOutput(Context->Pin)) + { + Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); + Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); } if (Context->Pin->Direction == EGPD_Input && CanUserRemoveInput(Context->Pin)) @@ -860,7 +866,14 @@ void UFlowGraphNode::CreateInputPin(const FFlowPin& FlowPin, const int32 Index / NewPin->PinToolTip = FlowPin.PinToolTip; - InputPins.Emplace(NewPin); + if (Index == INDEX_NONE) + { + InputPins.Emplace(NewPin); + } + else + { + InputPins.Insert(NewPin, Index); + } } void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index /*= INDEX_NONE*/) @@ -874,9 +887,16 @@ void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index const FName PinSubCategory = NAME_None; UObject* PinSubCategoryObject = FlowPin.GetPinSubCategoryObject().Get(); constexpr bool bIsReference = false; + int32 PinIndex = Index; + + if (PinIndex != INDEX_NONE) + { + UFlowNode* FlowNode = Cast(NodeInstance); + PinIndex += FlowNode->GetInputPins().Num(); + } const FEdGraphPinType PinType = FEdGraphPinType(PinCategory, PinSubCategory, PinSubCategoryObject, EPinContainerType::None, bIsReference, FEdGraphTerminalType()); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, Index); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinType, FlowPin.PinName, PinIndex); check(NewPin); if (!FlowPin.PinFriendlyName.IsEmpty()) @@ -887,7 +907,14 @@ void UFlowGraphNode::CreateOutputPin(const FFlowPin& FlowPin, const int32 Index NewPin->PinToolTip = FlowPin.PinToolTip; - OutputPins.Emplace(NewPin); + if (Index == INDEX_NONE) + { + OutputPins.Emplace(NewPin); + } + else + { + OutputPins.Insert(NewPin, Index); + } } void UFlowGraphNode::RemoveOrphanedPin(UEdGraphPin* Pin) @@ -925,16 +952,28 @@ bool UFlowGraphNode::CanUserAddOutput() const return FlowNode && FlowNode->CanUserAddOutput() && OutputPins.Num() < 256; } +bool UFlowGraphNode::CanUserInsertInput(const UEdGraphPin* Pin) const +{ + const UFlowNode* FlowNode = Cast(NodeInstance); + return FlowNode && CanUserAddInput() && FlowNode->CanUserInsertInput(Pin->PinName); +} + +bool UFlowGraphNode::CanUserInsertOutput(const UEdGraphPin* Pin) const +{ + const UFlowNode* FlowNode = Cast(NodeInstance); + return FlowNode && CanUserAddOutput() && FlowNode->CanUserInsertOutput(Pin->PinName); +} + bool UFlowGraphNode::CanUserRemoveInput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->InputPins.Contains(Pin->PinName); + return FlowNode && FlowNode->CanUserRemoveInput(Pin->PinName); } bool UFlowGraphNode::CanUserRemoveOutput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->OutputPins.Contains(Pin->PinName); + return FlowNode && FlowNode->CanUserRemoveOutput(Pin->PinName); } void UFlowGraphNode::AddUserInput() @@ -954,34 +993,61 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const const FScopedTransaction Transaction(LOCTEXT("AddInstancePin", "Add Instance Pin")); Modify(); - const FFlowPin PinName = FFlowPin(FString::FromInt(NumberedPinsAmount)); + const FName PinName = FName(FString::FromInt(NumberedPinsAmount)); UFlowNode* FlowNode = Cast(NodeInstance); + FlowNode->Modify(); + if (Direction == EGPD_Input) { - if (FlowNode->InputPins.IsValidIndex(NumberedPinsAmount)) - { - FlowNode->InputPins.Insert(PinName, NumberedPinsAmount); - } - else - { - FlowNode->InputPins.Add(PinName); - } - + FlowNode->AddUserInput(PinName, NumberedPinsAmount); CreateInputPin(PinName, NumberedPinsAmount); } else { - if (FlowNode->OutputPins.IsValidIndex(NumberedPinsAmount)) - { - FlowNode->OutputPins.Insert(PinName, NumberedPinsAmount); - } - else - { - FlowNode->OutputPins.Add(PinName); - } + FlowNode->AddUserOutput(PinName, NumberedPinsAmount); + CreateOutputPin(PinName, NumberedPinsAmount); + } + + GetGraph()->NotifyNodeChanged(this); +} - CreateOutputPin(PinName, FlowNode->InputPins.Num() + NumberedPinsAmount); +void UFlowGraphNode::InsertInstancePin(UEdGraphPin* TargetPin, const EEdGraphPinDirection Direction, EPinInsertPosition Position) +{ + TArray& DestPins = Direction == EEdGraphPinDirection::EGPD_Input ? InputPins : OutputPins; + uint8 PinIndex = DestPins.Find(TargetPin); + + if (PinIndex == INDEX_NONE) + { + return; + } + + const FScopedTransaction Transaction(LOCTEXT("InsertInstancePin", "Insert Instance Pin")); + Modify(); + + if (Position == EPinInsertPosition::After) + { + PinIndex = PinIndex + 1; + } + + const FName PinName = FName(FString::FromInt(PinIndex)); + + UFlowNode* FlowNode = Cast(NodeInstance); + FlowNode->Modify(); + + if (Direction == EGPD_Input) + { + FlowNode->AddUserInput(PinName, PinIndex); + CreateInputPin(PinName, PinIndex); + + RenumberUserPins(InputPins); + } + else + { + FlowNode->AddUserOutput(PinName, PinIndex); + CreateOutputPin(PinName, PinIndex); + + RenumberUserPins(OutputPins); } GetGraph()->NotifyNodeChanged(this); @@ -1007,6 +1073,8 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); + + RenumberUserPins(InputPins); } } else @@ -1018,6 +1086,8 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); + + RenumberUserPins(OutputPins); } } @@ -1025,6 +1095,19 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) GetGraph()->NotifyNodeChanged(this); } +void UFlowGraphNode::RenumberUserPins(const TArray& PinArray) +{ + // Renumber the pins so the numbering is compact + for (int32 Index = 0; Index < PinArray.Num(); ++Index) + { + UEdGraphPin* PotentialPin = PinArray[Index]; + if (PotentialPin->PinName.ToString().IsNumeric()) + { + PotentialPin->PinName = *FString::FromInt(Index); + } + } +} + void UFlowGraphNode::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const { // start with the default hover text (from the pin's tool-tip) @@ -1103,6 +1186,7 @@ void UFlowGraphNode::SetSignalMode(const EFlowSignalMode Mode) { if (UFlowNode* FlowNode = Cast(NodeInstance)) { + FlowNode->Modify(); FlowNode->SignalMode = Mode; OnSignalModeChanged.ExecuteIfBound(); } @@ -1156,6 +1240,8 @@ void UFlowGraphNode::PostEditUndo() { RebuildRuntimeAddOnsFromEditorSubNodes(); } + + RebuildPinArrays(); } UFlowAsset* UFlowGraphNode::GetFlowAsset() const @@ -1840,8 +1926,11 @@ bool UFlowGraphNode::IsAncestorNode(const UFlowGraphNode& OtherNode) const return false; } -void UFlowGraphNode::RebuildPinArraysOnLoad() +void UFlowGraphNode::RebuildPinArrays() { + InputPins.Reset(); + OutputPins.Reset(); + for (UEdGraphPin* Pin : Pins) { switch (Pin->Direction) diff --git a/Source/FlowEditor/Public/FlowEditorCommands.h b/Source/FlowEditor/Public/FlowEditorCommands.h index d83f84d5b..25c29add4 100644 --- a/Source/FlowEditor/Public/FlowEditorCommands.h +++ b/Source/FlowEditor/Public/FlowEditorCommands.h @@ -35,6 +35,8 @@ class FLOWEDITOR_API FFlowGraphCommands : public TCommands /** Pins */ TSharedPtr AddInput; TSharedPtr AddOutput; + TSharedPtr InsertPinBefore; + TSharedPtr InsertPinAfter; TSharedPtr RemovePin; /** Breakpoints */ diff --git a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h index c910d60d4..efd3c873c 100644 --- a/Source/FlowEditor/Public/Graph/FlowGraphEditor.h +++ b/Source/FlowEditor/Public/Graph/FlowGraphEditor.h @@ -113,6 +113,9 @@ class FLOWEDITOR_API SFlowGraphEditor : public SGraphEditor void AddOutput() const; bool CanAddOutput() const; + void InsertPin(EPinInsertPosition Position); + bool CanInsertPin(); + void RemovePin(); bool CanRemovePin(); diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index cabe0854d..2cef6cc0b 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -121,7 +121,7 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode bool IsAncestorNode(const UFlowGraphNode& OtherNode) const; protected: - void RebuildPinArraysOnLoad(); + void RebuildPinArrays(); ////////////////////////////////////////////////////////////////////////// // Utils @@ -184,6 +184,9 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode bool CanUserAddInput() const; bool CanUserAddOutput() const; + + bool CanUserInsertInput(const UEdGraphPin* Pin) const; + bool CanUserInsertOutput(const UEdGraphPin* Pin) const; bool CanUserRemoveInput(const UEdGraphPin* Pin) const; bool CanUserRemoveOutput(const UEdGraphPin* Pin) const; @@ -191,12 +194,16 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode void AddUserInput(); void AddUserOutput(); - // Add pin only on this instance of node, under default pins + // Add pin only on this instance of node, before default pins void AddInstancePin(const EEdGraphPinDirection Direction, const uint8 NumberedPinsAmount); + void InsertInstancePin(UEdGraphPin* TargetPin, const EEdGraphPinDirection Direction, EPinInsertPosition Position); // Call node and graph updates manually, if using bBatchRemoval void RemoveInstancePin(UEdGraphPin* Pin); +private: + void RenumberUserPins(const TArray& PinArray); + public: // UEdGraphNode virtual void GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const override;