You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1173 lines
33 KiB
C++
1173 lines
33 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
#include "SGraphPin.h"
|
|
#include "Widgets/SBoxPanel.h"
|
|
#include "Widgets/Layout/SWrapBox.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "GraphEditorSettings.h"
|
|
#include "SGraphPanel.h"
|
|
#include "GraphEditorDragDropAction.h"
|
|
#include "DragConnection.h"
|
|
#include "K2Node_Knot.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "Kismet2/KismetDebugUtilities.h"
|
|
#include "DragAndDrop/AssetDragDropOp.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "SLevelOfDetailBranchNode.h"
|
|
#include "SPinTypeSelector.h"
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FGraphPinHandle
|
|
|
|
FGraphPinHandle::FGraphPinHandle(UEdGraphPin* InPin)
|
|
{
|
|
if (InPin != nullptr)
|
|
{
|
|
if (UEdGraphNode* Node = InPin->GetOwningNodeUnchecked())
|
|
{
|
|
NodeGuid = Node->NodeGuid;
|
|
PinId = InPin->PinId;
|
|
}
|
|
}
|
|
}
|
|
|
|
UEdGraphPin* FGraphPinHandle::GetPinObj(const SGraphPanel& Panel) const
|
|
{
|
|
UEdGraphPin* AssociatedPin = nullptr;
|
|
if (IsValid())
|
|
{
|
|
TSharedPtr<SGraphNode> NodeWidget = Panel.GetNodeWidgetFromGuid(NodeGuid);
|
|
if (NodeWidget.IsValid())
|
|
{
|
|
UEdGraphNode* NodeObj = NodeWidget->GetNodeObj();
|
|
AssociatedPin = NodeObj->FindPinById(PinId);
|
|
}
|
|
}
|
|
return AssociatedPin;
|
|
}
|
|
|
|
TSharedPtr<SGraphPin> FGraphPinHandle::FindInGraphPanel(const SGraphPanel& InPanel) const
|
|
{
|
|
if (UEdGraphPin* ReferencedPin = GetPinObj(InPanel))
|
|
{
|
|
TSharedPtr<SGraphNode> GraphNode = InPanel.GetNodeWidgetFromGuid(NodeGuid);
|
|
return GraphNode->FindWidgetForPin(ReferencedPin);
|
|
}
|
|
return TSharedPtr<SGraphPin>();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
// SGraphPin
|
|
|
|
|
|
SGraphPin::SGraphPin()
|
|
: GraphPinObj(nullptr)
|
|
, PinColorModifier(FLinearColor::White)
|
|
, CachedNodeOffset(FVector2D::ZeroVector)
|
|
, bGraphDataInvalid(false)
|
|
, bShowLabel(true)
|
|
, bOnlyShowDefaultValue(false)
|
|
, bIsMovingLinks(false)
|
|
, bUsePinColorForText(false)
|
|
{
|
|
IsEditable = true;
|
|
|
|
// Make these names const so they're not created for every pin
|
|
|
|
/** Original Pin Styles */
|
|
static const FName NAME_Pin_Connected("Graph.Pin.Connected");
|
|
static const FName NAME_Pin_Disconnected("Graph.Pin.Disconnected");
|
|
|
|
/** Variant A Pin Styles */
|
|
static const FName NAME_Pin_Connected_VarA("Graph.Pin.Connected_VarA");
|
|
static const FName NAME_Pin_Disconnected_VarA("Graph.Pin.Disconnected_VarA");
|
|
|
|
static const FName NAME_ArrayPin_Connected("Graph.ArrayPin.Connected");
|
|
static const FName NAME_ArrayPin_Disconnected("Graph.ArrayPin.Disconnected");
|
|
|
|
static const FName NAME_RefPin_Connected("Graph.RefPin.Connected");
|
|
static const FName NAME_RefPin_Disconnected("Graph.RefPin.Disconnected");
|
|
|
|
static const FName NAME_DelegatePin_Connected("Graph.DelegatePin.Connected");
|
|
static const FName NAME_DelegatePin_Disconnected("Graph.DelegatePin.Disconnected");
|
|
|
|
static const FName NAME_SetPin("Kismet.VariableList.SetTypeIcon");
|
|
static const FName NAME_MapPinKey("Kismet.VariableList.MapKeyTypeIcon");
|
|
static const FName NAME_MapPinValue("Kismet.VariableList.MapValueTypeIcon");
|
|
|
|
static const FName NAME_Pin_Background("Graph.Pin.Background");
|
|
static const FName NAME_Pin_BackgroundHovered("Graph.Pin.BackgroundHovered");
|
|
|
|
const EBlueprintPinStyleType StyleType = GetDefault<UGraphEditorSettings>()->DataPinStyle;
|
|
|
|
switch(StyleType)
|
|
{
|
|
case BPST_VariantA:
|
|
CachedImg_Pin_Connected = FEditorStyle::GetBrush( NAME_Pin_Connected_VarA );
|
|
CachedImg_Pin_Disconnected = FEditorStyle::GetBrush( NAME_Pin_Disconnected_VarA );
|
|
break;
|
|
case BPST_Original:
|
|
default:
|
|
CachedImg_Pin_Connected = FEditorStyle::GetBrush( NAME_Pin_Connected );
|
|
CachedImg_Pin_Disconnected = FEditorStyle::GetBrush( NAME_Pin_Disconnected );
|
|
break;
|
|
}
|
|
|
|
CachedImg_RefPin_Connected = FEditorStyle::GetBrush( NAME_RefPin_Connected );
|
|
CachedImg_RefPin_Disconnected = FEditorStyle::GetBrush( NAME_RefPin_Disconnected );
|
|
|
|
CachedImg_ArrayPin_Connected = FEditorStyle::GetBrush( NAME_ArrayPin_Connected );
|
|
CachedImg_ArrayPin_Disconnected = FEditorStyle::GetBrush( NAME_ArrayPin_Disconnected );
|
|
|
|
CachedImg_DelegatePin_Connected = FEditorStyle::GetBrush( NAME_DelegatePin_Connected );
|
|
CachedImg_DelegatePin_Disconnected = FEditorStyle::GetBrush( NAME_DelegatePin_Disconnected );
|
|
|
|
CachedImg_SetPin = FEditorStyle::GetBrush(NAME_SetPin);
|
|
CachedImg_MapPinKey = FEditorStyle::GetBrush(NAME_MapPinKey);
|
|
CachedImg_MapPinValue = FEditorStyle::GetBrush(NAME_MapPinValue);
|
|
|
|
CachedImg_Pin_Background = FEditorStyle::GetBrush( NAME_Pin_Background );
|
|
CachedImg_Pin_BackgroundHovered = FEditorStyle::GetBrush( NAME_Pin_BackgroundHovered );
|
|
}
|
|
|
|
void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin)
|
|
{
|
|
bUsePinColorForText = InArgs._UsePinColorForText;
|
|
this->SetCursor(EMouseCursor::Default);
|
|
|
|
Visibility = TAttribute<EVisibility>(this, &SGraphPin::GetPinVisiblity);
|
|
|
|
GraphPinObj = InPin;
|
|
check(GraphPinObj != NULL);
|
|
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
|
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")
|
|
);
|
|
|
|
const bool bIsInput = (GetDirection() == EGPD_Input);
|
|
|
|
// Create the pin icon widget
|
|
TSharedRef<SWidget> PinWidgetRef = SPinTypeSelector::ConstructPinTypeImage(
|
|
TAttribute<const FSlateBrush*>::Create( TAttribute<const FSlateBrush*>::FGetter::CreateRaw(this, &SGraphPin::GetPinIcon ) ),
|
|
TAttribute<FSlateColor>::Create( TAttribute<FSlateColor>::FGetter::CreateRaw(this, &SGraphPin::GetPinColor) ),
|
|
TAttribute<const FSlateBrush*>::Create( TAttribute<const FSlateBrush*>::FGetter::CreateRaw(this, &SGraphPin::GetSecondaryPinIcon ) ),
|
|
TAttribute<FSlateColor>::Create( TAttribute<FSlateColor>::FGetter::CreateRaw(this, &SGraphPin::GetSecondaryPinColor) ));
|
|
PinImage = PinWidgetRef;
|
|
|
|
PinWidgetRef->SetCursor(
|
|
TAttribute<TOptional<EMouseCursor::Type> >::Create (
|
|
TAttribute<TOptional<EMouseCursor::Type> >::FGetter::CreateRaw( this, &SGraphPin::GetPinCursor )
|
|
)
|
|
);
|
|
|
|
// Create the pin indicator widget (used for watched values)
|
|
static const FName NAME_NoBorder("NoBorder");
|
|
TSharedRef<SWidget> PinStatusIndicator =
|
|
SNew(SButton)
|
|
.ButtonStyle(FEditorStyle::Get(), NAME_NoBorder)
|
|
.Visibility(this, &SGraphPin::GetPinStatusIconVisibility)
|
|
.ContentPadding(0)
|
|
.OnClicked(this, &SGraphPin::ClickedOnPinStatusIcon)
|
|
[
|
|
SNew(SImage)
|
|
.Image(this, &SGraphPin::GetPinStatusIcon)
|
|
];
|
|
|
|
TSharedRef<SWidget> LabelWidget = GetLabelWidget(InArgs._PinLabelStyle);
|
|
|
|
// Create the widget used for the pin body (status indicator, label, and value)
|
|
LabelAndValue =
|
|
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
|
|
];
|
|
|
|
ValueWidget = GetDefaultValueWidget();
|
|
|
|
if (ValueWidget != SNullWidget::NullWidget)
|
|
{
|
|
TSharedPtr<SBox> ValueBox;
|
|
LabelAndValue->AddSlot()
|
|
.Padding(bIsInput ? FMargin(InArgs._SideToSideMargin, 0, 0, 0) : FMargin(0, 0, InArgs._SideToSideMargin, 0))
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SAssignNew(ValueBox, SBox)
|
|
.Padding(0.0f)
|
|
[
|
|
ValueWidget.ToSharedRef()
|
|
]
|
|
];
|
|
|
|
if (!DoesWidgetHandleSettingEditingEnabled())
|
|
{
|
|
ValueBox->SetEnabled(TAttribute<bool>(this, &SGraphPin::IsEditingEnabled));
|
|
}
|
|
}
|
|
|
|
LabelAndValue->AddSlot()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
PinStatusIndicator
|
|
];
|
|
}
|
|
|
|
TSharedPtr<SHorizontalBox> PinContent;
|
|
if (bIsInput)
|
|
{
|
|
// Input pin
|
|
FullPinHorizontalRowWidget = PinContent =
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(0, 0, InArgs._SideToSideMargin, 0)
|
|
[
|
|
PinWidgetRef
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
LabelAndValue.ToSharedRef()
|
|
];
|
|
}
|
|
else
|
|
{
|
|
// Output pin
|
|
FullPinHorizontalRowWidget = PinContent = SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
LabelAndValue.ToSharedRef()
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(InArgs._SideToSideMargin, 0, 0, 0)
|
|
[
|
|
PinWidgetRef
|
|
];
|
|
}
|
|
|
|
// Set up a hover for pins that is tinted the color of the pin.
|
|
SBorder::Construct(SBorder::FArguments()
|
|
.BorderImage(this, &SGraphPin::GetPinBorder)
|
|
.BorderBackgroundColor(this, &SGraphPin::GetPinColor)
|
|
.OnMouseButtonDown(this, &SGraphPin::OnPinNameMouseDown)
|
|
[
|
|
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
|
|
PinWidgetRef
|
|
]
|
|
.HighDetail()
|
|
[
|
|
PinContent.ToSharedRef()
|
|
]
|
|
]
|
|
);
|
|
|
|
TAttribute<FText> ToolTipAttribute = TAttribute<FText>::Create(TAttribute<FText>::FGetter::CreateSP(this, &SGraphPin::GetTooltipText));
|
|
SetToolTipText(ToolTipAttribute);
|
|
}
|
|
|
|
TSharedRef<SWidget> SGraphPin::GetDefaultValueWidget()
|
|
{
|
|
return SNullWidget::NullWidget;
|
|
}
|
|
|
|
TSharedRef<SWidget> SGraphPin::GetLabelWidget(const FName& InLabelStyle)
|
|
{
|
|
return SNew(STextBlock)
|
|
.Text(this, &SGraphPin::GetPinLabel)
|
|
.TextStyle(FEditorStyle::Get(), InLabelStyle)
|
|
.Visibility(this, &SGraphPin::GetPinLabelVisibility)
|
|
.ColorAndOpacity(this, &SGraphPin::GetPinTextColor);
|
|
}
|
|
|
|
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 (IsEditingEnabled())
|
|
{
|
|
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();
|
|
}
|
|
|
|
TSharedPtr<SGraphNode> 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< FGraphPinHandle, TSharedRef<SGraphPin> > PinToPinWidgetMap;
|
|
for (const TSharedRef<SWidget>& SomePinWidget : AllPins)
|
|
{
|
|
const SGraphPin& PinWidget = static_cast<const SGraphPin&>(SomePinWidget.Get());
|
|
|
|
UEdGraphPin* GraphPin = PinWidget.GetPinObj();
|
|
if (GraphPin->LinkedTo.Num() > 0)
|
|
{
|
|
PinToPinWidgetMap.Add(FGraphPinHandle(GraphPin), StaticCastSharedRef<SGraphPin>(SomePinWidget));
|
|
}
|
|
}
|
|
|
|
// Define a local struct to temporarily store lookup information for pins that we are currently linked to
|
|
struct FLinkedToPinInfo
|
|
{
|
|
// Pin name string
|
|
FName 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<FLinkedToPinInfo> LinkedToPinInfoArray;
|
|
for (UEdGraphPin* Pin : GetPinObj()->LinkedTo)
|
|
{
|
|
if (TSharedRef<SGraphPin>* PinWidget = PinToPinWidgetMap.Find(Pin))
|
|
{
|
|
check((*PinWidget)->OwnerNodePtr.IsValid());
|
|
|
|
FLinkedToPinInfo PinInfo;
|
|
PinInfo.PinName = (*PinWidget)->GetPinObj()->PinName;
|
|
PinInfo.OwnerNodePtr = (*PinWidget)->OwnerNodePtr.Pin()->GetNodeObj();
|
|
LinkedToPinInfoArray.Add(MoveTemp(PinInfo));
|
|
}
|
|
}
|
|
|
|
|
|
// Now iterate over our lookup table to find the instances of pin widgets that we had previously linked to
|
|
TArray<TSharedRef<SGraphPin>> PinArray;
|
|
for (FLinkedToPinInfo PinInfo : LinkedToPinInfoArray)
|
|
{
|
|
if (UEdGraphNode* OwnerNodeObj = PinInfo.OwnerNodePtr.Get())
|
|
{
|
|
for (UEdGraphPin* Pin : PinInfo.OwnerNodePtr.Get()->Pins)
|
|
{
|
|
if (Pin->PinName == PinInfo.PinName)
|
|
{
|
|
if (TSharedRef<SGraphPin>* pWidget = PinToPinWidgetMap.Find(FGraphPinHandle(Pin)))
|
|
{
|
|
PinArray.Add(*pWidget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TSharedPtr<FDragDropOperation> DragEvent;
|
|
if (PinArray.Num() > 0)
|
|
{
|
|
DragEvent = SpawnPinDragEvent(OwnerPanelPtr.ToSharedRef(), PinArray);
|
|
}
|
|
|
|
// 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.
|
|
// So the break MUST come after the SpawnPinDragEvent(), since that acquires handles from PinArray (the pins need to be
|
|
// around for us to construct valid handles from).
|
|
const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
|
|
Schema->BreakPinLinks(*GraphPinObj, true);
|
|
|
|
if (DragEvent.IsValid())
|
|
{
|
|
bIsMovingLinks = true;
|
|
return FReply::Handled().BeginDragDrop(DragEvent.ToSharedRef());
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
|
|
if (!GraphPinObj->bNotConnectable)
|
|
{
|
|
// 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));
|
|
}
|
|
else
|
|
{
|
|
return FReply::Unhandled();
|
|
}
|
|
}
|
|
}
|
|
|
|
// It's not connectible, 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) || FMath::Abs( SenderGeometry.GetLocalSize().X - LocalX ) < 60.f )
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
TSharedRef<FDragDropOperation> SGraphPin::SpawnPinDragEvent(const TSharedRef<SGraphPanel>& InGraphPanel, const TArray< TSharedRef<SGraphPin> >& InStartingPins)
|
|
{
|
|
FDragConnection::FDraggedPinTable PinHandles;
|
|
PinHandles.Reserve(InStartingPins.Num());
|
|
// since the graph can be refreshed and pins can be reconstructed/replaced
|
|
// behind the scenes, the DragDropOperation holds onto FGraphPinHandles
|
|
// instead of direct widgets/graph-pins
|
|
for (const TSharedRef<SGraphPin>& PinWidget : InStartingPins)
|
|
{
|
|
PinHandles.Add(PinWidget->GetPinObj());
|
|
}
|
|
|
|
return FDragConnection::New(InGraphPanel, PinHandles);
|
|
}
|
|
|
|
/**
|
|
* 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 )
|
|
{
|
|
if (!bIsHovered && ensure(!bGraphDataInvalid))
|
|
{
|
|
UEdGraphPin* MyPin = GetPinObj();
|
|
if (MyPin && !MyPin->IsPendingKill() && MyPin->GetOuter() && MyPin->GetOuter()->IsA(UEdGraphNode::StaticClass()))
|
|
{
|
|
struct FHoverPinHelper
|
|
{
|
|
FHoverPinHelper(TSharedPtr<SGraphPanel> Panel, TSet<FEdGraphPinReference>& PinSet)
|
|
: PinSetOut(PinSet), TargetPanel(Panel)
|
|
{}
|
|
|
|
void SetHovered(UEdGraphPin* Pin)
|
|
{
|
|
bool bAlreadyAdded = false;
|
|
PinSetOut.Add(Pin, &bAlreadyAdded);
|
|
if (bAlreadyAdded)
|
|
{
|
|
return;
|
|
}
|
|
TargetPanel->AddPinToHoverSet(Pin);
|
|
|
|
for (UEdGraphPin* LinkedPin : Pin->LinkedTo)
|
|
{
|
|
int32 InputPinIndex = -1;
|
|
int32 OutputPinIndex = -1;
|
|
UEdGraphNode* InKnot = LinkedPin->GetOwningNodeUnchecked();
|
|
if (InKnot != nullptr && InKnot->ShouldDrawNodeAsControlPointOnly(InputPinIndex, OutputPinIndex) == true &&
|
|
InputPinIndex >= 0 && OutputPinIndex >= 0)
|
|
{
|
|
SetHovered(InKnot);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
void SetHovered(UEdGraphNode* KnotNode)
|
|
{
|
|
bool bAlreadyTraversed = false;
|
|
IntermediateNodes.Add(KnotNode, &bAlreadyTraversed);
|
|
|
|
if (!bAlreadyTraversed)
|
|
{
|
|
for (UEdGraphPin* KnotPin : KnotNode->Pins)
|
|
{
|
|
SetHovered(KnotPin);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
TSet<UEdGraphNode*> IntermediateNodes;
|
|
TSet<FEdGraphPinReference>& PinSetOut;
|
|
TSharedPtr<SGraphPanel> TargetPanel;
|
|
};
|
|
|
|
|
|
TSharedPtr<SGraphPanel> Panel = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
if (Panel.IsValid())
|
|
{
|
|
FHoverPinHelper(Panel, HoverPinSet).SetHovered(MyPin);
|
|
}
|
|
}
|
|
}
|
|
|
|
SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent);
|
|
}
|
|
|
|
void SGraphPin::OnMouseLeave( const FPointerEvent& MouseEvent )
|
|
{
|
|
TSharedPtr<SGraphPanel> Panel = OwnerNodePtr.Pin()->GetOwnerPanel();
|
|
|
|
for (const FEdGraphPinReference& WeakPin : HoverPinSet)
|
|
{
|
|
if (UEdGraphPin* PinInNet = WeakPin.Get())
|
|
{
|
|
Panel->RemovePinFromHoverSet(PinInNet);
|
|
}
|
|
}
|
|
HoverPinSet.Empty();
|
|
|
|
SCompoundWidget::OnMouseLeave(MouseEvent);
|
|
}
|
|
|
|
void SGraphPin::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
{
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
if (!Operation.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Is someone dragging a connection?
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
|
{
|
|
// Ensure that the pin is valid before using it
|
|
if(GraphPinObj != NULL && !GraphPinObj->IsPendingKill() && GraphPinObj->GetOuter() != NULL && GraphPinObj->GetOuter()->IsA(UEdGraphNode::StaticClass()))
|
|
{
|
|
// Inform the Drag and Drop operation that we are hovering over this pin.
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
|
DragConnectionOp->SetHoveredPin(GraphPinObj);
|
|
}
|
|
|
|
// 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 );
|
|
}
|
|
}
|
|
|
|
void SGraphPin::OnDragLeave( const FDragDropEvent& DragDropEvent )
|
|
{
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
if (!Operation.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Is someone dragging a connection?
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
|
{
|
|
// Inform the Drag and Drop operation that we are not hovering any pins
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
|
DragConnectionOp->SetHoveredPin(nullptr);
|
|
|
|
SBorder::OnMouseLeave(DragDropEvent);
|
|
}
|
|
|
|
else if (Operation->IsOfType<FAssetDragDropOp>())
|
|
{
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
|
AssetOp->ResetToDefaultToolTip();
|
|
}
|
|
}
|
|
|
|
FReply SGraphPin::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
|
|
{
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
if (!Operation.IsValid())
|
|
{
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
if (Operation->IsOfType<FAssetDragDropOp>())
|
|
{
|
|
TSharedPtr<SGraphNode> NodeWidget = OwnerNodePtr.Pin();
|
|
if (NodeWidget.IsValid())
|
|
{
|
|
UEdGraphNode* Node = NodeWidget->GetNodeObj();
|
|
if(Node != NULL && Node->GetSchema() != NULL)
|
|
{
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
|
bool bOkIcon = false;
|
|
FString TooltipText;
|
|
if (AssetOp->HasAssets())
|
|
{
|
|
Node->GetSchema()->GetAssetsPinHoverMessage(AssetOp->GetAssets(), GraphPinObj, TooltipText, bOkIcon);
|
|
}
|
|
const FSlateBrush* TooltipIcon = bOkIcon ? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")) : FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));;
|
|
AssetOp->SetToolTip(FText::FromString(TooltipText), TooltipIcon);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
}
|
|
}
|
|
|
|
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 )
|
|
{
|
|
TSharedPtr<SGraphNode> NodeWidget = OwnerNodePtr.Pin();
|
|
bool bReadOnly = NodeWidget.IsValid() ? !NodeWidget->IsNodeEditable() : false;
|
|
|
|
TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
|
|
if (!Operation.IsValid() || bReadOnly)
|
|
{
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
// Is someone dropping a connection onto this pin?
|
|
if (Operation->IsOfType<FGraphEditorDragDropAction>())
|
|
{
|
|
TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
|
|
|
|
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
|
|
else if (Operation->IsOfType<FAssetDragDropOp>() && NodeWidget.IsValid())
|
|
{
|
|
UEdGraphNode* Node = NodeWidget->GetNodeObj();
|
|
if(Node != NULL && Node->GetSchema() != NULL)
|
|
{
|
|
TSharedPtr<FAssetDragDropOp> AssetOp = StaticCastSharedPtr<FAssetDragDropOp>(Operation);
|
|
if (AssetOp->HasAssets())
|
|
{
|
|
Node->GetSchema()->DroppedAssetsOnPin(AssetOp->GetAssets(), NodeWidget->GetPosition() + MyGeometry.Position, GraphPinObj);
|
|
}
|
|
}
|
|
return FReply::Handled();
|
|
}
|
|
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
void SGraphPin::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
{
|
|
CachedNodeOffset = AllottedGeometry.AbsolutePosition/AllottedGeometry.Scale - OwnerNodePtr.Pin()->GetUnscaledPosition();
|
|
CachedNodeOffset.Y += AllottedGeometry.Size.Y * 0.5f;
|
|
}
|
|
|
|
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->IsPendingKill() && GraphPinObj->bAdvancedView;
|
|
const bool bCanBeHidden = !IsConnected();
|
|
return (bIsAdvancedPin && bHideAdvancedPin && bCanBeHidden) ? EVisibility::Collapsed : EVisibility::Visible;
|
|
}
|
|
|
|
FVector2D SGraphPin::GetNodeOffset() const
|
|
{
|
|
return CachedNodeOffset;
|
|
}
|
|
|
|
FText SGraphPin::GetPinLabel() const
|
|
{
|
|
if (UEdGraphNode* GraphNode = GetPinObj()->GetOwningNodeUnchecked())
|
|
{
|
|
return GraphNode->GetPinDisplayName(GetPinObj());
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** @return whether this pin is incoming or outgoing */
|
|
EEdGraphPinDirection SGraphPin::GetDirection() const
|
|
{
|
|
return static_cast<EEdGraphPinDirection>(GraphPinObj->Direction);
|
|
}
|
|
|
|
bool SGraphPin::IsArray() const
|
|
{
|
|
return GraphPinObj->PinType.IsArray();
|
|
}
|
|
|
|
bool SGraphPin::IsSet() const
|
|
{
|
|
return GraphPinObj->PinType.IsSet();
|
|
}
|
|
|
|
bool SGraphPin::IsMap() const
|
|
{
|
|
return GraphPinObj->PinType.IsMap();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/** @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 CachedImg_ArrayPin_Connected;
|
|
}
|
|
else
|
|
{
|
|
return CachedImg_ArrayPin_Disconnected;
|
|
}
|
|
}
|
|
else if(IsDelegate())
|
|
{
|
|
if (IsConnected())
|
|
{
|
|
return CachedImg_DelegatePin_Connected;
|
|
}
|
|
else
|
|
{
|
|
return CachedImg_DelegatePin_Disconnected;
|
|
}
|
|
}
|
|
else if (GraphPinObj->bDisplayAsMutableRef || IsByMutableRef())
|
|
{
|
|
if (IsConnected())
|
|
{
|
|
return CachedImg_RefPin_Connected;
|
|
}
|
|
else
|
|
{
|
|
return CachedImg_RefPin_Disconnected;
|
|
}
|
|
|
|
}
|
|
else if (IsSet())
|
|
{
|
|
return CachedImg_SetPin;
|
|
}
|
|
else if (IsMap())
|
|
{
|
|
return CachedImg_MapPinKey;
|
|
}
|
|
else
|
|
{
|
|
if (IsConnected())
|
|
{
|
|
return CachedImg_Pin_Connected;
|
|
}
|
|
else
|
|
{
|
|
return CachedImg_Pin_Disconnected;
|
|
}
|
|
}
|
|
}
|
|
|
|
const FSlateBrush* SGraphPin::GetSecondaryPinIcon() const
|
|
{
|
|
if( !GraphPinObj->IsPendingKill() && GraphPinObj->PinType.IsMap() )
|
|
{
|
|
return CachedImg_MapPinValue;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
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 || bOnlyShowDefaultValue) ? CachedImg_Pin_BackgroundHovered : CachedImg_Pin_Background;
|
|
}
|
|
|
|
|
|
FSlateColor SGraphPin::GetPinColor() const
|
|
{
|
|
if (!GraphPinObj->IsPendingKill())
|
|
{
|
|
if (GraphPinObj->bIsDiffing)
|
|
{
|
|
return FSlateColor(FLinearColor(0.9f, 0.2f, 0.15f));
|
|
}
|
|
if (GraphPinObj->bOrphanedPin)
|
|
{
|
|
return FSlateColor(FLinearColor::Red);
|
|
}
|
|
if (const UEdGraphSchema* Schema = GraphPinObj->GetSchema())
|
|
{
|
|
if (!GetPinObj()->GetOwningNode()->IsNodeEnabled() || GetPinObj()->GetOwningNode()->IsDisplayAsDisabledForced() || !IsEditingEnabled())
|
|
{
|
|
return Schema->GetPinTypeColor(GraphPinObj->PinType) * FLinearColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
}
|
|
|
|
return Schema->GetPinTypeColor(GraphPinObj->PinType) * PinColorModifier;
|
|
}
|
|
}
|
|
|
|
return FLinearColor::White;
|
|
}
|
|
|
|
FSlateColor SGraphPin::GetSecondaryPinColor() const
|
|
{
|
|
const UEdGraphSchema_K2* Schema = Cast<UEdGraphSchema_K2>(!GraphPinObj->IsPendingKill() ? GraphPinObj->GetSchema() : nullptr);
|
|
return Schema ? Schema->GetSecondaryPinTypeColor(GraphPinObj->PinType) : FLinearColor::White;
|
|
}
|
|
|
|
FSlateColor SGraphPin::GetPinTextColor() const
|
|
{
|
|
// If there is no schema there is no owning node (or basically this is a deleted node)
|
|
if (UEdGraphNode* GraphNode = GraphPinObj->GetOwningNodeUnchecked())
|
|
{
|
|
const bool bDisabled = (!GraphNode->IsNodeEnabled() || GraphNode->IsDisplayAsDisabledForced() || !IsEditingEnabled());
|
|
if (GraphPinObj->bOrphanedPin)
|
|
{
|
|
FLinearColor PinColor = FLinearColor::Red;
|
|
if (bDisabled)
|
|
{
|
|
PinColor.A = 0.5f;
|
|
}
|
|
return PinColor;
|
|
}
|
|
else if (bDisabled)
|
|
{
|
|
return FLinearColor(1.0f, 1.0f, 1.0f, 0.5f);
|
|
}
|
|
if (bUsePinColorForText)
|
|
{
|
|
return GetPinColor();
|
|
}
|
|
}
|
|
return FLinearColor::White;
|
|
}
|
|
|
|
|
|
const FSlateBrush* SGraphPin::GetPinStatusIcon() const
|
|
{
|
|
if (!GraphPinObj->IsPendingKill())
|
|
{
|
|
UEdGraphPin* WatchedPin = ((GraphPinObj->Direction == EGPD_Input) && (GraphPinObj->LinkedTo.Num() > 0)) ? GraphPinObj->LinkedTo[0] : GraphPinObj;
|
|
|
|
if (UEdGraphNode* GraphNode = WatchedPin->GetOwningNodeUnchecked())
|
|
{
|
|
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(GraphNode);
|
|
|
|
if (FKismetDebugUtilities::IsPinBeingWatched(Blueprint, WatchedPin))
|
|
{
|
|
return FEditorStyle::GetBrush(TEXT("Graph.WatchedPinIcon_Pinned"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
EVisibility SGraphPin::GetPinStatusIconVisibility() const
|
|
{
|
|
if (GraphPinObj->IsPendingKill())
|
|
{
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
UEdGraphPin const* WatchedPin = ((GraphPinObj->Direction == EGPD_Input) && (GraphPinObj->LinkedTo.Num() > 0)) ? GraphPinObj->LinkedTo[0] : GraphPinObj;
|
|
|
|
UEdGraphSchema const* Schema = GraphPinObj->GetSchema();
|
|
return Schema && Schema->IsPinBeingWatched(WatchedPin) ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
FReply SGraphPin::ClickedOnPinStatusIcon()
|
|
{
|
|
if (GraphPinObj->IsPendingKill())
|
|
{
|
|
return FReply::Handled();
|
|
}
|
|
|
|
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
|
|
{
|
|
// If this is only for showing default value, always show
|
|
if (bOnlyShowDefaultValue)
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
|
|
// First ask schema
|
|
const UEdGraphSchema* Schema = !GraphPinObj->IsPendingKill() ? GraphPinObj->GetSchema() : nullptr;
|
|
if (Schema == nullptr || Schema->ShouldHidePinDefaultValue(GraphPinObj))
|
|
{
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
if (GraphPinObj->bNotConnectable && !GraphPinObj->bOrphanedPin)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
void SGraphPin::SetOnlyShowDefaultValue(bool bNewOnlyShowDefaultValue)
|
|
{
|
|
bOnlyShowDefaultValue = bNewOnlyShowDefaultValue;
|
|
}
|
|
|
|
FText SGraphPin::GetTooltipText() const
|
|
{
|
|
if(!ensure(!bGraphDataInvalid))
|
|
{
|
|
return FText();
|
|
}
|
|
|
|
FText HoverText = FText::GetEmpty();
|
|
|
|
UEdGraphNode* GraphNode = GraphPinObj && !GraphPinObj->IsPendingKill() ? GraphPinObj->GetOwningNodeUnchecked() : nullptr;
|
|
if (GraphNode != nullptr)
|
|
{
|
|
FString HoverStr;
|
|
GraphNode->GetPinHoverText(*GraphPinObj, /*out*/HoverStr);
|
|
if (!HoverStr.IsEmpty())
|
|
{
|
|
HoverText = FText::FromString(HoverStr);
|
|
}
|
|
}
|
|
|
|
return HoverText;
|
|
}
|
|
|
|
bool SGraphPin::IsEditingEnabled() const
|
|
{
|
|
if (OwnerNodePtr.IsValid())
|
|
{
|
|
return OwnerNodePtr.Pin()->IsNodeEditable() && IsEditable.Get();
|
|
}
|
|
return IsEditable.Get();
|
|
}
|
|
|
|
bool SGraphPin::UseLowDetailPinNames() const
|
|
{
|
|
SGraphNode* MyOwnerNode = OwnerNodePtr.Pin().Get();
|
|
if (MyOwnerNode && MyOwnerNode->GetOwnerPanel().IsValid())
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool SGraphPin::GetIsConnectable() const
|
|
{
|
|
const bool bCanConnectToPin = !GraphPinObj->bNotConnectable;
|
|
return bCanConnectToPin;
|
|
}
|