void UK2Node_Knot::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UEdGraphPin* MyInputPin = GetInputPin(); UEdGraphPin* MyOutputPin = GetOutputPin(); const int32 NumLinks = MyInputPin->LinkedTo.Num() + MyOutputPin->LinkedTo.Num(); if (Pin->LinkedTo.Num() > 0) { // Just made a connection, was it the first? if (NumLinks == 1) { UEdGraphPin* TypeSource = Pin->LinkedTo[0]; MyInputPin->PinType = TypeSource->PinType; MyOutputPin->PinType = TypeSource->PinType; } } else { // Just broke a connection, was it the last? if (NumLinks == 0) { // Revert to wildcard MyInputPin->BreakAllPinLinks(); MyInputPin->PinType.ResetToDefaults(); MyInputPin->PinType.PinCategory = K2Schema->PC_Wildcard; MyOutputPin->BreakAllPinLinks(); MyOutputPin->PinType.ResetToDefaults(); MyOutputPin->PinType.PinCategory = K2Schema->PC_Wildcard; } } }
void UK2Node_CommutativeAssociativeBinaryOperator::RemoveInputPin(UEdGraphPin* Pin) { if(CanRemovePin(Pin)) { FScopedTransaction Transaction( LOCTEXT("RemovePinTx", "RemovePin") ); Modify(); if (RemovePin(Pin)) { --NumAdditionalInputs; int32 NameIndex = 0; const UEdGraphPin* OutPin = FindOutPin(); const UEdGraphPin* SelfPin = FindSelfPin(); for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* LocalPin = Pins[PinIndex]; if(LocalPin && (LocalPin != OutPin) && (LocalPin != SelfPin)) { const FString PinName = GetNameForPin(NameIndex); if(PinName != LocalPin->PinName) { LocalPin->Modify(); LocalPin->PinName = PinName; } NameIndex++; } } FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } } }
void UEdGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const { #if WITH_EDITOR // Copy the old pin links TArray<class UEdGraphPin*> OldLinkedTo(TargetPin.LinkedTo); #endif TargetPin.BreakAllPinLinks(); #if WITH_EDITOR TSet<UEdGraphNode*> NodeList; // Notify this node TargetPin.GetOwningNode()->PinConnectionListChanged(&TargetPin); NodeList.Add(TargetPin.GetOwningNode()); // As well as all other nodes that were connected for (TArray<UEdGraphPin*>::TIterator PinIt(OldLinkedTo); PinIt; ++PinIt) { UEdGraphPin* OtherPin = *PinIt; UEdGraphNode* OtherNode = OtherPin->GetOwningNode(); OtherNode->PinConnectionListChanged(OtherPin); NodeList.Add(OtherNode); } if (bSendsNodeNotifcation) { // Send all nodes that received a new pin connection a notification for (auto It = NodeList.CreateConstIterator(); It; ++It) { UEdGraphNode* Node = (*It); Node->NodeConnectionListChanged(); } } #endif //#if WITH_EDITOR }
UEdGraphPin* FWeakGraphPinPtr::Get() { UEdGraphNode* Node = NodeObjectPtr.Get(); if(Node != NULL) { // If pin is no longer valid or has a different owner, attempt to fix up the reference UEdGraphPin* Pin = PinObjectPtr.Get(); if(Pin == NULL || Pin->GetOuter() != Node) { for(auto PinIter = Node->Pins.CreateConstIterator(); PinIter; ++PinIter) { UEdGraphPin* TestPin = *PinIter; if(TestPin->PinName.Equals(PinName)) { Pin = TestPin; PinObjectPtr = Pin; break; } } } return Pin; } return NULL; }
void USoundCueGraphNode_Base::InsertNewNode(UEdGraphPin* FromPin, UEdGraphPin* NewLinkPin, TSet<UEdGraphNode*>& OutNodeList) { const USoundCueGraphSchema* Schema = CastChecked<USoundCueGraphSchema>(GetSchema()); // The pin we are creating from already has a connection that needs to be broken. We want to "insert" the new node in between, so that the output of the new node is hooked up too UEdGraphPin* OldLinkedPin = FromPin->LinkedTo[0]; check(OldLinkedPin); FromPin->BreakAllPinLinks(); // Hook up the old linked pin to the first valid output pin on the new node for (int32 OutpinPinIdx=0; OutpinPinIdx<Pins.Num(); OutpinPinIdx++) { UEdGraphPin* OutputExecPin = Pins[OutpinPinIdx]; check(OutputExecPin); if (ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE == Schema->CanCreateConnection(OldLinkedPin, OutputExecPin).Response) { if (Schema->TryCreateConnection(OldLinkedPin, OutputExecPin)) { OutNodeList.Add(OldLinkedPin->GetOwningNode()); OutNodeList.Add(this); } break; } } if (Schema->TryCreateConnection(FromPin, NewLinkPin)) { OutNodeList.Add(FromPin->GetOwningNode()); OutNodeList.Add(this); } }
void UK2Node_FormatText::PinConnectionListChanged(UEdGraphPin* Pin) { const auto FormatPin = GetFormatPin(); Modify(); // Clear all pins. if(Pin == FormatPin && !FormatPin->DefaultTextValue.IsEmpty()) { PinNames.Empty(); GetSchema()->TrySetDefaultText(*FormatPin, FText::GetEmpty()); for(auto It = Pins.CreateConstIterator(); It; ++It) { UEdGraphPin* CheckPin = *It; if(CheckPin != FormatPin && CheckPin->Direction == EGPD_Input) { CheckPin->Modify(); CheckPin->BreakAllPinLinks(); Pins.Remove(CheckPin); --It; } } FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
UEdGraphPin* UEdGraphNode::CreatePin(EEdGraphPinDirection Dir, const FEdGraphPinType& InPinType, const FString& PinName, int32 Index /*= INDEX_NONE*/) { UEdGraphPin* NewPin = NewObject<UEdGraphPin>(this); NewPin->PinName = PinName; NewPin->Direction = Dir; NewPin->PinType = InPinType; NewPin->SetFlags(RF_Transactional); if (HasAnyFlags(RF_Transient)) { NewPin->SetFlags(RF_Transient); } Modify(false); if (Pins.IsValidIndex(Index)) { Pins.Insert(NewPin, Index); } else { Pins.Add(NewPin); } return NewPin; }
void UK2Node_SwitchEnum::AddPinToSwitchNode() { // first try to restore unconnected pin, since connected one is always visible for(auto PinIt = Pins.CreateIterator(); PinIt; ++PinIt) { UEdGraphPin* Pin = *PinIt; if(Pin && (0 == Pin->LinkedTo.Num()) && Pin->bAdvancedView) { Pin->Modify(); Pin->bAdvancedView = false; return; } } for(auto PinIt = Pins.CreateIterator(); PinIt; ++PinIt) { UEdGraphPin* Pin = *PinIt; if(Pin && Pin->bAdvancedView) { Pin->Modify(); Pin->bAdvancedView = false; return; } } }
FPinConnectionResponse UEdGraphSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsIntermediateMove) const { #if WITH_EDITOR ensureMsg(bIsIntermediateMove || !MoveToPin.GetOwningNode()->GetGraph()->HasAnyFlags(RF_Transient), TEXT("When moving to an Intermediate pin, use FKismetCompilerContext::MovePinLinksToIntermediate() instead of UEdGraphSchema::MovePinLinks()")); #endif // #if WITH_EDITOR FPinConnectionResponse FinalResponse = FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); // First copy the current set of links TArray<UEdGraphPin*> CurrentLinks = MoveFromPin.LinkedTo; // Then break all links at pin we are moving from MoveFromPin.BreakAllPinLinks(); // Try and make each new connection for (int32 i=0; i<CurrentLinks.Num(); i++) { UEdGraphPin* NewLink = CurrentLinks[i]; FPinConnectionResponse Response = CanCreateConnection(&MoveToPin, NewLink); if(Response.CanSafeConnect()) { MoveToPin.MakeLinkTo(NewLink); } else { FinalResponse = Response; } } // Move over the default values MoveToPin.DefaultValue = MoveFromPin.DefaultValue; MoveToPin.DefaultObject = MoveFromPin.DefaultObject; MoveToPin.DefaultTextValue = MoveFromPin.DefaultTextValue; return FinalResponse; }
void UK2Node_Select::PostReconstructNode() { bReconstructNode = false; const UEdGraphSchema_K2* Schema = Cast<UEdGraphSchema_K2>(GetSchema()); UEdGraphPin* ReturnPin = GetReturnValuePin(); PinConnectionListChanged(ReturnPin); const bool bFillTypeFromReturn = Schema && ReturnPin && (ReturnPin->PinType.PinCategory != Schema->PC_Wildcard); TArray<UEdGraphPin*> OptionPins; GetOptionPins(OptionPins); for (auto It = OptionPins.CreateConstIterator(); It; It++) { UEdGraphPin* Pin = *It; const bool bTypeShouldBeFilled = Schema && Pin && (Pin->PinType.PinCategory == Schema->PC_Wildcard); if (bTypeShouldBeFilled && bFillTypeFromReturn) { Pin->Modify(); Pin->PinType = ReturnPin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(Pin); } PinConnectionListChanged(*It); } //After ReconstructNode we must be sure, that no additional reconstruction is required bReconstructNode = false; }
void UK2Node_GetArrayItem::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { Super::NotifyPinConnectionListChanged(Pin); if (Pin != GetIndexPin() && Pin->ParentPin == nullptr) { UEdGraphPin* ArrayPin = Pins[0]; UEdGraphPin* ResultPin = Pins[2]; auto ClearWildcardType = [ArrayPin, ResultPin]() { ArrayPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; ArrayPin->PinType.PinSubCategory = TEXT(""); ArrayPin->PinType.PinSubCategoryObject = NULL; ResultPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; ResultPin->PinType.PinSubCategory = TEXT(""); ResultPin->PinType.PinSubCategoryObject = NULL; ResultPin->PinType.bIsReference = true; ArrayPin->BreakAllPinLinks(); ResultPin->BreakAllPinLinks(); }; const int32 NewLinkCount = Pin->LinkedTo.Num(); const bool bPinsHasLinks = (NewLinkCount > 0); if (ArrayPin == Pin) { if (bPinsHasLinks) { // if we had more than one input, we'd have to find the common base type ensure(NewLinkCount == 1); // the input array has authority, change output types, even if they are connected PropagatePinType(Pin->LinkedTo[0]->PinType); } // if the array pin was disconnected from everything, and... else if (ResultPin->LinkedTo.Num() == 0) { ClearWildcardType(); } } else if (ArrayPin->LinkedTo.Num() == 0) { // if we cleared the result pin's connections if (!bPinsHasLinks) { ClearWildcardType(); } // if this is the first connection to the result pin... else if (NewLinkCount == 1) { PropagatePinType(Pin->LinkedTo[0]->PinType); } // else, the result pin already had a connection and a type, leave // it alone, as it is what facilitated this connection as well } // else, leave this node alone, the array input is still connected and // it has authority over the wildcard types (the type set should already be good) } }
void UEdGraphSchema::TrySetDefaultText(UEdGraphPin& InPin, const FText& InNewDefaultText) const { if(InNewDefaultText.IsEmpty()) { InPin.DefaultTextValue = InNewDefaultText; } else { #if WITH_EDITOR if(InNewDefaultText.IsCultureInvariant()) { InPin.DefaultTextValue = InNewDefaultText; } else { InPin.DefaultTextValue = FText::ChangeKey(TEXT(""), InPin.GetOwningNode()->NodeGuid.ToString() + TEXT("_") + InPin.PinName, InNewDefaultText); } #endif } #if WITH_EDITOR UEdGraphNode* Node = InPin.GetOwningNode(); check(Node); Node->PinDefaultValueChanged(&InPin); #endif //#if WITH_EDITOR }
void UK2Node_VariableSetRef::CoerceTypeFromPin(const UEdGraphPin* Pin) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UEdGraphPin* TargetPin = GetTargetPin(); UEdGraphPin* ValuePin = GetValuePin(); if( Pin ) { check((Pin != TargetPin) || (Pin->PinType.bIsReference && !Pin->PinType.bIsArray)); TargetPin->PinType = Pin->PinType; TargetPin->PinType.bIsReference = true; ValuePin->PinType = Pin->PinType; ValuePin->PinType.bIsReference = false; } else { // Pin disconnected...revert to wildcard TargetPin->PinType.PinCategory = K2Schema->PC_Wildcard; TargetPin->PinType.PinSubCategory = TEXT(""); TargetPin->PinType.PinSubCategoryObject = NULL; TargetPin->BreakAllPinLinks(); ValuePin->PinType.PinCategory = K2Schema->PC_Wildcard; ValuePin->PinType.PinSubCategory = TEXT(""); ValuePin->PinType.PinSubCategoryObject = NULL; ValuePin->BreakAllPinLinks(); CachedNodeTitle.MarkDirty(); } }
FPinConnectionResponse UEdGraphSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsIntermediateCopy) const { #if WITH_EDITOR ensureMsg(bIsIntermediateCopy || !CopyToPin.GetOwningNode()->GetGraph()->HasAnyFlags(RF_Transient), TEXT("When copying to an Intermediate pin, use FKismetCompilerContext::CopyPinLinksToIntermediate() instead of UEdGraphSchema::CopyPinLinks()")); #endif // #if WITH_EDITOR FPinConnectionResponse FinalResponse = FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); for (int32 i=0; i<CopyFromPin.LinkedTo.Num(); i++) { UEdGraphPin* NewLink = CopyFromPin.LinkedTo[i]; FPinConnectionResponse Response = CanCreateConnection(&CopyToPin, NewLink); if (Response.CanSafeConnect()) { CopyToPin.MakeLinkTo(NewLink); } else { FinalResponse = Response; } } CopyToPin.DefaultValue = CopyFromPin.DefaultValue; CopyToPin.DefaultObject = CopyFromPin.DefaultObject; CopyToPin.DefaultTextValue = CopyFromPin.DefaultTextValue; return FinalResponse; }
bool SGraphPin::TryHandlePinConnection(SGraphPin& OtherSPin) { UEdGraphPin* PinA = GetPinObj(); UEdGraphPin* PinB = OtherSPin.GetPinObj(); UEdGraph* MyGraphObj = PinA->GetOwningNode()->GetGraph(); return MyGraphObj->GetSchema()->TryCreateConnection(PinA, PinB); }
void UMaterialGraphNode_Base::ReplaceNode(UMaterialGraphNode_Base* OldNode) { check(OldNode); check(OldNode != this); // Get Pins from node passed in TArray<UEdGraphPin*> OldInputPins; TArray<UEdGraphPin*> OldOutputPins; OldNode->GetInputPins(OldInputPins); OldNode->GetOutputPins(OldOutputPins); // Get our Input and Output pins TArray<UEdGraphPin*> NewInputPins; TArray<UEdGraphPin*> NewOutputPins; GetInputPins(NewInputPins); GetOutputPins(NewOutputPins); // Copy Inputs from old node for (int32 PinIndex = 0; PinIndex < OldInputPins.Num(); PinIndex++) { if (PinIndex < NewInputPins.Num()) { ModifyAndCopyPersistentPinData(*NewInputPins[PinIndex], *OldInputPins[PinIndex]); } } // Copy Outputs from old node for (int32 PinIndex = 0; PinIndex < OldOutputPins.Num(); PinIndex++) { // If we can't find an equivalent output in this node, just use the first // The user will have to fix up any issues from the mismatch int32 FoundPinIndex = 0; // Try to find an equivalent output in this node for (int32 NewPinIndex = 0; NewPinIndex < NewOutputPins.Num(); NewPinIndex++) { if (OldOutputPins[PinIndex]->PinType == NewOutputPins[NewPinIndex]->PinType) { FoundPinIndex = NewPinIndex; break; } } if (FoundPinIndex < NewOutputPins.Num()) { ModifyAndCopyPersistentPinData(*NewOutputPins[FoundPinIndex], *OldOutputPins[PinIndex]); } } // Break the original pin links for (int32 OldPinIndex = 0; OldPinIndex < OldNode->Pins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldNode->Pins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); } }
void UEdGraphPin::CopyPersistentDataFromOldPin(const UEdGraphPin& SourcePin) { // The name matches already, doesn't get copied here // The PinType, Direction, and bNotConnectable are properties generated from the schema // Only move the default value if it was modified; inherit the new default value otherwise if (SourcePin.DefaultValue != SourcePin.AutogeneratedDefaultValue || SourcePin.DefaultObject != NULL || SourcePin.DefaultTextValue.ToString() != SourcePin.AutogeneratedDefaultValue) { DefaultObject = SourcePin.DefaultObject; DefaultValue = SourcePin.DefaultValue; DefaultTextValue = SourcePin.DefaultTextValue; } // Copy the links for (int32 LinkIndex = 0; LinkIndex < SourcePin.LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* OtherPin = SourcePin.LinkedTo[LinkIndex]; check(NULL != OtherPin); Modify(); OtherPin->Modify(); LinkedTo.Add(OtherPin); // Unlike MakeLinkTo(), we attempt to ensure that the new pin (this) is inserted at the same position as the old pin (source) // in the OtherPin's LinkedTo array. This is necessary to ensure that the node's position in the execution order will remain // unchanged after nodes are reconstructed, because OtherPin may be connected to more than just this node. int32 Index = OtherPin->LinkedTo.Find(const_cast<UEdGraphPin*>(&SourcePin)); if(Index != INDEX_NONE) { OtherPin->LinkedTo.Insert(this, Index); } else { // Fallback to "normal" add, just in case the old pin doesn't exist in the other pin's LinkedTo array for some reason. OtherPin->LinkedTo.Add(this); } } // If the source pin is split, then split the new one, but don't split multiple times, typically splitting is done // by UK2Node::ReallocatePinsDuringReconstruction or FBlueprintEditor::OnSplitStructPin, but there are several code // paths into this, and split state should be persistent: if (SourcePin.SubPins.Num() > 0 && SubPins.Num() == 0) { GetSchema()->SplitPin(this); } #if WITH_EDITORONLY_DATA // Copy advanced visibility property, if it can be changed by user. // Otherwise we don't want to copy this, or we'd be ignoring new metadata that tries to hide old pins. UEdGraphNode* OuterNode = Cast<UEdGraphNode>(GetOuter()); if (OuterNode != nullptr && OuterNode->CanUserEditPinAdvancedViewFlag()) { bAdvancedView = SourcePin.bAdvancedView; } #endif // WITH_EDITORONLY_DATA }
// 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); } }
FReply FKismetVariableDragDropAction::DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) { UK2Node_Variable* TargetNode = Cast<UK2Node_Variable>(GetHoveredNode()); if (TargetNode && (VariableName != TargetNode->GetVarName())) { const FScopedTransaction Transaction( LOCTEXT("ReplacePinVariable", "Replace Pin Variable") ); UProperty* VariableProperty = GetVariableProperty(); if(CanVariableBeDropped(VariableProperty, *TargetNode->GetGraph())) { const FString OldVarName = TargetNode->GetVarNameString(); const UEdGraphSchema_K2* Schema = Cast<const UEdGraphSchema_K2>(TargetNode->GetSchema()); TArray<class UEdGraphPin*> BadLinks; GetLinksThatWillBreak(TargetNode,VariableProperty,BadLinks); // Change the variable name and context UBlueprint* DropOnBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(TargetNode->GetGraph()); UEdGraphPin* Pin = TargetNode->FindPin(OldVarName); DropOnBlueprint->Modify(); TargetNode->Modify(); if (Pin != NULL) { Pin->Modify(); } UEdGraphSchema_K2::ConfigureVarNode(TargetNode, VariableName, VariableSource.Get(), DropOnBlueprint); if ((Pin == NULL) || (Pin->LinkedTo.Num() == BadLinks.Num()) || (Schema == NULL)) { TargetNode->GetSchema()->ReconstructNode(*TargetNode); } else { FEdGraphPinType NewPinType; Schema->ConvertPropertyToPinType(VariableProperty,NewPinType); Pin->PinName = VariableName.ToString(); Pin->PinType = NewPinType; //break bad links for(TArray<class UEdGraphPin*>::TIterator OtherPinIt(BadLinks);OtherPinIt;) { Pin->BreakLinkTo(*OtherPinIt); } } return FReply::Handled(); } } return FReply::Unhandled(); }
void UK2Node::ReconstructNode() { Modify(); UBlueprint* Blueprint = GetBlueprint(); // Break any links to 'orphan' pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; TArray<class UEdGraphPin*> LinkedToCopy = Pin->LinkedTo; for (int32 LinkIdx = 0; LinkIdx < LinkedToCopy.Num(); LinkIdx++) { UEdGraphPin* OtherPin = LinkedToCopy[LinkIdx]; // If we are linked to a pin that its owner doesn't know about, break that link if ((OtherPin == NULL) || !OtherPin->GetOwningNodeUnchecked() || !OtherPin->GetOwningNode()->Pins.Contains(OtherPin)) { Pin->LinkedTo.Remove(OtherPin); } } } // Move the existing pins to a saved array TArray<UEdGraphPin*> OldPins(Pins); Pins.Empty(); // Recreate the new pins ReallocatePinsDuringReconstruction(OldPins); bool bDestroyOldPins = true; if (Pins.Num() == 0) { //keep old pins on callfunction so that graph doesn't get broken up just because function is missing if (IsA(UK2Node_CallFunction::StaticClass()) || IsA(UK2Node_MacroInstance::StaticClass())) { Pins = OldPins; bDestroyOldPins = false; } } else { RewireOldPinsToNewPins(OldPins, Pins); } if (bDestroyOldPins) { DestroyPinList(OldPins); } // Let subclasses do any additional work PostReconstructNode(); GetGraph()->NotifyGraphChanged(); }
UEdGraphNode* FEdGraphSchemaAction_K2AddCallOnActor::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode/* = true*/) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Snap the node placement location to the grid, ensures calculations later match up better FVector2D LocalLocation; LocalLocation.X = FMath::GridSnap( Location.X, SNAP_GRID ); LocalLocation.Y = FMath::GridSnap( Location.Y, SNAP_GRID ); // First use the base functionality to spawn the 'call function' node UEdGraphNode* CallNode = FEdGraphSchemaAction_K2NewNode::PerformAction(ParentGraph, FromPin, LocalLocation); const float FunctionNodeHeightUnsnapped = UEdGraphSchema_K2::EstimateNodeHeight( CallNode ); // this is the guesstimate of the function node's height, snapped to grid units const float FunctionNodeHeight = FMath::GridSnap( FunctionNodeHeightUnsnapped, SNAP_GRID ); // this is roughly the middle of the function node height const float FunctionNodeMidY = LocalLocation.Y + FunctionNodeHeight * 0.5f; // this is the offset up from the mid point at which we start placing nodes const float StartYOffset = (float((LevelActors.Num() > 0) ? LevelActors.Num()-1 : 0) * -NodeLiteralHeight) * 0.5f; // The Y location we start placing nodes from const float ReferencedNodesPlacementYLocation = FunctionNodeMidY + StartYOffset; // Now we need to create the actor literal to wire up for ( int32 ActorIndex = 0; ActorIndex < LevelActors.Num(); ActorIndex++ ) { AActor* LevelActor = LevelActors[ActorIndex]; if(LevelActor != NULL) { UK2Node_Literal* LiteralNode = NewObject<UK2Node_Literal>(ParentGraph); ParentGraph->AddNode(LiteralNode, false, bSelectNewNode); LiteralNode->SetFlags(RF_Transactional); LiteralNode->SetObjectRef(LevelActor); LiteralNode->AllocateDefaultPins(); LiteralNode->NodePosX = LocalLocation.X - FunctionNodeLiteralReferencesXOffset; // this is the current offset down from the Y start location to place the next node at float CurrentNodeOffset = NodeLiteralHeight * float(ActorIndex); LiteralNode->NodePosY = ReferencedNodesPlacementYLocation + CurrentNodeOffset; LiteralNode->SnapToGrid(SNAP_GRID); // Connect the literal out to the self of the call UEdGraphPin* LiteralOutput = LiteralNode->GetValuePin(); UEdGraphPin* CallSelfInput = CallNode->FindPin(K2Schema->PN_Self); if(LiteralOutput != NULL && CallSelfInput != NULL) { LiteralOutput->MakeLinkTo(CallSelfInput); } } } return CallNode; }
void UK2Node_SpawnActorFromClass::OnClassPinChanged() { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Remove all pins related to archetype variables TArray<UEdGraphPin*> OldPins = Pins; TArray<UEdGraphPin*> OldClassPins; for (int32 i = 0; i < OldPins.Num(); i++) { UEdGraphPin* OldPin = OldPins[i]; if (IsSpawnVarPin(OldPin)) { Pins.Remove(OldPin); OldClassPins.Add(OldPin); } } CachedNodeTitle.MarkDirty(); UClass* UseSpawnClass = GetClassToSpawn(); TArray<UEdGraphPin*> NewClassPins; if (UseSpawnClass != NULL) { CreatePinsForClass(UseSpawnClass, NewClassPins); } UEdGraphPin* ResultPin = GetResultPin(); // Cache all the pin connections to the ResultPin, we will attempt to recreate them TArray<UEdGraphPin*> ResultPinConnectionList = ResultPin->LinkedTo; // Because the archetype has changed, we break the output link as the output pin type will change ResultPin->BreakAllPinLinks(); // Recreate any pin links to the Result pin that are still valid for (UEdGraphPin* Connections : ResultPinConnectionList) { K2Schema->TryCreateConnection(ResultPin, Connections); } K2Schema->ConstructBasicPinTooltip(*ResultPin, LOCTEXT("ResultPinDescription", "The spawned Actor"), ResultPin->PinToolTip); // Rewire the old pins to the new pins so connections are maintained if possible RewireOldPinsToNewPins(OldClassPins, NewClassPins); // Destroy the old pins DestroyPinList(OldClassPins); // Refresh the UI for the graph so the pin changes show up UEdGraph* Graph = GetGraph(); Graph->NotifyGraphChanged(); // Mark dirty FBlueprintEditorUtils::MarkBlueprintAsModified(GetBlueprint()); }
void FSoundCueEditor::DeleteInput() { UEdGraphPin* SelectedPin = SoundCueGraphEditor->GetGraphPinForMenu(); USoundCueGraphNode* SelectedNode = Cast<USoundCueGraphNode>(SelectedPin->GetOwningNode()); if (SelectedNode && SelectedNode == SelectedPin->GetOwningNode()) { SelectedNode->RemoveInputPin(SelectedPin); } }
void FScriptExecutionTunnelExit::NavigateToExitSite(const uint32 TracePath) const { UEdGraphPin* Pin = ObservedPin.Get(); if (const FTunnelExitInstanceData* SearchResult = InstanceExitSiteInfo.Find(TracePath)) { Pin = SearchResult->InstancePin.Get(); } if (Pin) { FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(Pin->GetOwningNode()); } }
void UK2Node_AddComponent::AllocatePinsForExposedVariables() { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); const UActorComponent* TemplateComponent = GetTemplateFromNode(); const UClass* ComponentClass = TemplateComponent ? TemplateComponent->GetClass() : nullptr; if (ComponentClass != nullptr) { const UObject* ClassDefaultObject = ComponentClass ? ComponentClass->ClassDefaultObject : nullptr; for (TFieldIterator<UProperty> PropertyIt(ComponentClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) { UProperty* Property = *PropertyIt; const bool bNotDelegate = !Property->IsA(UMulticastDelegateProperty::StaticClass()); const bool bIsExposedToSpawn = UEdGraphSchema_K2::IsPropertyExposedOnSpawn(Property); const bool bIsVisible = Property->HasAllPropertyFlags(CPF_BlueprintVisible); const bool bNotParam = !Property->HasAllPropertyFlags(CPF_Parm); if(bNotDelegate && bIsExposedToSpawn && bIsVisible && bNotParam) { FEdGraphPinType PinType; K2Schema->ConvertPropertyToPinType(Property, /*out*/ PinType); const bool bIsUnique = (NULL == FindPin(Property->GetName())); if (K2Schema->FindSetVariableByNameFunction(PinType) && bIsUnique) { UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); Pin->PinType = PinType; bHasExposedVariable = true; if ((ClassDefaultObject != nullptr) && K2Schema->PinDefaultValueIsEditable(*Pin)) { FString DefaultValueAsString; const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast<const uint8*>(ClassDefaultObject), DefaultValueAsString); check(bDefaultValueSet); K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString); } // Copy tooltip from the property. K2Schema->ConstructBasicPinTooltip(*Pin, Property->GetToolTipText(), Pin->PinToolTip); } } } } // Hide transform and attachment pins if it is not a scene component const bool bHideTransformPins = (ComponentClass != nullptr) ? !ComponentClass->IsChildOf(USceneComponent::StaticClass()) : false; UEdGraphPin* ManualAttachmentPin = GetManualAttachmentPin(); ManualAttachmentPin->SafeSetHidden(bHideTransformPins); UEdGraphPin* TransformPin = GetRelativeTransformPin(); TransformPin->SafeSetHidden(bHideTransformPins); }
UEdGraphPin* UEdGraphNode::AllocatePinFromPool(UEdGraphNode* OuterNode) { if (PooledPins.Num() > 0) { UEdGraphPin* Result = PooledPins.Pop(); Result->Rename(NULL, OuterNode); return Result; } else { UEdGraphPin* Result = NewObject<UEdGraphPin>(OuterNode); return Result; } }
ERenamePinResult UK2Node::RenameUserDefinedPin(const FString& OldName, const FString& NewName, bool bTest) { UEdGraphPin* Pin = NULL; for (int32 PinIdx=0; PinIdx<Pins.Num(); PinIdx++) { if (OldName == Pins[PinIdx]->PinName) { Pin = Pins[PinIdx]; } else if(NewName == Pins[PinIdx]->PinName) { return ERenamePinResult::ERenamePinResult_NameCollision; } } if(!Pin) { return ERenamePinResult::ERenamePinResult_NoSuchPin; } if(!bTest) { Pin->Modify(); Pin->PinName = NewName; if(!Pin->DefaultTextValue.IsEmpty()) { Pin->GetSchema()->TrySetDefaultText(*Pin, Pin->DefaultTextValue); } if (Pin->SubPins.Num() > 0) { TArray<UEdGraphPin*> PinsToUpdate = Pin->SubPins; while (PinsToUpdate.Num() > 0) { UEdGraphPin* PinToRename = PinsToUpdate.Pop(/*bAllowShrinking=*/ false); if (PinToRename->SubPins.Num() > 0) { PinsToUpdate.Append(PinToRename->SubPins); } PinToRename->Modify(); PinToRename->PinName = NewName + PinToRename->PinName.RightChop(OldName.Len()); PinToRename->PinFriendlyName = FText::FromString(NewName + PinToRename->PinFriendlyName.ToString().RightChop(OldName.Len())); } } } return ERenamePinResult::ERenamePinResult_Success; }
void UMaterialGraphNode_Base::ModifyAndCopyPersistentPinData(UEdGraphPin& TargetPin, const UEdGraphPin& SourcePin) const { if (SourcePin.LinkedTo.Num() > 0) { TargetPin.Modify(); for (int32 LinkIndex = 0; LinkIndex < SourcePin.LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* OtherPin = SourcePin.LinkedTo[LinkIndex]; OtherPin->Modify(); } } TargetPin.CopyPersistentDataFromOldPin(SourcePin); }
/** Find Pin in array that matches pin */ static class UEdGraphPin* FindOtherLink(TArray<class UEdGraphPin*>& Links2, int32 OriginalIndex, class UEdGraphPin* PinToFind) { //sometimes the order of the pins is different between revisions, although the pins themselves are unchanged, so we have to look at all of them UEdGraphNode* Node1 = PinToFind->GetOwningNode(); for(auto It(Links2.CreateIterator());It;++It) { UEdGraphPin* Other = *It; UEdGraphNode* Node2 = Other->GetOwningNode(); if(IsNodeMatch(Node1, Node2)) { return Other; } } return Links2[OriginalIndex]; }
const FSlateBrush* SGraphPin::GetPinStatusIcon() const { UEdGraphPin* WatchedPin = ((GraphPinObj->Direction == EGPD_Input) && (GraphPinObj->LinkedTo.Num() > 0)) ? GraphPinObj->LinkedTo[0] : GraphPinObj; UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(WatchedPin->GetOwningNode()); if (FKismetDebugUtilities::IsPinBeingWatched(Blueprint, WatchedPin) ) { return FEditorStyle::GetBrush( TEXT("Graph.WatchedPinIcon_Pinned") ); } else { return NULL; } }