Trying to add a combo graph editor.

This commit is contained in:
Jamie Greunbaum
2023-09-27 00:21:59 -04:00
parent bf43acf0dc
commit ea4dd54ec9
43 changed files with 6809 additions and 1 deletions
@@ -0,0 +1,434 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionGraphSchema.h"
#include "ComboActionGraph.h"
#include "FConnectionDrawingPolicy_ComboActionGraph.h"
#include "GraphEditorActions.h"
#include "Ed/EdComboActionGraphEdge.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Framework/Commands/GenericCommands.h"
#include "Nodes/ComboActionGraphEdge.h"
#include "Nodes/ComboActionGraphNode.h"
#define LOCTEXT_NAMESPACE "ComboActionGraph"
UEdGraphNode *FAssetSchemaAction_ComboActionGraphSchema_NewNode::PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode)
{
UEdGraphNode *ResultNode = nullptr;
if (NodeTemplate != nullptr)
{
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorNewNode", "Combo Action Graph Editor: New Node"));
ParentGraph->Modify();
if (FromPin != nullptr)
FromPin->Modify();
NodeTemplate->Rename(nullptr, ParentGraph);
ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode);
NodeTemplate->CreateNewGuid();
NodeTemplate->PostPlacedNewNode();
NodeTemplate->AllocateDefaultPins();
NodeTemplate->AutowireNewNode(FromPin);
NodeTemplate->NodePosX = Location.X;
NodeTemplate->NodePosY = Location.Y;
NodeTemplate->ComboActionGraphNode->SetFlags(EObjectFlags::RF_Transactional);
NodeTemplate->SetFlags(EObjectFlags::RF_Transactional);
ResultNode = NodeTemplate;
}
return ResultNode;
}
void FAssetSchemaAction_ComboActionGraphSchema_NewNode::AddReferencedObjects(FReferenceCollector &Collector)
{
FEdGraphSchemaAction::AddReferencedObjects(Collector);
Collector.AddReferencedObject(NodeTemplate);
}
UEdGraphNode *FAssetSchemaAction_ComboActionGraphSchema_NewEdge::PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode)
{
UEdGraphNode *ResultNode = nullptr;
if (NodeTemplate != nullptr)
{
const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorNewEdge", "Combo Action Graph Editor: New Edge"));
ParentGraph->Modify();
if (FromPin != nullptr)
FromPin->Modify();
NodeTemplate->Rename(nullptr, ParentGraph);
ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode);
NodeTemplate->CreateNewGuid();
NodeTemplate->PostPlacedNewNode();
NodeTemplate->AllocateDefaultPins();
NodeTemplate->AutowireNewNode(FromPin);
NodeTemplate->NodePosX = Location.X;
NodeTemplate->NodePosY = Location.Y;
NodeTemplate->ComboActionGraphEdge->SetFlags(EObjectFlags::RF_Transactional);
NodeTemplate->SetFlags(EObjectFlags::RF_Transactional);
ResultNode = NodeTemplate;
}
return ResultNode;
}
void FAssetSchemaAction_ComboActionGraphSchema_NewEdge::AddReferencedObjects(FReferenceCollector &Collector)
{
FEdGraphSchemaAction::AddReferencedObjects(Collector);
Collector.AddReferencedObject(NodeTemplate);
}
void UComboActionGraphSchema::GetBreakLinkToSubMenuActions(UToolMenu *Menu, UEdGraphPin *InGraphPin)
{
// Make sure we have a unique name for every entry in the list
TMap<FString, uint32> LinkTitleCount;
FToolMenuSection &Section = Menu->FindOrAddSection("ComboActionGraphAssetGraphSchemaPinActions");
// 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.ToString());
// 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;
Section.AddMenuEntry(NAME_None, Description, Description, FSlateIcon(), FUIAction(
FExecuteAction::CreateUObject(this, &UComboActionGraphSchema::BreakSinglePinLink, const_cast<UEdGraphPin*>(InGraphPin), *Links)));
}
}
void UComboActionGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder &ContextMenuBuilder) const
{
UComboActionGraph *Graph = CastChecked<UComboActionGraph>(ContextMenuBuilder.CurrentGraph->GetOuter());
if (Graph->NodeType == nullptr)
{
return;
}
const bool bNoParent = (ContextMenuBuilder.FromPin == NULL);
FText AddToolTip = LOCTEXT("NewMoutneaDialogueGraphNodeTooltip", "Add Dialogue Node here");
TSet<TSubclassOf<UComboActionGraphNode>> Visited;
FText Desc = Graph->NodeType.GetDefaultObject()->ContextMenuName;
FText NodeCategory = Graph->NodeType.GetDefaultObject()->GetNodeCategory();
if (Desc.IsEmpty())
{
FString Title = Graph->NodeType->GetName();
Title.RemoveFromEnd("_C");
Desc = FText::FromString(Title);
}
if (!Graph->NodeType->HasAnyClassFlags(CLASS_Abstract))
{
TSharedPtr<FAssetSchemaAction_ComboActionGraphSchema_NewNode> NewNodeAction(new FAssetSchemaAction_ComboActionGraphSchema_NewNode(NodeCategory, Desc, AddToolTip, 0));
NewNodeAction->NodeTemplate = NewObject<UEdComboActionGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
NewNodeAction->NodeTemplate->ComboActionGraphNode = NewObject<UComboActionGraphNode>(NewNodeAction->NodeTemplate, Graph->NodeType);
NewNodeAction->NodeTemplate->ComboActionGraphNode->Graph = Graph;
ContextMenuBuilder.AddAction(NewNodeAction);
Visited.Add(Graph->NodeType);
}
for (TObjectIterator<UClass> It; It; ++It)
{
if (It->IsChildOf(Graph->NodeType) && !It->HasAnyClassFlags(CLASS_Abstract) && !Visited.Contains(*It))
{
TSubclassOf<UComboActionGraphNode> NodeType = *It;
if (It->GetName().StartsWith("REINST") || It->GetName().StartsWith("SKEL"))
continue;
if (!Graph->GetClass()->IsChildOf(NodeType.GetDefaultObject()->CompatibleGraphType))
continue;
if (!NodeType.GetDefaultObject()->bAllowManualCreate)
continue;
Desc = NodeType.GetDefaultObject()->ContextMenuName;
AddToolTip = NodeType.GetDefaultObject()->GetDescription();
NodeCategory = NodeType.GetDefaultObject()->GetNodeCategory();
if (Desc.IsEmpty())
{
FString Title = NodeType->GetName();
Title.RemoveFromEnd("_C");
Desc = FText::FromString(Title);
}
TSharedPtr<FAssetSchemaAction_ComboActionGraphSchema_NewNode> Action(new FAssetSchemaAction_ComboActionGraphSchema_NewNode(NodeCategory, Desc, AddToolTip, 0));
Action->NodeTemplate = NewObject<UEdComboActionGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
Action->NodeTemplate->ComboActionGraphNode = NewObject<UComboActionGraphNode>(Action->NodeTemplate, NodeType);
Action->NodeTemplate->ComboActionGraphNode->Graph = Graph;
ContextMenuBuilder.AddAction(Action);
Visited.Add(NodeType);
}
}
}
void UComboActionGraphSchema::GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
{
if (Context->Pin)
{
{
FToolMenuSection& Section = Menu->AddSection("ComboActionGraphAssetGraphSchemaNodeActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions"));
// Only display the 'Break Links' option if there is a link to break!
if (Context->Pin->LinkedTo.Num() > 0)
{
Section.AddMenuEntry(FGraphEditorCommands::Get().BreakPinLinks);
// add sub menu for break link to
if (Context->Pin->LinkedTo.Num() > 1)
{
Section.AddSubMenu(
"BreakLinkTo",
LOCTEXT("BreakLinkTo", "Break Link To..."),
LOCTEXT("BreakSpecificLinks", "Break a specific link..."),
FNewToolMenuDelegate::CreateUObject((UComboActionGraphSchema *const)this, &UComboActionGraphSchema::GetBreakLinkToSubMenuActions, const_cast<UEdGraphPin*>(Context->Pin)));
}
else
{
((UComboActionGraphSchema *const)this)->GetBreakLinkToSubMenuActions(Menu, const_cast<UEdGraphPin*>(Context->Pin));
}
}
}
}
else if (Context->Node)
{
{
FToolMenuSection& Section = Menu->AddSection("ComboActionGraphAssetGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
Section.AddSeparator(FName(TEXT("Main Options")));
Section.AddMenuEntry(FGenericCommands::Get().Rename);
Section.AddSeparator(FName(TEXT("Other Options")));
Section.AddMenuEntry(FGenericCommands::Get().Delete);
Section.AddMenuEntry(FGenericCommands::Get().Cut);
Section.AddMenuEntry(FGenericCommands::Get().Copy);
Section.AddMenuEntry(FGenericCommands::Get().Duplicate);
Section.AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
}
}
Super::GetContextMenuActions(Menu, Context);
}
const FPinConnectionResponse UComboActionGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const
{
// Make sure the pins are not on the same node
if (A->GetOwningNode() == B->GetOwningNode())
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorSameNode", "Both are on the same node"));
}
// Compare the directions
if ((A->Direction == EGPD_Input) && (B->Direction == EGPD_Input))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorInput", "Can't connect input node to input node"));
}
else if ((A->Direction == EGPD_Output) && (B->Direction == EGPD_Output))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorOutput", "Can't connect output node to output node"));
}
// check for cycles
FComboActionNodeVisitorCycleChecker CycleChecker;
if (!CycleChecker.CheckForLoop(A->GetOwningNode(), B->GetOwningNode()))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorCycle", "Can't create a graph cycle"));
}
if (!CycleChecker.CheckForLoop(B->GetOwningNode(), A->GetOwningNode()))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorCycle", "Can't create a graph cycle"));
}
UEdComboActionGraphNode* EdNode_A = Cast<UEdComboActionGraphNode>(A->GetOwningNode());
UEdComboActionGraphNode* EdNode_B = Cast<UEdComboActionGraphNode>(B->GetOwningNode());
if (EdNode_A == nullptr || EdNode_B == nullptr)
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinError", "Not a valid UComboActionGraphEdNode"));
}
FText ErrorMessage;
if (A->Direction == EGPD_Input)
{
if (!EdNode_A->ComboActionGraphNode->CanCreateConnection(EdNode_B->ComboActionGraphNode, EGPD_Input, ErrorMessage))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
}
}
else
{
if (!EdNode_B->ComboActionGraphNode->CanCreateConnection(EdNode_A->ComboActionGraphNode, EGPD_Output, ErrorMessage))
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
}
}
if (EdNode_A->ComboActionGraphNode->GetGraph()->bEdgeEnabled)
{
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE, LOCTEXT("PinConnect", "Connect nodes with edge"));
}
else
{
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("PinConnect", "Connect nodes"));
}
}
bool UComboActionGraphSchema::CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const
{
UEdComboActionGraphNode *NodeA = Cast<UEdComboActionGraphNode>(A->GetOwningNode());
UEdComboActionGraphNode *NodeB = Cast<UEdComboActionGraphNode>(B->GetOwningNode());
if (NodeA == nullptr || NodeB == nullptr)
return false;
if (NodeA->GetInputPin() == nullptr || NodeA->GetOutputPin() == nullptr || NodeB->GetInputPin() == nullptr || NodeB->GetOutputPin() == nullptr)
return false;
UComboActionGraph* Graph = NodeA->ComboActionGraphNode->GetGraph();
FVector2D InitPos((NodeA->NodePosX + NodeB->NodePosX) / 2, (NodeA->NodePosY + NodeB->NodePosY) / 2);
FAssetSchemaAction_ComboActionGraphSchema_NewEdge Action;
Action.NodeTemplate = NewObject<UEdComboActionGraphEdge>(NodeA->GetGraph());
Action.NodeTemplate->SetEdge(NewObject<UComboActionGraphEdge>(Action.NodeTemplate, Graph->EdgeType));
UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(Action.PerformAction(NodeA->GetGraph(), nullptr, InitPos, false));
if (A->Direction == EEdGraphPinDirection::EGPD_Output)
{
EdgeNode->CreateConnections(NodeA, NodeB);
}
else
{
EdgeNode->CreateConnections(NodeB, NodeA);
}
return true;
}
FConnectionDrawingPolicy *UComboActionGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj) const
{
/*
if (const UMounteaDialogueGraphEditorSettings* MounteaDialogueGraphEditorSettings = GetMutableDefault<UMounteaDialogueGraphEditorSettings>())
{
if (MounteaDialogueGraphEditorSettings->AllowAdvancedWiring())
{
return new FConnectionDrawingPolicy_AdvancedMounteaDialogueGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
}
}
*/
return new FConnectionDrawingPolicy_ComboActionGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
}
FLinearColor UComboActionGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) const
{
return FColor::White;
}
void UComboActionGraphSchema::BreakNodeLinks(UEdGraphNode& TargetNode) const
{
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakNodeLinks", "Break Node Links"));
Super::BreakNodeLinks(TargetNode);
}
void UComboActionGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const
{
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakPinLinks", "Break Pin Links"));
Super::BreakPinLinks(TargetPin, bSendsNodeNotifcation);
}
void UComboActionGraphSchema::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const
{
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakSinglePinLink", "Break Pin Link"));
Super::BreakSinglePinLink(SourcePin, TargetPin);
}
UEdGraphPin *UComboActionGraphSchema::DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const
{
UEdComboActionGraphNode* EdNode = Cast<UEdComboActionGraphNode>(InTargetNode);
switch (InSourcePinDirection)
{
case EEdGraphPinDirection::EGPD_Input:
return EdNode->GetOutputPin();
case EEdGraphPinDirection::EGPD_Output:
return EdNode->GetInputPin();
default:
return nullptr;
}
}
bool UComboActionGraphSchema::SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const
{
return Cast<UEdComboActionGraphNode>(InTargetNode) != nullptr;
}
bool UComboActionGraphSchema::IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const
{
return CurrentCacheRefreshID != InVisualizationCacheID;
}
int32 UComboActionGraphSchema::GetCurrentVisualizationCacheID() const
{
return CurrentCacheRefreshID;
}
void UComboActionGraphSchema::ForceVisualizationCacheClear() const
{
CurrentCacheRefreshID++;
}
void UComboActionGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const
{
Super::CreateDefaultNodesForGraph(Graph);
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,164 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ComboActionGraphSchema.generated.h"
class FComboActionNodeVisitorCycleChecker
{
public:
/** Check whether a loop in the graph would be caused by linking the passed-in nodes */
bool CheckForLoop(UEdGraphNode *StartNode, UEdGraphNode *EndNode)
{
VisitedNodes.Add(StartNode);
if (!QuiCheckDirectConnections(StartNode, EndNode))
{
return false;
}
return TraverseInputNodesToRoot(EndNode);
}
private:
bool TraverseInputNodesToRoot(UEdGraphNode *Node)
{
VisitedNodes.Add(Node);
for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
{
UEdGraphPin *MyPin = Node->Pins[PinIndex];
if (MyPin->Direction == EGPD_Output)
{
for (int32 LinkedPinIndex = 0; LinkedPinIndex < MyPin->LinkedTo.Num(); ++LinkedPinIndex)
{
UEdGraphPin *OtherPin = MyPin->LinkedTo[LinkedPinIndex];
if (OtherPin)
{
UEdGraphNode *OtherNode = OtherPin->GetOwningNode();
if (VisitedNodes.Contains(OtherNode))
{
return false;
}
else
{
return TraverseInputNodesToRoot(OtherNode);
}
}
}
}
}
return true;
}
bool QuiCheckDirectConnections(UEdGraphNode *A, UEdGraphNode *B)
{
for (auto Itr : B->Pins)
{
if (A->Pins.Contains(Itr))
{
return false;
}
}
for (auto Itr : A->Pins)
{
if (B->Pins.Contains(Itr))
{
return false;
}
}
return true;
}
TSet<UEdGraphNode *> VisitedNodes;
};
/** Action to add a node to the graph */
USTRUCT()
struct FAssetSchemaAction_ComboActionGraphSchema_NewNode : public FEdGraphSchemaAction
{
GENERATED_BODY();
public:
FAssetSchemaAction_ComboActionGraphSchema_NewNode() : NodeTemplate(nullptr){}
FAssetSchemaAction_ComboActionGraphSchema_NewNode(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping)
: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr){}
virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
virtual void AddReferencedObjects(FReferenceCollector &Collector) override;
class UEdComboActionGraphNode *NodeTemplate;
};
USTRUCT()
struct FAssetSchemaAction_ComboActionGraphSchema_NewEdge : public FEdGraphSchemaAction
{
GENERATED_BODY();
public:
FAssetSchemaAction_ComboActionGraphSchema_NewEdge() : NodeTemplate(nullptr)
{}
FAssetSchemaAction_ComboActionGraphSchema_NewEdge(const FText &InNodeCategory, const FText &InMenuDesc, const FText &InToolTip, const int32 InGrouping)
: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr)
{}
virtual UEdGraphNode *PerformAction(class UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
virtual void AddReferencedObjects(FReferenceCollector &Collector) override;
class UEdComboActionGraphEdge *NodeTemplate;
};
UCLASS(MinimalAPI)
class UComboActionGraphSchema : public UEdGraphSchema
{
GENERATED_BODY()
public:
void GetBreakLinkToSubMenuActions(class UToolMenu* Menu, class UEdGraphPin* InGraphPin);
virtual EGraphType GetGraphType(const UEdGraph* TestEdGraph) const override { return EGraphType::GT_StateMachine; }
virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override;
virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override;
virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override;
virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override;
virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override;
virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override;
virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override;
virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const override;
virtual void BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const override;
virtual UEdGraphPin* DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const override;
virtual bool SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const override;
virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override;
virtual int32 GetCurrentVisualizationCacheID() const override;
virtual void ForceVisualizationCacheClear() const override;
virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override;
private:
static int32 CurrentCacheRefreshID;
};
@@ -0,0 +1,209 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "Ed/EdComboActionGraph.h"
#include "Ed/EdComboActionGraphEdge.h"
#include "Ed/EdComboActionGraphNode.h"
#include "ComboActionGraph.h"
#include "Nodes/ComboActionGraphNode.h"
#include "Nodes/ComboActionGraphEdge.h"
//#include "Helpers/MounteaDialogueGraphEditorHelpers.h"
//#include "Helpers/MounteaDialogueGraphEditorUtilities.h"
//#include "Helpers/MounteaDialogueSystemEditorBFC.h"
DEFINE_LOG_CATEGORY(LogEdComboActionGraph);
void UEdComboActionGraph::RebuildComboActionGraph()
{
UE_LOG(LogEdComboActionGraph, Warning, TEXT("UEdComboActionGraph::RebuildComboActionGraph has been called"));
UComboActionGraph *Graph = GetComboActionGraph();
Clear();
for (int i = 0; i < Nodes.Num(); ++i)
{
if (UEdComboActionGraphNode *EdNode = Cast<UEdComboActionGraphNode>(Nodes[i]))
{
if (EdNode->ComboActionGraphNode == nullptr)
continue;
UComboActionGraphNode *ComboActionGraphNode = EdNode->ComboActionGraphNode;
NodeMap.Add(ComboActionGraphNode, EdNode);
Graph->AllNodes.Add(ComboActionGraphNode);
//EdNode->SetDialogueNodeIndex( Graph->AllNodes.Find(EdNode->ComboActionGraphNode) );
for (int PinIdx = 0; PinIdx < EdNode->Pins.Num(); ++PinIdx)
{
UEdGraphPin* Pin = EdNode->Pins[PinIdx];
if (Pin->Direction != EEdGraphPinDirection::EGPD_Output)
continue;
for (int LinkToIdx = 0; LinkToIdx < Pin->LinkedTo.Num(); ++LinkToIdx)
{
UComboActionGraphNode *ChildNode = nullptr;
if (UEdComboActionGraphNode *EdNode_Child = Cast<UEdComboActionGraphNode>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
{
ChildNode = EdNode_Child->ComboActionGraphNode;
}
else if (UEdComboActionGraphEdge *EdNode_Edge = Cast<UEdComboActionGraphEdge>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
{
UEdComboActionGraphNode *Child = EdNode_Edge->GetEndNode();;
if (Child != nullptr)
{
ChildNode = Child->ComboActionGraphNode;
}
}
if (ChildNode != nullptr)
{
ComboActionGraphNode->ChildrenNodes.Add(ChildNode);
ChildNode->ParentNodes.Add(ComboActionGraphNode);
}
else
{
UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildComboActionGraph] Can't find child node"));
}
}
}
}
else if (UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(Nodes[i]))
{
UEdComboActionGraphNode *StartNode = EdgeNode->GetStartNode();
UEdComboActionGraphNode *EndNode = EdgeNode->GetEndNode();
UComboActionGraphEdge *Edge = EdgeNode->ComboActionGraphEdge;
if (StartNode == nullptr || EndNode == nullptr || Edge == nullptr)
{
UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildMounteaDialogueGraph] Add edge failed."));
continue;
}
EdgeMap.Add(Edge, EdgeNode);
Edge->Graph = Graph;
Edge->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
Edge->StartNode = StartNode->ComboActionGraphNode;
Edge->EndNode = EndNode->ComboActionGraphNode;
Edge->StartNode->Edges.Add(Edge->EndNode, Edge);
}
}
for (int i = 0; i < Graph->AllNodes.Num(); ++i)
{
UComboActionGraphNode *Node = Graph->AllNodes[i];
if (Node->ParentNodes.Num() == 0)
{
Graph->RootNodes.Add(Node);
SortNodes(Node);
}
Node->Graph = Graph;
Node->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
}
Graph->RootNodes.Sort([&](const UComboActionGraphNode &L, const UComboActionGraphNode &R)
{
UEdComboActionGraphNode* EdNode_LNode = NodeMap[&L];
UEdComboActionGraphNode* EdNode_RNode = NodeMap[&R];
return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
});
}
UComboActionGraph *UEdComboActionGraph::GetComboActionGraph() const
{
return CastChecked<UComboActionGraph>(GetOuter());
}
bool UEdComboActionGraph::Modify(bool bAlwaysMarkDirty)
{
bool Rtn = Super::Modify(bAlwaysMarkDirty);
this->GetComboActionGraph()->Modify();
for (int32 i = 0; i < Nodes.Num(); ++i)
{
Nodes[i]->Modify();
}
return Rtn;
}
void UEdComboActionGraph::PostEditUndo()
{
NotifyGraphChanged();
Super::PostEditUndo();
}
//void UEdComboActionGraph::SetDialogueEditorPtr(TWeakPtr<FAssetEditor_MounteaDialogueGraph> NewPtr)
//{
// DialogueEditorPtr = NewPtr;
//}
//bool UEdComboActionGraph::JumpToNode(const UMounteaDialogueGraphNode* Node)
//{
// return FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(DialogueEditorPtr, *NodeMap.Find(Node));
//}
void UEdComboActionGraph::Clear()
{
UComboActionGraph *Graph = this->GetComboActionGraph();
Graph->ClearGraph();
this->NodeMap.Reset();
this->EdgeMap.Reset();
for (int i = 0; i < this->Nodes.Num(); ++i)
{
if (UEdComboActionGraphNode *EdNode = Cast<UEdComboActionGraphNode>(Nodes[i]))
{
UComboActionGraphNode *MounteaDialogueGraphNode = EdNode->ComboActionGraphNode;
MounteaDialogueGraphNode->ParentNodes.Reset();
MounteaDialogueGraphNode->ChildrenNodes.Reset();
MounteaDialogueGraphNode->Edges.Reset();
}
}
}
void UEdComboActionGraph::SortNodes(UComboActionGraphNode *RootNode)
{
int Level = 0;
TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
TArray<UComboActionGraphNode*> NextLevelNodes;
while (CurrLevelNodes.Num() != 0)
{
int32 LevelWidth = 0;
for (int i = 0; i < CurrLevelNodes.Num(); ++i)
{
UComboActionGraphNode *Node = CurrLevelNodes[i];
auto Comp = [&](const UComboActionGraphNode &L, const UComboActionGraphNode &R)
{
UEdComboActionGraphNode *EdNode_LNode = NodeMap[&L];
UEdComboActionGraphNode *EdNode_RNode = NodeMap[&R];
return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
};
Node->ChildrenNodes.Sort(Comp);
Node->ParentNodes.Sort(Comp);
for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
{
NextLevelNodes.Add(Node->ChildrenNodes[j]);
}
}
CurrLevelNodes = NextLevelNodes;
NextLevelNodes.Reset();
++Level;
}
}
@@ -0,0 +1,49 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "EdGraph/EdGraph.h"
#include "EdComboActionGraph.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogEdComboActionGraph, Log, All);
UCLASS()
class COMBOINPUT_API UEdComboActionGraph : public UEdGraph
{
GENERATED_BODY()
public:
virtual void RebuildComboActionGraph();
UComboActionGraph *GetComboActionGraph() const;
virtual bool Modify(bool bAlwaysMarkDirty) override;
virtual void PostEditUndo() override;
//TWeakPtr<FAssetEditor_ComboActionGraph> GetDialogueEditorPtr() const { return DialogueEditorPtr; }
//void SetDialogueEditorPtr(TWeakPtr<FAssetEditor_ComboActionGraph> NewPtr);
//void ResetDialogueEditorPtr() { DialogueEditorPtr.Reset(); }
//bool JumpToNode(const class UComboActionGraphNode *Node);
public:
UPROPERTY(Transient)
TMap<class UComboActionGraphNode*, class UEdComboActionGraphNode*> NodeMap;
UPROPERTY(Transient)
TMap<class UComboActionGraphEdge*, class UEdComboActionGraphEdge*> EdgeMap;
protected:
void Clear();
void SortNodes(UComboActionGraphNode *RootNode);
private:
/** Pointer back to the Dialogue editor that owns us */
//TWeakPtr<FAssetEditor_ComboActionGraph> DialogueEditorPtr;
};
@@ -0,0 +1,83 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "EdComboActionGraphEdge.h"
#include "EdComboActionGraphNode.h"
#include "Nodes/ComboActionGraphEdge.h"
void UEdComboActionGraphEdge::SetEdge(UComboActionGraphEdge *Edge)
{
this->ComboActionGraphEdge = Edge;
}
void UEdComboActionGraphEdge::AllocateDefaultPins()
{
UEdGraphPin* Inputs = this->CreatePin(EGPD_Input, TEXT("Edge"), FName(), TEXT("In"));
Inputs->bHidden = true;
UEdGraphPin* Outputs = this->CreatePin(EGPD_Output, TEXT("Edge"), FName(), TEXT("Out"));
Outputs->bHidden = true;
}
FText UEdComboActionGraphEdge::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return Super::GetNodeTitle(TitleType);
}
void UEdComboActionGraphEdge::PinConnectionListChanged(UEdGraphPin *Pin)
{
if (Pin->LinkedTo.Num() == 0)
{
// Commit suicide; transitions must always have an input and output connection
Modify();
// Our parent graph will have our graph in SubGraphs so needs to be modified to record that.
if (UEdGraph *ParentGraph = GetGraph())
{
ParentGraph->Modify();
}
DestroyNode();
}
}
void UEdComboActionGraphEdge::PrepareForCopying()
{
this->ComboActionGraphEdge->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
}
void UEdComboActionGraphEdge::CreateConnections(UEdComboActionGraphNode *Start, UEdComboActionGraphNode *End)
{
Pins[0]->Modify();
Pins[0]->LinkedTo.Empty();
Start->GetOutputPin()->Modify();
Pins[0]->MakeLinkTo(Start->GetOutputPin());
// This to next
Pins[1]->Modify();
Pins[1]->LinkedTo.Empty();
End->GetInputPin()->Modify();
Pins[1]->MakeLinkTo(End->GetInputPin());
}
UEdComboActionGraphNode *UEdComboActionGraphEdge::GetStartNode()
{
if (Pins[0]->LinkedTo.Num() > 0)
{
return Cast<UEdComboActionGraphNode>(Pins[0]->LinkedTo[0]->GetOwningNode());
}
return nullptr;
}
UEdComboActionGraphNode *UEdComboActionGraphEdge::GetEndNode()
{
if (Pins[1]->LinkedTo.Num() > 0)
{
return Cast<UEdComboActionGraphNode>(Pins[1]->LinkedTo[0]->GetOwningNode());
}
return nullptr;
}
@@ -0,0 +1,45 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "EdGraph/EdGraphNode.h"
#include "EdComboActionGraphEdge.generated.h"
/**
*
*/
UCLASS(MinimalAPI)
class UEdComboActionGraphEdge : public UEdGraphNode
{
GENERATED_BODY()
public:
UPROPERTY()
class UEdGraph *Graph;
UPROPERTY(VisibleAnywhere, Instanced, Category="Combo Action Graph")
class UComboActionGraphEdge *ComboActionGraphEdge;
public:
void SetEdge(class UComboActionGraphEdge *Edge);
virtual void AllocateDefaultPins() override;
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
virtual void PinConnectionListChanged(UEdGraphPin *Pin) override;
virtual void PrepareForCopying() override;
virtual UEdGraphPin *GetInputPin() const { return Pins[0]; }
virtual UEdGraphPin *GetOutputPin() const { return Pins[1]; }
void CreateConnections(class UEdComboActionGraphNode *Start, class UEdComboActionGraphNode* End);
class UEdComboActionGraphNode *GetStartNode();
class UEdComboActionGraphNode *GetEndNode();
};
@@ -0,0 +1,169 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "EdComboActionGraphNode.h"
#include "Ed/EdComboActionGraph.h"
#include "Helpers/ComboActionEditorBFC.h"
#include "Nodes/ComboActionGraphNode.h"
#include "Settings/ComboActionGraphEditorSettings.h"
#include "Settings/FComboActionGraphEditorStyle.h"
#define LOCTEXT_NAMESPACE "UEdComboActionGraphNode"
DEFINE_LOG_CATEGORY(LogEdComboActionGraphNode);
UEdComboActionGraphNode::UEdComboActionGraphNode()
{
bCanRenameNode = true;
bAllowCopy = true;
bAllowDelete = true;
bAllowDuplicate = true;
bAllowPaste = true;
}
UEdComboActionGraph *UEdComboActionGraphNode::GetEdComboActionGraph() const
{
return Cast<UEdComboActionGraph>(this->GetGraph());
};
void UEdComboActionGraphNode::AllocateDefaultPins()
{
if (this->ComboActionGraphNode == nullptr)
{
UE_LOG(LogEdComboActionGraphNode, Error, TEXT("[AllocateDefaultPins] Cannot find Owning Graph Node!"));
return;
}
if (this->ComboActionGraphNode->bAllowInputNodes)
{
this->CreatePin(EGPD_Input, "MultipleNodes", FName(), TEXT("In"));
}
if (this->ComboActionGraphNode->bAllowOutputNodes)
{
this->CreatePin(EGPD_Output, "MultipleNodes", FName(), TEXT("Out"));
}
}
FText UEdComboActionGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
return UComboActionEditorBFC::GetNodeTitle(this->ComboActionGraphNode);
}
void UEdComboActionGraphNode::PrepareForCopying()
{
this->ComboActionGraphNode->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
}
void UEdComboActionGraphNode::AutowireNewNode(UEdGraphPin* FromPin)
{
Super::AutowireNewNode(FromPin);
if (FromPin != nullptr)
{
if (GetSchema()->TryCreateConnection(FromPin, GetInputPin()))
{
FromPin->GetOwningNode()->NodeConnectionListChanged();
}
}
}
FLinearColor UEdComboActionGraphNode::GetBackgroundColor() const
{
// Getting Node colour based on the Settings if any found, otherwise use this logic
if (UComboActionGraphEditorSettings *GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
{
FLinearColor ReturnColour;
if (GraphEditorSettings->FindNodeBackgroundColourOverride(this->ComboActionGraphNode->GetClass(), ReturnColour))
{
return ReturnColour;
}
}
return this->ComboActionGraphNode ? this->ComboActionGraphNode->GetBackgroundColor() : FLinearColor::Black;
}
UEdGraphPin* UEdComboActionGraphNode::GetInputPin() const
{
return Pins[0];
}
UEdGraphPin* UEdComboActionGraphNode::GetOutputPin() const
{
if (Pins.IsValidIndex(1))
{
return Pins[1];
}
return Pins[0];
}
bool UEdComboActionGraphNode::CanUserDeleteNode() const
{
if(!Super::CanUserDeleteNode())
{
return false;
}
if (this->ComboActionGraphNode)
{
return this->ComboActionGraphNode->bAllowDelete;
}
return bAllowDelete;
}
bool UEdComboActionGraphNode::CanDuplicateNode() const
{
if(!Super::CanUserDeleteNode())
{
return false;
}
if (this->ComboActionGraphNode)
{
return this->ComboActionGraphNode->bAllowCopy;
}
return bAllowCopy;
}
bool UEdComboActionGraphNode::CanUserPasteNodes() const
{
if (this->ComboActionGraphNode)
{
return this->ComboActionGraphNode->bAllowPaste;
}
return bAllowPaste;
}
FText UEdComboActionGraphNode::GetTooltipText() const
{
if (this->ComboActionGraphNode)
{
return this->ComboActionGraphNode->GetNodeTooltipText();
}
return NSLOCTEXT("UEdComboActionGraphNode", "DefaultToolTip", "Mountea Dialogue Node");
}
FSlateIcon UEdComboActionGraphNode::GetIconAndTint(FLinearColor& OutColor) const
{
static const FSlateIcon Icon = FSlateIcon(FComboActionGraphEditorStyle::GetAppStyleSetName(), "MDSStyleSet.Node.Icon.small");
OutColor = this->ComboActionGraphNode->GetBackgroundColor();
return Icon;
}
void UEdComboActionGraphNode::PostEditUndo()
{
Super::PostEditUndo();
}
void UEdComboActionGraphNode::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,60 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "SEdComboActionGraphNode.h"
#include "EdGraph/EdGraphNode.h"
#include "EdComboActionGraphNode.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogEdComboActionGraphNode, Log, All);
/**
*
*/
UCLASS(MinimalAPI)
class UEdComboActionGraphNode : public UEdGraphNode
{
GENERATED_BODY()
public:
UEdComboActionGraphNode();
class UEdComboActionGraph *GetEdComboActionGraph() const;
virtual void AllocateDefaultPins() override;
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
virtual void PrepareForCopying() override;
virtual void AutowireNewNode(UEdGraphPin *FromPin) override;
virtual FLinearColor GetBackgroundColor() const;
virtual UEdGraphPin *GetInputPin() const;
virtual UEdGraphPin *GetOutputPin() const;
virtual bool CanUserDeleteNode() const override;
virtual bool CanDuplicateNode() const override;
virtual bool CanUserPasteNodes() const;
virtual FText GetTooltipText() const override;
virtual FSlateIcon GetIconAndTint(FLinearColor &OutColor) const override;
#if WITH_EDITOR
virtual void PostEditUndo() override;
virtual void PostEditChangeProperty(FPropertyChangedEvent &PropertyChangedEvent) override;
#endif
UPROPERTY(VisibleAnywhere, Instanced, Category="Combo Action Graph")
class UComboActionGraphNode *ComboActionGraphNode;
SEdComboActionGraphNode *SEdNode;
private:
bool bAllowCopy;
bool bAllowDelete;
bool bAllowDuplicate;
bool bAllowPaste;
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,89 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "SGraphNode.h"
#include "Settings\ComboActionGraphEditorSettings.h"
class SEdComboActionGraphNode : public SGraphNode
{
public:
SLATE_BEGIN_ARGS(SEdComboActionGraphNode) {}
SLATE_END_ARGS()
void Construct(const FArguments &InArgs, class UEdComboActionGraphNode *InNode);
virtual void OnMouseEnter(const FGeometry &MyGeometry, const FPointerEvent &MouseEvent) override;
virtual void OnMouseLeave(const FPointerEvent &MouseEvent) override;
const FSlateBrush *GetIndexBrush() const;
virtual void UpdateGraphNode() override;
virtual void CreatePinWidgets() override;
virtual void AddPin(const TSharedRef<SGraphPin> &PinToAdd) override;
virtual bool IsNameReadOnly() const override;
void OnNameTextCommitted(const FText &InText, ETextCommit::Type CommitInfo);
virtual const FSlateBrush *GetNodeTypeBrush () const;
virtual const FSlateBrush *GetTextNodeTypeBrush () const;
virtual FSlateColor GetBorderBackgroundColor() const;
virtual FSlateColor GetBorderFrontColor() const;
virtual FSlateColor GetNodeTitleBackgroundColor() const;
virtual FSlateColor GetDecoratorsBackgroundColor() const;
virtual FSlateColor GetPinsDockColor() const;
virtual EVisibility GetDragOverMarkerVisibility() const;
virtual const FSlateBrush *GetNameIcon() const;
virtual const FSlateBrush *GetInheritsImageBrush() const;
virtual FSlateColor GetInheritsImageTint() const;
const FSlateBrush *GetBulletPointImageBrush() const;
virtual FText GetIndexOverlayTooltipText() const;
virtual FText GetIndexText() const;
EVisibility GetIndexSlotVisibility() const;
FVector2D GetIndexSlotOffset() const;
FVector2D GetIndexSlotSize() const;
virtual void OnIndexHoverStateChanged(bool bArg) const;
virtual FSlateColor GetOverlayWidgetBackgroundColor(bool bArg) const;
bool HasGraphDecorators() const;
bool HasNodeDecorators() const;
virtual FText GetDecoratorsText() const;
virtual FText GetNumberOfDecorators() const;
virtual FText GetDecoratorsInheritanceText() const;
EVisibility ShowImplementsOnlySlot_Unified() const;
EVisibility ShowInheritsDecoratorsSlot_Unified() const;
EVisibility ShowImplementsOnlySlot_Stack() const;
EVisibility ShowInheritsDecoratorsSlot_Stack() const;
EVisibility ShowAllDecorators() const;
EVisibility ShowDecoratorsBottomPadding() const;
FSlateColor GetImplementsRowColor() const;
FSlateColor GetBulletPointsImagePointColor() const;
virtual EComboActionDecoratorsInfoStyle GetDecoratorsStyle() const;
EVisibility GetStackVisibility() const;
EVisibility GetUnifiedVisibility() const;
FText GetTooltipText() const;
protected:
TSharedPtr<SBorder> NodeBody;
TSharedPtr<SHorizontalBox> OutputPinBox;
class UComboActionGraphEditorSettings *GraphEditorSettings = nullptr;
FLinearColor NodeInnerColor;
FLinearColor PinsDockColor;
};
@@ -0,0 +1,36 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "SEdComboActionGraphNodeIndex.h"
#include "Settings/FComboActionGraphEditorStyle.h"
void SEdComboActionGraphNodeIndex::Construct(const FArguments &InArgs)
{
const FSlateBrush* CircleBrush = FComboActionGraphEditorStyle::GetBrush(TEXT("MDSStyleSet.Node.IndexCircle"));
ChildSlot
[
SNew(SOverlay)
+SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
// Add a dummy box here to make sure the widget doesnt get smaller than the brush
SNew(SBox)
.WidthOverride(CircleBrush->ImageSize.X)
.HeightOverride(CircleBrush->ImageSize.Y)
]
+SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SBorder)
.BorderImage(CircleBrush)
.BorderBackgroundColor(this, &SEdComboActionGraphNodeIndex::GetBackgroundColor)
.Padding(FMargin(4.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
]
];
}
@@ -0,0 +1,33 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
class SEdComboActionGraphNodeIndex : public SCompoundWidget
{
public:
/** Delegate event fired when the hover state of this widget changes */
DECLARE_DELEGATE_OneParam(FOnHoverStateChanged, bool /* bHovered */);
/** Delegate used to receive the background color of the node, depending on hover state and state of other siblings */
DECLARE_DELEGATE_RetVal_OneParam(FSlateColor, FOnGetBackgroundColor, bool /* bHovered */);
SLATE_BEGIN_ARGS(SEdComboActionGraphNodeIndex) {}
SLATE_ATTRIBUTE(TSharedPtr<SWidget>, OverlayBody)
// Events
SLATE_EVENT(FOnHoverStateChanged, OnHoverStateChanged)
SLATE_EVENT(FOnGetBackgroundColor, OnGetBackgroundColor)
SLATE_END_ARGS()
void Construct(const FArguments &InArgs);
/** Get the color we use to display the rounded border */
FSlateColor GetBackgroundColor() const { return FSlateColor::UseForeground(); }
private:
/** The OverlayBody used for this widget*/
TSharedPtr<SWidget> OverlayBody;
};
@@ -0,0 +1,208 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "FConnectionDrawingPolicy_ComboActionGraph.h"
#include "Ed/EdComboActionGraphEdge.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Settings/ComboActionGraphEditorSettings.h"
#include "Settings/FComboActionGraphEditorStyle.h"
DEFINE_LOG_CATEGORY(LogConnectionDrawingPolicy_ComboActionGraph);
FConnectionDrawingPolicy_ComboActionGraph::FConnectionDrawingPolicy_ComboActionGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect &InClippingRect, FSlateWindowElementList &InDrawElements, UEdGraph *InGraphObj)
: FKismetConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements, InGraphObj)
, GraphObj(InGraphObj)
{
if (const UComboActionGraphEditorSettings* GraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
{
switch (GraphEditorSettings->GetArrowType())
{
case EComboActionArrowType::SimpleArrow:
ArrowImage = FComboActionGraphEditorStyle::GetBrush(TEXT("MDSStyleSet.Graph.SimpleArrow"));
break;
case EComboActionArrowType::HollowArrow:
ArrowImage = FComboActionGraphEditorStyle::GetBrush(TEXT("MDSStyleSet.Graph.HollowArrow"));
break;
case EComboActionArrowType::FancyArrow:
ArrowImage = FComboActionGraphEditorStyle::GetBrush(TEXT("MDSStyleSet.Graph.FancyArrow"));
break;
case EComboActionArrowType::Bubble:
ArrowImage = FComboActionGraphEditorStyle::GetBrush(TEXT("MDSStyleSet.Graph.Bubble"));
break;
case EComboActionArrowType::None:
default:
ArrowImage = nullptr;
}
}
else
{
ArrowImage = FAppStyle::GetBrush( TEXT("GenericPlay") );
}
ArrowRadius = ArrowImage ? ArrowImage->ImageSize * ZoomFactor * 0.5f : FVector2D(0.f);
MidpointImage = nullptr;
MidpointRadius = FVector2D::ZeroVector;
HoverDeemphasisDarkFraction = 0.8f;
BubbleImage = FAppStyle::GetBrush( TEXT("Graph.Arrow") );
}
void FConnectionDrawingPolicy_ComboActionGraph::DetermineWiringStyle(UEdGraphPin *OutputPin, UEdGraphPin *InputPin, FConnectionParams &Params)
{
Params.AssociatedPin1 = OutputPin;
Params.AssociatedPin2 = InputPin;
const UComboActionGraphEditorSettings *MounteaDialogueGraphEditorSettings = GetDefault<UComboActionGraphEditorSettings>();
if (MounteaDialogueGraphEditorSettings)
{
Params.WireThickness = MounteaDialogueGraphEditorSettings->GetWireWidth();
}
else
{
Params.WireThickness = 1.f;
}
const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0;
if (bDeemphasizeUnhoveredPins)
{
ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor);
}
}
void FConnectionDrawingPolicy_ComboActionGraph::Draw(TMap<TSharedRef<SWidget>, FArrangedWidget> &InPinGeometries, FArrangedChildren &ArrangedNodes)
{
// Build an acceleration structure to quickly find geometry for the nodes
NodeWidgetMap.Empty();
for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex)
{
FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex];
TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(CurWidget.Widget);
NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex);
}
// Now draw
FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes);
}
void FConnectionDrawingPolicy_ComboActionGraph::DrawSplineWithArrow(const FGeometry &StartGeom, const FGeometry &EndGeom, const FConnectionParams &Params)
{
// 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);
this->DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params);
}
void FConnectionDrawingPolicy_ComboActionGraph::DrawSplineWithArrow(const FVector2D &StartPoint, const FVector2D &EndPoint, const FConnectionParams &Params)
{
// bUserFlag1 indicates that we need to reverse the direction of connection (used by debugger)
const FVector2D &P0 = Params.bUserFlag1 ? EndPoint : StartPoint;
const FVector2D &P1 = Params.bUserFlag1 ? StartPoint : EndPoint;
UE_LOG(LogConnectionDrawingPolicy_ComboActionGraph, Verbose, TEXT("%s I %s"), *P0.ToString(), *P1.ToString());
FConnectionParams NewParams = Params;
//NewParams.bDrawBubbles = true;
if (const UComboActionGraphEditorSettings *MounteaDialogueGraphEditorSettings = GetMutableDefault<UComboActionGraphEditorSettings>())
{
NewParams.WireThickness = MounteaDialogueGraphEditorSettings->GetWireWidth();
}
Internal_DrawLineWithArrow(P0, P1, NewParams);
}
void FConnectionDrawingPolicy_ComboActionGraph::DrawPreviewConnector(const FGeometry &PinGeometry, const FVector2D &StartPoint, const FVector2D &EndPoint, UEdGraphPin* Pin)
{
FConnectionParams Params;
DetermineWiringStyle(Pin, nullptr, /*inout*/ Params);
if (Pin->Direction == EEdGraphPinDirection::EGPD_Output)
{
DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, EndPoint), EndPoint, Params);
}
else
{
DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, StartPoint), StartPoint, Params);
}
}
FVector2D FConnectionDrawingPolicy_ComboActionGraph::ComputeSplineTangent(const FVector2D &Start, const FVector2D &End) const
{
const FVector2D Delta = End - Start;
const FVector2D NormDelta = Delta.GetSafeNormal();
return NormDelta;
}
void FConnectionDrawingPolicy_ComboActionGraph::DetermineLinkGeometry(FArrangedChildren &ArrangedNodes, TSharedRef<SWidget> &OutputPinWidget, UEdGraphPin *OutputPin, UEdGraphPin *InputPin, FArrangedWidget *&StartWidgetGeometry, FArrangedWidget *&EndWidgetGeometry)
{
if (UEdComboActionGraphEdge *EdgeNode = Cast<UEdComboActionGraphEdge>(InputPin->GetOwningNode()))
{
UEdComboActionGraphNode* Start = EdgeNode->GetStartNode();
UEdComboActionGraphNode* End = EdgeNode->GetEndNode();
if (Start != nullptr && End != nullptr)
{
int32* StartNodeIndex = NodeWidgetMap.Find(Start);
int32* EndNodeIndex = NodeWidgetMap.Find(End);
if (StartNodeIndex != nullptr && EndNodeIndex != nullptr)
{
StartWidgetGeometry = &(ArrangedNodes[*StartNodeIndex]);
EndWidgetGeometry = &(ArrangedNodes[*EndNodeIndex]);
}
}
}
else
{
StartWidgetGeometry = PinGeometries->Find(OutputPinWidget);
if (TSharedPtr<SGraphPin>* pTargetWidget = PinToPinWidgetMap.Find(InputPin))
{
TSharedRef<SGraphPin> InputWidget = (*pTargetWidget).ToSharedRef();
EndWidgetGeometry = PinGeometries->Find(InputWidget);
}
}
}
void FConnectionDrawingPolicy_ComboActionGraph::Internal_DrawLineWithArrow(const FVector2D &StartAnchorPoint, const FVector2D &EndAnchorPoint, const FConnectionParams &Params)
{
const float LineSeparationAmount = 4.5f;
const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint;
const FVector2D UnitDelta = DeltaPos.GetSafeNormal();
const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
// Come up with the final start/end points
const FVector2D DirectionBias = Normal * LineSeparationAmount;
const FVector2D LengthBias = ArrowRadius.X * UnitDelta;
const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias;
const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias;
// Draw a line/spline
DrawConnection(WireLayerID, StartPoint, EndPoint, Params);
// Draw the arrow
if (ArrowImage)
{
const FVector2D ArrowDrawPos = EndPoint - ArrowRadius;
const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X);
FSlateDrawElement::MakeRotatedBox(
DrawElementsList,
ArrowLayerID,
FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor),
ArrowImage,
ESlateDrawEffect::None,
AngleInRadians,
TOptional<FVector2D>(),
FSlateDrawElement::RelativeToElement,
Params.WireColor
);
}
}
@@ -0,0 +1,36 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "BlueprintConnectionDrawingPolicy.h"
#include "ConnectionDrawingPolicy.h"
DECLARE_LOG_CATEGORY_EXTERN(LogConnectionDrawingPolicy_ComboActionGraph, Log, All);
class FConnectionDrawingPolicy_ComboActionGraph : public FKismetConnectionDrawingPolicy
{
public:
FConnectionDrawingPolicy_ComboActionGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj);
virtual ~FConnectionDrawingPolicy_ComboActionGraph() {};
// FConnectionDrawingPolicy interface
virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) override;
virtual void Draw(TMap<TSharedRef<SWidget>, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes) override;
virtual void DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) override;
virtual void DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, const FConnectionParams& Params) override;
virtual void DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) override;
virtual FVector2D ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const override;
virtual void DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, TSharedRef<SWidget>& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FArrangedWidget*& StartWidgetGeometry, FArrangedWidget*& EndWidgetGeometry) override;
// End of FConnectionDrawingPolicy interface
protected:
void Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params);
protected:
UEdGraph *GraphObj;
TMap<UEdGraphNode*, int32> NodeWidgetMap;
};
@@ -0,0 +1,86 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Nodes/ComboActionGraphNode.h"
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
#include "Settings/ComboActionGraphEditorSettings.h"
#include "ComboActionEditorBFC.generated.h"
/**
* Editor Only helper functions.
*/
UCLASS()
class UComboActionEditorBFC : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
#if WITH_EDITOR
static FText GetNodeTitle(UComboActionGraphNode *Node)
{
if (!Node) return FText::FromString("Invalid Node");
const UComboActionGraphEditorSettings *Settings = GetDefault<UComboActionGraphEditorSettings>();
if (Settings)
{
if (Settings->ShowAutomaticNames())
{
if (const UComboActionGraphNode_ActionNodeBase *DialogueNodeBase = Cast<UComboActionGraphNode_ActionNodeBase>(Node))
{
if (DialogueNodeBase->GetDataTable())
{
FString ReturnString;
DialogueNodeBase->GetRowName().ToString(ReturnString);
return FText::FromString(ReturnString);
}
}
return Node->GetInternalName();
}
}
return Node->GetNodeTitle();
}
static EComboActionNodeTheme GetNodeTheme()
{
const UComboActionGraphEditorSettings *Settings = GetDefault<UComboActionGraphEditorSettings>();
if (Settings != nullptr)
{
return Settings->GetNodeTheme();
}
return EComboActionNodeTheme::DarkTheme;
}
static void TriggerPreviewRefresh(TArray<UObject*> NodeObjects)
{
for (auto Itr : NodeObjects)
{
UEdComboActionGraphNode *SelectedNode = Cast<UEdComboActionGraphNode>(Itr);
if (!SelectedNode || !SelectedNode->ComboActionGraphNode)
{
continue;
}
UComboActionGraphNode_ActionNodeBase *DialogueNodeBase = Cast<UComboActionGraphNode_ActionNodeBase>(SelectedNode->ComboActionGraphNode);
if (!DialogueNodeBase)
{
continue;
}
DialogueNodeBase->UpdatePreviews();
}
}
#endif
};
@@ -0,0 +1,92 @@
#pragma once
#include "CoreMinimal.h"
namespace ComboActionGraphColors
{
namespace NodeBody
{
constexpr FLinearColor Default(0.1f, 0.1f, 0.1f);
constexpr FLinearColor Root(0.5f, 0.5f, 0.5f, 0.1f);
constexpr FLinearColor Error(1.0f, 0.0f, 0.0f);
}
namespace DecoratorsBody
{
constexpr FLinearColor Default(0.1f, 0.1f, 0.1f);
}
namespace NodeBorder
{
constexpr FLinearColor Inactive(0.08f, 0.08f, 0.08f);
constexpr FLinearColor Root(0.2f, 0.2f, 0.2f, 0.2f);
constexpr FLinearColor Selected(1.00f, 0.08f, 0.08f);
constexpr FLinearColor ActiveDebugging(1.0f, 1.0f, 0.0f);
constexpr FLinearColor InactiveDebugging(0.4f, 0.4f, 0.0f);
constexpr FLinearColor HighlightAbortRange0(0.0f, 0.22f, 0.4f);
constexpr FLinearColor HighlightAbortRange1(0.0f, 0.4f, 0.22f);
constexpr FLinearColor Disconnected(0.f, 0.f, 0.f);
constexpr FLinearColor BrokenWithParent(1.f, 0.f, 1.f);
constexpr FLinearColor QuickFind(0.f, 0.8f, 0.f);
}
namespace Pin
{
constexpr FLinearColor Diff(0.9f, 0.2f, 0.15f);
constexpr FLinearColor Hover(1.0f, 0.7f, 0.0f);
constexpr FLinearColor Default(0.02f, 0.02f, 0.02f);
constexpr FLinearColor SingleNode(0.02f, 0.02f, 0.02f);
}
namespace Connection
{
constexpr FLinearColor Default(1.0f, 1.0f, 1.0f);
}
namespace Action
{
constexpr FLinearColor DragMarker(1.0f, 1.0f, 0.2f);
}
namespace Overlay
{
constexpr FLinearColor LightTheme(1.f, 1.f, 1.f, 0.45f);
constexpr FLinearColor DarkTheme(0.f, 0.f, 0.f, 0.9f);
}
namespace PinsDock
{
constexpr FLinearColor DarkTheme(0.075f, 0.075f, 0.075f, 1.f);
constexpr FLinearColor LightTheme(0.075f, 0.075f, 0.075f, 1.f);
}
namespace ValidationGraph
{
constexpr FLinearColor LightTheme(0.1f, 0.1f, 0.1f, 1.f);
constexpr FLinearColor DarkTheme(0.05f, 0.05f, 0.05f, 1.f);
}
namespace IndexBorder
{
constexpr FLinearColor NormalState(0.05f, 0.05f, 0.05f, 1.f);
constexpr FLinearColor HoveredState(0.05f, 0.05f, 0.05f, 1.f);
}
namespace BulletPointsColors
{
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 1.f);
constexpr FLinearColor Disabled(0.8f, 0.8f, 0.8f, 0.2f);
}
namespace TextColors
{
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 1.f);
constexpr FLinearColor Disabled(0.8f, 0.8f, 0.8f, 0.2f);
}
namespace Previews
{
constexpr FLinearColor Normal(0.8f, 0.8f, 0.8f, 0.05f);
constexpr FLinearColor Invalid(0.8f, 0.8f, 0.8f, 0.2f);
}
}
@@ -0,0 +1,40 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionGraphEditorSettings.h"
#define LOCTEXT_NAMESPACE "ComboActionGraphEditorSettings"
UComboActionGraphEditorSettings::UComboActionGraphEditorSettings()
{
NodeType = EComboActionNodeType::SoftCorners;
NodeTheme = EComboActionNodeTheme::DarkTheme;
ArrowType = EComboActionArrowType::HollowArrow;
CategoryName = TEXT("Combo Input");
SectionName = TEXT("Combo Input (Editor)");
AutoLayoutStrategy = EComboActionAutoLayoutStrategyType::Tree;
bFirstPassOnly = false;
bRandomInit = false;
OptimalDistance = 100.f;
MaxIteration = 50;
InitTemperature = 10.f;
CoolDownRate = 10.f;
WireWidth = 0.8f;
//WireStyle = EWiringStyle::EWS_Simple;
//BubbleDrawRule = EBubbleDrawRule::EBDR_OnSelected;
bAllowRenameNodes = true;
bDisplayAutomaticNames = false;
bShowDetailedInfo_InheritsDecorators = true;
bShowDetailedInfo_NumDecorators = true;
DecoratorsInfoStyle = EComboActionDecoratorsInfoStyle::Unified;
bAllowNativeDecoratorsEdit = false;
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,292 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DeveloperSettings.h"
#include "ComboActionGraphEditorSettings.generated.h"
#pragma region Enums
UENUM(BlueprintType)
enum class EComboActionAutoLayoutStrategyType : uint8
{
Tree UMETA(DisplayName="Tree"),
ForceDirected UMETA(DisplayName="Force Directed"),
Default UMETA(Hidden)
};
UENUM(BlueprintType)
enum class EComboActionWiringStyle : uint8
{
Vanilla UMETA(DisplayName="Vanilla"),
Simple UMETA(DisplayName="90° Angle"),
Complex UMETA(DisplayName="45° Angle"),
Default UMETA(Hidden)
};
UENUM(BlueprintType)
enum class EComboActionBubbleDrawRule : uint8
{
Always UMETA(DisplayName="Always"),
OnSelected UMETA(DisplayName="When Selected")
};
UENUM(BlueprintType)
enum class EComboActionNodeTheme : uint8
{
DarkTheme UMETA(DisplayName="Dark Theme"),
LightTheme UMETA(DisplayName="Light Theme")
};
UENUM(BlueprintType)
enum class EComboActionDecoratorsInfoStyle : uint8
{
Stack UMETA(DisplayName="Stack"),
Unified UMETA(DisplayName="Unified")
};
UENUM(BlueprintType)
enum class EComboActionNodeType : uint8
{
SoftCorners UMETA(DisplayName="Soft Corners"),
HardCorners UMETA(DisplayName="Hard Corners")
};
UENUM(BlueprintType)
enum class EComboActionArrowType : uint8
{
SimpleArrow UMETA(DisplayName="Simple Arrow"),
HollowArrow UMETA(DisplayName="Hollow Arrow"),
FancyArrow UMETA(DisplayName="Fancy Arrow"),
Bubble UMETA(DisplayName="Bubble"),
None UMETA(DisplayName="Nothing")
};
#pragma endregion
/**
* Combo Action Graph global settings.
*/
UCLASS(config = MounteaSettings)
class COMBOINPUT_API UComboActionGraphEditorSettings : public UDeveloperSettings
{
GENERATED_BODY()
public:
UComboActionGraphEditorSettings();
private:
#pragma region GraphNodes
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
EComboActionNodeType NodeType;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
EComboActionNodeTheme NodeTheme;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings|DecoratorsInfo")
uint8 bShowDetailedInfo_NumDecorators : 1;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings|DecoratorsInfo")
uint8 bShowDetailedInfo_InheritsDecorators : 1;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
EComboActionDecoratorsInfoStyle DecoratorsInfoStyle;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
bool bDisplayAutomaticNames;
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
bool bAllowRenameNodes;
/**
* Select a Node Class and specify Override Colour for this Node type.
* Only non-abstract classes are allowed!
*/
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings", meta=(ShowTreeView))
TMap<TSoftClassPtr<class UComboActionGraphNode>, FLinearColor> OverrideNodeBackgroundColours;
#pragma endregion
#pragma region GraphDecorators
// Enables 'Edit' button for Native Code Decorators
UPROPERTY(config, EditDefaultsOnly, Category = "NodesSettings")
bool bAllowNativeDecoratorsEdit;
#pragma endregion
#pragma region GraphWiring
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", meta=(UIMin=0.1f, ClampMin=0.1f, UIMax=1.5f, ClampMax=1.5f))
float WireWidth;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring") //, meta=(ConfigRestartRequired=true))
EComboActionArrowType ArrowType;
/* Advanced Wiring doesn't work now
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!"))
bool bUseAdvancedWiring;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
EWiringStyle WireStyle;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
uint32 HorizontalOffset = 16;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
EBubbleDrawRule BubbleDrawRule;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
int32 BubbleZoomThreshold;
// Space between bubbles on the wires. Default: 20.0
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta = (ClampMin = "10.0", ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
float BubbleSpace = 20.0f;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta = (ClampMin = "10.0", ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
float BubbleSize = 2.0f;
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta = (ClampMin = "10.0", ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
float BubbleSpeed = 2.0f;
// Disable the offset for pins. Default: false
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
bool DisablePinOffset = false;
// Fix default zoomed-out wire displacement. Default: true
UPROPERTY(config, EditDefaultsOnly, Category = "NodeWiring", AdvancedDisplay, meta=(ToolTip="Work in Progress!", EditCondition="bUseAdvancedWiring"))
bool FixZoomDisplacement = true;
*/
#pragma endregion
#pragma region GraphArrange
UPROPERTY(config, EditDefaultsOnly, Category = "AutoArrange")
float OptimalDistance;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
EComboActionAutoLayoutStrategyType AutoLayoutStrategy;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
int32 MaxIteration;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
bool bFirstPassOnly;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
bool bRandomInit;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
float InitTemperature;
UPROPERTY(config, EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
float CoolDownRate;
#pragma endregion
#if WITH_EDITOR
virtual FText GetSectionText() const override
{
return NSLOCTEXT("ComboActionGraphEditorSystem", "ComboActionGraphEditorSection", "Combo Action Graph (Editor)");
}
virtual FText GetSectionDescription() const override
{
return NSLOCTEXT("ComboActionGraphEditorSystem", "ComboActionGraphEditorDescription", "Default values for Mountea Plugins (Editor).");
}
virtual FName GetContainerName() const override
{
return "Project";
}
#endif
public:
#pragma region GraphNodes_Getters
EComboActionNodeTheme GetNodeTheme() const { return NodeTheme; }
EComboActionNodeType GetNodeType() const { return NodeType; }
bool ShowDetailedInfo_NumDecorators() const { return bShowDetailedInfo_NumDecorators; }
bool ShowDetailedInfo_InheritsDecorators() const { return bShowDetailedInfo_InheritsDecorators; }
bool ShowAutomaticNames() const { return bDisplayAutomaticNames; }
EComboActionDecoratorsInfoStyle GetDecoratorsStyle() const { return DecoratorsInfoStyle; }
bool AllowRenameNodes() const { return bAllowRenameNodes; }
bool FindNodeBackgroundColourOverride(const TSoftClassPtr<class UComboActionGraphNode> NodeClass, FLinearColor& BackgroundColour)
{
if (OverrideNodeBackgroundColours.Contains(NodeClass))
{
BackgroundColour = *OverrideNodeBackgroundColours.Find(NodeClass);
return true;
}
return false;
}
#pragma endregion
#pragma region GraphDecorators_Getters
bool IsNativeDecoratorsEditAllowed() const { return bAllowNativeDecoratorsEdit; }
#pragma endregion
#pragma region GraphWiring_Getters
float GetWireWidth() const { return this->WireWidth; }
EComboActionArrowType GetArrowType() const { return this->ArrowType; }
/*
bool AllowAdvancedWiring() const
{ return bUseAdvancedWiring; };
EWiringStyle GetWireStyle() const
{ return WireStyle; };
int32 GetHorizontalOffset() const
{ return HorizontalOffset; };
EBubbleDrawRule GetBubbleDrawRule() const
{ return BubbleDrawRule; };
int32 GetBubbleZoomThreshold() const
{ return BubbleZoomThreshold; };
float GetBubbleSpace() const
{ return BubbleSpace; };
float GetBubbleSpeed() const
{ return BubbleSpeed; };
float GetBubbleSize() const
{ return BubbleSize; };
*/
#pragma endregion
#pragma region GraphArrange_Getters
EComboActionAutoLayoutStrategyType GetAutoLayoutStrategy() const { return this->AutoLayoutStrategy; }
float GetOptimalDistance() const { return this->OptimalDistance; }
int32 GetMaxIteration() const { return this->MaxIteration; }
bool IsFirstPassOnly() const { return this->bFirstPassOnly; }
bool IsRandomInit() const { return this->bRandomInit; }
float GetInitTemperature() const { return this->InitTemperature; }
float GetCoolDownRate() const { return this->CoolDownRate; }
#pragma endregion
};
@@ -0,0 +1,138 @@
// Copyright Dominik Pavlicek 2023. All Rights Reserved.
#include "FComboActionGraphEditorStyle.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/Paths.h"
#include "Styling/SlateStyleRegistry.h"
#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(StyleSet->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define BOX_BRUSH(RelativePath, ...) FSlateBoxBrush(StyleSet->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define DEFAULT_FONT(...) FCoreStyle::GetDefaultFontStyle(__VA_ARGS__)
TSharedPtr<FSlateStyleSet> FComboActionGraphEditorStyle::StyleSet = nullptr;
void FComboActionGraphEditorStyle::Initialize()
{
if (!StyleSet.IsValid() )
{
Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());
}
}
void FComboActionGraphEditorStyle::Shutdown()
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet.Get());
ensure(StyleSet.IsUnique());
StyleSet.Reset();
}
void FComboActionGraphEditorStyle::Create()
{
const FVector2D Icon12x12(12.0f, 12.0f);
const FVector2D Icon16x16(16.0f, 16.0f);
const FVector2D Icon40x40(40.0f, 40.0f);
const FVector2D Icon64x64(64.0f, 64.0f);
const FVector2D Icon128x128(128.f, 128.f);
const FVector2D Icon200x70(200.f, 70.f);
StyleSet = MakeShareable(new FSlateStyleSet(GetAppStyleSetName()));
StyleSet->SetContentRoot(IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir() / TEXT("Resources"));
StyleSet->SetCoreContentRoot(IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir() / TEXT("Content"));
StyleSet->Set("MDSStyleSet.AutoArrange.small", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon16x16));
StyleSet->Set("MDSStyleSet.AutoArrange", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon40x40));
StyleSet->Set("MDSStyleSet.AutoArrange.large", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon64x64));
StyleSet->Set("MDSStyleSet.GraphSettings.small", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon16x16));
StyleSet->Set("MDSStyleSet.GraphSettings", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon40x40));
StyleSet->Set("MDSStyleSet.GraphSettings.large", new IMAGE_BRUSH(TEXT("GraphSettings"), Icon64x64));
StyleSet->Set("MDSStyleSet.ValidateGraph.small", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon16x16));
StyleSet->Set("MDSStyleSet.ValidateGraph", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon40x40));
StyleSet->Set("MDSStyleSet.ValidateGraph.large", new IMAGE_BRUSH(TEXT("ValidateGraph"), Icon64x64));
StyleSet->Set("MDSStyleSet.Graph.NodeOverlay", new BOX_BRUSH( TEXT("NodeOverlay"), FMargin(8.0f/64.0f, 3.0f/32.0f, 0, 0) ));
StyleSet->Set("MDSStyleSet.Graph.PinDocksOverlay", new BOX_BRUSH( TEXT("PinDocksOverlay"), FMargin(8.0f/64.0f, 3.0f/32.0f, 0, 0) ));
StyleSet->Set("MDSStyleSet.Graph.SimpleArrow", new IMAGE_BRUSH(TEXT("SimpleArrow"), Icon16x16));
StyleSet->Set("MDSStyleSet.Graph.HollowArrow", new IMAGE_BRUSH(TEXT("HollowArrow"), Icon16x16));
StyleSet->Set("MDSStyleSet.Graph.FancyArrow", new IMAGE_BRUSH(TEXT("FancyArrow"), Icon16x16));
StyleSet->Set("MDSStyleSet.Graph.Bubble", new IMAGE_BRUSH(TEXT("Bubble"), Icon16x16));
StyleSet->Set("MDSStyleSet.Node.SoftEdges", new BOX_BRUSH( TEXT("NodeSoftCorners") , FMargin(16.f/64.f, 25.f/64.f, 16.f/64.f, 16.f/64.f) ));
StyleSet->Set("MDSStyleSet.Node.HardEdges", new BOX_BRUSH( TEXT("NodeHardCorners") , FMargin(16.f/64.f, 25.f/64.f, 16.f/64.f, 16.f/64.f) ));
StyleSet->Set("MDSStyleSet.Node.TextSoftEdges", new BOX_BRUSH( TEXT("TextSoftCorners") , FMargin(16.f/64.f, 25.f/64.f, 16.f/64.f, 16.f/64.f) ));
StyleSet->Set("MDSStyleSet.Node.TextHardEdges", new BOX_BRUSH( TEXT("TextHardCorners") , FMargin(16.f/64.f, 25.f/64.f, 16.f/64.f, 16.f/64.f) ));
StyleSet->Set("MDSStyleSet.Node.IndexCircle", new IMAGE_BRUSH(TEXT("IndexIcon"), Icon16x16));
StyleSet->Set("MDSStyleSet.Icon.OK", new IMAGE_BRUSH(TEXT("OKIcon"), Icon16x16));
StyleSet->Set("MDSStyleSet.Icon.Error", new IMAGE_BRUSH(TEXT("ErroIcon"), Icon16x16));
StyleSet->Set("MDSStyleSet.Icon.BulletPoint", new IMAGE_BRUSH(TEXT("CircleBox"), Icon16x16));
StyleSet->Set("MDSStyleSet.Graph.CornerImage", new IMAGE_BRUSH(TEXT("Icon128"), Icon128x128));
StyleSet->Set("MDSStyleSet.Icon.Browse", new IMAGE_BRUSH(TEXT("BrowseIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.Edit", new IMAGE_BRUSH(TEXT("EditIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Buttons.Documentation", new IMAGE_BRUSH(TEXT("Documentation"), Icon200x70));
StyleSet->Set("MDSStyleSet.Buttons.Documentation.small", new IMAGE_BRUSH(TEXT("DocumentationIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Node.Icon.large", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon64x64));
StyleSet->Set("MDSStyleSet.Node.Icon", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon16x16));
StyleSet->Set("MDSStyleSet.Node.Icon.small", new IMAGE_BRUSH(TEXT("DialogueNodeIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.Close", new IMAGE_BRUSH(TEXT("CloseIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.SupportDiscord", new IMAGE_BRUSH(TEXT("DiscordIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.HeartIcon", new IMAGE_BRUSH(TEXT("HeartIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.UBIcon", new IMAGE_BRUSH(TEXT("UnrealBucketIcon"), Icon12x12));
StyleSet->Set("MDSStyleSet.Icon.MoneyIcon", new IMAGE_BRUSH(TEXT("MoneyIcon"), Icon12x12));
const FButtonStyle MounteaButtonStyle = FButtonStyle()
.SetNormal(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, 1, 1, 0.1f)))
.SetHovered(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, .55f, 0, 0.2f)))
.SetPressed(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, .55f, 0, 0.4f)));
StyleSet->Set("MDSStyleSet.Buttons.Style", MounteaButtonStyle);
{
const FScrollBarStyle ScrollBar = GetWidgetStyle<FScrollBarStyle>( "ScrollBar" );
FTextBlockStyle NormalText = FTextBlockStyle()
.SetFont(DEFAULT_FONT("Regular", FCoreStyle::RegularTextSize))
.SetColorAndOpacity(FSlateColor::UseForeground())
.SetShadowOffset(FVector2D::ZeroVector)
.SetShadowColorAndOpacity(FLinearColor::Black)
.SetHighlightColor( FLinearColor( 0.02f, 0.3f, 0.0f ) )
.SetHighlightShape( BOX_BRUSH( "TextBlockHighlightShape", FMargin(3.f/8.f) ) );
FTextBlockStyle NodeTitle = FTextBlockStyle(NormalText)
.SetFont( DEFAULT_FONT( "Bold", 14 ) )
.SetColorAndOpacity( FLinearColor(230.0f/255.0f,230.0f/255.0f,230.0f/255.0f) )
.SetShadowOffset( FVector2D( 2,2 ) )
.SetShadowColorAndOpacity( FLinearColor(0.f,0.f,0.f, 0.7f) );
StyleSet->Set( "MDSStyleSet.NodeTitle", NodeTitle );
FEditableTextBoxStyle NodeTitleEditableText = FEditableTextBoxStyle()
.SetFont(NormalText.Font)
.SetBackgroundImageNormal( BOX_BRUSH( "TextBox", FMargin(4.0f/16.0f) ) )
.SetBackgroundImageHovered( BOX_BRUSH( "TextBox_Hovered", FMargin(4.0f/16.0f) ) )
.SetBackgroundImageFocused( BOX_BRUSH( "TextBox_Hovered", FMargin(4.0f/16.0f) ) )
.SetBackgroundImageReadOnly( BOX_BRUSH( "TextBox_ReadOnly", FMargin(4.0f/16.0f) ) )
.SetScrollBarStyle( ScrollBar );
StyleSet->Set( "MDSStyleSet.NodeTitleEditableText", NodeTitleEditableText );
StyleSet->Set( "MDSStyleSet.NodeTitleInlineEditableText", FInlineEditableTextBlockStyle()
.SetTextStyle(NodeTitle)
.SetEditableTextBoxStyle(NodeTitleEditableText)
);
}
}
#undef DEFAULT_FONT
#undef BOX_BRUSH
#undef IMAGE_BRUSH
@@ -0,0 +1,40 @@
// Copyright Dominik Pavlicek 2023. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Styling/SlateStyle.h"
class FComboActionGraphEditorStyle
{
public:
static void Create();
static void Initialize();
static void Shutdown();
static ISlateStyle &Get()
{
return *(StyleSet.Get());
}
static const FSlateBrush *GetBrush(FName PropertyName, const ANSICHAR *Specifier = NULL)
{
return StyleSet->GetBrush(PropertyName, Specifier);
};
static const FName &GetAppStyleSetName()
{
static FName StyleSetName(TEXT("ComboActionGraphEditorStyle"));
return StyleSetName;
};
template< class T >
static const T &GetWidgetStyle( FName PropertyName, const ANSICHAR *Specifier = NULL )
{
return StyleSet->GetWidgetStyle< T >( PropertyName, Specifier );
}
private:
static TSharedPtr<FSlateStyleSet> StyleSet;
};