2014-12-07 19:09:38 -05:00
|
|
|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "GraphEditorCommon.h"
|
|
|
|
|
#include "Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h"
|
|
|
|
|
#include "Editor/UnrealEd/Public/Kismet2/KismetDebugUtilities.h"
|
|
|
|
|
#include "Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h"
|
|
|
|
|
#include "BlueprintUtilities.h"
|
|
|
|
|
#include "SLevelOfDetailBranchNode.h"
|
|
|
|
|
#include "ScopedTransaction.h"
|
|
|
|
|
|
2014-05-15 17:34:14 -04:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
|
// FKnotNetCollector
|
|
|
|
|
|
|
|
|
|
struct FKnotNetCollector
|
|
|
|
|
{
|
|
|
|
|
TSet<UEdGraphNode*> VisitedNodes;
|
|
|
|
|
TSet<UEdGraphPin*> VisitedPins;
|
|
|
|
|
|
|
|
|
|
FKnotNetCollector(UEdGraphPin* StartingPin)
|
|
|
|
|
{
|
|
|
|
|
TraversePin(StartingPin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TraversePin(UEdGraphPin* Pin)
|
|
|
|
|
{
|
2014-09-03 09:51:48 -04:00
|
|
|
if (UK2Node_Knot* Knot = Cast<UK2Node_Knot>(Pin->GetOwningNodeUnchecked()))
|
2014-05-15 17:34:14 -04:00
|
|
|
{
|
|
|
|
|
TraverseNodes(Knot);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
VisitedPins.Add(Pin);
|
|
|
|
|
|
|
|
|
|
for (UEdGraphPin* OtherPin : Pin->LinkedTo)
|
|
|
|
|
{
|
2014-09-03 09:51:48 -04:00
|
|
|
UEdGraphNode* OtherNode = OtherPin->GetOwningNodeUnchecked();
|
|
|
|
|
if (OtherNode && OtherNode->IsA(UK2Node_Knot::StaticClass()))
|
2014-05-15 17:34:14 -04:00
|
|
|
{
|
|
|
|
|
TraverseNodes(OtherNode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TraverseNodes(UEdGraphNode* Node)
|
|
|
|
|
{
|
|
|
|
|
if (VisitedNodes.Contains(Node))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
VisitedNodes.Add(Node);
|
|
|
|
|
|
|
|
|
|
for (UEdGraphPin* MyPin : Node->Pins)
|
|
|
|
|
{
|
|
|
|
|
VisitedPins.Add(MyPin);
|
|
|
|
|
|
|
|
|
|
for (UEdGraphPin* OtherPin : MyPin->LinkedTo)
|
|
|
|
|
{
|
2014-09-03 09:51:48 -04:00
|
|
|
UEdGraphNode* OtherNode = OtherPin->GetOwningNodeUnchecked();
|
|
|
|
|
if (OtherNode && OtherNode->IsA(UK2Node_Knot::StaticClass()))
|
2014-05-15 17:34:14 -04:00
|
|
|
{
|
|
|
|
|
TraverseNodes(OtherNode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
|
// SGraphPin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SGraphPin::SGraphPin()
|
2015-03-18 20:17:21 -04:00
|
|
|
: GraphPinObj(nullptr)
|
|
|
|
|
, bShowLabel(true)
|
2014-03-14 14:13:41 -04:00
|
|
|
, bIsMovingLinks(false)
|
|
|
|
|
, PinColorModifier(FLinearColor::White)
|
2015-04-21 14:13:02 -04:00
|
|
|
, CachedNodeOffset(FVector2D::ZeroVector)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
IsEditable = true;
|
|
|
|
|
|
|
|
|
|
// Make these names const so they're not created for every pin
|
|
|
|
|
|
|
|
|
|
/** Original Pin Styles */
|
|
|
|
|
static const FName NAME_Pin_ConnectedHovered("Graph.Pin.ConnectedHovered");
|
|
|
|
|
static const FName NAME_Pin_Connected("Graph.Pin.Connected");
|
|
|
|
|
static const FName NAME_Pin_DisconnectedHovered("Graph.Pin.DisconnectedHovered");
|
|
|
|
|
static const FName NAME_Pin_Disconnected("Graph.Pin.Disconnected");
|
|
|
|
|
|
|
|
|
|
/** Variant A Pin Styles */
|
|
|
|
|
static const FName NAME_Pin_ConnectedHovered_VarA("Graph.Pin.ConnectedHovered_VarA");
|
|
|
|
|
static const FName NAME_Pin_Connected_VarA("Graph.Pin.Connected_VarA");
|
|
|
|
|
static const FName NAME_Pin_DisconnectedHovered_VarA("Graph.Pin.DisconnectedHovered_VarA");
|
|
|
|
|
static const FName NAME_Pin_Disconnected_VarA("Graph.Pin.Disconnected_VarA");
|
|
|
|
|
|
|
|
|
|
static const FName NAME_ArrayPin_ConnectedHovered("Graph.ArrayPin.ConnectedHovered");
|
|
|
|
|
static const FName NAME_ArrayPin_Connected("Graph.ArrayPin.Connected");
|
|
|
|
|
static const FName NAME_ArrayPin_DisconnectedHovered("Graph.ArrayPin.DisconnectedHovered");
|
|
|
|
|
static const FName NAME_ArrayPin_Disconnected("Graph.ArrayPin.Disconnected");
|
|
|
|
|
|
|
|
|
|
static const FName NAME_RefPin_ConnectedHovered("Graph.RefPin.ConnectedHovered");
|
|
|
|
|
static const FName NAME_RefPin_Connected("Graph.RefPin.Connected");
|
|
|
|
|
static const FName NAME_RefPin_DisconnectedHovered("Graph.RefPin.DisconnectedHovered");
|
|
|
|
|
static const FName NAME_RefPin_Disconnected("Graph.RefPin.Disconnected");
|
|
|
|
|
|
|
|
|
|
static const FName NAME_DelegatePin_ConnectedHovered("Graph.DelegatePin.ConnectedHovered");
|
|
|
|
|
static const FName NAME_DelegatePin_Connected("Graph.DelegatePin.Connected");
|
|
|
|
|
static const FName NAME_DelegatePin_DisconnectedHovered("Graph.DelegatePin.DisconnectedHovered");
|
|
|
|
|
static const FName NAME_DelegatePin_Disconnected("Graph.DelegatePin.Disconnected");
|
|
|
|
|
|
|
|
|
|
static const FName NAME_Pin_Background("Graph.Pin.Background");
|
|
|
|
|
static const FName NAME_Pin_BackgroundHovered("Graph.Pin.BackgroundHovered");
|
|
|
|
|
|
2014-05-20 19:00:53 -04:00
|
|
|
const EBlueprintPinStyleType StyleType = GetDefault<UGraphEditorSettings>()->DataPinStyle;
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
switch(StyleType)
|
|
|
|
|
{
|
|
|
|
|
case BPST_VariantA:
|
|
|
|
|
CachedImg_Pin_ConnectedHovered = FEditorStyle::GetBrush( NAME_Pin_ConnectedHovered_VarA );
|
|
|
|
|
CachedImg_Pin_Connected = FEditorStyle::GetBrush( NAME_Pin_Connected_VarA );
|
|
|
|
|
CachedImg_Pin_DisconnectedHovered = FEditorStyle::GetBrush( NAME_Pin_DisconnectedHovered_VarA );
|
|
|
|
|
CachedImg_Pin_Disconnected = FEditorStyle::GetBrush( NAME_Pin_Disconnected_VarA );
|
|
|
|
|
break;
|
|
|
|
|
case BPST_Original:
|
|
|
|
|
default:
|
|
|
|
|
CachedImg_Pin_ConnectedHovered = FEditorStyle::GetBrush( NAME_Pin_ConnectedHovered );
|
|
|
|
|
CachedImg_Pin_Connected = FEditorStyle::GetBrush( NAME_Pin_Connected );
|
|
|
|
|
CachedImg_Pin_DisconnectedHovered = FEditorStyle::GetBrush( NAME_Pin_DisconnectedHovered );
|
|
|
|
|
CachedImg_Pin_Disconnected = FEditorStyle::GetBrush( NAME_Pin_Disconnected );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CachedImg_RefPin_ConnectedHovered = FEditorStyle::GetBrush( NAME_RefPin_ConnectedHovered );
|
|
|
|
|
CachedImg_RefPin_Connected = FEditorStyle::GetBrush( NAME_RefPin_Connected );
|
|
|
|
|
CachedImg_RefPin_DisconnectedHovered = FEditorStyle::GetBrush( NAME_RefPin_DisconnectedHovered );
|
|
|
|
|
CachedImg_RefPin_Disconnected = FEditorStyle::GetBrush( NAME_RefPin_Disconnected );
|
|
|
|
|
|
|
|
|
|
CachedImg_ArrayPin_ConnectedHovered = FEditorStyle::GetBrush( NAME_ArrayPin_ConnectedHovered );
|
|
|
|
|
CachedImg_ArrayPin_Connected = FEditorStyle::GetBrush( NAME_ArrayPin_Connected );
|
|
|
|
|
CachedImg_ArrayPin_DisconnectedHovered = FEditorStyle::GetBrush( NAME_ArrayPin_DisconnectedHovered );
|
|
|
|
|
CachedImg_ArrayPin_Disconnected = FEditorStyle::GetBrush( NAME_ArrayPin_Disconnected );
|
|
|
|
|
|
|
|
|
|
CachedImg_DelegatePin_ConnectedHovered = FEditorStyle::GetBrush( NAME_DelegatePin_ConnectedHovered );
|
|
|
|
|
CachedImg_DelegatePin_Connected = FEditorStyle::GetBrush( NAME_DelegatePin_Connected );
|
|
|
|
|
CachedImg_DelegatePin_DisconnectedHovered = FEditorStyle::GetBrush( NAME_DelegatePin_DisconnectedHovered );
|
|
|
|
|
CachedImg_DelegatePin_Disconnected = FEditorStyle::GetBrush( NAME_DelegatePin_Disconnected );
|
|
|
|
|
|
|
|
|
|
CachedImg_Pin_Background = FEditorStyle::GetBrush( NAME_Pin_Background );
|
|
|
|
|
CachedImg_Pin_BackgroundHovered = FEditorStyle::GetBrush( NAME_Pin_BackgroundHovered );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin)
|
|
|
|
|
{
|
2015-02-17 11:23:23 -05:00
|
|
|
bUsePinColorForText = InArgs._UsePinColorForText;
|
2015-03-18 22:45:35 -04:00
|
|
|
this->SetCursor(EMouseCursor::Default);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
Visibility = TAttribute<EVisibility>(this, &SGraphPin::GetPinVisiblity);
|
|
|
|
|
|
|
|
|
|
GraphPinObj = InPin;
|
|
|
|
|
check(GraphPinObj != NULL);
|
|
|
|
|
|
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
2015-05-01 19:31:19 -04:00
|
|
|
checkf(
|
|
|
|
|
Schema,
|
|
|
|
|
TEXT("Missing schema for pin: %s with outer: %s of type %s"),
|
|
|
|
|
*(GraphPinObj->GetName()),
|
|
|
|
|
GraphPinObj->GetOuter() ? *(GraphPinObj->GetOuter()->GetName()) : TEXT("NULL OUTER"),
|
|
|
|
|
GraphPinObj->GetOuter() ? *(GraphPinObj->GetOuter()->GetClass()->GetName()) : TEXT("NULL OUTER")
|
|
|
|
|
);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
const bool bCanConnectToPin = !GraphPinObj->bNotConnectable;
|
|
|
|
|
const bool bIsInput = (GetDirection() == EGPD_Input);
|
|
|
|
|
|
|
|
|
|
// Create the pin icon widget
|
2015-03-18 22:45:35 -04:00
|
|
|
TSharedRef<SWidget> ActualPinWidget =
|
2014-03-14 14:13:41 -04:00
|
|
|
SAssignNew(PinImage, SImage)
|
2015-03-18 22:45:35 -04:00
|
|
|
.Image(this, &SGraphPin::GetPinIcon)
|
|
|
|
|
.IsEnabled(bCanConnectToPin)
|
2014-03-14 14:13:41 -04:00
|
|
|
.ColorAndOpacity(this, &SGraphPin::GetPinColor)
|
2015-03-18 22:45:35 -04:00
|
|
|
.OnMouseButtonDown(this, &SGraphPin::OnPinMouseDown)
|
|
|
|
|
.Cursor(this, &SGraphPin::GetPinCursor);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Create the pin indicator widget (used for watched values)
|
|
|
|
|
static const FName NAME_NoBorder("NoBorder");
|
|
|
|
|
TSharedRef<SWidget> PinStatusIndicator =
|
|
|
|
|
SNew(SButton)
|
2015-03-18 22:45:35 -04:00
|
|
|
.ButtonStyle(FEditorStyle::Get(), NAME_NoBorder)
|
|
|
|
|
.Visibility(this, &SGraphPin::GetPinStatusIconVisibility)
|
2014-03-14 14:13:41 -04:00
|
|
|
.ContentPadding(0)
|
2015-03-18 22:45:35 -04:00
|
|
|
.OnClicked(this, &SGraphPin::ClickedOnPinStatusIcon)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
|
|
|
|
SNew(SImage)
|
2015-03-18 22:45:35 -04:00
|
|
|
.Image(this, &SGraphPin::GetPinStatusIcon)
|
2014-03-14 14:13:41 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
TSharedRef<SWidget> LabelWidget = SNew(STextBlock)
|
|
|
|
|
.Text(this, &SGraphPin::GetPinLabel)
|
2015-03-18 22:45:35 -04:00
|
|
|
.TextStyle(FEditorStyle::Get(), InArgs._PinLabelStyle)
|
2014-03-14 14:13:41 -04:00
|
|
|
.Visibility(this, &SGraphPin::GetPinLabelVisibility)
|
2015-02-17 11:23:23 -05:00
|
|
|
.ColorAndOpacity(this, &SGraphPin::GetPinTextColor);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Create the widget used for the pin body (status indicator, label, and value)
|
2015-03-18 22:45:35 -04:00
|
|
|
TSharedRef<SWrapBox> LabelAndValue =
|
2014-03-14 14:13:41 -04:00
|
|
|
SNew(SWrapBox)
|
|
|
|
|
.PreferredWidth(150.f);
|
|
|
|
|
|
|
|
|
|
if (!bIsInput)
|
|
|
|
|
{
|
|
|
|
|
LabelAndValue->AddSlot()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
PinStatusIndicator
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
LabelAndValue->AddSlot()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
LabelWidget
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LabelAndValue->AddSlot()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
LabelWidget
|
|
|
|
|
];
|
|
|
|
|
|
2014-05-15 17:34:14 -04:00
|
|
|
TSharedRef<SWidget> ValueWidget = GetDefaultValueWidget();
|
|
|
|
|
|
|
|
|
|
if (ValueWidget != SNullWidget::NullWidget)
|
|
|
|
|
{
|
|
|
|
|
LabelAndValue->AddSlot()
|
|
|
|
|
.Padding(bIsInput ? FMargin(InArgs._SideToSideMargin, 0, 0, 0) : FMargin(0, 0, InArgs._SideToSideMargin, 0))
|
|
|
|
|
.VAlign(VAlign_Center)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
2014-05-15 17:34:14 -04:00
|
|
|
SNew(SBox)
|
|
|
|
|
.Padding(0.0f)
|
|
|
|
|
.IsEnabled(this, &SGraphPin::IsEditingEnabled)
|
|
|
|
|
[
|
|
|
|
|
ValueWidget
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
LabelAndValue->AddSlot()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
PinStatusIndicator
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSharedPtr<SWidget> PinContent;
|
|
|
|
|
if (bIsInput)
|
|
|
|
|
{
|
|
|
|
|
// Input pin
|
|
|
|
|
PinContent = SNew(SHorizontalBox)
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
.VAlign(VAlign_Center)
|
2014-05-15 17:34:14 -04:00
|
|
|
.Padding(0, 0, InArgs._SideToSideMargin, 0)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
|
|
|
|
ActualPinWidget
|
|
|
|
|
]
|
2015-03-18 22:45:35 -04:00
|
|
|
+SHorizontalBox::Slot()
|
2014-03-14 14:13:41 -04:00
|
|
|
.AutoWidth()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
LabelAndValue
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Output pin
|
|
|
|
|
PinContent = SNew(SHorizontalBox)
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
[
|
|
|
|
|
LabelAndValue
|
|
|
|
|
]
|
|
|
|
|
+SHorizontalBox::Slot()
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
.VAlign(VAlign_Center)
|
2014-05-15 17:34:14 -04:00
|
|
|
.Padding(InArgs._SideToSideMargin, 0, 0, 0)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
|
|
|
|
ActualPinWidget
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set up a hover for pins that is tinted the color of the pin.
|
2015-03-18 22:45:35 -04:00
|
|
|
SBorder::Construct(SBorder::FArguments()
|
|
|
|
|
.BorderImage(this, &SGraphPin::GetPinBorder)
|
|
|
|
|
.BorderBackgroundColor(this, &SGraphPin::GetPinColor)
|
|
|
|
|
.OnMouseButtonDown(this, &SGraphPin::OnPinNameMouseDown)
|
2014-03-14 14:13:41 -04:00
|
|
|
[
|
|
|
|
|
SNew(SLevelOfDetailBranchNode)
|
|
|
|
|
.UseLowDetailSlot(this, &SGraphPin::UseLowDetailPinNames)
|
|
|
|
|
.LowDetail()
|
|
|
|
|
[
|
|
|
|
|
//@TODO: Try creating a pin-colored line replacement that doesn't measure text / call delegates but still renders
|
|
|
|
|
ActualPinWidget
|
|
|
|
|
]
|
|
|
|
|
.HighDetail()
|
2015-03-18 22:45:35 -04:00
|
|
|
[
|
|
|
|
|
PinContent.ToSharedRef()
|
|
|
|
|
]
|
2014-03-14 14:13:41 -04:00
|
|
|
]
|
|
|
|
|
);
|
2015-03-18 22:45:35 -04:00
|
|
|
|
|
|
|
|
TAttribute<FText> ToolTipAttribute = TAttribute<FText>::Create(TAttribute<FText>::FGetter::CreateSP(this, &SGraphPin::GetTooltipText));
|
|
|
|
|
SetToolTipText(ToolTipAttribute);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TSharedRef<SWidget> SGraphPin::GetDefaultValueWidget()
|
|
|
|
|
{
|
|
|
|
|
return SNew(SBox);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SGraphPin::SetIsEditable(TAttribute<bool> InIsEditable)
|
|
|
|
|
{
|
|
|
|
|
IsEditable = InIsEditable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
else if (MouseEvent.IsControlDown() && (GraphPinObj->LinkedTo.Num() > 0))
|
|
|
|
|
{
|
|
|
|
|
// Get a reference to the owning panel widget
|
|
|
|
|
check(OwnerNodePtr.IsValid());
|
|
|
|
|
TSharedPtr<SGraphPanel> OwnerPanelPtr = OwnerNodePtr.Pin()->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(OwnerNodePtr.Pin()->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;
|
|
|
|
|
|
2014-05-15 17:34:14 -04:00
|
|
|
return FReply::Handled().BeginDragDrop(SpawnPinDragEvent(OwnerPanelPtr.ToSharedRef(), PinArray, /*bIsShiftOperation=*/ false));
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
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
|
2014-05-15 17:34:14 -04:00
|
|
|
{
|
|
|
|
|
TArray<TSharedRef<SGraphPin>> PinArray;
|
|
|
|
|
PinArray.Add(SharedThis(this));
|
|
|
|
|
|
|
|
|
|
return FReply::Handled().BeginDragDrop(SpawnPinDragEvent(this->OwnerNodePtr.Pin()->GetOwnerPanel().ToSharedRef(), PinArray, MouseEvent.IsShiftDown()));
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FReply SGraphPin::OnPinNameMouseDown( const FGeometry& SenderGeometry, const FPointerEvent& MouseEvent )
|
|
|
|
|
{
|
|
|
|
|
const float LocalX = SenderGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X;
|
|
|
|
|
|
|
|
|
|
if ((GetDirection() == EGPD_Input) || (LocalX > SenderGeometry.GetDrawSize().X * 0.5f))
|
|
|
|
|
{
|
|
|
|
|
// Right half of the output pin or all of the input pin, treat it like a connection attempt
|
|
|
|
|
return OnPinMouseDown(SenderGeometry, MouseEvent);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FReply SGraphPin::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
|
|
|
{
|
|
|
|
|
bIsMovingLinks = MouseEvent.IsControlDown() && (GraphPinObj->LinkedTo.Num() > 0);
|
|
|
|
|
|
|
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TOptional<EMouseCursor::Type> SGraphPin::GetPinCursor() const
|
|
|
|
|
{
|
|
|
|
|
check(PinImage.IsValid());
|
|
|
|
|
|
|
|
|
|
if (PinImage->IsHovered())
|
|
|
|
|
{
|
|
|
|
|
if (bIsMovingLinks)
|
|
|
|
|
{
|
|
|
|
|
return EMouseCursor::GrabHandClosed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return EMouseCursor::Crosshairs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return EMouseCursor::Default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 17:34:14 -04:00
|
|
|
TSharedRef<FDragDropOperation> SGraphPin::SpawnPinDragEvent(const TSharedRef<SGraphPanel>& InGraphPanel, const TArray< TSharedRef<SGraphPin> >& InStartingPins, bool bShiftOperation)
|
|
|
|
|
{
|
|
|
|
|
return FDragConnection::New(InGraphPanel, InStartingPins, bShiftOperation);
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The system calls this method to notify the widget that a mouse button was release within it. This event is bubbled.
|
|
|
|
|
*
|
|
|
|
|
* @param MyGeometry The Geometry of the widget receiving the event
|
|
|
|
|
* @param MouseEvent Information about the input event
|
|
|
|
|
*
|
|
|
|
|
* @return Whether the event was handled along with possible requests for the system to take action.
|
|
|
|
|
*/
|
|
|
|
|
FReply SGraphPin::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
|
|
|
{
|
|
|
|
|
if (MouseEvent.IsShiftDown())
|
|
|
|
|
{
|
|
|
|
|
// Either store the shift-clicked pin or attempt to connect it if already stored
|
|
|
|
|
TSharedPtr<SGraphPanel> OwnerPanelPtr = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
|
|
|
check(OwnerPanelPtr.IsValid());
|
|
|
|
|
if (OwnerPanelPtr->MarkedPin.IsValid())
|
|
|
|
|
{
|
|
|
|
|
// avoid creating transaction if toggling the marked pin
|
|
|
|
|
if (!OwnerPanelPtr->MarkedPin.HasSameObject(this))
|
|
|
|
|
{
|
|
|
|
|
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "GraphEd_CreateConnection", "Create Pin Link") );
|
|
|
|
|
TryHandlePinConnection(*OwnerPanelPtr->MarkedPin.Pin());
|
|
|
|
|
}
|
|
|
|
|
OwnerPanelPtr->MarkedPin.Reset();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OwnerPanelPtr->MarkedPin = SharedThis(this);
|
|
|
|
|
}
|
|
|
|
|
return FReply::Handled();
|
|
|
|
|
}
|
|
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
|
|
|
{
|
2015-03-18 21:37:27 -04:00
|
|
|
if (!bIsHovered)
|
2014-05-15 17:34:14 -04:00
|
|
|
{
|
2015-03-18 21:37:27 -04:00
|
|
|
FKnotNetCollector NetCollector(GetPinObj());
|
|
|
|
|
|
|
|
|
|
TSharedPtr<SGraphPanel> Panel = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
|
|
|
for (UEdGraphPin* PinInNet : NetCollector.VisitedPins)
|
|
|
|
|
{
|
|
|
|
|
Panel->AddPinToHoverSet(PinInNet);
|
|
|
|
|
HoverPinSet.Add(PinInNet);
|
|
|
|
|
}
|
2014-05-15 17:34:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::OnMouseLeave( const FPointerEvent& MouseEvent )
|
|
|
|
|
{
|
2014-05-15 17:34:14 -04:00
|
|
|
TSharedPtr<SGraphPanel> Panel = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
|
|
|
|
|
|
|
|
for (TWeakObjectPtr<UEdGraphPin> WeakPin : HoverPinSet)
|
|
|
|
|
{
|
|
|
|
|
if (UEdGraphPin* PinInNet = WeakPin.Get())
|
|
|
|
|
{
|
|
|
|
|
Panel->RemovePinFromHoverSet(PinInNet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
HoverPinSet.Empty();
|
|
|
|
|
|
|
|
|
|
SCompoundWidget::OnMouseLeave(MouseEvent);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
|
|
|
{
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
|
|
|
if (!Operation.IsValid())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
// Is someone dragging a connection?
|
2014-04-23 18:00:50 -04:00
|
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// Ensure that the pin is valid before using it
|
|
|
|
|
if(GraphPinObj != NULL && GraphPinObj->GetOuter() != NULL && GraphPinObj->GetOuter()->IsA(UEdGraphNode::StaticClass()))
|
|
|
|
|
{
|
|
|
|
|
// Inform the Drag and Drop operation that we are hovering over this pin.
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
2014-05-15 17:34:14 -04:00
|
|
|
DragConnectionOp->SetHoveredPin(GraphPinObj);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pins treat being dragged over the same as being hovered outside of drag and drop if they know how to respond to the drag action.
|
|
|
|
|
SBorder::OnMouseEnter( MyGeometry, DragDropEvent );
|
|
|
|
|
}
|
2014-04-23 18:00:50 -04:00
|
|
|
else if (Operation->IsOfType<FAssetDragDropOp>())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
TSharedPtr<SGraphNode> NodeWidget = OwnerNodePtr.Pin();
|
|
|
|
|
if (NodeWidget.IsValid())
|
|
|
|
|
{
|
|
|
|
|
UEdGraphNode* Node = NodeWidget->GetNodeObj();
|
|
|
|
|
if(Node != NULL && Node->GetSchema() != NULL)
|
|
|
|
|
{
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
2014-03-14 14:13:41 -04:00
|
|
|
bool bOkIcon = false;
|
|
|
|
|
FString TooltipText;
|
|
|
|
|
Node->GetSchema()->GetAssetsPinHoverMessage(AssetOp->AssetData, GraphPinObj, TooltipText, bOkIcon);
|
|
|
|
|
const FSlateBrush* TooltipIcon = bOkIcon ? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")) : FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));;
|
2014-04-23 17:55:20 -04:00
|
|
|
AssetOp->SetToolTip(FText::FromString(TooltipText), TooltipIcon);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::OnDragLeave( const FDragDropEvent& DragDropEvent )
|
|
|
|
|
{
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
|
|
|
if (!Operation.IsValid())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
// Is someone dragging a connection?
|
2014-04-23 18:00:50 -04:00
|
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// Inform the Drag and Drop operation that we are not hovering any pins
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
2014-05-15 17:34:14 -04:00
|
|
|
DragConnectionOp->SetHoveredPin(nullptr);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2014-05-15 17:34:14 -04:00
|
|
|
SBorder::OnMouseLeave(DragDropEvent);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
2014-04-23 18:00:50 -04:00
|
|
|
|
|
|
|
|
else if (Operation->IsOfType<FAssetDragDropOp>())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
2014-03-14 14:13:41 -04:00
|
|
|
AssetOp->ResetToDefaultToolTip();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FReply SGraphPin::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
|
|
|
{
|
|
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::TryHandlePinConnection(SGraphPin& OtherSPin)
|
|
|
|
|
{
|
|
|
|
|
UEdGraphPin* PinA = GetPinObj();
|
|
|
|
|
UEdGraphPin* PinB = OtherSPin.GetPinObj();
|
|
|
|
|
UEdGraph* MyGraphObj = PinA->GetOwningNode()->GetGraph();
|
|
|
|
|
|
|
|
|
|
return MyGraphObj->GetSchema()->TryCreateConnection(PinA, PinB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FReply SGraphPin::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
|
|
|
{
|
2014-06-18 05:04:59 -04:00
|
|
|
TSharedPtr<SGraphNode> NodeWidget = OwnerNodePtr.Pin();
|
|
|
|
|
bool bReadOnly = NodeWidget.IsValid() ? !NodeWidget->IsNodeEditable() : false;
|
|
|
|
|
|
2014-04-23 18:00:50 -04:00
|
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
2014-06-18 05:04:59 -04:00
|
|
|
if (!Operation.IsValid() || bReadOnly)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-04-23 18:00:50 -04:00
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is someone dropping a connection onto this pin?
|
|
|
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
|
|
|
|
{
|
|
|
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
FVector2D NodeAddPosition = FVector2D::ZeroVector;
|
|
|
|
|
TSharedPtr<SGraphNode> OwnerNode = OwnerNodePtr.Pin();
|
|
|
|
|
if (OwnerNode.IsValid())
|
|
|
|
|
{
|
|
|
|
|
NodeAddPosition = OwnerNode->GetPosition() + MyGeometry.Position;
|
|
|
|
|
|
|
|
|
|
//Don't have access to bounding information for node, using fixed offet that should work for most cases.
|
|
|
|
|
const float FixedOffset = 200.0f;
|
|
|
|
|
|
|
|
|
|
//Line it up vertically with pin
|
|
|
|
|
NodeAddPosition.Y += MyGeometry.Size.Y;
|
|
|
|
|
|
|
|
|
|
if(GetDirection() == EEdGraphPinDirection::EGPD_Input)
|
|
|
|
|
{
|
|
|
|
|
//left side just offset by fixed amount
|
|
|
|
|
//@TODO: knowing the width of the node we are about to create would allow us to line this up more precisely,
|
|
|
|
|
// but this information is not available currently
|
|
|
|
|
NodeAddPosition.X -= FixedOffset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//right side we need the width of the pin + fixed amount because our reference position is the upper left corner of pin(which is variable length)
|
|
|
|
|
NodeAddPosition.X += MyGeometry.Size.X + FixedOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DragConnectionOp->DroppedOnPin(DragDropEvent.GetScreenSpacePosition(), NodeAddPosition);
|
|
|
|
|
}
|
|
|
|
|
// handle dropping an asset on the pin
|
2014-06-18 05:04:59 -04:00
|
|
|
else if (Operation->IsOfType<FAssetDragDropOp>() && NodeWidget.IsValid())
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-18 05:04:59 -04:00
|
|
|
UEdGraphNode* Node = NodeWidget->GetNodeObj();
|
|
|
|
|
if(Node != NULL && Node->GetSchema() != NULL)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-18 05:04:59 -04:00
|
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2014-06-18 05:04:59 -04:00
|
|
|
Node->GetSchema()->DroppedAssetsOnPin(AssetOp->AssetData, DragDropEvent.GetScreenSpacePosition(), GraphPinObj);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
return FReply::Handled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
|
|
|
{
|
2015-04-21 14:13:02 -04:00
|
|
|
CachedNodeOffset = AllottedGeometry.AbsolutePosition/AllottedGeometry.Scale - OwnerNodePtr.Pin()->GetUnscaledPosition();
|
|
|
|
|
CachedNodeOffset.Y += AllottedGeometry.Size.Y * 0.5f;
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UEdGraphPin* SGraphPin::GetPinObj() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @param OwnerNode The SGraphNode that this pin belongs to */
|
|
|
|
|
void SGraphPin::SetOwner( const TSharedRef<SGraphNode> OwnerNode )
|
|
|
|
|
{
|
|
|
|
|
check( !OwnerNodePtr.IsValid() );
|
|
|
|
|
OwnerNodePtr = OwnerNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SGraphPin::IsPinVisibleAsAdvanced() const
|
|
|
|
|
{
|
|
|
|
|
bool bHideAdvancedPin = false;
|
|
|
|
|
const TSharedPtr<SGraphNode> NodeWidget = OwnerNodePtr.Pin();
|
|
|
|
|
if (NodeWidget.IsValid())
|
|
|
|
|
{
|
|
|
|
|
if(const UEdGraphNode* Node = NodeWidget->GetNodeObj())
|
|
|
|
|
{
|
|
|
|
|
bHideAdvancedPin = (ENodeAdvancedPins::Hidden == Node->AdvancedPinDisplay);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool bIsAdvancedPin = GraphPinObj && GraphPinObj->bAdvancedView;
|
|
|
|
|
const bool bCanBeHidden = !IsConnected();
|
|
|
|
|
return (bIsAdvancedPin && bHideAdvancedPin && bCanBeHidden) ? EVisibility::Collapsed : EVisibility::Visible;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-21 14:13:02 -04:00
|
|
|
FVector2D SGraphPin::GetNodeOffset() const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2015-04-21 14:13:02 -04:00
|
|
|
return CachedNodeOffset;
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
2015-01-07 09:52:40 -05:00
|
|
|
FText SGraphPin::GetPinLabel() const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
return GetPinObj()->GetOwningNode()->GetPinDisplayName(GetPinObj());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return whether this pin is incoming or outgoing */
|
|
|
|
|
EEdGraphPinDirection SGraphPin::GetDirection() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<EEdGraphPinDirection>(GraphPinObj->Direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return whether this pin is an array value */
|
|
|
|
|
bool SGraphPin::IsArray() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj->PinType.bIsArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::IsByRef() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj->PinType.bIsReference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::IsByMutableRef() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj->PinType.bIsReference && !GraphPinObj->PinType.bIsConst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::IsDelegate() const
|
|
|
|
|
{
|
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
|
|
|
|
return Schema && Schema->IsDelegateCategory(GraphPinObj->PinType.PinCategory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::IsByConstRef() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj->PinType.bIsReference && GraphPinObj->PinType.bIsConst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return whether this pin is connected to another pin */
|
|
|
|
|
bool SGraphPin::IsConnected() const
|
|
|
|
|
{
|
|
|
|
|
return GraphPinObj->LinkedTo.Num() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return The brush with which to pain this graph pin's incoming/outgoing bullet point */
|
|
|
|
|
const FSlateBrush* SGraphPin::GetPinIcon() const
|
|
|
|
|
{
|
|
|
|
|
if (IsArray())
|
|
|
|
|
{
|
|
|
|
|
if (IsConnected())
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_ArrayPin_ConnectedHovered : CachedImg_ArrayPin_Connected;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_ArrayPin_DisconnectedHovered : CachedImg_ArrayPin_Disconnected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(IsDelegate())
|
|
|
|
|
{
|
|
|
|
|
if (IsConnected())
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_DelegatePin_ConnectedHovered : CachedImg_DelegatePin_Connected;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_DelegatePin_DisconnectedHovered : CachedImg_DelegatePin_Disconnected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ( IsByMutableRef() )
|
|
|
|
|
{
|
|
|
|
|
if (IsConnected())
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_RefPin_ConnectedHovered : CachedImg_RefPin_Connected;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_RefPin_DisconnectedHovered : CachedImg_RefPin_Disconnected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (IsConnected())
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_Pin_ConnectedHovered : CachedImg_Pin_Connected;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsHovered() ? CachedImg_Pin_DisconnectedHovered : CachedImg_Pin_Disconnected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* SGraphPin::GetPinBorder() const
|
|
|
|
|
{
|
|
|
|
|
bool bIsMarkedPin = false;
|
|
|
|
|
TSharedPtr<SGraphPanel> OwnerPanelPtr = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
|
|
|
check(OwnerPanelPtr.IsValid());
|
|
|
|
|
if (OwnerPanelPtr->MarkedPin.IsValid())
|
|
|
|
|
{
|
|
|
|
|
bIsMarkedPin = (OwnerPanelPtr->MarkedPin.Pin() == SharedThis(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (IsHovered() || bIsMarkedPin || GraphPinObj->bIsDiffing) ? CachedImg_Pin_BackgroundHovered : CachedImg_Pin_Background;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FSlateColor SGraphPin::GetPinColor() const
|
|
|
|
|
{
|
|
|
|
|
if(GraphPinObj->bIsDiffing)
|
|
|
|
|
{
|
|
|
|
|
return FSlateColor(FLinearColor(0.9f,0.2f,0.15f));
|
|
|
|
|
}
|
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
2015-02-17 11:23:23 -05:00
|
|
|
if(!GetPinObj()->GetOwningNode()->bIsNodeEnabled)
|
|
|
|
|
{
|
|
|
|
|
return Schema->GetPinTypeColor(GraphPinObj->PinType) * FLinearColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
return Schema->GetPinTypeColor(GraphPinObj->PinType) * PinColorModifier;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 11:23:23 -05:00
|
|
|
FSlateColor SGraphPin::GetPinTextColor() const
|
|
|
|
|
{
|
|
|
|
|
if(!GetPinObj()->GetOwningNode()->bIsNodeEnabled)
|
|
|
|
|
{
|
|
|
|
|
return FLinearColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
else if(bUsePinColorForText)
|
|
|
|
|
{
|
|
|
|
|
return GetPinColor();
|
|
|
|
|
}
|
|
|
|
|
return FLinearColor::White;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SGraphPin::GetPinStatusIconVisibility() const
|
|
|
|
|
{
|
|
|
|
|
UEdGraphPin const* WatchedPin = ((GraphPinObj->Direction == EGPD_Input) && (GraphPinObj->LinkedTo.Num() > 0)) ? GraphPinObj->LinkedTo[0] : GraphPinObj;
|
|
|
|
|
|
|
|
|
|
UEdGraphSchema const* Schema = GraphPinObj->GetSchema();
|
|
|
|
|
return Schema->IsPinBeingWatched(WatchedPin) ? EVisibility::Visible : EVisibility::Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FReply SGraphPin::ClickedOnPinStatusIcon()
|
|
|
|
|
{
|
|
|
|
|
UEdGraphPin* WatchedPin = ((GraphPinObj->Direction == EGPD_Input) && (GraphPinObj->LinkedTo.Num() > 0)) ? GraphPinObj->LinkedTo[0] : GraphPinObj;
|
|
|
|
|
|
|
|
|
|
UEdGraphSchema const* Schema = GraphPinObj->GetSchema();
|
|
|
|
|
Schema->ClearPinWatch(WatchedPin);
|
|
|
|
|
|
|
|
|
|
return FReply::Handled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SGraphPin::GetDefaultValueVisibility() const
|
|
|
|
|
{
|
|
|
|
|
// First ask schema
|
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
|
|
|
|
if (Schema->ShouldHidePinDefaultValue(GraphPinObj))
|
|
|
|
|
{
|
|
|
|
|
return EVisibility::Collapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GraphPinObj->bNotConnectable)
|
|
|
|
|
{
|
|
|
|
|
// The only reason this pin exists is to show something, so do so
|
|
|
|
|
return EVisibility::Visible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GraphPinObj->Direction == EGPD_Output)
|
|
|
|
|
{
|
|
|
|
|
//@TODO: Should probably be a bLiteralOutput flag or a Schema call
|
|
|
|
|
return EVisibility::Collapsed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsConnected() ? EVisibility::Collapsed : EVisibility::Visible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SGraphPin::SetShowLabel(bool bNewShowLabel)
|
|
|
|
|
{
|
|
|
|
|
bShowLabel = bNewShowLabel;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 22:45:35 -04:00
|
|
|
FText SGraphPin::GetTooltipText() const
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2015-01-08 11:35:01 -05:00
|
|
|
FText HoverText = FText::GetEmpty();
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2015-03-18 16:35:00 -04:00
|
|
|
UEdGraphNode* GraphNode = GraphPinObj ? GraphPinObj->GetOwningNodeUnchecked() : nullptr;
|
2014-03-14 14:13:41 -04:00
|
|
|
if (GraphNode != nullptr)
|
|
|
|
|
{
|
2015-01-08 11:35:01 -05:00
|
|
|
FString HoverStr;
|
|
|
|
|
GraphNode->GetPinHoverText(*GraphPinObj, /*out*/HoverStr);
|
|
|
|
|
if (!HoverStr.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
HoverText = FText::FromString(HoverStr);
|
|
|
|
|
}
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return HoverText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::IsEditingEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return IsEditable.Get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SGraphPin::UseLowDetailPinNames() const
|
|
|
|
|
{
|
|
|
|
|
if (SGraphNode* MyOwnerNode = OwnerNodePtr.Pin().Get())
|
|
|
|
|
{
|
|
|
|
|
return MyOwnerNode->GetOwnerPanel()->GetCurrentLOD() <= EGraphRenderingLOD::LowDetail;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVisibility SGraphPin::GetPinVisiblity() const
|
|
|
|
|
{
|
|
|
|
|
// The pin becomes too small to use at low LOD, so disable the hit test.
|
|
|
|
|
if(UseLowDetailPinNames())
|
|
|
|
|
{
|
|
|
|
|
return EVisibility::HitTestInvisible;
|
|
|
|
|
}
|
|
|
|
|
return EVisibility::Visible;
|
|
|
|
|
}
|