From 749c24f68e0dd17f430615b6da94a52a93d8ea96 Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Thu, 5 Jun 2025 14:22:00 +0300 Subject: [PATCH 1/6] Added transaction for changing signal mode --- Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp | 2 ++ Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 19066bd05..0cd82fb10 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -1415,6 +1415,8 @@ 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); diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 8edd89c8d..fddd2e4a0 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -1103,6 +1103,7 @@ void UFlowGraphNode::SetSignalMode(const EFlowSignalMode Mode) { if (UFlowNode* FlowNode = Cast(NodeInstance)) { + FlowNode->Modify(); FlowNode->SignalMode = Mode; OnSignalModeChanged.ExecuteIfBound(); } From 9440e5888e519b55577d462e54ca47d90d2ecfc3 Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Thu, 5 Jun 2025 14:23:35 +0300 Subject: [PATCH 2/6] Remove unnecessary Modify() --- Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 0cd82fb10..395ccfe31 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -1422,7 +1422,6 @@ void SFlowGraphEditor::SetSignalMode(const EFlowSignalMode Mode) const SelectedNode->SetSignalMode(Mode); } - FlowAsset->Modify(); } bool SFlowGraphEditor::CanSetSignalMode(const EFlowSignalMode Mode) const From 222bf691c0e02873337162f7219ba1ce9a445e1c Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Thu, 5 Jun 2025 14:27:21 +0300 Subject: [PATCH 3/6] Reworked deletion of numbered pins ('user pins') from nodes. Now any pin can be deleted and pin connections correctly moved --- .../Private/Graph/Nodes/FlowGraphNode.cpp | 44 +++++++++++++++++-- .../Public/Graph/Nodes/FlowGraphNode.h | 4 +- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index fddd2e4a0..3c774f51b 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) @@ -913,6 +913,11 @@ bool UFlowGraphNode::SupportsContextPins() const return NodeInstance && NodeInstance->SupportsContextPins(); } +bool UFlowGraphNode::IsNumberedPin(const UEdGraphPin* Pin) +{ + return Pin && Pin->PinName.ToString().IsNumeric(); +} + bool UFlowGraphNode::CanUserAddInput() const { const UFlowNode* FlowNode = Cast(NodeInstance); @@ -928,13 +933,13 @@ bool UFlowGraphNode::CanUserAddOutput() const bool UFlowGraphNode::CanUserRemoveInput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->InputPins.Contains(Pin->PinName); + return FlowNode && IsNumberedPin(Pin) && FlowNode->CountNumberedInputs() > 2; } bool UFlowGraphNode::CanUserRemoveOutput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && !FlowNode->GetClass()->GetDefaultObject()->OutputPins.Contains(Pin->PinName); + return FlowNode && IsNumberedPin(Pin) && FlowNode->CountNumberedOutputs() > 2; } void UFlowGraphNode::AddUserInput() @@ -957,6 +962,8 @@ void UFlowGraphNode::AddInstancePin(const EEdGraphPinDirection Direction, const const FFlowPin PinName = FFlowPin(FString::FromInt(NumberedPinsAmount)); UFlowNode* FlowNode = Cast(NodeInstance); + FlowNode->Modify(); + if (Direction == EGPD_Input) { if (FlowNode->InputPins.IsValidIndex(NumberedPinsAmount)) @@ -1007,6 +1014,18 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); + + // Renumber the pins so the numbering is compact + int32 Index = 0; + for (int32 i = 0; i < Pins.Num(); ++i) + { + UEdGraphPin* PotentialPin = Pins[i]; + if (PotentialPin->Direction == EGPD_Input && PotentialPin->PinName.ToString().IsNumeric()) + { + PotentialPin->PinName = *FString::FromInt(Index); + ++Index; + } + } } } else @@ -1018,6 +1037,18 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); + + // Renumber the pins so the numbering is compact + int32 Index = 0; + for (int32 i = 0; i < Pins.Num(); ++i) + { + UEdGraphPin* PotentialPin = Pins[i]; + if (PotentialPin->Direction == EGPD_Output && PotentialPin->PinName.ToString().IsNumeric()) + { + PotentialPin->PinName = *FString::FromInt(Index); + ++Index; + } + } } } @@ -1157,6 +1188,8 @@ void UFlowGraphNode::PostEditUndo() { RebuildRuntimeAddOnsFromEditorSubNodes(); } + + RebuildPinArrays(); } UFlowAsset* UFlowGraphNode::GetFlowAsset() const @@ -1841,8 +1874,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/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index cabe0854d..68fe3397d 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 @@ -182,6 +182,8 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode bool SupportsContextPins() const; + static bool IsNumberedPin(const UEdGraphPin* Pin); + bool CanUserAddInput() const; bool CanUserAddOutput() const; From 297293bd910bee7003555890b930a2458bff1f49 Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Mon, 9 Jun 2025 14:51:42 +0300 Subject: [PATCH 4/6] Added option to insert pins between existing user pins --- Source/Flow/Private/Nodes/FlowNode.cpp | 64 ++++++-- .../Route/FlowNode_ExecutionMultiGate.cpp | 5 + .../Route/FlowNode_ExecutionSequence.cpp | 5 + .../Nodes/Route/FlowNode_LogicalAND.cpp | 5 + .../Nodes/Route/FlowNode_LogicalOR.cpp | 5 + Source/Flow/Public/Nodes/FlowNode.h | 15 ++ .../Nodes/Route/FlowNode_ExecutionMultiGate.h | 1 + .../Nodes/Route/FlowNode_ExecutionSequence.h | 1 + .../Public/Nodes/Route/FlowNode_LogicalAND.h | 1 + .../Public/Nodes/Route/FlowNode_LogicalOR.h | 1 + .../FlowEditor/Private/FlowEditorCommands.cpp | 2 + .../Private/Graph/FlowGraphEditor.cpp | 42 +++++ .../Private/Graph/Nodes/FlowGraphNode.cpp | 147 ++++++++++++------ Source/FlowEditor/Public/FlowEditorCommands.h | 2 + .../FlowEditor/Public/Graph/FlowGraphEditor.h | 3 + .../Public/Graph/Nodes/FlowGraphNode.h | 8 +- 16 files changed, 239 insertions(+), 68 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index b53c2a9a4..a27c79f2f 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -308,6 +308,46 @@ bool UFlowNode::CanUserAddOutput() const return K2_CanUserAddOutput(); } +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 +364,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 +383,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..e7cde479c 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -22,6 +22,11 @@ UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitiali AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } +bool UFlowNode_ExecutionMultiGate::CanUserRemoveOutput(const FName& PinName) const +{ + return OutputPins.Num() > 2; +} + 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..2043390e8 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -17,6 +17,11 @@ UFlowNode_ExecutionSequence::UFlowNode_ExecutionSequence(const FObjectInitialize AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled}; } +bool UFlowNode_ExecutionSequence::CanUserRemoveOutput(const FName& PinName) const +{ + return OutputPins.Num() > 2; +} + 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..5c2ecdf73 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp @@ -15,6 +15,11 @@ UFlowNode_LogicalAND::UFlowNode_LogicalAND(const FObjectInitializer& ObjectIniti SetNumberedInputPins(0, 1); } +bool UFlowNode_LogicalAND::CanUserRemoveInput(const FName& PinName) const +{ + return InputPins.Num() > 2; +} + 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..a17953a22 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp @@ -20,6 +20,11 @@ UFlowNode_LogicalOR::UFlowNode_LogicalOR(const FObjectInitializer& ObjectInitial InputPins.Add(FFlowPin(TEXT("Disable"), TEXT("Disabling resets Execution Count"))); } +bool UFlowNode_LogicalOR::CanUserRemoveInput(const FName& PinName) const +{ + return InputPins.Num() > 2; +} + 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..9029be87f 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -139,6 +139,12 @@ class FLOW_API UFlowNode virtual bool CanUserAddInput() const; virtual bool CanUserAddOutput() 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 +152,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 +164,12 @@ 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 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..a02c739b4 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -34,6 +34,7 @@ class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode public: #if WITH_EDITOR virtual bool CanUserAddOutput() 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..799488ff9 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -32,6 +32,7 @@ class FLOW_API UFlowNode_ExecutionSequence final : public UFlowNode public: #if WITH_EDITOR virtual bool CanUserAddOutput() 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..483f214f3 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h @@ -21,6 +21,7 @@ class FLOW_API UFlowNode_LogicalAND final : public UFlowNode #if WITH_EDITOR public: virtual bool CanUserAddInput() 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..9ec4ac8b1 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h @@ -30,6 +30,7 @@ class FLOW_API UFlowNode_LogicalOR final : public UFlowNode #if WITH_EDITOR public: virtual bool CanUserAddInput() const override { return true; } + 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 395ccfe31..55787bf8d 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->CanUserAddInput(); + } + else + { + return GraphNode->CanUserAddOutput(); + } + } + } + } + + return false; +} + void SFlowGraphEditor::RemovePin() { if (UEdGraphPin* SelectedPin = GetGraphPinForMenu()) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 3c774f51b..8d4182a16 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -472,6 +472,17 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra Section.AddMenuEntry(GraphCommands.BreakPinLinks); } + if (Context->Pin->Direction == EGPD_Input && CanUserAddInput()) + { + Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); + Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); + } + else if (Context->Pin->Direction == EGPD_Output && CanUserAddOutput()) + { + Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); + Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); + } + if (Context->Pin->Direction == EGPD_Input && CanUserRemoveInput(Context->Pin)) { Section.AddMenuEntry(FlowGraphCommands.RemovePin); @@ -860,7 +871,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 +892,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 +912,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) @@ -913,11 +945,6 @@ bool UFlowGraphNode::SupportsContextPins() const return NodeInstance && NodeInstance->SupportsContextPins(); } -bool UFlowGraphNode::IsNumberedPin(const UEdGraphPin* Pin) -{ - return Pin && Pin->PinName.ToString().IsNumeric(); -} - bool UFlowGraphNode::CanUserAddInput() const { const UFlowNode* FlowNode = Cast(NodeInstance); @@ -933,13 +960,13 @@ bool UFlowGraphNode::CanUserAddOutput() const bool UFlowGraphNode::CanUserRemoveInput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && IsNumberedPin(Pin) && FlowNode->CountNumberedInputs() > 2; + return FlowNode && FlowNode->CanUserRemoveInput(Pin->PinName); } bool UFlowGraphNode::CanUserRemoveOutput(const UEdGraphPin* Pin) const { const UFlowNode* FlowNode = Cast(NodeInstance); - return FlowNode && IsNumberedPin(Pin) && FlowNode->CountNumberedOutputs() > 2; + return FlowNode && FlowNode->CanUserRemoveOutput(Pin->PinName); } void UFlowGraphNode::AddUserInput() @@ -959,36 +986,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); @@ -1015,17 +1067,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); - // Renumber the pins so the numbering is compact - int32 Index = 0; - for (int32 i = 0; i < Pins.Num(); ++i) - { - UEdGraphPin* PotentialPin = Pins[i]; - if (PotentialPin->Direction == EGPD_Input && PotentialPin->PinName.ToString().IsNumeric()) - { - PotentialPin->PinName = *FString::FromInt(Index); - ++Index; - } - } + RenumberUserPins(InputPins); } } else @@ -1038,17 +1080,7 @@ void UFlowGraphNode::RemoveInstancePin(UEdGraphPin* Pin) Pin->MarkAsGarbage(); Pins.Remove(Pin); - // Renumber the pins so the numbering is compact - int32 Index = 0; - for (int32 i = 0; i < Pins.Num(); ++i) - { - UEdGraphPin* PotentialPin = Pins[i]; - if (PotentialPin->Direction == EGPD_Output && PotentialPin->PinName.ToString().IsNumeric()) - { - PotentialPin->PinName = *FString::FromInt(Index); - ++Index; - } - } + RenumberUserPins(OutputPins); } } @@ -1056,6 +1088,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) 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 68fe3397d..1775d8d45 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -182,8 +182,6 @@ class FLOWEDITOR_API UFlowGraphNode : public UEdGraphNode bool SupportsContextPins() const; - static bool IsNumberedPin(const UEdGraphPin* Pin); - bool CanUserAddInput() const; bool CanUserAddOutput() const; @@ -193,12 +191,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; From 5230efb432b6fc18f4edebabda8b2aba500a6b2f Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Tue, 10 Jun 2025 02:52:39 +0300 Subject: [PATCH 5/6] Added separate functions to check if user can insert pins --- Source/Flow/Private/Nodes/FlowNode.cpp | 10 ++++++++++ .../Nodes/Route/FlowNode_ExecutionMultiGate.cpp | 2 ++ .../Nodes/Route/FlowNode_ExecutionSequence.cpp | 2 ++ .../Private/Nodes/Route/FlowNode_LogicalAND.cpp | 2 ++ .../Private/Nodes/Route/FlowNode_LogicalOR.cpp | 14 +++++++++++++- Source/Flow/Public/Nodes/FlowNode.h | 10 ++++++++++ .../Nodes/Route/FlowNode_ExecutionMultiGate.h | 1 + .../Nodes/Route/FlowNode_ExecutionSequence.h | 1 + .../Public/Nodes/Route/FlowNode_LogicalAND.h | 1 + .../Flow/Public/Nodes/Route/FlowNode_LogicalOR.h | 1 + .../FlowEditor/Private/Graph/FlowGraphEditor.cpp | 4 ++-- .../Private/Graph/Nodes/FlowGraphNode.cpp | 16 ++++++++++++++-- .../Public/Graph/Nodes/FlowGraphNode.h | 3 +++ 13 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Source/Flow/Private/Nodes/FlowNode.cpp b/Source/Flow/Private/Nodes/FlowNode.cpp index a27c79f2f..42e3a6c5d 100644 --- a/Source/Flow/Private/Nodes/FlowNode.cpp +++ b/Source/Flow/Private/Nodes/FlowNode.cpp @@ -308,6 +308,16 @@ 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)) diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp index e7cde479c..362b49998 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionMultiGate.cpp @@ -22,10 +22,12 @@ 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) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp index 2043390e8..d828aef27 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_ExecutionSequence.cpp @@ -17,10 +17,12 @@ 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) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp index 5c2ecdf73..062693753 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalAND.cpp @@ -15,10 +15,12 @@ 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) { diff --git a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp index a17953a22..130577d67 100644 --- a/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp +++ b/Source/Flow/Private/Nodes/Route/FlowNode_LogicalOR.cpp @@ -20,10 +20,22 @@ 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 { - return InputPins.Num() > 2; + if (PinName == TEXT("Enable") || PinName == TEXT("Disable")) + { + return false; + } + + return CountNumberedInputs() > 2; } +#endif void UFlowNode_LogicalOR::ExecuteInput(const FName& PinName) { diff --git a/Source/Flow/Public/Nodes/FlowNode.h b/Source/Flow/Public/Nodes/FlowNode.h index 9029be87f..32003bdd0 100644 --- a/Source/Flow/Public/Nodes/FlowNode.h +++ b/Source/Flow/Public/Nodes/FlowNode.h @@ -139,6 +139,10 @@ 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); @@ -164,6 +168,12 @@ 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; diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h index a02c739b4..8b96f7ad3 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionMultiGate.h @@ -34,6 +34,7 @@ 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 diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h index 799488ff9..b5309ed2d 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_ExecutionSequence.h @@ -32,6 +32,7 @@ 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 diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h index 483f214f3..2219fbb6b 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalAND.h @@ -21,6 +21,7 @@ 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 diff --git a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h index 9ec4ac8b1..d6ab03da8 100644 --- a/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h +++ b/Source/Flow/Public/Nodes/Route/FlowNode_LogicalOR.h @@ -30,6 +30,7 @@ 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 diff --git a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp index 55787bf8d..5bd8bed03 100644 --- a/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp +++ b/Source/FlowEditor/Private/Graph/FlowGraphEditor.cpp @@ -1126,11 +1126,11 @@ bool SFlowGraphEditor::CanInsertPin() { if (Pin->Direction == EGPD_Input) { - return GraphNode->CanUserAddInput(); + return GraphNode->CanUserInsertInput(Pin); } else { - return GraphNode->CanUserAddOutput(); + return GraphNode->CanUserInsertOutput(Pin); } } } diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index 8d4182a16..dc04ff371 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -472,12 +472,12 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra Section.AddMenuEntry(GraphCommands.BreakPinLinks); } - if (Context->Pin->Direction == EGPD_Input && CanUserAddInput()) + if (Context->Pin->Direction == EGPD_Input && CanUserInsertInput(Context->Pin)) { Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); } - else if (Context->Pin->Direction == EGPD_Output && CanUserAddOutput()) + else if (Context->Pin->Direction == EGPD_Output && CanUserInsertOutput(Context->Pin)) { Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore); Section.AddMenuEntry(FlowGraphCommands.InsertPinAfter); @@ -957,6 +957,18 @@ 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); diff --git a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h index 1775d8d45..2cef6cc0b 100644 --- a/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h +++ b/Source/FlowEditor/Public/Graph/Nodes/FlowGraphNode.h @@ -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; From b047b1e93ad53aa0d4f0ad1b2cb190aea3ddce8e Mon Sep 17 00:00:00 2001 From: MaksymKapelianovych Date: Tue, 10 Jun 2025 03:00:30 +0300 Subject: [PATCH 6/6] Removed redundant pin menu entry --- Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp index dc04ff371..74952466f 100644 --- a/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp +++ b/Source/FlowEditor/Private/Graph/Nodes/FlowGraphNode.cpp @@ -467,11 +467,6 @@ void UFlowGraphNode::GetNodeContextMenuActions(class UToolMenu* Menu, class UGra { { FToolMenuSection& Section = Menu->AddSection("FlowGraphPinActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions")); - if (Context->Pin->LinkedTo.Num() > 0) - { - Section.AddMenuEntry(GraphCommands.BreakPinLinks); - } - if (Context->Pin->Direction == EGPD_Input && CanUserInsertInput(Context->Pin)) { Section.AddMenuEntry(FlowGraphCommands.InsertPinBefore);