//------------------------------------------------------------------------------ UEdGraphNode* FBlueprintActionMenuItem::PerformAction(UEdGraph* ParentGraph, TArray<UEdGraphPin*>& FromPins, FVector2D const Location, bool bSelectNewNode/* = true*/) { UEdGraphPin* FromPin = nullptr; if (FromPins.Num() > 0) { FromPin = FromPins[0]; } UEdGraphNode* SpawnedNode = PerformAction(ParentGraph, FromPin, Location, bSelectNewNode); // try auto-wiring the rest of the pins (if there are any) for (int32 PinIndex = 1; PinIndex < FromPins.Num(); ++PinIndex) { SpawnedNode->AutowireNewNode(FromPins[PinIndex]); } return SpawnedNode; }
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* FDecoratorSchemaAction_NewNode::PerformAction(class UEdGraph* ParentGraph, TArray<UEdGraphPin*>& FromPins, const FVector2D Location, bool bSelectNewNode) { UEdGraphNode* ResultNode = NULL; if (FromPins.Num() > 0) { ResultNode = PerformAction(ParentGraph, FromPins[0], Location); // Try autowiring the rest of the pins for (int32 Index = 1; Index < FromPins.Num(); ++Index) { ResultNode->AutowireNewNode(FromPins[Index]); } } else { ResultNode = PerformAction(ParentGraph, NULL, Location, bSelectNewNode); } 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* FBlueprintActionMenuItem::PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, FVector2D const Location, bool bSelectNewNode/* = true*/) { using namespace FBlueprintMenuActionItemImpl; FScopedTransaction Transaction(LOCTEXT("AddNodeTransaction", "Add Node")); FVector2D ModifiedLocation = Location; if (FromPin != nullptr) { // for input pins, a new node will generally overlap the node being // dragged from... work out if we want add in some spacing from the connecting node if (FromPin->Direction == EGPD_Input) { UEdGraphNode* FromNode = FromPin->GetOwningNode(); check(FromNode != nullptr); float const FromNodeX = FromNode->NodePosX; static const float MinNodeDistance = 60.f; // min distance between spawned nodes (to keep them from overlapping) if (MinNodeDistance > FMath::Abs(FromNodeX - Location.X)) { ModifiedLocation.X = FromNodeX - MinNodeDistance; } } // modify before the call to AutowireNewNode() below FromPin->Modify(); } TSet<const UEdGraphNode*> NodesToFocus; int32 const PreSpawnNodeCount = ParentGraph->Nodes.Num(); UEdGraphNode* LastSpawnedNode = nullptr; auto BoundObjIt = Bindings.CreateConstIterator(); do { IBlueprintNodeBinder::FBindingSet BindingsSubset; for (; BoundObjIt && (Action->CanBindMultipleObjects() || (BindingsSubset.Num() == 0)); ++BoundObjIt) { if (BoundObjIt->IsValid()) { BindingsSubset.Add(BoundObjIt->Get()); } } bool bNewNode = false; LastSpawnedNode = InvokeAction(Action, ParentGraph, ModifiedLocation, BindingsSubset, /*out*/ bNewNode); // could already be an existent node, so we have to add here (can't // catch it as we go through all new nodes) NodesToFocus.Add(LastSpawnedNode); //NOTE: Between the new node is spawned and AutowireNewNode is called, the blueprint should not be compiled. if (FromPin != nullptr) { // make sure to auto-wire after we position the new node (in case // the auto-wire creates a conversion node to put between them) LastSpawnedNode->AutowireNewNode(FromPin); } if (bNewNode) { DirtyBlueprintFromNewNode(LastSpawnedNode); } // Increase the node location a safe distance so follow-up nodes are not stacked ModifiedLocation.Y += UEdGraphSchema_K2::EstimateNodeHeight(LastSpawnedNode); } while (BoundObjIt); if (bSelectNewNode) { int32 const PostSpawnCount = ParentGraph->Nodes.Num(); for (int32 NodeIndex = PreSpawnNodeCount; NodeIndex < PostSpawnCount; ++NodeIndex) { NodesToFocus.Add(ParentGraph->Nodes[NodeIndex]); } ParentGraph->SelectNodeSet(NodesToFocus, /*bFromUI =*/true); } // @TODO: select ALL spawned nodes return LastSpawnedNode; }