UEdGraphPin* UK2Node_Tunnel::CreatePinFromUserDefinition(const TSharedPtr<FUserPinInfo> NewPinInfo) { // Create the new pin EEdGraphPinDirection Direction = bCanHaveInputs ? EGPD_Input : EGPD_Output; // Let the user pick the pin direction if legal if ( (bCanHaveInputs && NewPinInfo->DesiredPinDirection == EGPD_Input) || (bCanHaveOutputs && NewPinInfo->DesiredPinDirection == EGPD_Output) ) { Direction = NewPinInfo->DesiredPinDirection; } UEdGraphPin* Result = CreatePin(Direction, NewPinInfo->PinType, NewPinInfo->PinName); Result->DefaultValue = Result->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue; // Make sure it mirrors onto the associated node UEdGraphNode* TargetNode = ((InputSinkNode != NULL) ? InputSinkNode : OutputSourceNode); if (Cast<UK2Node_Composite>(TargetNode) != NULL || Cast<UK2Node_MacroInstance>(TargetNode) != NULL) { UEdGraphPin* HasPinAlready = TargetNode->FindPin(Result->PinName); if (HasPinAlready == NULL) { TargetNode->CreatePin(UEdGraphPin::GetComplementaryDirection(Direction), NewPinInfo->PinType, NewPinInfo->PinName); } } else if (UK2Node_Tunnel* TunnelNode = Cast<UK2Node_Tunnel>(TargetNode)) { TunnelNode->CreateUserDefinedPin(NewPinInfo->PinName, NewPinInfo->PinType, (Direction == EGPD_Input)? EGPD_Output : EGPD_Input); } //@TODO: Automatically update loaded macro instances when this node is changed too return Result; }
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; }
UEdGraphNode* FEdGraphSchemaAction_K2AddCallOnVariable::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 FVector2D TempLocation = LocalLocation; UEdGraphNode* CallNode = FEdGraphSchemaAction_K2NewNode::PerformAction(ParentGraph, FromPin, TempLocation, bSelectNewNode); // this is the guesstimate of the function node's height, snapped to grid units const float FunctionNodeHeight = FMath::GridSnap( TempLocation.Y - LocalLocation.Y, 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 = -NodeLiteralHeight * 0.5f; // The Y location we start placing nodes from const float ReferencedNodesPlacementYLocation = FunctionNodeMidY + StartYOffset; // Now we need to create the variable literal to wire up if(VariableName != NAME_None) { UK2Node_VariableGet* GetVarNode = NewObject<UK2Node_VariableGet>(ParentGraph); ParentGraph->AddNode(GetVarNode, false, bSelectNewNode); GetVarNode->SetFlags(RF_Transactional); GetVarNode->VariableReference.SetSelfMember(VariableName); GetVarNode->AllocateDefaultPins(); GetVarNode->NodePosX = LocalLocation.X - FunctionNodeLiteralReferencesXOffset; GetVarNode->NodePosY = ReferencedNodesPlacementYLocation; GetVarNode->SnapToGrid(SNAP_GRID); // Connect the literal out to the self of the call UEdGraphPin* LiteralOutput = GetVarNode->GetValuePin(); UEdGraphPin* CallSelfInput = CallNode->FindPin(K2Schema->PN_Self); if(LiteralOutput != NULL && CallSelfInput != NULL) { LiteralOutput->MakeLinkTo(CallSelfInput); } } return CallNode; }
TSharedPtr<SGraphPin> SGraphPanel::FGraphPinHandle::FindInGraphPanel(const SGraphPanel& InPanel) const { // First off, find the node TSharedPtr<SGraphNode> GraphNode = InPanel.GetNodeWidgetFromGuid(NodeGuid); if (GraphNode.IsValid()) { UEdGraphNode* Node = GraphNode->GetNodeObj(); UEdGraphPin* Pin = Node->FindPin(PinName); if (Pin) { return GraphNode->FindWidgetForPin(Pin); } } return TSharedPtr<SGraphPin>(); }
static bool CreateMap(UEdGraphNode& KeyNode, UEdGraphNode& ValueNode, EEdGraphPinDirection KeyPinDirection, UEdGraphSchema_K2* Schema, TMap<UEdGraphPin*, UEdGraphPin*>& OutMap) { check(Schema); for (auto InnerInputPin : KeyNode.Pins) { if (!InnerInputPin || InnerInputPin->Direction != KeyPinDirection) { return false; } auto OuterInputPin = ValueNode.FindPin(InnerInputPin->PinName); if (!OuterInputPin || !Schema->ArePinsCompatible(InnerInputPin, OuterInputPin, nullptr, false)) { return false; } OutMap.Add(InnerInputPin, OuterInputPin); } return true; }
void UK2Node::AutowireNewNode(UEdGraphPin* FromPin) { const UEdGraphSchema_K2* K2Schema = CastChecked<UEdGraphSchema_K2>(GetSchema()); // Do some auto-connection if (FromPin != NULL) { TSet<UEdGraphNode*> NodeList; // sometimes we don't always find an ideal connection, but we want to exhaust // all our options first... this stores a secondary less-ideal pin to connect to, if nothing better was found UEdGraphPin* BackupConnection = NULL; // If not dragging an exec pin, auto-connect from dragged pin to first compatible pin on the new node for (int32 i=0; i<Pins.Num(); i++) { UEdGraphPin* Pin = Pins[i]; check(Pin); ECanCreateConnectionResponse ConnectResponse = K2Schema->CanCreateConnection(FromPin, Pin).Response; if (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE) { if (K2Schema->TryCreateConnection(FromPin, Pin)) { NodeList.Add(FromPin->GetOwningNode()); NodeList.Add(this); } // null out the backup connection (so we don't attempt to make it // once we exit the loop... we successfully made this connection!) BackupConnection = NULL; break; } else if((FromPin->PinType.PinCategory == K2Schema->PC_Exec) && (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_A)) { InsertNewNode(FromPin, Pin, NodeList); // null out the backup connection (so we don't attempt to make it // once we exit the loop... we successfully made this connection!) BackupConnection = NULL; break; } else if ((BackupConnection == NULL) && (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE)) { // save this off, in-case we don't make any connection at all BackupConnection = Pin; } } // if we didn't find an ideal connection, then lets connect this pin to // the BackupConnection (something, like a connection that requires a conversion node, etc.) if ((BackupConnection != NULL) && K2Schema->TryCreateConnection(FromPin, BackupConnection)) { NodeList.Add(FromPin->GetOwningNode()); NodeList.Add(this); } // If we were not dragging an exec pin, but it was an output pin, try and connect the Then and Execute pins if ((FromPin->PinType.PinCategory != K2Schema->PC_Exec && FromPin->Direction == EGPD_Output)) { UEdGraphNode* FromPinNode = FromPin->GetOwningNode(); UEdGraphPin* FromThenPin = FromPinNode->FindPin(K2Schema->PN_Then); UEdGraphPin* ToExecutePin = FindPin(K2Schema->PN_Execute); if ((FromThenPin != NULL) && (FromThenPin->LinkedTo.Num() == 0) && (ToExecutePin != NULL) && K2Schema->ArePinsCompatible(FromThenPin, ToExecutePin, NULL)) { if (K2Schema->TryCreateConnection(FromThenPin, ToExecutePin)) { NodeList.Add(FromPinNode); NodeList.Add(this); } } } // Send all nodes that received a new pin connection a notification for (auto It = NodeList.CreateConstIterator(); It; ++It) { UEdGraphNode* Node = (*It); Node->NodeConnectionListChanged(); } } }