FReply SGraphPin::OnPinMouseDown( const FGeometry& SenderGeometry, const FPointerEvent& MouseEvent ) { bIsMovingLinks = false; if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { if (!GraphPinObj->bNotConnectable && IsEditable.Get()) { if (MouseEvent.IsAltDown()) { // Alt-Left clicking will break all existing connections to a pin const UEdGraphSchema* Schema = GraphPinObj->GetSchema(); Schema->BreakPinLinks(*GraphPinObj, true); return FReply::Handled(); } auto OwnerNodePinned = OwnerNodePtr.Pin(); if (MouseEvent.IsControlDown() && (GraphPinObj->LinkedTo.Num() > 0)) { // Get a reference to the owning panel widget check(OwnerNodePinned.IsValid()); TSharedPtr<SGraphPanel> OwnerPanelPtr = OwnerNodePinned->GetOwnerPanel(); check(OwnerPanelPtr.IsValid()); // Obtain the set of all pins within the panel TSet<TSharedRef<SWidget> > AllPins; OwnerPanelPtr->GetAllPins(AllPins); // Construct a UEdGraphPin->SGraphPin mapping for the full pin set TMap< UEdGraphPin*, TSharedRef<SGraphPin> > PinToPinWidgetMap; for( TSet< TSharedRef<SWidget> >::TIterator ConnectorIt(AllPins); ConnectorIt; ++ConnectorIt ) { const TSharedRef<SWidget>& SomePinWidget = *ConnectorIt; const SGraphPin& PinWidget = static_cast<const SGraphPin&>(SomePinWidget.Get()); PinToPinWidgetMap.Add(PinWidget.GetPinObj(), StaticCastSharedRef<SGraphPin>(SomePinWidget)); } // Define a local struct to temporarily store lookup information for pins that we are currently linked to struct LinkedToPinInfo { // Pin name string FString PinName; // A weak reference to the node object that owns the pin TWeakObjectPtr<UEdGraphNode> OwnerNodePtr; }; // Build a lookup table containing information about the set of pins that we're currently linked to TArray<LinkedToPinInfo> LinkedToPinInfoArray; for( TArray<UEdGraphPin*>::TIterator LinkArrayIter(GetPinObj()->LinkedTo); LinkArrayIter; ++LinkArrayIter ) { if (auto PinWidget = PinToPinWidgetMap.Find(*LinkArrayIter)) { check((*PinWidget)->OwnerNodePtr.IsValid()); LinkedToPinInfo PinInfo; PinInfo.PinName = (*PinWidget)->GetPinObj()->PinName; PinInfo.OwnerNodePtr = (*PinWidget)->OwnerNodePtr.Pin()->GetNodeObj(); LinkedToPinInfoArray.Add(PinInfo); } } // Control-Left clicking will break all existing connections to a pin // Note that for some nodes, this can cause reconstruction. In that case, pins we had previously linked to may now be destroyed. const UEdGraphSchema* Schema = GraphPinObj->GetSchema(); Schema->BreakPinLinks(*GraphPinObj, true); // Check to see if the panel has been invalidated by a graph change notification if (!OwnerPanelPtr->Contains(OwnerNodePinned->GetNodeObj())) { // Force the panel to update. This will cause node & pin widgets to be reinstanced to match any reconstructed node/pin object references. OwnerPanelPtr->Update(); // Obtain the full set of pins again after the update AllPins.Empty(AllPins.Num()); OwnerPanelPtr->GetAllPins(AllPins); // Rebuild the UEdGraphPin->SGraphPin mapping for the full pin set PinToPinWidgetMap.Empty(PinToPinWidgetMap.Num()); for( TSet< TSharedRef<SWidget> >::TIterator ConnectorIt(AllPins); ConnectorIt; ++ConnectorIt ) { const TSharedRef<SWidget>& SomePinWidget = *ConnectorIt; const SGraphPin& PinWidget = static_cast<const SGraphPin&>(SomePinWidget.Get()); PinToPinWidgetMap.Add(PinWidget.GetPinObj(), StaticCastSharedRef<SGraphPin>(SomePinWidget)); } } // Now iterate over our lookup table to find the instances of pin widgets that we had previously linked to TArray<TSharedRef<SGraphPin>> PinArray; for(auto LinkedToPinInfoIter = LinkedToPinInfoArray.CreateConstIterator(); LinkedToPinInfoIter; ++LinkedToPinInfoIter) { LinkedToPinInfo PinInfo = *LinkedToPinInfoIter; UEdGraphNode* OwnerNodeObj = PinInfo.OwnerNodePtr.Get(); if(OwnerNodeObj != NULL) { for(auto PinIter = PinInfo.OwnerNodePtr.Get()->Pins.CreateConstIterator(); PinIter; ++PinIter) { UEdGraphPin* Pin = *PinIter; if(Pin->PinName == PinInfo.PinName) { if (auto pWidget = PinToPinWidgetMap.Find(Pin)) { PinArray.Add(*pWidget); } } } } } if(PinArray.Num() > 0) { bIsMovingLinks = true; return FReply::Handled().BeginDragDrop(SpawnPinDragEvent(OwnerPanelPtr.ToSharedRef(), PinArray, /*bIsShiftOperation=*/ false)); } else { // Shouldn't get here, but just in case we lose our previous links somehow after breaking them, we'll just skip the drag. return FReply::Handled(); } } // Start a drag-drop on the pin if (ensure(OwnerNodePinned.IsValid())) { TArray<TSharedRef<SGraphPin>> PinArray; PinArray.Add(SharedThis(this)); return FReply::Handled().BeginDragDrop(SpawnPinDragEvent(OwnerNodePinned->GetOwnerPanel().ToSharedRef(), PinArray, MouseEvent.IsShiftDown())); } else { return FReply::Unhandled(); } } else { // It's not connectable, but we don't want anything above us to process this left click. return FReply::Handled(); } } else { return FReply::Unhandled(); } }