From de9865758a2d0444c9c00e484bfe067bc1f946ff Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Fri, 29 Sep 2023 01:33:09 -0400 Subject: [PATCH] ComboActionGraph classes can now be added in the content browser. No asset editor yet though. --- .../ComboInputEditor.build.cs | 7 +- .../Private/ComboActionGraphSchema.cpp | 5 +- .../Private/ComboInputEditor.cpp | 137 ++- .../Ed/AssetEditor_ComboActionGraph.cpp | 978 ++++++++++++++++++ .../Private/Ed/AssetEditor_ComboActionGraph.h | 167 +++ .../Private/Ed/EdComboActionGraph.cpp | 45 +- .../Private/Ed/EdComboActionGraph.h | 15 +- .../Private/Ed/EdComboActionGraphNode.cpp | 13 + .../Private/Ed/EdComboActionGraphNode.h | 3 +- ...nnectionDrawingPolicy_ComboActionGraph.cpp | 0 ...ConnectionDrawingPolicy_ComboActionGraph.h | 0 .../Private/Ed/SEdComboActionGraphEdge.cpp | 131 +++ .../Private/Ed/SEdComboActionGraphEdge.h | 33 + .../Public/ComboInputEditor.h | 20 +- 14 files changed, 1492 insertions(+), 62 deletions(-) create mode 100644 Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.cpp create mode 100644 Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.h rename Source/ComboInputEditor/Private/{ => Ed}/FConnectionDrawingPolicy_ComboActionGraph.cpp (100%) rename Source/ComboInputEditor/Private/{ => Ed}/FConnectionDrawingPolicy_ComboActionGraph.h (100%) create mode 100644 Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.cpp create mode 100644 Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.h diff --git a/Source/ComboInputEditor/ComboInputEditor.build.cs b/Source/ComboInputEditor/ComboInputEditor.build.cs index b965237..135e492 100644 --- a/Source/ComboInputEditor/ComboInputEditor.build.cs +++ b/Source/ComboInputEditor/ComboInputEditor.build.cs @@ -28,12 +28,13 @@ public class ComboInputEditor : ModuleRules "Engine", "UnrealEd", + "ApplicationCore", "AssetTools", + "DeveloperSettings", + "GraphEditor", + "Projects", "Slate", "SlateCore", - "Projects", - "GraphEditor", - "DeveloperSettings", "ToolMenus", } ); diff --git a/Source/ComboInputEditor/Private/ComboActionGraphSchema.cpp b/Source/ComboInputEditor/Private/ComboActionGraphSchema.cpp index da22b8e..b7e5578 100644 --- a/Source/ComboInputEditor/Private/ComboActionGraphSchema.cpp +++ b/Source/ComboInputEditor/Private/ComboActionGraphSchema.cpp @@ -3,7 +3,7 @@ #include "ComboActionGraphSchema.h" #include "ComboActionGraph.h" -#include "FConnectionDrawingPolicy_ComboActionGraph.h" +//#include "FConnectionDrawingPolicy_ComboActionGraph.h" #include "GraphEditorActions.h" #include "Ed/EdComboActionGraphEdge.h" @@ -365,7 +365,8 @@ FConnectionDrawingPolicy *UComboActionGraphSchema::CreateConnectionDrawingPolicy } */ - return new FConnectionDrawingPolicy_ComboActionGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj); + //return new FConnectionDrawingPolicy_ComboActionGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj); + return nullptr; } FLinearColor UComboActionGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) const diff --git a/Source/ComboInputEditor/Private/ComboInputEditor.cpp b/Source/ComboInputEditor/Private/ComboInputEditor.cpp index 5ff1e51..66214d7 100644 --- a/Source/ComboInputEditor/Private/ComboInputEditor.cpp +++ b/Source/ComboInputEditor/Private/ComboInputEditor.cpp @@ -2,10 +2,15 @@ #include "ComboInputEditor.h" +#include "ComboActionGraph.h" #include "ComboInputAssets.h" #include "ToolMenuSection.h" #include "AssetTypeActions/AssetTypeActions_DataAsset.h" +#include "Ed/EdComboActionGraphEdge.h" +#include "Ed/EdComboActionGraphNode.h" +#include "Ed/SEdComboActionGraphEdge.h" +#include "Ed/SEdComboActionGraphNode.h" #include "Interfaces/IPluginManager.h" #include "Settings/FComboActionGraphEditorStyle.h" #include "Styling/SlateStyle.h" @@ -17,6 +22,7 @@ #define LOCTEXT_NAMESPACE "FComboInputEditorModule" EAssetTypeCategories::Type FComboInputEditorModule::ComboAssetsCategory; +EAssetTypeCategories::Type FComboInputEditorModule::ComboActionGraphCategory; class FAssetTypeActions_ComboAction : public FAssetTypeActions_DataAsset @@ -45,30 +51,70 @@ public: virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputAsset", "Combo Input Asset"); } virtual uint32 GetCategories() override { return FComboInputEditorModule::GetInputAssetsCategory(); } virtual FColor GetTypeColor() const override { return FColor(255, 127, 255); } - virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputAssetDesc", "This maps a sequence of button inputs from EnhancedInput to a combo action that can be used to execute a sequence of moves.This gets sent from the input buffer subsystem to the player controller's ComboManagerComponent, which executes the associated action in the current ComboSequenceNode."); } + virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboInputAssetDesc", "This maps a sequence of button inputs from EnhancedInput to a combo action that can be used to execute a sequence of moves. This gets sent from the input buffer subsystem to the player controller's ComboManagerComponent, which executes the associated action in the current ComboSequenceNode."); } virtual UClass *GetSupportedClass() const override { return UComboInputAsset::StaticClass(); } }; +class FAssetTypeActions_ComboActionGraph : public FAssetTypeActions_Base +{ +public: + virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboActionGraph", "Combo Action Graph"); } + virtual uint32 GetCategories() override { return FComboInputEditorModule::GetInputAssetsCategory(); } + virtual FColor GetTypeColor() const override { return FColor(255, 127, 255); } + virtual FText GetAssetDescription(const FAssetData &AssetData) const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_ComboActionGraphDesc", "This maps a sequence of button inputs from EnhancedInput to a combo action that can be used to execute a sequence of moves. This gets sent from the input buffer subsystem to the player controller's ComboManagerComponent, which executes the associated action in the current ComboSequenceNode."); } + virtual UClass *GetSupportedClass() const override { return UComboActionGraph::StaticClass(); } + + virtual void OpenAssetEditor(const TArray &InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override + { + //const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; + //for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ObjIt++) + //{ + // if (UComboActionGraph *Graph = Cast(*ObjIt)) + // { + // TSharedRef NewGraphEditor(new FAssetEditor_ComboActionGraph()); + // NewGraphEditor->InitMounteaDialogueGraphAssetEditor(Mode, EditWithinLevelEditor, Graph); + // } + //} + } +}; + +class FComboActionGraphPanelNodeFactory : public FGraphPanelNodeFactory +{ +public: + virtual TSharedPtr CreateNode(UEdGraphNode *Node) const override + { + + if (UEdComboActionGraphNode *EdGraphNode = Cast(Node)) + { + return SNew(SEdComboActionGraphNode, EdGraphNode); + } + else if (UEdComboActionGraphEdge *EdGraphEdge = Cast(Node)) + { + return SNew(SEdComboActionGraphEdge, EdGraphEdge); + } + return nullptr; + } +}; UComboAction_Factory::UComboAction_Factory(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer) { - SupportedClass = UComboAction::StaticClass(); - bEditAfterNew = true; - bCreateNew = true; + this->SupportedClass = UComboAction::StaticClass(); + this->bEditAfterNew = true; + this->bCreateNew = true; } UObject *UComboAction_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) { if (this->ComboActionClass != nullptr) { - return NewObject(InParent, this->ComboActionClass, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, this->ComboActionClass, Name, Flags | EObjectFlags::RF_Transactional, Context); } else { check(Class->IsChildOf(UComboAction::StaticClass())); - return NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context); } } @@ -76,21 +122,21 @@ UObject *UComboAction_Factory::FactoryCreateNew(UClass *Class, UObject *InParent UComboSequenceNode_Factory::UComboSequenceNode_Factory(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer) { - SupportedClass = UComboSequenceNode::StaticClass(); - bEditAfterNew = true; - bCreateNew = true; + this->SupportedClass = UComboSequenceNode::StaticClass(); + this->bEditAfterNew = true; + this->bCreateNew = true; } UObject *UComboSequenceNode_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) { if (this->ComboSequenceNodeClass != nullptr) { - return NewObject(InParent, this->ComboSequenceNodeClass, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, this->ComboSequenceNodeClass, Name, Flags | EObjectFlags::RF_Transactional, Context); } else { check(Class->IsChildOf(UComboSequenceNode::StaticClass())); - return NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context); } } @@ -98,25 +144,46 @@ UObject *UComboSequenceNode_Factory::FactoryCreateNew(UClass *Class, UObject *In UComboInputAsset_Factory::UComboInputAsset_Factory(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer) { - SupportedClass = UComboInputAsset::StaticClass(); - bEditAfterNew = true; - bCreateNew = true; + this->SupportedClass = UComboInputAsset::StaticClass(); + this->bEditAfterNew = true; + this->bCreateNew = true; } UObject *UComboInputAsset_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) { if (this->ComboInputAssetClass != nullptr) { - return NewObject(InParent, this->ComboInputAssetClass, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, this->ComboInputAssetClass, Name, Flags | EObjectFlags::RF_Transactional, Context); } else { check(Class->IsChildOf(UComboInputAsset::StaticClass())); - return NewObject(InParent, Class, Name, Flags | RF_Transactional, Context); + return NewObject(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context); } } +UComboActionGraph_Factory::UComboActionGraph_Factory(const FObjectInitializer &ObjectInitializer) + : Super(ObjectInitializer) +{ + this->SupportedClass = UComboActionGraph::StaticClass(); + this->bEditAfterNew = true; + this->bCreateNew = true; +} + +UObject *UComboActionGraph_Factory::FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) +{ + if (this->ComboActionGraphClass != nullptr) + { + return NewObject(InParent, this->ComboActionGraphClass, Name, Flags | EObjectFlags::RF_Transactional, Context); + } + else + { + check(Class->IsChildOf(UComboActionGraph::StaticClass())); + return NewObject(InParent, Class, Name, Flags | EObjectFlags::RF_Transactional, Context); + } +} + class FComboInputSlateStyle final : public FSlateStyleSet { @@ -149,12 +216,11 @@ public: }; - void FComboInputEditorModule::StartupModule() { // Register combo action asset IAssetTools &AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); - FComboInputEditorModule::ComboAssetsCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Input")), LOCTEXT("InputAssetsCategory", "Input")); + FComboInputEditorModule::ComboAssetsCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Combo Input")), LOCTEXT("ComboInputAssetsCategory", "Combo Input")); this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboAction)); this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboSequenceNode)); this->RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_ComboInputAsset)); @@ -163,13 +229,36 @@ void FComboInputEditorModule::StartupModule() this->ComboInputEditorStyleSet = MakeShared(); FSlateStyleRegistry::RegisterSlateStyle(*this->ComboInputEditorStyleSet.Get()); - // Make a new style set for Combo Action Graph - this->ComboActionGraphEditorStyleSet = MakeShared(); - FSlateStyleRegistry::RegisterSlateStyle(*this->ComboActionGraphEditorStyleSet.Get()); -} + // Combo Action Graph + { + // Make a new style set for Combo Action Graph + this->ComboActionGraphEditorStyleSet = MakeShared(); + FSlateStyleRegistry::RegisterSlateStyle(*this->ComboActionGraphEditorStyleSet.Get()); -void FComboInputEditorModule::ShutdownModule() -{ + this->ComboActionGraphPanelNodeFactory = MakeShareable(new FComboActionGraphPanelNodeFactory()); + FEdGraphUtilities::RegisterVisualNodeFactory(this->ComboActionGraphPanelNodeFactory); + + // Register asset actions + this->ComboActionGraphAssetActions = MakeShared(); + this->RegisterAssetTypeActions(AssetTools, this->ComboActionGraphAssetActions.ToSharedRef()); + + // Register thumbnails and icons + this->ComboActionGraphStyleSet = MakeShareable(new FSlateStyleSet("ComboActionGraphStyleSet")); + const TSharedPtr PluginPtr = IPluginManager::Get().FindPlugin("ComboInput"); + if (PluginPtr.IsValid()) + { + const FString ContentDir = PluginPtr->GetBaseDir(); + this->ComboActionGraphStyleSet->SetContentRoot(ContentDir); + FSlateImageBrush *ComboActionGraphStyleSetClassThumb = new FSlateImageBrush(this->ComboActionGraphStyleSet->RootToContentDir(TEXT("Resources/ComboActionGraphIcon_128"), TEXT(".png")), FVector2D(128.0f, 128.0f)); + FSlateImageBrush *ComboActionGraphStyleSetClassIcon = new FSlateImageBrush(this->ComboActionGraphStyleSet->RootToContentDir(TEXT("Resources/ComboActionGraphIcon_16"), TEXT(".png")), FVector2D(16.0f, 16.0f)); + if (ComboActionGraphStyleSetClassThumb && ComboActionGraphStyleSetClassIcon) + { + this->ComboActionGraphStyleSet->Set("ClassThumbnail.ComboActionGraph", ComboActionGraphStyleSetClassThumb); + this->ComboActionGraphStyleSet->Set("ClassIcon.ComboActionGraph", ComboActionGraphStyleSetClassIcon); + } + FSlateStyleRegistry::RegisterSlateStyle(*this->ComboActionGraphStyleSet.Get()); + } + } } #undef LOCTEXT_NAMESPACE diff --git a/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.cpp b/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.cpp new file mode 100644 index 0000000..d80fb93 --- /dev/null +++ b/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.cpp @@ -0,0 +1,978 @@ +// Copyright Dominik Pavlicek 2023. All Rights Reserved. + +#include "AssetEditor_ComboActionGraph.h" + +#include "GraphEditorActions.h" +#include "Framework/Commands/GenericCommands.h" +#include "Kismet2/BlueprintEditorUtils.h" +#include "HAL/PlatformApplicationMisc.h" +#include "EdGraphUtilities.h" + +#include "ComboInputEditor.h" +#include "ComboActionGraph.h" +#include "Nodes/ComboActionGraphNode.h" +//#include "EditorCommands/FComboActionGraphEditorCommands.h" +//#include "AssetEditor/FAssetEditorToolbarComboActionGraph.h" +#include "Ed/EdComboActionGraph.h" +#include "Ed/EdComboActionGraphEdge.h" +#include "Ed/EdComboActionGraphNode.h" +#include "Settings/FComboActionGraphEditorStyle.h" +#include "ComboActionGraphSchema.h" +//#include "Layout/AssetEditorTabs.h" +//#include "Helpers/ComboActionGraphHelpers.h" +//#include "Helpers/ComboActionSystemEditorBFC.h" +//#include "Layout/ForceDirectedSolveLayoutStrategy.h" +//#include "Layout/ComboActionGraphLayoutStrategy.h" +//#include "Layout/TreeSolveLayoutStrategy.h" +//#include "Popups/MDSPopup_GraphValidation.h" +//#include "Search/ComboActionSearchUtils.h" +#include "Settings/ComboActionGraphEditorSettings.h" +#include "UObject/ObjectSaveContext.h" + +#define LOCTEXT_NAMESPACE "AssetEditor_ComboActionGraph" + +DEFINE_LOG_CATEGORY(LogAssetEditorComboActionGraph); + +#pragma region ConstantNames + +const FName ComboActionGraphEditorAppName = FName(TEXT("ComboActionGraphEditorApp")); +//const FName FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID(TEXT("ComboActionGraphProperty")); +//const FName FAssetEditorTabs_ComboActionGraph::ViewportID(TEXT("Viewport")); +//const FName FAssetEditorTabs_ComboActionGraph::SearchToolbarID(TEXT("Search")); + +#pragma endregion + + +FAssetEditor_ComboActionGraph::FAssetEditor_ComboActionGraph() +{ + this->EditingGraph = nullptr; + this->ComboActionGraphEditorSettings = GetMutableDefault(); + this->OnPackageSavedDelegateHandle = UPackage::PackageSavedWithContextEvent.AddRaw(this, &FAssetEditor_ComboActionGraph::OnPackageSaved); +} + +FAssetEditor_ComboActionGraph::~FAssetEditor_ComboActionGraph() +{ + this->EditingGraph = nullptr; + UPackage::PackageSavedWithContextEvent.Remove(this->OnPackageSavedDelegateHandle); + + //FGenericCommands::Unregister(); + //FGraphEditorCommands::Unregister(); + //FComboActionGraphEditorCommands::Unregister(); + + //this->ToolbarBuilder.Reset(); +} + +void FAssetEditor_ComboActionGraph::OnPackageSaved(const FString& String, UPackage* Package, FObjectPostSaveContext ObjectPostSaveContext) +{ + this->RebuildComboActionGraph(); +} + +void FAssetEditor_ComboActionGraph::InitComboActionGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, UComboActionGraph *Graph) +{ + this->EditingGraph = Graph; + this->CreateEdGraph(); + + //FGenericCommands::Register(); + //FGraphEditorCommands::Register(); + //FComboActionGraphEditorCommands::Register(); + + //if (!this->ToolbarBuilder.IsValid()) + //{ + // this->ToolbarBuilder = MakeShareable(new FAssetEditorToolbarComboActionGraph(SharedThis(this))); + //} + + this->BindCommands(); + + this->CreateInternalWidgets(); + + //TSharedPtr ToolbarExtender = MakeShareable(new FExtender); + //this->ToolbarBuilder->AddMounteaDialogueGraphToolbar(ToolbarExtender); + + // Layout + //const TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_MounteaDialogueGraphEditor_LayoutV0.3") + // ->AddArea + // ( + // FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) + // ->Split + // ( + // FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f) + // ->Split + // ( + // FTabManager::NewStack() + // ->SetSizeCoefficient(3.f) + // ->AddTab(FAssetEditorTabs_MounteaDialogueGraph::ViewportID, ETabState::OpenedTab)->SetHideTabWell(true) + // ) + // ->Split + // ( + // FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) + // ->Split + // ( + // FTabManager::NewSplitter()->SetOrientation(Orient_Vertical) + // ->Split + // ( + // FTabManager::NewStack() + // ->SetSizeCoefficient(0.9f) + // ->AddTab(FAssetEditorTabs_MounteaDialogueGraph::MounteaDialogueGraphPropertyID, ETabState::OpenedTab)->SetHideTabWell(true) + // ) + + // ->Split + // ( + // FTabManager::NewStack() + // ->SetSizeCoefficient(0.3f) + // ->AddTab(FAssetEditorTabs_MounteaDialogueGraph::SearchToolbarID, ETabState::OpenedTab) + // ) + // ) + // ) + // ) + // ); + + //const bool bCreateDefaultStandaloneMenu = true; + //const bool bCreateDefaultToolbar = true; + //FAssetEditorToolkit::InitAssetEditor + //( + // Mode, + // InitToolkitHost, + // ComboActionGraphEditorAppName, + // StandaloneDefaultLayout, + // bCreateDefaultStandaloneMenu, + // bCreateDefaultToolbar, + // EditingGraph, + // false + // ); + + this->RegenerateMenusAndToolbars(); +} + +UComboActionGraphEditorSettings *FAssetEditor_ComboActionGraph::GetSettings() const +{ + return this->ComboActionGraphEditorSettings; +} + +void FAssetEditor_ComboActionGraph::RegisterTabSpawners(const TSharedRef &InTabManager) +{ + //WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_MounteaDialogueTreeEditor", "Mountea Dialogue Tree Editor")); + //auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); + + //FAssetEditorToolkit::RegisterTabSpawners(InTabManager); + + //InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ViewportID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Viewport)) + // .SetDisplayName(LOCTEXT("GraphCanvasTab", "Viewport")) + // .SetGroup(WorkspaceMenuCategoryRef) + // .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "GraphEditor.EventGraph_16x")); + + //InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::MounteaDialogueGraphPropertyID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Details)) + // .SetDisplayName(LOCTEXT("DetailsTab", "Property")) + // .SetGroup(WorkspaceMenuCategoryRef) + // .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details")); + + //InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Search)) + // .SetDisplayName(LOCTEXT("SearchTab", "Search")) + // .SetGroup(WorkspaceMenuCategoryRef) + // .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "Kismet.Tabs.FindResults")); +} + +void FAssetEditor_ComboActionGraph::UnregisterTabSpawners(const TSharedRef& InTabManager) +{ + //FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); + + //InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ViewportID); + //InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID); + //InTabManager->UnregisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID); +} + +bool FAssetEditor_ComboActionGraph::CloseWindow() +{ + const bool bSatisfied = FAssetEditorToolkit::CloseWindow(); + + if (this->EditingGraph) + { + if (this->EditingGraph->EdGraph) + { + UEdComboActionGraph *EdGraph = Cast(this->EditingGraph->EdGraph); + if (EdGraph->GetComboActionEditorPtr().HasSameObject(this)) EdGraph->ResetDialogueEditorPtr(); + } + } + + return bSatisfied; +} + +FName FAssetEditor_ComboActionGraph::GetToolkitFName() const +{ + return FName("FComboActionGraphEditor"); +} + +FText FAssetEditor_ComboActionGraph::GetBaseToolkitName() const +{ + return LOCTEXT("ComboActionGraphEditorAppLabel", "Combo Action Graph Editor"); +} + +FText FAssetEditor_ComboActionGraph::GetToolkitName() const +{ + const bool bDirtyState = this->EditingGraph->GetOutermost()->IsDirty(); + + FFormatNamedArguments Args; + Args.Add(TEXT("ComboActionGraphName"), FText::FromString(this->EditingGraph->GetName())); + Args.Add(TEXT("DirtyState"), bDirtyState ? FText::FromString(TEXT("*")) : FText::GetEmpty()); + return FText::Format(LOCTEXT("ComboActionGraphEditorToolkitName", "{ComboActionGraphName}{DirtyState}"), Args); +} + +FText FAssetEditor_ComboActionGraph::GetToolkitToolTipText() const +{ + return FAssetEditorToolkit::GetToolTipTextForObject(EditingGraph); +} + +FLinearColor FAssetEditor_ComboActionGraph::GetWorldCentricTabColorScale() const +{ + return FLinearColor::Gray; +} + +FString FAssetEditor_ComboActionGraph::GetWorldCentricTabPrefix() const +{ + return TEXT("ComboActionGraphEditor"); +} + +FString FAssetEditor_ComboActionGraph::GetDocumentationLink() const +{ + return TEXT("There should be a link to the documentation here someday."); +} + +void FAssetEditor_ComboActionGraph::SaveAsset_Execute() +{ + if (this->EditingGraph != nullptr) + { + this->RebuildComboActionGraph(); + } + + FAssetEditorToolkit::SaveAsset_Execute(); +} + +void FAssetEditor_ComboActionGraph::UpdateToolbar() +{ + // TODO +} + +void FAssetEditor_ComboActionGraph::RegisterToolbarTab(const TSharedRef& InTabManager) +{ + FAssetEditorToolkit::RegisterTabSpawners(InTabManager); +} + +void FAssetEditor_ComboActionGraph::AddReferencedObjects(FReferenceCollector& Collector) +{ + Collector.AddReferencedObject(this->EditingGraph); + Collector.AddReferencedObject(this->EditingGraph->EdGraph); +} + +FString FAssetEditor_ComboActionGraph::GetReferencerName() const +{ + return TEXT("FAssetEditor_ComboActionGraph"); +} + +void FAssetEditor_ComboActionGraph::SetDialogueBeingEdited(UComboActionGraph *NewDialogue) +{ + if (NewDialogue == nullptr) return; + if (NewDialogue == this->EditingGraph) return; + + UComboActionGraph *Previous = this->EditingGraph; + this->EditingGraph = NewDialogue; + + this->RemoveEditingObject(Previous); + this->AddEditingObject(NewDialogue); +} + +void FAssetEditor_ComboActionGraph::CreateInternalWidgets() +{ + this->ViewportWidget = this->CreateViewportWidget(); + + FDetailsViewArgs Args; //( false, false, true, FDetailsViewArgs::HideNameArea, false ); + Args.bUpdatesFromSelection = false; + Args.bLockable = false; + Args.bAllowSearch = true; + Args.NameAreaSettings = FDetailsViewArgs::HideNameArea; + Args.bHideSelectionTip = false; + Args.bShowObjectLabel = false; + + FPropertyEditorModule &PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + this->PropertyWidget = PropertyModule.CreateDetailView(Args); + this->PropertyWidget->SetObject(EditingGraph); + + this->PropertyWidget->OnFinishedChangingProperties().AddSP(this, &FAssetEditor_ComboActionGraph::OnFinishedChangingProperties); + + //this->FindResultsView = SNew(SComboActionSearch, SharedThis(this)); +} + +TSharedRef FAssetEditor_ComboActionGraph::CreateViewportWidget() +{ + const FComboInputEditorModule &Module = FModuleManager::GetModuleChecked("ComboInputEditor"); + FGraphAppearanceInfo AppearanceInfo; + AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText_ComboActionGraph", "Combo Action Tree"); + AppearanceInfo.CornerImage = Module.Get().ComboActionGraphEditorStyleSet->GetBrush(TEXT("MDSStyleSet.Graph.CornerImage")); + AppearanceInfo.InstructionText = LOCTEXT("InstructionText_ComboActionGraph", "Place action nodes by right clicking."); + + this->CreateCommandList(); + + SGraphEditor::FGraphEditorEvents InEvents; + InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FAssetEditor_ComboActionGraph::OnSelectedNodesChanged); + InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FAssetEditor_ComboActionGraph::OnNodeDoubleClicked); + + return SNew(SGraphEditor) + .AdditionalCommands(GraphEditorCommands) + .IsEditable(true) + .Appearance(AppearanceInfo) + .GraphToEdit(EditingGraph->EdGraph) + .GraphEvents(InEvents) + .AutoExpandActionMenu(true) + .ShowGraphStateOverlay(false); +} + +void FAssetEditor_ComboActionGraph::BindCommands() +{ + //this->ToolkitCommands->MapAction + //( + // FComboActionGraphEditorCommands::Get().AutoArrange, + // FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::AutoArrange), + // FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanAutoArrange) + //); + + //this->ToolkitCommands->MapAction + //( + // FComboActionGraphEditorCommands::Get().ValidateGraph, + // FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::ValidateGraph), + // FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanValidateGraph) + //); + // + //this->ToolkitCommands->MapAction + //( + // FComboActionGraphEditorCommands::Get().FindInDialogue, + // FExecuteAction::CreateLambda([this] { this->SummonSearchUI(); }) + //); +} + +void FAssetEditor_ComboActionGraph::CreateEdGraph() +{ + if (this->EditingGraph->EdGraph == nullptr) + { + this->EditingGraph->EdGraph = CastChecked(FBlueprintEditorUtils::CreateNewGraph(EditingGraph, NAME_None, UEdComboActionGraph::StaticClass(), UComboActionGraphSchema::StaticClass())); + this->EditingGraph->EdGraph->bAllowDeletion = false; + + // Give the schema a chance to fill out any required nodes (like the results node) + const UEdGraphSchema *Schema = this->EditingGraph->EdGraph->GetSchema(); + Schema->CreateDefaultNodesForGraph(*this->EditingGraph->EdGraph); + + UEdComboActionGraph *ComboActionGraph = Cast(this->EditingGraph->EdGraph); + UEdComboActionGraphNode *NewNode = ComboActionGraph->CreateIntermediateNode(); + + NewNode->SetComboActionGraphNode(this->EditingGraph->StartNode); + NewNode->CreateNewGuid(); + NewNode->PostPlacedNewNode(); + NewNode->AllocateDefaultPins(); + NewNode->AutowireNewNode(nullptr); + + NewNode->NodePosX = 0; + NewNode->NodePosY = 0; + + NewNode->ComboActionGraphNode->SetFlags(EObjectFlags::RF_Transactional); + NewNode->SetFlags(EObjectFlags::RF_Transactional); + + ComboActionGraph->RebuildComboActionGraph(); + } + + if (UEdComboActionGraph *EdComboActionGraph = Cast(this->EditingGraph->EdGraph)) + { + EdComboActionGraph->SetDialogueEditorPtr(SharedThis(this)); + EdComboActionGraph->RebuildComboActionGraph(); + } +} + +void FAssetEditor_ComboActionGraph::CreateCommandList() +{ + if (this->GraphEditorCommands.IsValid()) + { + return; + } + + this->GraphEditorCommands = MakeShareable(new FUICommandList); + + //this->GraphEditorCommands->MapAction(FComboActionGraphEditorCommands::Get().AutoArrange, + // FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::AutoArrange), + // FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanAutoArrange)); + + //this->GraphEditorCommands->MapAction(FComboActionGraphEditorCommands::Get().ValidateGraph, + // FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::ValidateGraph), + // FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanValidateGraph)); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().SelectAll, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::SelectAllNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanSelectAllNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Delete, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::DeleteSelectedNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanDeleteNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Copy, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CopySelectedNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanCopyNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Cut, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CutSelectedNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanCutNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Paste, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::PasteNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanPasteNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Duplicate, + FExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::DuplicateNodes), + FCanExecuteAction::CreateRaw(this, &FAssetEditor_ComboActionGraph::CanDuplicateNodes) + ); + + this->GraphEditorCommands->MapAction(FGenericCommands::Get().Rename, + FExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::OnRenameNode), + FCanExecuteAction::CreateSP(this, &FAssetEditor_ComboActionGraph::CanRenameNodes) + ); + + //this->ToolkitCommands->MapAction + //( + // FComboActionGraphEditorCommands::Get().FindInDialogue, + // FExecuteAction::CreateLambda([this] { SummonSearchUI(); }) + //); +} + +TSharedPtr FAssetEditor_ComboActionGraph::GetCurrentGraphEditor() const +{ + return this->ViewportWidget; +} + +FGraphPanelSelectionSet FAssetEditor_ComboActionGraph::GetSelectedNodes() const +{ + FGraphPanelSelectionSet CurrentSelection; + TSharedPtr FocusedGraphEd = this->GetCurrentGraphEditor(); + if (FocusedGraphEd.IsValid()) + { + CurrentSelection = FocusedGraphEd->GetSelectedNodes(); + } + + return CurrentSelection; +} + +void FAssetEditor_ComboActionGraph::RebuildComboActionGraph() +{ + if (this->EditingGraph == nullptr) + { + UE_LOG(LogAssetEditorComboActionGraph, Warning, TEXT("[RebuildComboActionGraph] EditingGraph is nullptr")); + return; + } + + UEdComboActionGraph *EdGraph = Cast(this->EditingGraph->EdGraph); + check(EdGraph != nullptr); + + EdGraph->RebuildComboActionGraph(); +} + +void FAssetEditor_ComboActionGraph::SummonSearchUI(FString NewSearch, bool bSelectFirstResult) +{ + //TSharedPtr FindResultsToUse; + //FindResultsToUse = FindResultsView; + //FMounteaDialogueSearchHelpers::InvokeTab(TabManager, FAssetEditorTabs_MounteaDialogueGraph::SearchToolbarID); + + //if (FindResultsToUse.IsValid()) + //{ + // FMounteaDialogueSearchFilter Filter; + // Filter.SearchString = NewSearch; + // FindResultsToUse->FocusForUse(Filter, bSelectFirstResult); + //} +} + +void FAssetEditor_ComboActionGraph::SelectAllNodes() +{ + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (CurrentGraphEditor.IsValid()) + { + CurrentGraphEditor->SelectAllNodes(); + } +} + +bool FAssetEditor_ComboActionGraph::CanSelectAllNodes() +{ + return true; +} + +void FAssetEditor_ComboActionGraph::DeleteSelectedNodes() +{ + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (!CurrentGraphEditor.IsValid()) + { + return; + } + + const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription()); + + CurrentGraphEditor->GetCurrentGraph()->Modify(); + + const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes(); + CurrentGraphEditor->ClearSelectionSet(); + + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + UEdGraphNode* EdNode = Cast(*NodeIt); + if (EdNode == nullptr || !EdNode->CanUserDeleteNode()) + continue;; + + if (UEdComboActionGraphNode *EdNode_Node = Cast(EdNode)) + { + EdNode_Node->Modify(); + + const UEdGraphSchema *Schema = EdNode_Node->GetSchema(); + if (Schema != nullptr) + { + Schema->BreakNodeLinks(*EdNode_Node); + } + + EdNode_Node->DestroyNode(); + } + else + { + EdNode->Modify(); + EdNode->DestroyNode(); + } + } + + // Update UI + CurrentGraphEditor->NotifyGraphChanged(); + + UEdGraph *EdGraph = CurrentGraphEditor->GetCurrentGraph(); + UObject *GraphOwner = EdGraph->GetOuter(); + if (GraphOwner) + { + GraphOwner->PostEditChange(); + GraphOwner->MarkPackageDirty(); + } + + this->RebuildComboActionGraph(); +} + +bool FAssetEditor_ComboActionGraph::CanDeleteNodes() +{ + // If any of the nodes can be deleted then we should allow deleting + const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + UEdGraphNode* Node = Cast(*SelectedIter); + if (Node != nullptr && Node->CanUserDeleteNode()) + { + return true; + } + } + + return false; +} + +void FAssetEditor_ComboActionGraph::DeleteSelectedDuplicatableNodes() +{ + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (!CurrentGraphEditor.IsValid()) + { + return; + } + + const FGraphPanelSelectionSet OldSelectedNodes = CurrentGraphEditor->GetSelectedNodes(); + CurrentGraphEditor->ClearSelectionSet(); + + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter) + { + UEdGraphNode *Node = Cast(*SelectedIter); + if (Node && Node->CanDuplicateNode()) + { + CurrentGraphEditor->SetNodeSelection(Node, true); + } + } + + // Delete the duplicatable nodes + this->DeleteSelectedNodes(); + + CurrentGraphEditor->ClearSelectionSet(); + + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter) + { + if (UEdGraphNode* Node = Cast(*SelectedIter)) + { + CurrentGraphEditor->SetNodeSelection(Node, true); + } + } +} + +void FAssetEditor_ComboActionGraph::CutSelectedNodes() +{ + this->CopySelectedNodes(); + this->DeleteSelectedDuplicatableNodes(); +} + +bool FAssetEditor_ComboActionGraph::CanCutNodes() +{ + return this->CanCopyNodes() && this->CanDeleteNodes(); +} + +void FAssetEditor_ComboActionGraph::CopySelectedNodes() +{ + // Export the selected nodes and place the text on the clipboard + FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); + + FString ExportedText; + + for (FGraphPanelSelectionSet::TIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + UEdGraphNode* Node = Cast(*SelectedIter); + if (Node == nullptr) + { + SelectedIter.RemoveCurrent(); + continue; + } + + if (UEdComboActionGraphEdge *EdNode_Edge = Cast(*SelectedIter)) + { + UEdComboActionGraphNode *StartNode = EdNode_Edge->GetStartNode(); + UEdComboActionGraphNode *EndNode = EdNode_Edge->GetEndNode(); + + if (!SelectedNodes.Contains(StartNode) || !SelectedNodes.Contains(EndNode)) + { + SelectedIter.RemoveCurrent(); + continue; + } + } + + Node->PrepareForCopying(); + } + + FEdGraphUtilities::ExportNodesToText(SelectedNodes, ExportedText); + FPlatformApplicationMisc::ClipboardCopy(*ExportedText); +} + +bool FAssetEditor_ComboActionGraph::CanCopyNodes() +{ + // If any of the nodes can be duplicated then we should allow copying + const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + UEdGraphNode *Node = Cast(*SelectedIter); + if (Node && Node->CanDuplicateNode() == false) + { + return false; + } + } + + return true; +} + +void FAssetEditor_ComboActionGraph::PasteNodes() +{ + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (CurrentGraphEditor.IsValid()) + { + PasteNodesHere(CurrentGraphEditor->GetPasteLocation()); + } +} + +void FAssetEditor_ComboActionGraph::PasteNodesHere(const FVector2D& Location) +{ + // Find the graph editor with focus + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (!CurrentGraphEditor.IsValid()) + { + return; + } + // Select the newly pasted stuff + UEdGraph* EdGraph = CurrentGraphEditor->GetCurrentGraph(); + + { + const FScopedTransaction Transaction(FGenericCommands::Get().Paste->GetDescription()); + EdGraph->Modify(); + + // Clear the selection set (newly pasted stuff will be selected) + CurrentGraphEditor->ClearSelectionSet(); + + // Grab the text to paste from the clipboard. + FString TextToImport; + FPlatformApplicationMisc::ClipboardPaste(TextToImport); + + // Import the nodes + TSet PastedNodes; + FEdGraphUtilities::ImportNodesFromText(EdGraph, TextToImport, PastedNodes); + + //Average position of nodes so we can move them while still maintaining relative distances to each other + FVector2D AvgNodePosition(0.0f, 0.0f); + + for (TSet::TIterator It(PastedNodes); It; ++It) + { + UEdGraphNode* Node = *It; + AvgNodePosition.X += Node->NodePosX; + AvgNodePosition.Y += Node->NodePosY; + } + + float InvNumNodes = 1.0f / float(PastedNodes.Num()); + AvgNodePosition.X *= InvNumNodes; + AvgNodePosition.Y *= InvNumNodes; + + // 0 is always Start Node! + int32 SharedIndex = EditingGraph->GetAllNodes().Num(); + + for (TSet::TIterator It(PastedNodes); It; ++It) + { + UEdGraphNode* Node = *It; + CurrentGraphEditor->SetNodeSelection(Node, true); + + Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X; + Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y; + + Node->SnapToGrid(16); + + // Give new node a different Guid from the old one + Node->CreateNewGuid(); + + if (UEdComboActionGraphNode *MounteaNode = Cast(Node)) + { + if (MounteaNode->ComboActionGraphNode) + { + MounteaNode->ComboActionGraphNode->OnPasted(); + //MounteaNode->SetDialogueNodeIndex(SharedIndex); + } + + SharedIndex++; + } + } + } + + // Update UI + CurrentGraphEditor->NotifyGraphChanged(); + + UObject* GraphOwner = EdGraph->GetOuter(); + if (GraphOwner) + { + GraphOwner->PostEditChange(); + GraphOwner->MarkPackageDirty(); + } + + this->RebuildComboActionGraph(); +} + +bool FAssetEditor_ComboActionGraph::CanPasteNodes() +{ + const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + const UEdComboActionGraphNode *Node = Cast(*SelectedIter); + if (Node && Node->CanUserPasteNodes() == false) + { + return false; + } + } + + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (!CurrentGraphEditor.IsValid()) + { + return false; + } + + FString ClipboardContent; + FPlatformApplicationMisc::ClipboardPaste(ClipboardContent); + + return FEdGraphUtilities::CanImportNodesFromText(CurrentGraphEditor->GetCurrentGraph(), ClipboardContent); +} + +void FAssetEditor_ComboActionGraph::DuplicateNodes() +{ + this->CopySelectedNodes(); + this->PasteNodes(); +} + +bool FAssetEditor_ComboActionGraph::CanDuplicateNodes() +{ + return this->CanCopyNodes(); +} + +void FAssetEditor_ComboActionGraph::AutoArrange() +{ + UEdComboActionGraph *EdGraph = Cast(this->EditingGraph->EdGraph); + check(EdGraph != nullptr); + + const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorAutoArrange", "Combo Action Graph Editor: Auto Arrange all Nodes")); + + EdGraph->Modify(true); + + //UComboActionGraphLayoutStrategy *LayoutStrategy = nullptr; + //switch (this->ComboActionGraphEditorSettings->GetAutoLayoutStrategy()) + //{ + // case EComboActionAutoLayoutStrategyType::Tree: + // LayoutStrategy = NewObject(EdGraph, UTreeSolveLayoutStrategy::StaticClass()); + // break; + // case EComboActionAutoLayoutStrategyType::ForceDirected: + // LayoutStrategy = NewObject(EdGraph, UForceDirectedSolveLayoutStrategy::StaticClass()); + // break; + // default: + // break; + //} + + //if (LayoutStrategy != nullptr) + //{ + // LayoutStrategy->Layout(EdGraph); + // LayoutStrategy->ConditionalBeginDestroy(); + //} + //else + //{ + // LOG_ERROR(TEXT("[AutoArrange] LayoutStrategy is null.")); + //} +} + +bool FAssetEditor_ComboActionGraph::CanAutoArrange() const +{ + return this->EditingGraph != nullptr && Cast(this->EditingGraph->EdGraph) != nullptr; +} + +void FAssetEditor_ComboActionGraph::ValidateGraph() +{ + if (this->ValidationWindow.IsValid()) + { + this->ValidationWindow->RequestDestroyWindow(); + } + + UEdComboActionGraph *EdGraph = Cast(this->EditingGraph->EdGraph); + check(EdGraph != nullptr); + + const FScopedTransaction Transaction(LOCTEXT("ComboActionGraphEditorValidateGraph", "Combo Action Graph Editor: Validate Graph.")); + + UComboActionGraph *ComboActionGraph = EdGraph->GetComboActionGraph(); + check(ComboActionGraph != nullptr); + + this->RebuildComboActionGraph(); + + //TArray ValidationMessages; + //if (ComboActionGraph->ValidateGraph(ValidationMessages, true) == false) + //{ + // ValidationWindow = MDSPopup_GraphValidation::Open(ValidationMessages); + //} + //else + //{ + // ValidationMessages.Empty(); + // ValidationWindow = MDSPopup_GraphValidation::Open(ValidationMessages); + //} +} + +bool FAssetEditor_ComboActionGraph::CanValidateGraph() const +{ + return true; +} + +void FAssetEditor_ComboActionGraph::OnRenameNode() +{ + TSharedPtr CurrentGraphEditor = this->GetCurrentGraphEditor(); + if (CurrentGraphEditor.IsValid()) + { + const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + UEdGraphNode *SelectedNode = Cast(*NodeIt); + if (SelectedNode != nullptr && SelectedNode->bCanRenameNode) + { + CurrentGraphEditor->IsNodeTitleVisible(SelectedNode, true); + break; + } + } + } +} + +bool FAssetEditor_ComboActionGraph::CanRenameNodes() const +{ + check(this->GetSettings() != nullptr); + return this->GetSettings()->AllowRenameNodes() == true && this->GetSelectedNodes().Num() == 1; +} + +void FAssetEditor_ComboActionGraph::OnSelectedNodesChanged(const TSet &NewSelection) +{ + TArray Selection; + + for (UObject* SelectionEntry : NewSelection) + { + Selection.Add(SelectionEntry); + } + + if (Selection.Num() == 1) + { + // When just one node is selected, add it to PropertyWidget + this->PropertyWidget->SetObjects(Selection); + this->PropertyWidget->ShowAllAdvancedProperties(); + + //UComboActionEditorBFC::TriggerPreviewRefresh(Selection); + } + else + { + this->PropertyWidget->SetObject(this->EditingGraph); + } + + this->RebuildComboActionGraph(); +} + +void FAssetEditor_ComboActionGraph::OnNodeDoubleClicked(UEdGraphNode *Node) +{ + this->GraphEditorCommands->TryExecuteAction(FGenericCommands::Get().Rename.ToSharedRef()); +} + +void FAssetEditor_ComboActionGraph::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent) +{ + if (this->EditingGraph == nullptr) + return; + + this->EditingGraph->EdGraph->GetSchema()->ForceVisualizationCacheClear(); + + this->RebuildComboActionGraph(); +} + +TSharedRef FAssetEditor_ComboActionGraph::SpawnTab_Viewport(const FSpawnTabArgs &Args) +{ + //check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::ViewportID); + + TSharedRef SpawnedTab = SNew(SDockTab) + .Label(LOCTEXT("ViewportTab_Title", "Viewport")); + + if (this->ViewportWidget.IsValid()) + { + SpawnedTab->SetContent(this->ViewportWidget.ToSharedRef()); + } + + return SpawnedTab; +} + +TSharedRef FAssetEditor_ComboActionGraph::SpawnTab_Details(const FSpawnTabArgs& Args) +{ + //check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::ComboActionGraphPropertyID); + + auto DockTab = SNew(SDockTab) + .Label(LOCTEXT("Details_Title", "Property")) + [ + PropertyWidget.ToSharedRef() + ]; + + DockTab->SetTabIcon(FAppStyle::GetBrush("LevelEditor.Tabs.Details")); + return DockTab; +} + +TSharedRef FAssetEditor_ComboActionGraph::SpawnTab_Search(const FSpawnTabArgs& Args) +{ + //check(Args.GetTabId() == FAssetEditorTabs_MounteaDialogueGraph::SearchToolbarID); + + //auto DockTab = SNew(SDockTab) + // .Label(LOCTEXT("Search_Title", "Search")) + // [ + // this->FindResultsView.ToSharedRef() + // ]; + + //DockTab->SetTabIcon(FAppStyle::GetBrush("Kismet.Tabs.FindResults")); + //return DockTab; + + return SNew(SDockTab); +} + +#undef LOCTEXT_NAMESPACE + diff --git a/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.h b/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.h new file mode 100644 index 0000000..233a203 --- /dev/null +++ b/Source/ComboInputEditor/Private/Ed/AssetEditor_ComboActionGraph.h @@ -0,0 +1,167 @@ +// Copyright Dominik Pavlicek 2023. All Rights Reserved. + +#pragma once + +//#include "Search/SComboActionSearch.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogAssetEditorComboActionGraph, Log, All); + + +class COMBOINPUTEDITOR_API FAssetEditor_ComboActionGraph : public FAssetEditorToolkit, public FNotifyHook, public FGCObject +{ + +public: + FAssetEditor_ComboActionGraph(); + virtual ~FAssetEditor_ComboActionGraph() override; + + void OnPackageSaved(const FString &String, UPackage *Package, FObjectPostSaveContext ObjectPostSaveContext); + + void InitComboActionGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr &InitToolkitHost, class UComboActionGraph *Graph); + class UComboActionGraphEditorSettings *GetSettings() const; + +#pragma region ToolkitInterface + +public: + // IToolkit interface + virtual void RegisterTabSpawners(const TSharedRef &InTabManager) override; + virtual void UnregisterTabSpawners(const TSharedRef &InTabManager) override; + + virtual bool CloseWindow() override; + // End of IToolkit interface + +#pragma endregion + +#pragma region AssetEditorToolkit + + virtual FName GetToolkitFName() const override; + virtual FText GetBaseToolkitName() const override; + virtual FText GetToolkitName() const override; + virtual FText GetToolkitToolTipText() const override; + virtual FLinearColor GetWorldCentricTabColorScale() const override; + virtual FString GetWorldCentricTabPrefix() const override; + virtual FString GetDocumentationLink() const override; + virtual void SaveAsset_Execute() override; + +#pragma endregion + +#pragma region Toolbar + + void UpdateToolbar(); + //TSharedPtr GetToolbarBuilder() { return ToolbarBuilder; } + void RegisterToolbarTab(const TSharedRef &InTabManager); + +#pragma endregion + +#pragma region SerializableObjectInterface + + virtual void AddReferencedObjects(FReferenceCollector &Collector) override; + +#pragma endregion + +#pragma region FGCObject + + virtual FString GetReferencerName() const override; + +#pragma endregion + + // Gets/Sets the dialogue being edited + class UComboActionGraph *GetEditingGraphSafe() + { + check(EditingGraph); + return EditingGraph; + } + void SetDialogueBeingEdited(class UComboActionGraph *NewDialogue); + + virtual void JumpToNode(const class UEdGraphNode *JumpToMe, bool bRequestRename = false, bool bSelectNode = true) + { + if (this->ViewportWidget.IsValid()) + { + this->ViewportWidget->JumpToNode(JumpToMe, bRequestRename, bSelectNode); + } + } + +private: + void CreateInternalWidgets(); + TSharedRef CreateViewportWidget(); + + void BindCommands(); + void CreateEdGraph(); + void CreateCommandList(); + + TSharedPtr GetCurrentGraphEditor() const; + + FGraphPanelSelectionSet GetSelectedNodes() const; + + void RebuildComboActionGraph(); + + void SummonSearchUI(FString NewSearch = FString(), bool bSelectFirstResult = false); + +#pragma region GraphEditorCommands + + void SelectAllNodes(); + bool CanSelectAllNodes(); + void DeleteSelectedNodes(); + bool CanDeleteNodes(); + void DeleteSelectedDuplicatableNodes(); + void CutSelectedNodes(); + bool CanCutNodes(); + void CopySelectedNodes(); + bool CanCopyNodes(); + void PasteNodes(); + void PasteNodesHere(const FVector2D &Location); + bool CanPasteNodes(); + void DuplicateNodes(); + bool CanDuplicateNodes(); + + void AutoArrange(); + bool CanAutoArrange() const; + + void ValidateGraph(); + bool CanValidateGraph() const; + + void OnRenameNode(); + bool CanRenameNodes() const; + +#pragma endregion + +#pragma region GraphEditorEvents + + void OnSelectedNodesChanged(const TSet &NewSelection); + + void OnNodeDoubleClicked(UEdGraphNode *Node); + + void OnFinishedChangingProperties(const FPropertyChangedEvent &PropertyChangedEvent); + + //void OnPackageSaved(const FString &PackageFileName, UObject *Outer); + +#pragma endregion + +#pragma region Variables + +private: + + TSharedRef SpawnTab_Viewport(const FSpawnTabArgs &Args); + TSharedRef SpawnTab_Details(const FSpawnTabArgs &Args); + TSharedRef SpawnTab_Search(const FSpawnTabArgs &Args); + + class UComboActionGraphEditorSettings *ComboActionGraphEditorSettings; + + class UComboActionGraph *EditingGraph; + + //Toolbar + //TSharedPtr ToolbarBuilder; + + /** Handle to the registered OnPackageSave delegate */ + FDelegateHandle OnPackageSavedDelegateHandle; + + TSharedPtr ViewportWidget; + TSharedPtr PropertyWidget; + //TSharedPtr FindResultsView; + + /** The command list for this editor */ + TSharedPtr GraphEditorCommands; + + TSharedPtr ValidationWindow; + +#pragma endregion +}; diff --git a/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.cpp b/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.cpp index 01c36f1..d7a90c6 100644 --- a/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.cpp +++ b/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.cpp @@ -3,6 +3,7 @@ #include "Ed/EdComboActionGraph.h" #include "ComboActionGraph.h" +#include "Ed/AssetEditor_ComboActionGraph.h" #include "Ed/EdComboActionGraphEdge.h" #include "Ed/EdComboActionGraphNode.h" #include "Nodes/ComboActionGraphEdge.h" @@ -20,18 +21,18 @@ void UEdComboActionGraph::RebuildComboActionGraph() UComboActionGraph *Graph = GetComboActionGraph(); - Clear(); + this->Clear(); - for (int i = 0; i < Nodes.Num(); ++i) + for (const TObjectPtr &Node : this->Nodes) { - if (UEdComboActionGraphNode *EdNode = Cast(Nodes[i])) + if (UEdComboActionGraphNode *EdNode = Cast(Node)) { if (EdNode->ComboActionGraphNode == nullptr) continue; UComboActionGraphNode *ComboActionGraphNode = EdNode->ComboActionGraphNode; - NodeMap.Add(ComboActionGraphNode, EdNode); + this->NodeMap.Add(ComboActionGraphNode, EdNode); Graph->AllNodes.Add(ComboActionGraphNode); @@ -73,7 +74,7 @@ void UEdComboActionGraph::RebuildComboActionGraph() } } } - else if (UEdComboActionGraphEdge *EdgeNode = Cast(Nodes[i])) + else if (UEdComboActionGraphEdge *EdgeNode = Cast(Node)) { UEdComboActionGraphNode *StartNode = EdgeNode->GetStartNode(); UEdComboActionGraphNode *EndNode = EdgeNode->GetEndNode(); @@ -81,11 +82,11 @@ void UEdComboActionGraph::RebuildComboActionGraph() if (StartNode == nullptr || EndNode == nullptr || Edge == nullptr) { - UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildMounteaDialogueGraph] Add edge failed.")); + UE_LOG(LogEdComboActionGraph, Error, TEXT("[RebuildComboActionGraph] Add edge failed.")); continue; } - EdgeMap.Add(Edge, EdgeNode); + this->EdgeMap.Add(Edge, EdgeNode); Edge->Graph = Graph; Edge->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty); @@ -95,9 +96,8 @@ void UEdComboActionGraph::RebuildComboActionGraph() } } - for (int i = 0; i < Graph->AllNodes.Num(); ++i) + for (UComboActionGraphNode *Node : Graph->AllNodes) { - UComboActionGraphNode *Node = Graph->AllNodes[i]; if (Node->ParentNodes.Num() == 0) { Graph->RootNodes.Add(Node); @@ -111,8 +111,8 @@ void UEdComboActionGraph::RebuildComboActionGraph() Graph->RootNodes.Sort([&](const UComboActionGraphNode &L, const UComboActionGraphNode &R) { - UEdComboActionGraphNode* EdNode_LNode = NodeMap[&L]; - UEdComboActionGraphNode* EdNode_RNode = NodeMap[&R]; + UEdComboActionGraphNode *EdNode_LNode = this->NodeMap[&L]; + UEdComboActionGraphNode *EdNode_RNode = this->NodeMap[&R]; return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX; }); } @@ -128,9 +128,9 @@ bool UEdComboActionGraph::Modify(bool bAlwaysMarkDirty) this->GetComboActionGraph()->Modify(); - for (int32 i = 0; i < Nodes.Num(); ++i) + for (TObjectPtr &Node : this->Nodes) { - Nodes[i]->Modify(); + Node->Modify(); } return Rtn; @@ -138,20 +138,21 @@ bool UEdComboActionGraph::Modify(bool bAlwaysMarkDirty) void UEdComboActionGraph::PostEditUndo() { - NotifyGraphChanged(); + this->NotifyGraphChanged(); Super::PostEditUndo(); } -//void UEdComboActionGraph::SetDialogueEditorPtr(TWeakPtr NewPtr) -//{ -// DialogueEditorPtr = NewPtr; -//} +void UEdComboActionGraph::SetDialogueEditorPtr(TWeakPtr NewPtr) +{ + this->ComboActionEditorPtr = NewPtr; +} -//bool UEdComboActionGraph::JumpToNode(const UMounteaDialogueGraphNode* Node) -//{ -// return FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(DialogueEditorPtr, *NodeMap.Find(Node)); -//} +bool UEdComboActionGraph::JumpToNode(const UComboActionGraphNode *Node) +{ + //return FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(this->ComboActionEditorPtr, *NodeMap.Find(Node)); + return false; +} void UEdComboActionGraph::Clear() { diff --git a/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.h b/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.h index c0e9e81..7327b0f 100644 --- a/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.h +++ b/Source/ComboInputEditor/Private/Ed/EdComboActionGraph.h @@ -23,14 +23,13 @@ public: virtual bool Modify(bool bAlwaysMarkDirty) override; virtual void PostEditUndo() override; - //TWeakPtr GetDialogueEditorPtr() const { return DialogueEditorPtr; } - //void SetDialogueEditorPtr(TWeakPtr NewPtr); - //void ResetDialogueEditorPtr() { DialogueEditorPtr.Reset(); } + TWeakPtr GetComboActionEditorPtr() const { return this->ComboActionEditorPtr; } + void SetDialogueEditorPtr(TWeakPtr NewPtr); + void ResetDialogueEditorPtr() { this->ComboActionEditorPtr.Reset(); } - //bool JumpToNode(const class UComboActionGraphNode *Node); + bool JumpToNode(const class UComboActionGraphNode *Node); public: - UPROPERTY(Transient) TMap NodeMap; @@ -38,12 +37,10 @@ public: TMap EdgeMap; protected: - void Clear(); void SortNodes(UComboActionGraphNode *RootNode); private: - - /** Pointer back to the Dialogue editor that owns us */ - //TWeakPtr DialogueEditorPtr; + /** Pointer back to the combo action editor that owns us */ + TWeakPtr ComboActionEditorPtr; }; diff --git a/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.cpp b/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.cpp index e8b6fbb..97d5d3e 100644 --- a/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.cpp +++ b/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.cpp @@ -23,6 +23,19 @@ UEdComboActionGraphNode::UEdComboActionGraphNode() bAllowPaste = true; } +void UEdComboActionGraphNode::SetComboActionGraphNode(UComboActionGraphNode *NewNode) +{ + this->ComboActionGraphNode = NewNode; + + if (this->ComboActionGraphNode) + { + this->bAllowCopy = this->ComboActionGraphNode->bAllowCopy; + this->bAllowDelete = this->ComboActionGraphNode->bAllowDelete; + this->bAllowDuplicate = this->ComboActionGraphNode->bAllowPaste; + this->bAllowPaste = this->ComboActionGraphNode->bAllowPaste; + } +} + UEdComboActionGraph *UEdComboActionGraphNode::GetEdComboActionGraph() const { return Cast(this->GetGraph()); diff --git a/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.h b/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.h index ad9c75e..605f8ae 100644 --- a/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.h +++ b/Source/ComboInputEditor/Private/Ed/EdComboActionGraphNode.h @@ -22,7 +22,8 @@ class UEdComboActionGraphNode : public UEdGraphNode public: UEdComboActionGraphNode(); - + + void SetComboActionGraphNode(UComboActionGraphNode *NewNode); class UEdComboActionGraph *GetEdComboActionGraph() const; virtual void AllocateDefaultPins() override; diff --git a/Source/ComboInputEditor/Private/FConnectionDrawingPolicy_ComboActionGraph.cpp b/Source/ComboInputEditor/Private/Ed/FConnectionDrawingPolicy_ComboActionGraph.cpp similarity index 100% rename from Source/ComboInputEditor/Private/FConnectionDrawingPolicy_ComboActionGraph.cpp rename to Source/ComboInputEditor/Private/Ed/FConnectionDrawingPolicy_ComboActionGraph.cpp diff --git a/Source/ComboInputEditor/Private/FConnectionDrawingPolicy_ComboActionGraph.h b/Source/ComboInputEditor/Private/Ed/FConnectionDrawingPolicy_ComboActionGraph.h similarity index 100% rename from Source/ComboInputEditor/Private/FConnectionDrawingPolicy_ComboActionGraph.h rename to Source/ComboInputEditor/Private/Ed/FConnectionDrawingPolicy_ComboActionGraph.h diff --git a/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.cpp b/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.cpp new file mode 100644 index 0000000..1e875e7 --- /dev/null +++ b/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.cpp @@ -0,0 +1,131 @@ +#include "SEdComboActionGraphEdge.h" + +#include "ConnectionDrawingPolicy.h" +#include "SGraphPanel.h" + +#include "Ed/EdComboActionGraphEdge.h" +#include "Ed/EdComboActionGraphNode.h" +#include "Widgets/Images/SImage.h" + +#define LOCTEXT_NAMESPACE "SEdComboActionGraphEdge" + + +void SEdComboActionGraphEdge::Construct(const FArguments &InArgs, UEdComboActionGraphEdge *InNode) +{ + this->GraphNode = InNode; + this->UpdateGraphNode(); +} + +bool SEdComboActionGraphEdge::RequiresSecondPassLayout() const +{ + return true; +} + +void SEdComboActionGraphEdge::PerformSecondPassLayout(const TMap>& NodeToWidgetLookup) const +{ + UEdComboActionGraphEdge *EdgeNode = CastChecked(GraphNode); + + FGeometry StartGeom; + FGeometry EndGeom; + + UEdComboActionGraphNode *Start = EdgeNode->GetStartNode(); + UEdComboActionGraphNode *End = EdgeNode->GetEndNode(); + if (Start != nullptr && End != nullptr) + { + const TSharedRef *pFromWidget = NodeToWidgetLookup.Find(Start); + const TSharedRef *pToWidget = NodeToWidgetLookup.Find(End); + if (pFromWidget != nullptr && pToWidget != nullptr) + { + const TSharedRef& FromWidget = *pFromWidget; + const TSharedRef& 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 SEdComboActionGraphEdge::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(FAppStyle::GetBrush("Graph.TransitionNode.ColorSpill")) + .ColorAndOpacity(this, &SEdComboActionGraphEdge::GetEdgeColor) + ]*/ + + SOverlay::Slot() + [ + SNew(SImage) + .Image(FAppStyle::GetBrush("GraphEditor.RefPinIcon")) + .ColorAndOpacity(this, &SEdComboActionGraphEdge::GetEdgeColor) + ] + ]; +} + +void SEdComboActionGraphEdge::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 + // towards the PrevStateNode and +1 is 1 towards the NextStateNode. + + const float MutliNodeSpace = 0.2f; // Space between multiple transition nodes (in units of ) + 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 SEdComboActionGraphEdge::GetEdgeColor() const +{ + return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.h b/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.h new file mode 100644 index 0000000..4f70620 --- /dev/null +++ b/Source/ComboInputEditor/Private/Ed/SEdComboActionGraphEdge.h @@ -0,0 +1,33 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Styling/SlateColor.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SWidget.h" +#include "SNodePanel.h" +#include "SGraphNode.h" + + +class SEdComboActionGraphEdge : public SGraphNode +{ +public: + SLATE_BEGIN_ARGS(SEdComboActionGraphEdge){} + SLATE_END_ARGS() + + void Construct(const FArguments &InArgs, class UEdComboActionGraphEdge *InNode); + + virtual bool RequiresSecondPassLayout() const override; + virtual void PerformSecondPassLayout(const TMap > &NodeToWidgetLookup) const override; + + virtual void UpdateGraphNode() override; + + // 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; + +protected: + FSlateColor GetEdgeColor() const; + +private: + TSharedPtr TextEntryWidget; + +}; diff --git a/Source/ComboInputEditor/Public/ComboInputEditor.h b/Source/ComboInputEditor/Public/ComboInputEditor.h index 698b6a3..6453fe8 100644 --- a/Source/ComboInputEditor/Public/ComboInputEditor.h +++ b/Source/ComboInputEditor/Public/ComboInputEditor.h @@ -55,6 +55,20 @@ public: virtual UObject *FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) override; }; +UCLASS() +class COMBOINPUTEDITOR_API UComboActionGraph_Factory : public UFactory +{ + GENERATED_BODY() + +public: + UComboActionGraph_Factory(const class FObjectInitializer &ObjectInitializer); + + UPROPERTY(EditAnywhere, Category = "Combo Input|Action") + TSubclassOf ComboActionGraphClass; + + virtual UObject *FactoryCreateNew(UClass *Class, UObject *InParent, FName Name, EObjectFlags Flags, UObject *Context, FFeedbackContext *Warn) override; +}; + class FComboInputEditorModule : public IModuleInterface { @@ -63,7 +77,7 @@ public: static bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("ComboInputEditor"); } virtual void StartupModule() override; - virtual void ShutdownModule() override; + virtual void ShutdownModule() override{} static EAssetTypeCategories::Type GetInputAssetsCategory() { return FComboInputEditorModule::ComboAssetsCategory; } @@ -77,8 +91,12 @@ private: } static EAssetTypeCategories::Type ComboAssetsCategory; + static EAssetTypeCategories::Type ComboActionGraphCategory; TArray> CreatedAssetTypeActions; TSharedPtr ComboInputEditorStyleSet; + TSharedPtr ComboActionGraphPanelNodeFactory; + TSharedPtr ComboActionGraphAssetActions; + TSharedPtr ComboActionGraphStyleSet; };