// Reconcile other pin links: // - Links between nodes within the copied set are fine // - Links to nodes that were not copied need to be fixed up if the copy-paste was in the same graph or broken completely // Call PostPasteNode on each node void FEdGraphUtilities::PostProcessPastedNodes(TSet<UEdGraphNode*>& SpawnedNodes) { // Run thru and fix up the node's pin links; they may point to invalid pins if the paste was to another graph for (TSet<UEdGraphNode*>::TIterator It(SpawnedNodes); It; ++It) { UEdGraphNode* Node = *It; UEdGraph* CurrentGraph = Node->GetGraph(); for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) { UEdGraphPin* ThisPin = Node->Pins[PinIndex]; for (int32 LinkIndex = 0; LinkIndex < ThisPin->LinkedTo.Num(); ) { UEdGraphPin* OtherPin = ThisPin->LinkedTo[LinkIndex]; if (OtherPin == NULL) { // Totally bogus link ThisPin->LinkedTo.RemoveAtSwap(LinkIndex); } else if (!SpawnedNodes.Contains(OtherPin->GetOwningNode())) { // It's a link across the selection set, so it should be broken OtherPin->LinkedTo.RemoveSwap(ThisPin); ThisPin->LinkedTo.RemoveAtSwap(LinkIndex); } else if (!OtherPin->LinkedTo.Contains(ThisPin)) { // The link needs to be reciprocal check(OtherPin->GetOwningNode()->GetGraph() == CurrentGraph); OtherPin->LinkedTo.Add(ThisPin); ++LinkIndex; } else { // Everything seems fine but sanity check the graph check(OtherPin->GetOwningNode()->GetGraph() == CurrentGraph); ++LinkIndex; } } } } // Give every node a chance to deep copy associated resources, etc... for (TSet<UEdGraphNode*>::TIterator It(SpawnedNodes); It; ++It) { UEdGraphNode* Node = *It; Node->PostPasteNode(); Node->ReconstructNode(); // Ensure we have RF_Transactional set on all pasted nodes, as its not copied in the T3D format Node->SetFlags(RF_Transactional); } }
UEdGraphNode* UEdGraph::CreateNode( TSubclassOf<UEdGraphNode> NewNodeClass, bool bSelectNewNode/* = true*/ ) { UEdGraphNode* NewNode = NewObject<UEdGraphNode>(this, NewNodeClass, NAME_None, RF_Transactional); if (HasAnyFlags(RF_Transient)) { NewNode->SetFlags(RF_Transient); } AddNode(NewNode, false, bSelectNewNode ); return NewNode; }
UEdGraphNode* FEdGraphSchemaAction_K2NewNode::CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, class UK2Node* NodeTemplate, bool bSelectNewNode/* = true*/) { // Smart pointer that handles fixup after potential node reconstruction FWeakGraphPinPtr FromPinPtr = FromPin; // Duplicate template node to create new node UEdGraphNode* ResultNode = DuplicateObject<UK2Node>(NodeTemplate, ParentGraph); ResultNode->SetFlags(RF_Transactional); ParentGraph->AddNode(ResultNode, true, bSelectNewNode); ResultNode->CreateNewGuid(); ResultNode->PostPlacedNewNode(); ResultNode->AllocateDefaultPins(); // For input pins, new node will generally overlap node being dragged off // Work out if we want to visually push away from connected node int32 XLocation = Location.X; if (FromPinPtr.IsValid() && FromPinPtr->Direction == EGPD_Input) { UEdGraphNode* PinNode = FromPinPtr->GetOwningNode(); const float XDelta = FMath::Abs(PinNode->NodePosX - Location.X); if (XDelta < NodeDistance) { // Set location to edge of current node minus the max move distance // to force node to push off from connect node enough to give selection handle XLocation = PinNode->NodePosX - NodeDistance; } } ResultNode->NodePosX = XLocation; ResultNode->NodePosY = Location.Y; ResultNode->SnapToGrid(SNAP_GRID); // make sure to auto-wire after we position the new node (in case the // auto-wire creates a conversion node to put between them) ResultNode->AutowireNewNode(FromPinPtr); // Update Analytics for the new nodes FBlueprintEditorUtils::AnalyticsTrackNewNode( ResultNode ); // NOTE: At this point the node may have been reconstructed, depending on node type! return ResultNode; }
UEdGraphNode* FEdGraphSchemaAction_NewNode::CreateNode(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, class UEdGraphNode* NodeTemplate) { // Duplicate template node to create new node UEdGraphNode* ResultNode = NULL; #if WITH_EDITOR ResultNode = DuplicateObject<UEdGraphNode>(NodeTemplate, ParentGraph); ResultNode->SetFlags(RF_Transactional); ParentGraph->AddNode(ResultNode, true); ResultNode->CreateNewGuid(); ResultNode->PostPlacedNewNode(); ResultNode->AllocateDefaultPins(); ResultNode->AutowireNewNode(FromPin); // For input pins, new node will generally overlap node being dragged off // Work out if we want to visually push away from connected node int32 XLocation = Location.X; if (FromPin && FromPin->Direction == EGPD_Input) { UEdGraphNode* PinNode = FromPin->GetOwningNode(); const float XDelta = FMath::Abs(PinNode->NodePosX - Location.X); if (XDelta < NodeDistance) { // Set location to edge of current node minus the max move distance // to force node to push off from connect node enough to give selection handle XLocation = PinNode->NodePosX - NodeDistance; } } ResultNode->NodePosX = XLocation; ResultNode->NodePosY = Location.Y; ResultNode->SnapToGrid(SNAP_GRID); #endif // WITH_EDITOR return ResultNode; }
UEdGraphNode* FEdGraphSchemaAction_NewStateNode::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode/* = true*/) { UEdGraphNode* ResultNode = NULL; // If there is a template, we actually use it if (NodeTemplate != NULL) { const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "K2_AddNode", "Add Node") ); ParentGraph->Modify(); if (FromPin) { FromPin->Modify(); } // set outer to be the graph so it doesn't go away NodeTemplate->Rename(NULL, ParentGraph); ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode); NodeTemplate->CreateNewGuid(); NodeTemplate->PostPlacedNewNode(); NodeTemplate->AllocateDefaultPins(); NodeTemplate->AutowireNewNode(FromPin); NodeTemplate->NodePosX = Location.X; NodeTemplate->NodePosY = Location.Y; //@TODO: ANIM: SNAP_GRID isn't centralized or exposed - NodeTemplate->SnapToGrid(SNAP_GRID); ResultNode = NodeTemplate; ResultNode->SetFlags(RF_Transactional); UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraphChecked(ParentGraph); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint); } return ResultNode; }