You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
295 lines
10 KiB
C++
295 lines
10 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "AIGraphPrivatePCH.h"
|
|
#include "BlueprintGraphDefinitions.h"
|
|
#include "GraphEditorActions.h"
|
|
#include "AIGraphConnectionDrawingPolicy.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "SGraphEditorImpl.h"
|
|
#include "GenericCommands.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "AIGraph"
|
|
#define SNAP_GRID (16) // @todo ensure this is the same as SNodePanel::GetSnapGridSize()
|
|
|
|
namespace
|
|
{
|
|
// Maximum distance a drag can be off a node edge to require 'push off' from node
|
|
const int32 NodeDistance = 60;
|
|
}
|
|
|
|
UEdGraphNode* FAISchemaAction_NewNode::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode)
|
|
{
|
|
UEdGraphNode* ResultNode = NULL;
|
|
|
|
// If there is a template, we actually use it
|
|
if (NodeTemplate != NULL)
|
|
{
|
|
const FScopedTransaction Transaction(LOCTEXT("AddNode", "Add Node"));
|
|
ParentGraph->Modify();
|
|
if (FromPin)
|
|
{
|
|
FromPin->Modify();
|
|
}
|
|
|
|
NodeTemplate->SetFlags(RF_Transactional);
|
|
|
|
// set outer to be the graph so it doesn't go away
|
|
NodeTemplate->Rename(NULL, ParentGraph, REN_NonTransactional);
|
|
ParentGraph->AddNode(NodeTemplate, true);
|
|
|
|
NodeTemplate->CreateNewGuid();
|
|
NodeTemplate->PostPlacedNewNode();
|
|
|
|
// For input pins, new node will generally overlap node being dragged off
|
|
// Work out if we want to visually push away from connected node
|
|
int32 XLocation = Location.X;
|
|
if (FromPin && FromPin->Direction == EGPD_Input)
|
|
{
|
|
UEdGraphNode* PinNode = FromPin->GetOwningNode();
|
|
const float XDelta = FMath::Abs(PinNode->NodePosX - Location.X);
|
|
|
|
if (XDelta < NodeDistance)
|
|
{
|
|
// Set location to edge of current node minus the max move distance
|
|
// to force node to push off from connect node enough to give selection handle
|
|
XLocation = PinNode->NodePosX - NodeDistance;
|
|
}
|
|
}
|
|
|
|
NodeTemplate->NodePosX = XLocation;
|
|
NodeTemplate->NodePosY = Location.Y;
|
|
NodeTemplate->SnapToGrid(SNAP_GRID);
|
|
|
|
// setup pins after placing node in correct spot, since pin sorting will happen as soon as link connection change occurs
|
|
NodeTemplate->AllocateDefaultPins();
|
|
NodeTemplate->AutowireNewNode(FromPin);
|
|
|
|
ResultNode = NodeTemplate;
|
|
}
|
|
|
|
return ResultNode;
|
|
}
|
|
|
|
UEdGraphNode* FAISchemaAction_NewNode::PerformAction(class UEdGraph* ParentGraph, TArray<UEdGraphPin*>& FromPins, const FVector2D Location, bool bSelectNewNode)
|
|
{
|
|
UEdGraphNode* ResultNode = NULL;
|
|
if (FromPins.Num() > 0)
|
|
{
|
|
ResultNode = PerformAction(ParentGraph, FromPins[0], Location);
|
|
|
|
// Try autowiring the rest of the pins
|
|
for (int32 Index = 1; Index < FromPins.Num(); ++Index)
|
|
{
|
|
ResultNode->AutowireNewNode(FromPins[Index]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResultNode = PerformAction(ParentGraph, NULL, Location, bSelectNewNode);
|
|
}
|
|
|
|
return ResultNode;
|
|
}
|
|
|
|
void FAISchemaAction_NewNode::AddReferencedObjects(FReferenceCollector& Collector)
|
|
{
|
|
FEdGraphSchemaAction::AddReferencedObjects(Collector);
|
|
|
|
// These don't get saved to disk, but we want to make sure the objects don't get GC'd while the action array is around
|
|
Collector.AddReferencedObject(NodeTemplate);
|
|
}
|
|
|
|
UEdGraphNode* FAISchemaAction_NewSubNode::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode)
|
|
{
|
|
ParentNode->AddSubNode(NodeTemplate, ParentGraph);
|
|
return NULL;
|
|
}
|
|
|
|
UEdGraphNode* FAISchemaAction_NewSubNode::PerformAction(class UEdGraph* ParentGraph, TArray<UEdGraphPin*>& FromPins, const FVector2D Location, bool bSelectNewNode)
|
|
{
|
|
return PerformAction(ParentGraph, NULL, Location, bSelectNewNode);
|
|
}
|
|
|
|
void FAISchemaAction_NewSubNode::AddReferencedObjects(FReferenceCollector& Collector)
|
|
{
|
|
FEdGraphSchemaAction::AddReferencedObjects(Collector);
|
|
|
|
// These don't get saved to disk, but we want to make sure the objects don't get GC'd while the action array is around
|
|
Collector.AddReferencedObject(NodeTemplate);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
UAIGraphSchema::UAIGraphSchema(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
|
|
{
|
|
}
|
|
|
|
TSharedPtr<FAISchemaAction_NewNode> UAIGraphSchema::AddNewNodeAction(FGraphActionListBuilderBase& ContextMenuBuilder, const FText& Category, const FText& MenuDesc, const FString& Tooltip)
|
|
{
|
|
TSharedPtr<FAISchemaAction_NewNode> NewAction = TSharedPtr<FAISchemaAction_NewNode>(new FAISchemaAction_NewNode(Category, MenuDesc, Tooltip, 0));
|
|
ContextMenuBuilder.AddAction(NewAction);
|
|
|
|
return NewAction;
|
|
}
|
|
|
|
TSharedPtr<FAISchemaAction_NewSubNode> UAIGraphSchema::AddNewSubNodeAction(FGraphActionListBuilderBase& ContextMenuBuilder, const FText& Category, const FText& MenuDesc, const FString& Tooltip)
|
|
{
|
|
TSharedPtr<FAISchemaAction_NewSubNode> NewAction = TSharedPtr<FAISchemaAction_NewSubNode>(new FAISchemaAction_NewSubNode(Category, MenuDesc, Tooltip, 0));
|
|
ContextMenuBuilder.AddAction(NewAction);
|
|
return NewAction;
|
|
}
|
|
|
|
void UAIGraphSchema::GetSubNodeClasses(int32 SubNodeFlags, TArray<FGraphNodeClassData>& ClassData, UClass*& GraphNodeClass) const
|
|
{
|
|
// empty in base class
|
|
}
|
|
|
|
void UAIGraphSchema::GetGraphNodeContextActions(FGraphContextMenuBuilder& ContextMenuBuilder, int32 SubNodeFlags) const
|
|
{
|
|
UEdGraph* Graph = (UEdGraph*)ContextMenuBuilder.CurrentGraph;
|
|
UClass* GraphNodeClass = nullptr;
|
|
TArray<FGraphNodeClassData> NodeClasses;
|
|
GetSubNodeClasses(SubNodeFlags, NodeClasses, GraphNodeClass);
|
|
|
|
if (GraphNodeClass)
|
|
{
|
|
for (const auto& NodeClass : NodeClasses)
|
|
{
|
|
const FText NodeTypeName = FText::FromString(FName::NameToDisplayString(NodeClass.ToString(), false));
|
|
|
|
UAIGraphNode* OpNode = NewObject<UAIGraphNode>(Graph, GraphNodeClass);
|
|
OpNode->ClassData = NodeClass;
|
|
|
|
TSharedPtr<FAISchemaAction_NewSubNode> AddOpAction = UAIGraphSchema::AddNewSubNodeAction(ContextMenuBuilder, NodeClass.GetCategory(), NodeTypeName, "");
|
|
AddOpAction->ParentNode = Cast<UAIGraphNode>(ContextMenuBuilder.SelectedObjects[0]);
|
|
AddOpAction->NodeTemplate = OpNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UAIGraphSchema::GetContextMenuActions(const UEdGraph* CurrentGraph, const UEdGraphNode* InGraphNode, const UEdGraphPin* InGraphPin, class FMenuBuilder* MenuBuilder, bool bIsDebugging) const
|
|
{
|
|
if (InGraphPin)
|
|
{
|
|
MenuBuilder->BeginSection("AIGraphSchemaPinActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions"));
|
|
{
|
|
// Only display the 'Break Links' option if there is a link to break!
|
|
if (InGraphPin->LinkedTo.Num() > 0)
|
|
{
|
|
MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().BreakPinLinks);
|
|
|
|
// add sub menu for break link to
|
|
if (InGraphPin->LinkedTo.Num() > 1)
|
|
{
|
|
MenuBuilder->AddSubMenu(
|
|
LOCTEXT("BreakLinkTo", "Break Link To..."),
|
|
LOCTEXT("BreakSpecificLinks", "Break a specific link..."),
|
|
FNewMenuDelegate::CreateUObject((UAIGraphSchema*const)this, &UAIGraphSchema::GetBreakLinkToSubMenuActions, const_cast<UEdGraphPin*>(InGraphPin)));
|
|
}
|
|
else
|
|
{
|
|
((UAIGraphSchema*const)this)->GetBreakLinkToSubMenuActions(*MenuBuilder, const_cast<UEdGraphPin*>(InGraphPin));
|
|
}
|
|
}
|
|
}
|
|
MenuBuilder->EndSection();
|
|
}
|
|
else if (InGraphNode)
|
|
{
|
|
MenuBuilder->BeginSection("BehaviorTreeGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
|
|
{
|
|
MenuBuilder->AddMenuEntry(FGenericCommands::Get().Delete);
|
|
MenuBuilder->AddMenuEntry(FGenericCommands::Get().Cut);
|
|
MenuBuilder->AddMenuEntry(FGenericCommands::Get().Copy);
|
|
MenuBuilder->AddMenuEntry(FGenericCommands::Get().Duplicate);
|
|
|
|
MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
|
|
}
|
|
MenuBuilder->EndSection();
|
|
}
|
|
|
|
Super::GetContextMenuActions(CurrentGraph, InGraphNode, InGraphPin, MenuBuilder, bIsDebugging);
|
|
}
|
|
|
|
void UAIGraphSchema::GetBreakLinkToSubMenuActions(class FMenuBuilder& MenuBuilder, UEdGraphPin* InGraphPin)
|
|
{
|
|
// Make sure we have a unique name for every entry in the list
|
|
TMap< FString, uint32 > LinkTitleCount;
|
|
|
|
// Add all the links we could break from
|
|
for (TArray<class UEdGraphPin*>::TConstIterator Links(InGraphPin->LinkedTo); Links; ++Links)
|
|
{
|
|
UEdGraphPin* Pin = *Links;
|
|
FString TitleString = Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString();
|
|
FText Title = FText::FromString(TitleString);
|
|
if (Pin->PinName != TEXT(""))
|
|
{
|
|
TitleString = FString::Printf(TEXT("%s (%s)"), *TitleString, *Pin->PinName);
|
|
|
|
// Add name of connection if possible
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("NodeTitle"), Title);
|
|
Args.Add(TEXT("PinName"), Pin->GetDisplayName());
|
|
Title = FText::Format(LOCTEXT("BreakDescPin", "{NodeTitle} ({PinName})"), Args);
|
|
}
|
|
|
|
uint32 &Count = LinkTitleCount.FindOrAdd(TitleString);
|
|
|
|
FText Description;
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("NodeTitle"), Title);
|
|
Args.Add(TEXT("NumberOfNodes"), Count);
|
|
|
|
if (Count == 0)
|
|
{
|
|
Description = FText::Format(LOCTEXT("BreakDesc", "Break link to {NodeTitle}"), Args);
|
|
}
|
|
else
|
|
{
|
|
Description = FText::Format(LOCTEXT("BreakDescMulti", "Break link to {NodeTitle} ({NumberOfNodes})"), Args);
|
|
}
|
|
++Count;
|
|
|
|
MenuBuilder.AddMenuEntry(Description, Description, FSlateIcon(), FUIAction(
|
|
FExecuteAction::CreateUObject(this, &UAIGraphSchema::BreakSinglePinLink, const_cast< UEdGraphPin* >(InGraphPin), *Links)));
|
|
}
|
|
}
|
|
|
|
void UAIGraphSchema::BreakNodeLinks(UEdGraphNode& TargetNode) const
|
|
{
|
|
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakNodeLinks", "Break Node Links"));
|
|
|
|
Super::BreakNodeLinks(TargetNode);
|
|
}
|
|
|
|
void UAIGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotification) const
|
|
{
|
|
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakPinLinks", "Break Pin Links"));
|
|
|
|
Super::BreakPinLinks(TargetPin, bSendsNodeNotification);
|
|
}
|
|
|
|
void UAIGraphSchema::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin)
|
|
{
|
|
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakSinglePinLink", "Break Pin Link"));
|
|
|
|
Super::BreakSinglePinLink(SourcePin, TargetPin);
|
|
}
|
|
|
|
FLinearColor UAIGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) const
|
|
{
|
|
return FColor::White;
|
|
}
|
|
|
|
bool UAIGraphSchema::ShouldHidePinDefaultValue(UEdGraphPin* Pin) const
|
|
{
|
|
check(Pin != NULL);
|
|
return Pin->bDefaultValueIsIgnored;
|
|
}
|
|
|
|
class FConnectionDrawingPolicy* UAIGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const
|
|
{
|
|
return new FAIGraphConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|