Skip to content

Commit

Permalink
Merge branch 'edge-names'
Browse files Browse the repository at this point in the history
  • Loading branch information
sclark39 committed Apr 25, 2021
2 parents 6a6b4c6 + cd33f2f commit 5c847c6
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

#define LOCTEXT_NAMESPACE "EdNode_GenericGraphEdge"

UEdNode_GenericGraphEdge::UEdNode_GenericGraphEdge()
{
bCanRenameNode = true;
}

void UEdNode_GenericGraphEdge::SetEdge(UGenericGraphEdge* Edge)
{
GenericGraphEdge = Edge;
Expand All @@ -19,6 +24,10 @@ void UEdNode_GenericGraphEdge::AllocateDefaultPins()

FText UEdNode_GenericGraphEdge::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (GenericGraphEdge)
{
return GenericGraphEdge->GetNodeTitle();
}
return FText();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,134 +1,199 @@
#include "GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/SToolTip.h"
#include "SGraphPanel.h"
#include "EdGraphSchema_K2.h"
#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
#include "GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h"

#define LOCTEXT_NAMESPACE "SGenericGraphEdge"

void SEdNode_GenericGraphEdge::Construct(const FArguments& InArgs, UEdNode_GenericGraphEdge* InNode)
{
this->GraphNode = InNode;
this->UpdateGraphNode();
}

bool SEdNode_GenericGraphEdge::RequiresSecondPassLayout() const
{
return true;
}

void SEdNode_GenericGraphEdge::PerformSecondPassLayout(const TMap< UObject*, TSharedRef<SNode> >& NodeToWidgetLookup) const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);

FGeometry StartGeom;
FGeometry EndGeom;

UEdNode_GenericGraphNode* Start = EdgeNode->GetStartNode();
UEdNode_GenericGraphNode* End = EdgeNode->GetEndNode();
if (Start != nullptr && End != nullptr)
{
const TSharedRef<SNode>* pFromWidget = NodeToWidgetLookup.Find(Start);
const TSharedRef<SNode>* pToWidget = NodeToWidgetLookup.Find(End);
if (pFromWidget != nullptr && pToWidget != nullptr)
{
const TSharedRef<SNode>& FromWidget = *pFromWidget;
const TSharedRef<SNode>& ToWidget = *pToWidget;

StartGeom = FGeometry(FVector2D(Start->NodePosX, Start->NodePosY), FVector2D::ZeroVector, FromWidget->GetDesiredSize(), 1.0f);
EndGeom = FGeometry(FVector2D(End->NodePosX, End->NodePosY), FVector2D::ZeroVector, ToWidget->GetDesiredSize(), 1.0f);
}
}

PositionBetweenTwoNodesWithOffset(StartGeom, EndGeom, 0, 1);
}

void SEdNode_GenericGraphEdge::UpdateGraphNode()
{
InputPins.Empty();
OutputPins.Empty();

RightNodeBox.Reset();
LeftNodeBox.Reset();

this->ContentScale.Bind( this, &SGraphNode::GetContentScale );
this->GetOrAddSlot( ENodeZone::Center )
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SOverlay)
+ SOverlay::Slot()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Graph.TransitionNode.ColorSpill"))
.ColorAndOpacity(this, &SEdNode_GenericGraphEdge::GetEdgeColor)
]
+ SOverlay::Slot()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Graph.TransitionNode.Icon"))
]
];
}

void SEdNode_GenericGraphEdge::PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const
{
// Get a reasonable seed point (halfway between the boxes)
const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;

// Find the (approximate) closest points between the two boxes
const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);

// Position ourselves halfway along the connecting line between the nodes, elevated away perpendicular to the direction of the line
const float Height = 30.0f;

const FVector2D DesiredNodeSize = GetDesiredSize();

FVector2D DeltaPos(EndAnchorPoint - StartAnchorPoint);

if (DeltaPos.IsNearlyZero())
{
DeltaPos = FVector2D(10.0f, 0.0f);
}

const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();

const FVector2D NewCenter = StartAnchorPoint + (0.5f * DeltaPos) + (Height * Normal);

FVector2D DeltaNormal = DeltaPos.GetSafeNormal();

// Calculate node offset in the case of multiple transitions between the same two nodes
// MultiNodeOffset: the offset where 0 is the centre of the transition, -1 is 1 <size of node>
// towards the PrevStateNode and +1 is 1 <size of node> towards the NextStateNode.

const float MutliNodeSpace = 0.2f; // Space between multiple transition nodes (in units of <size of node> )
const float MultiNodeStep = (1.f + MutliNodeSpace); //Step between node centres (Size of node + size of node spacer)

const float MultiNodeStart = -((MaxNodes - 1) * MultiNodeStep) / 2.f;
const float MultiNodeOffset = MultiNodeStart + (NodeIndex * MultiNodeStep);

// Now we need to adjust the new center by the node size, zoom factor and multi node offset
const FVector2D NewCorner = NewCenter - (0.5f * DesiredNodeSize) + (DeltaNormal * MultiNodeOffset * DesiredNodeSize.Size());

GraphNode->NodePosX = NewCorner.X;
GraphNode->NodePosY = NewCorner.Y;
}

FSlateColor SEdNode_GenericGraphEdge::GetEdgeColor() const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
if (EdgeNode != nullptr && EdgeNode->GenericGraphEdge != nullptr)
{
return EdgeNode->GenericGraphEdge->GetEdgeColour();
}
return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f);
}

#undef LOCTEXT_NAMESPACE
#include "GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/SInlineEditableTextBlock.h"
#include "Widgets/SToolTip.h"
#include "SGraphPanel.h"
#include "EdGraphSchema_K2.h"
#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
#include "GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h"

#define LOCTEXT_NAMESPACE "SGenericGraphEdge"

void SEdNode_GenericGraphEdge::Construct(const FArguments& InArgs, UEdNode_GenericGraphEdge* InNode)
{
this->GraphNode = InNode;
this->UpdateGraphNode();
}

bool SEdNode_GenericGraphEdge::RequiresSecondPassLayout() const
{
return true;
}

void SEdNode_GenericGraphEdge::PerformSecondPassLayout(const TMap< UObject*, TSharedRef<SNode> >& NodeToWidgetLookup) const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);

FGeometry StartGeom;
FGeometry EndGeom;

UEdNode_GenericGraphNode* Start = EdgeNode->GetStartNode();
UEdNode_GenericGraphNode* End = EdgeNode->GetEndNode();
if (Start != nullptr && End != nullptr)
{
const TSharedRef<SNode>* pFromWidget = NodeToWidgetLookup.Find(Start);
const TSharedRef<SNode>* pToWidget = NodeToWidgetLookup.Find(End);
if (pFromWidget != nullptr && pToWidget != nullptr)
{
const TSharedRef<SNode>& FromWidget = *pFromWidget;
const TSharedRef<SNode>& ToWidget = *pToWidget;

StartGeom = FGeometry(FVector2D(Start->NodePosX, Start->NodePosY), FVector2D::ZeroVector, FromWidget->GetDesiredSize(), 1.0f);
EndGeom = FGeometry(FVector2D(End->NodePosX, End->NodePosY), FVector2D::ZeroVector, ToWidget->GetDesiredSize(), 1.0f);
}
}

PositionBetweenTwoNodesWithOffset(StartGeom, EndGeom, 0, 1);
}

void SEdNode_GenericGraphEdge::OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo)
{
SGraphNode::OnNameTextCommited(InText, CommitInfo);

UEdNode_GenericGraphEdge* MyNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);

if (MyNode != nullptr && MyNode->GenericGraphEdge != nullptr)
{
const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorRenameEdge", "Generic Graph Editor: Rename Edge"));
MyNode->Modify();
MyNode->GenericGraphEdge->SetNodeTitle(InText);
UpdateGraphNode();
}
}

void SEdNode_GenericGraphEdge::UpdateGraphNode()
{
InputPins.Empty();
OutputPins.Empty();

RightNodeBox.Reset();
LeftNodeBox.Reset();

TSharedPtr<SNodeTitle> NodeTitle = SNew(SNodeTitle, GraphNode);

this->ContentScale.Bind( this, &SGraphNode::GetContentScale );
this->GetOrAddSlot( ENodeZone::Center )
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SOverlay)
+ SOverlay::Slot()
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Graph.TransitionNode.ColorSpill"))
.ColorAndOpacity(this, &SEdNode_GenericGraphEdge::GetEdgeColor)
]
+ SOverlay::Slot()
[
SNew(SImage)
.Image(this, &SEdNode_GenericGraphEdge::GetEdgeImage)
.Visibility(this, &SEdNode_GenericGraphEdge::GetEdgeImageVisibility)
]

+ SOverlay::Slot()
.Padding(FMargin(4.0f, 4.0f, 4.0f, 4.0f))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.HAlign(HAlign_Center)
.AutoHeight()
[
SAssignNew(InlineEditableText, SInlineEditableTextBlock)
.ColorAndOpacity(FLinearColor::Black)
.Visibility(this, &SEdNode_GenericGraphEdge::GetEdgeTitleVisbility)
.Font(FCoreStyle::GetDefaultFontStyle("Regular", 12))
.Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle)
.OnTextCommitted(this, &SEdNode_GenericGraphEdge::OnNameTextCommited)
]
+ SVerticalBox::Slot()
.AutoHeight()
[
NodeTitle.ToSharedRef()
]

]
];
}

void SEdNode_GenericGraphEdge::PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const
{
// Get a reasonable seed point (halfway between the boxes)
const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;

// Find the (approximate) closest points between the two boxes
const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);

// Position ourselves halfway along the connecting line between the nodes, elevated away perpendicular to the direction of the line
const float Height = 30.0f;

const FVector2D DesiredNodeSize = GetDesiredSize();

FVector2D DeltaPos(EndAnchorPoint - StartAnchorPoint);

if (DeltaPos.IsNearlyZero())
{
DeltaPos = FVector2D(10.0f, 0.0f);
}

const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();

const FVector2D NewCenter = StartAnchorPoint + (0.5f * DeltaPos) + (Height * Normal);

FVector2D DeltaNormal = DeltaPos.GetSafeNormal();

// Calculate node offset in the case of multiple transitions between the same two nodes
// MultiNodeOffset: the offset where 0 is the centre of the transition, -1 is 1 <size of node>
// towards the PrevStateNode and +1 is 1 <size of node> towards the NextStateNode.

const float MutliNodeSpace = 0.2f; // Space between multiple transition nodes (in units of <size of node> )
const float MultiNodeStep = (1.f + MutliNodeSpace); //Step between node centres (Size of node + size of node spacer)

const float MultiNodeStart = -((MaxNodes - 1) * MultiNodeStep) / 2.f;
const float MultiNodeOffset = MultiNodeStart + (NodeIndex * MultiNodeStep);

// Now we need to adjust the new center by the node size, zoom factor and multi node offset
const FVector2D NewCorner = NewCenter - (0.5f * DesiredNodeSize) + (DeltaNormal * MultiNodeOffset * DesiredNodeSize.Size());

GraphNode->NodePosX = NewCorner.X;
GraphNode->NodePosY = NewCorner.Y;
}

FSlateColor SEdNode_GenericGraphEdge::GetEdgeColor() const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
if (EdgeNode != nullptr && EdgeNode->GenericGraphEdge != nullptr)
{
return EdgeNode->GenericGraphEdge->GetEdgeColour();
}
return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f);
}

const FSlateBrush* SEdNode_GenericGraphEdge::GetEdgeImage() const
{
return FEditorStyle::GetBrush("Graph.TransitionNode.Icon");
}

EVisibility SEdNode_GenericGraphEdge::GetEdgeImageVisibility() const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
if (EdgeNode && EdgeNode->GenericGraphEdge && EdgeNode->GenericGraphEdge->bShouldDrawTitle)
return EVisibility::Hidden;

return EVisibility::Visible;
}

EVisibility SEdNode_GenericGraphEdge::GetEdgeTitleVisbility() const
{
UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
if (EdgeNode && EdgeNode->GenericGraphEdge && EdgeNode->GenericGraphEdge->bShouldDrawTitle)
return EVisibility::Visible;

return EVisibility::Collapsed;
}

#undef LOCTEXT_NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class UEdNode_GenericGraphEdge : public UEdGraphNode
GENERATED_BODY()

public:
UEdNode_GenericGraphEdge();

UPROPERTY()
class UEdGraph* Graph;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ class GENERICGRAPHEDITOR_API SEdNode_GenericGraphEdge : public SGraphNode
// Calculate position for multiple nodes to be placed between a start and end point, by providing this nodes index and max expected nodes
void PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const;

void OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo);

protected:
FSlateColor GetEdgeColor() const;

const FSlateBrush* GetEdgeImage() const;

EVisibility GetEdgeImageVisibility() const;
EVisibility GetEdgeTitleVisbility() const;
private:
TSharedPtr<STextEntryPopup> TextEntryWidget;
};
7 changes: 7 additions & 0 deletions Source/GenericGraphRuntime/Private/GenericGraphEdge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@ UGenericGraph* UGenericGraphEdge::GetGraph() const
{
return Graph;
}

#if WITH_EDITOR
void UGenericGraphEdge::SetNodeTitle(const FText& NewTitle)
{
NodeTitle = NewTitle;
}
#endif // #if WITH_EDITOR
Loading

0 comments on commit 5c847c6

Please sign in to comment.