Added a bunch more stuff. Too much to care to mention. Still more to do though.

This commit is contained in:
Jamie Greunbaum 2023-09-30 01:25:51 -04:00
parent cfe285b94d
commit 102927a690
60 changed files with 1664 additions and 76 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -30,8 +30,10 @@ public class ComboInputEditor : ModuleRules
"ApplicationCore", "ApplicationCore",
"AssetTools", "AssetTools",
"BlueprintGraph",
"DeveloperSettings", "DeveloperSettings",
"GraphEditor", "GraphEditor",
"InputCore",
"Projects", "Projects",
"Slate", "Slate",
"SlateCore", "SlateCore",

View File

@ -10,6 +10,7 @@
#include "Ed/AssetEditor_ComboActionGraph.h" #include "Ed/AssetEditor_ComboActionGraph.h"
#include "Ed/EdComboActionGraphEdge.h" #include "Ed/EdComboActionGraphEdge.h"
#include "Ed/EdComboActionGraphNode.h" #include "Ed/EdComboActionGraphNode.h"
#include "Ed/FComboActionGraphEditorCommands.h"
#include "Ed/SEdComboActionGraphEdge.h" #include "Ed/SEdComboActionGraphEdge.h"
#include "Ed/SEdComboActionGraphNode.h" #include "Ed/SEdComboActionGraphNode.h"
#include "Interfaces/IPluginManager.h" #include "Interfaces/IPluginManager.h"
@ -217,8 +218,8 @@ FComboInputSlateStyle::FComboInputSlateStyle() : FSlateStyleSet("ComboInputEdito
// Combo Action Graph editor brushes // Combo Action Graph editor brushes
{ {
this->SetContentRoot(IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir() / TEXT("Resources")); this->SetContentRoot(PluginSlateDir / TEXT("Resources/Slate/Editor"));
this->SetCoreContentRoot(IPluginManager::Get().FindPlugin("ComboInput")->GetBaseDir() / TEXT("Content")); this->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate/Editor"));
this->Set("MDSStyleSet.AutoArrange.small", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon16)); this->Set("MDSStyleSet.AutoArrange.small", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon16));
this->Set("MDSStyleSet.AutoArrange", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon40)); this->Set("MDSStyleSet.AutoArrange", new IMAGE_BRUSH(TEXT("AutoArrangeIcon"), Icon40));
@ -330,6 +331,13 @@ void FComboInputEditorModule::StartupModule()
this->ComboActionGraphAssetActions = MakeShared<FAssetTypeActions_ComboActionGraph>(); this->ComboActionGraphAssetActions = MakeShared<FAssetTypeActions_ComboActionGraph>();
this->RegisterAssetTypeActions(AssetTools, this->ComboActionGraphAssetActions.ToSharedRef()); this->RegisterAssetTypeActions(AssetTools, this->ComboActionGraphAssetActions.ToSharedRef());
} }
FComboActionGraphEditorCommands::Register();
}
void FComboInputEditorModule::ShutdownModule()
{
FComboActionGraphEditorCommands::Unregister();
} }
#undef LOCTEXT_NAMESPACE #undef LOCTEXT_NAMESPACE

View File

@ -24,7 +24,8 @@
#include "Layout/ComboActionForceDirectedSolveLayoutStrategy.h" #include "Layout/ComboActionForceDirectedSolveLayoutStrategy.h"
#include "Layout/ComboActionTreeSolveLayoutStrategy.h" #include "Layout/ComboActionTreeSolveLayoutStrategy.h"
//#include "Popups/MDSPopup_GraphValidation.h" //#include "Popups/MDSPopup_GraphValidation.h"
//#include "Search/ComboActionSearchUtils.h" #include "Search/ComboActionSearchUtils.h"
#include "Search/SComboActionSearch.h"
#include "Settings/ComboActionGraphEditorSettings.h" #include "Settings/ComboActionGraphEditorSettings.h"
#include "UObject/ObjectSaveContext.h" #include "UObject/ObjectSaveContext.h"
@ -54,10 +55,6 @@ FAssetEditor_ComboActionGraph::~FAssetEditor_ComboActionGraph()
this->EditingGraph = nullptr; this->EditingGraph = nullptr;
UPackage::PackageSavedWithContextEvent.Remove(this->OnPackageSavedDelegateHandle); UPackage::PackageSavedWithContextEvent.Remove(this->OnPackageSavedDelegateHandle);
FGenericCommands::Unregister();
FGraphEditorCommands::Unregister();
FComboActionGraphEditorCommands::Unregister();
this->ToolbarBuilder.Reset(); this->ToolbarBuilder.Reset();
} }
@ -71,10 +68,6 @@ void FAssetEditor_ComboActionGraph::InitComboActionGraphAssetEditor(const EToolk
this->EditingGraph = Graph; this->EditingGraph = Graph;
this->CreateEdGraph(); this->CreateEdGraph();
FGenericCommands::Register();
FGraphEditorCommands::Register();
FComboActionGraphEditorCommands::Register();
if (!this->ToolbarBuilder.IsValid()) if (!this->ToolbarBuilder.IsValid())
{ {
this->ToolbarBuilder = MakeShareable(new FAssetEditorToolbarComboActionGraph(SharedThis(this))); this->ToolbarBuilder = MakeShareable(new FAssetEditorToolbarComboActionGraph(SharedThis(this)));
@ -164,10 +157,10 @@ void FAssetEditor_ComboActionGraph::RegisterTabSpawners(const TSharedRef<FTabMan
.SetGroup(WorkspaceMenuCategoryRef) .SetGroup(WorkspaceMenuCategoryRef)
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details")); .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
//InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Search)) InTabManager->RegisterTabSpawner(FAssetEditorTabs_ComboActionGraph::SearchToolbarID, FOnSpawnTab::CreateSP(this, &FAssetEditor_ComboActionGraph::SpawnTab_Search))
// .SetDisplayName(LOCTEXT("SearchTab", "Search")) .SetDisplayName(LOCTEXT("SearchTab", "Search"))
// .SetGroup(WorkspaceMenuCategoryRef) .SetGroup(WorkspaceMenuCategoryRef)
// .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "Kismet.Tabs.FindResults")); .SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "Kismet.Tabs.FindResults"));
} }
void FAssetEditor_ComboActionGraph::UnregisterTabSpawners(const TSharedRef<FTabManager> &InTabManager) void FAssetEditor_ComboActionGraph::UnregisterTabSpawners(const TSharedRef<FTabManager> &InTabManager)
@ -268,8 +261,10 @@ FString FAssetEditor_ComboActionGraph::GetReferencerName() const
void FAssetEditor_ComboActionGraph::SetDialogueBeingEdited(UComboActionGraph *NewDialogue) void FAssetEditor_ComboActionGraph::SetDialogueBeingEdited(UComboActionGraph *NewDialogue)
{ {
if (NewDialogue == nullptr) return; if (NewDialogue == nullptr || NewDialogue == this->EditingGraph)
if (NewDialogue == this->EditingGraph) return; {
return;
}
UComboActionGraph *Previous = this->EditingGraph; UComboActionGraph *Previous = this->EditingGraph;
this->EditingGraph = NewDialogue; this->EditingGraph = NewDialogue;
@ -282,7 +277,7 @@ void FAssetEditor_ComboActionGraph::CreateInternalWidgets()
{ {
this->ViewportWidget = this->CreateViewportWidget(); this->ViewportWidget = this->CreateViewportWidget();
FDetailsViewArgs Args; //( false, false, true, FDetailsViewArgs::HideNameArea, false ); FDetailsViewArgs Args;
Args.bUpdatesFromSelection = false; Args.bUpdatesFromSelection = false;
Args.bLockable = false; Args.bLockable = false;
Args.bAllowSearch = true; Args.bAllowSearch = true;
@ -292,11 +287,11 @@ void FAssetEditor_ComboActionGraph::CreateInternalWidgets()
FPropertyEditorModule &PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor"); FPropertyEditorModule &PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
this->PropertyWidget = PropertyModule.CreateDetailView(Args); this->PropertyWidget = PropertyModule.CreateDetailView(Args);
this->PropertyWidget->SetObject(EditingGraph); this->PropertyWidget->SetObject(this->EditingGraph);
this->PropertyWidget->OnFinishedChangingProperties().AddSP(this, &FAssetEditor_ComboActionGraph::OnFinishedChangingProperties); this->PropertyWidget->OnFinishedChangingProperties().AddSP(this, &FAssetEditor_ComboActionGraph::OnFinishedChangingProperties);
//this->FindResultsView = SNew(SComboActionSearch, SharedThis(this)); this->FindResultsView = SNew(SComboActionSearch, SharedThis(this));
} }
TSharedRef<SGraphEditor> FAssetEditor_ComboActionGraph::CreateViewportWidget() TSharedRef<SGraphEditor> FAssetEditor_ComboActionGraph::CreateViewportWidget()
@ -469,11 +464,6 @@ void FAssetEditor_ComboActionGraph::SelectAllNodes()
} }
} }
bool FAssetEditor_ComboActionGraph::CanSelectAllNodes()
{
return true;
}
void FAssetEditor_ComboActionGraph::DeleteSelectedNodes() void FAssetEditor_ComboActionGraph::DeleteSelectedNodes()
{ {
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor(); TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
@ -528,7 +518,7 @@ void FAssetEditor_ComboActionGraph::DeleteSelectedNodes()
this->RebuildComboActionGraph(); this->RebuildComboActionGraph();
} }
bool FAssetEditor_ComboActionGraph::CanDeleteNodes() bool FAssetEditor_ComboActionGraph::CanDeleteNodes() const
{ {
// If any of the nodes can be deleted then we should allow deleting // If any of the nodes can be deleted then we should allow deleting
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
@ -584,11 +574,6 @@ void FAssetEditor_ComboActionGraph::CutSelectedNodes()
this->DeleteSelectedDuplicatableNodes(); this->DeleteSelectedDuplicatableNodes();
} }
bool FAssetEditor_ComboActionGraph::CanCutNodes()
{
return this->CanCopyNodes() && this->CanDeleteNodes();
}
void FAssetEditor_ComboActionGraph::CopySelectedNodes() void FAssetEditor_ComboActionGraph::CopySelectedNodes()
{ {
// Export the selected nodes and place the text on the clipboard // Export the selected nodes and place the text on the clipboard
@ -624,7 +609,7 @@ void FAssetEditor_ComboActionGraph::CopySelectedNodes()
FPlatformApplicationMisc::ClipboardCopy(*ExportedText); FPlatformApplicationMisc::ClipboardCopy(*ExportedText);
} }
bool FAssetEditor_ComboActionGraph::CanCopyNodes() bool FAssetEditor_ComboActionGraph::CanCopyNodes() const
{ {
// If any of the nodes can be duplicated then we should allow copying // If any of the nodes can be duplicated then we should allow copying
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
@ -645,7 +630,7 @@ void FAssetEditor_ComboActionGraph::PasteNodes()
TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor(); TSharedPtr<SGraphEditor> CurrentGraphEditor = this->GetCurrentGraphEditor();
if (CurrentGraphEditor.IsValid()) if (CurrentGraphEditor.IsValid())
{ {
PasteNodesHere(CurrentGraphEditor->GetPasteLocation()); this->PasteNodesHere(CurrentGraphEditor->GetPasteLocation());
} }
} }
@ -731,7 +716,7 @@ void FAssetEditor_ComboActionGraph::PasteNodesHere(const FVector2D& Location)
this->RebuildComboActionGraph(); this->RebuildComboActionGraph();
} }
bool FAssetEditor_ComboActionGraph::CanPasteNodes() bool FAssetEditor_ComboActionGraph::CanPasteNodes() const
{ {
const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes(); const FGraphPanelSelectionSet SelectedNodes = this->GetSelectedNodes();
for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
@ -755,17 +740,6 @@ bool FAssetEditor_ComboActionGraph::CanPasteNodes()
return FEdGraphUtilities::CanImportNodesFromText(CurrentGraphEditor->GetCurrentGraph(), 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() void FAssetEditor_ComboActionGraph::AutoArrange()
{ {
UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph); UEdComboActionGraph *EdGraph = Cast<UEdComboActionGraph>(this->EditingGraph->EdGraph);
@ -821,21 +795,16 @@ void FAssetEditor_ComboActionGraph::ValidateGraph()
this->RebuildComboActionGraph(); this->RebuildComboActionGraph();
//TArray<FText> ValidationMessages; TArray<FText> ValidationMessages;
//if (ComboActionGraph->ValidateGraph(ValidationMessages, true) == false) 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; //ValidationWindow = MDSPopup_GraphValidation::Open(ValidationMessages);
}
else
{
ValidationMessages.Empty();
//ValidationWindow = MDSPopup_GraphValidation::Open(ValidationMessages);
}
} }
void FAssetEditor_ComboActionGraph::OnRenameNode() void FAssetEditor_ComboActionGraph::OnRenameNode()
@ -924,12 +893,26 @@ TSharedRef<SDockTab> FAssetEditor_ComboActionGraph::SpawnTab_Details(const FSpaw
auto DockTab = SNew(SDockTab) auto DockTab = SNew(SDockTab)
.Label(LOCTEXT("Details_Title", "Property")) .Label(LOCTEXT("Details_Title", "Property"))
[ [
PropertyWidget.ToSharedRef() this->PropertyWidget.ToSharedRef()
]; ];
DockTab->SetTabIcon(FAppStyle::GetBrush("LevelEditor.Tabs.Details")); DockTab->SetTabIcon(FAppStyle::GetBrush("LevelEditor.Tabs.Details"));
return DockTab; return DockTab;
} }
TSharedRef<SDockTab> FAssetEditor_ComboActionGraph::SpawnTab_Search(const FSpawnTabArgs &Args)
{
check(Args.GetTabId() == FAssetEditorTabs_ComboActionGraph::SearchToolbarID);
auto DockTab = SNew(SDockTab)
.Label(LOCTEXT("Search_Title", "Search"))
[
this->FindResultsView.ToSharedRef()
];
DockTab->SetTabIcon(FAppStyle::GetBrush("Kismet.Tabs.FindResults"));
return DockTab;
}
#undef LOCTEXT_NAMESPACE #undef LOCTEXT_NAMESPACE

View File

@ -99,25 +99,25 @@ private:
#pragma region GraphEditorCommands #pragma region GraphEditorCommands
void SelectAllNodes(); void SelectAllNodes();
bool CanSelectAllNodes(); bool CanSelectAllNodes() const { return true; }
void DeleteSelectedNodes(); void DeleteSelectedNodes();
bool CanDeleteNodes(); bool CanDeleteNodes() const;
void DeleteSelectedDuplicatableNodes(); void DeleteSelectedDuplicatableNodes();
void CutSelectedNodes(); void CutSelectedNodes();
bool CanCutNodes(); bool CanCutNodes() const { return this->CanCopyNodes() && this->CanDeleteNodes(); }
void CopySelectedNodes(); void CopySelectedNodes();
bool CanCopyNodes(); bool CanCopyNodes() const;
void PasteNodes(); void PasteNodes();
void PasteNodesHere(const FVector2D &Location); void PasteNodesHere(const FVector2D &Location);
bool CanPasteNodes(); bool CanPasteNodes() const;
void DuplicateNodes(); void DuplicateNodes() { this->CopySelectedNodes(); this->PasteNodes(); }
bool CanDuplicateNodes(); bool CanDuplicateNodes() { return this->CanCopyNodes(); }
void AutoArrange(); void AutoArrange();
bool CanAutoArrange() const; bool CanAutoArrange() const;
void ValidateGraph(); void ValidateGraph();
bool CanValidateGraph() const; bool CanValidateGraph() const { return true; }
void OnRenameNode(); void OnRenameNode();
bool CanRenameNodes() const; bool CanRenameNodes() const;
@ -142,6 +142,7 @@ private:
TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs &Args); TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs &Args);
TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs &Args); TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs &Args);
TSharedRef<SDockTab> SpawnTab_Search(const FSpawnTabArgs &Args);
class UComboActionGraphEditorSettings *ComboActionGraphEditorSettings; class UComboActionGraphEditorSettings *ComboActionGraphEditorSettings;
@ -155,7 +156,7 @@ private:
TSharedPtr<SGraphEditor> ViewportWidget; TSharedPtr<SGraphEditor> ViewportWidget;
TSharedPtr<class IDetailsView> PropertyWidget; TSharedPtr<class IDetailsView> PropertyWidget;
//TSharedPtr<class SComboActionSearch> FindResultsView; TSharedPtr<class SComboActionSearch> FindResultsView;
/** The command list for this editor */ /** The command list for this editor */
TSharedPtr<FUICommandList> GraphEditorCommands; TSharedPtr<FUICommandList> GraphEditorCommands;

View File

@ -0,0 +1,257 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionGraphEditorUtilities.h"
#include "ComboActionGraph.h"
#include "K2Node_Event.h"
#include "Ed/AssetEditor_ComboActionGraph.h"
#include "Ed/EdComboActionGraph.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Kismet2/SClassPickerDialog.h"
#include "Layout/AssetEditorTabs.h"
bool FComboActionGraphEditorUtilities::PickChildrenOfClass(const FText &TitleText, UClass *&OutChosenClass, UClass *Class)
{
// Create filter
TSharedPtr<FComboActionClassViewerFilter> Filter = MakeShareable(new FComboActionClassViewerFilter);
Filter->AllowedChildrenOfClasses.Add(Class);
// Fill in options
FClassViewerInitializationOptions Options;
Options.Mode = EClassViewerMode::ClassPicker;
Options.bShowUnloadedBlueprints = true;
Options.ClassFilters.Add(Filter.ToSharedRef());
Options.DisplayMode = EClassViewerDisplayMode::TreeView;
Options.bShowNoneOption = false;
Options.InitiallySelectedClass = Class;
Options.bExpandRootNodes = true;
Options.NameTypeToDisplay = EClassViewerNameTypeToDisplay::DisplayName;
return SClassPickerDialog::PickClass(TitleText, Options, OutChosenClass, Class);
}
bool FComboActionGraphEditorUtilities::OpenBlueprintEditor(UBlueprint *Blueprint, EComboActionBlueprintOpenType OpenType, FName FunctionNameToOpen, bool bForceFullEditor, bool bAddBlueprintFunctionIfItDoesNotExist)
{
if (!Blueprint)
{
return false;
}
Blueprint->bForceFullEditor = bForceFullEditor;
// Find Function Graph
UObject *ObjectToFocusOn = nullptr;
if (OpenType != EComboActionBlueprintOpenType::None && FunctionNameToOpen != NAME_None)
{
UClass* Class = Blueprint->GeneratedClass;
check(Class);
if (OpenType == EComboActionBlueprintOpenType::Function)
{
ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist
? FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(Blueprint, FunctionNameToOpen, Class)
: FComboActionGraphEditorUtilities::BlueprintGetFunction(Blueprint, FunctionNameToOpen, Class);
}
else if (OpenType == EComboActionBlueprintOpenType::Event)
{
ObjectToFocusOn = bAddBlueprintFunctionIfItDoesNotExist
? FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(Blueprint, FunctionNameToOpen, Class)
: FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, FunctionNameToOpen, Class);
}
}
// Default to the last uber graph
if (ObjectToFocusOn == nullptr)
{
ObjectToFocusOn = Blueprint->GetLastEditedUberGraph();
}
if (ObjectToFocusOn)
{
FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(ObjectToFocusOn);
return true;
}
return FComboActionGraphEditorUtilities::OpenEditorForAsset(Blueprint);
}
UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetOrAddFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature)
{
if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal)
{
return nullptr;
}
// Find existing function
if (UEdGraph *GraphFunction = BlueprintGetFunction(Blueprint, FunctionName, FunctionClassSignature))
{
return GraphFunction;
}
// Create a new function
UEdGraph *NewGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, FunctionName, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph(Blueprint, NewGraph, /*bIsUserCreated=*/ false, FunctionClassSignature);
Blueprint->LastEditedDocuments.Add(NewGraph);
return NewGraph;
}
UEdGraph *FComboActionGraphEditorUtilities::BlueprintGetFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature)
{
if (!Blueprint || Blueprint->BlueprintType != BPTYPE_Normal)
{
return nullptr;
}
// Find existing function
for (UEdGraph *GraphFunction : Blueprint->FunctionGraphs)
{
if (FunctionName == GraphFunction->GetFName())
{
return GraphFunction;
}
}
// Find in the implemented Interfaces Graphs
for (const FBPInterfaceDescription &Interface : Blueprint->ImplementedInterfaces)
{
for (UEdGraph *GraphFunction : Interface.Graphs)
{
if (FunctionName == GraphFunction->GetFName())
{
return GraphFunction;
}
}
}
return nullptr;
}
UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetOrAddEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature)
{
if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal)
{
return nullptr;
}
// Find existing event
if (UK2Node_Event *EventNode = FComboActionGraphEditorUtilities::BlueprintGetEvent(Blueprint, EventName, EventClassSignature))
{
return EventNode;
}
// Create a New Event
if (Blueprint->UbergraphPages.Num())
{
int32 NodePositionY = 0;
UK2Node_Event* NodeEvent = FKismetEditorUtilities::AddDefaultEventNode(
Blueprint,
Blueprint->UbergraphPages[0],
EventName,
EventClassSignature,
NodePositionY
);
NodeEvent->SetEnabledState(ENodeEnabledState::Enabled);
NodeEvent->NodeComment = "";
NodeEvent->bCommentBubbleVisible = false;
return NodeEvent;
}
return nullptr;
}
UK2Node_Event *FComboActionGraphEditorUtilities::BlueprintGetEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature)
{
if (!Blueprint || Blueprint->BlueprintType != EBlueprintType::BPTYPE_Normal)
{
return nullptr;
}
TArray<UK2Node_Event*> AllEvents;
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(Blueprint, AllEvents);
for (UK2Node_Event *EventNode : AllEvents)
{
if (EventNode->bOverrideFunction && EventNode->EventReference.GetMemberName() == EventName)
{
return EventNode;
}
}
return nullptr;
}
bool FComboActionGraphEditorUtilities::OpenEditorForAsset(const UObject* Asset)
{
if (!IsValid(Asset) || !GEditor)
{
return false;
}
return GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(const_cast<UObject*>(Asset));
}
bool FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(TWeakPtr<FAssetEditor_ComboActionGraph> DialogueEditorPtr, const UEdGraphNode *GraphNode, bool bFocusIfOpen)
{
if (!IsValid(GraphNode))
{
return false;
}
if (!DialogueEditorPtr.IsValid())
{
return false;
}
// Open if not already.
UComboActionGraph *Dialogue = FComboActionGraphEditorUtilities::GetActionFromGraphNode(GraphNode);
if (!FComboActionGraphEditorUtilities::OpenEditorForAsset(Dialogue))
{
return false;
}
// Could still fail focus on the graph node
if (IAssetEditorInstance *EditorInstance = FindEditorForAsset(Dialogue, bFocusIfOpen))
{
EditorInstance->FocusWindow(const_cast<UEdGraphNode*>(GraphNode));
UEdComboActionGraph *GraphEditor = Cast<UEdComboActionGraph>(Dialogue->EdGraph);
if (GraphEditor)
{
TSet<const UEdGraphNode*> SelectedNodes;
SelectedNodes.Add(GraphNode);
GraphEditor->SelectNodeSet(SelectedNodes);
DialogueEditorPtr.Pin()->JumpToNode(GraphNode);
}
return true;
}
return false;
}
UComboActionGraph *FComboActionGraphEditorUtilities::GetActionFromGraphNode(const UEdGraphNode *GraphNode)
{
if (const UEdComboActionGraphNode *ComboActionBaseNode = Cast<UEdComboActionGraphNode>(GraphNode))
{
return ComboActionBaseNode->GetEdComboActionGraph()->GetComboActionGraph();
}
if (const UEdComboActionGraph *ComboActionGraph = Cast<UEdComboActionGraph>(GraphNode->GetGraph()))
{
return Cast<UComboActionGraph>(ComboActionGraph->GetComboActionGraph());
}
return nullptr;
}
IAssetEditorInstance *FComboActionGraphEditorUtilities::FindEditorForAsset(UObject* Asset, bool bFocusIfOpen)
{
if (!IsValid(Asset) || !GEditor)
{
return nullptr;
}
return GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(Asset, bFocusIfOpen);
}

View File

@ -0,0 +1,103 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "ClassViewerFilter.h"
enum class EComboActionBlueprintOpenType : uint8
{
None = 0,
Function,
Event
};
class FComboActionClassViewerFilter : public IClassViewerFilter
{
public:
// All children of these classes will be included unless filtered out by another setting.
TSet<const UClass*> AllowedChildrenOfClasses;
virtual bool IsClassAllowed(const FClassViewerInitializationOptions &InInitOptions, const UClass *InClass, TSharedRef<FClassViewerFilterFuncs> InFilterFuncs) override
{
return !InClass->HasAnyClassFlags(this->DisallowedClassFlags)
&& InFilterFuncs->IfInChildOfClassesSet(this->AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed;
}
virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions &InInitOptions, const TSharedRef<const IUnloadedBlueprintData> InUnloadedClassData, TSharedRef<FClassViewerFilterFuncs> InFilterFuncs) override
{
return !InUnloadedClassData->HasAnyClassFlags(this->DisallowedClassFlags)
&& InFilterFuncs->IfInChildOfClassesSet(this->AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed;
}
private:
// Disallowed class flags.
EClassFlags DisallowedClassFlags = CLASS_Deprecated;
};
class FComboActionGraphEditorUtilities
{
public:
static bool PickChildrenOfClass(const FText &TitleText, UClass *&OutChosenClass, UClass *Class);
static bool OpenBlueprintEditor
(
UBlueprint *Blueprint,
EComboActionBlueprintOpenType OpenType = EComboActionBlueprintOpenType::None,
FName FunctionNameToOpen = NAME_None,
bool bForceFullEditor = true,
bool bAddBlueprintFunctionIfItDoesNotExist = false
);
static UEdGraph *BlueprintGetOrAddFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature);
static UEdGraph *BlueprintGetFunction(UBlueprint *Blueprint, FName FunctionName, UClass *FunctionClassSignature);
static class UK2Node_Event *BlueprintGetOrAddEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature);
static class UK2Node_Event *BlueprintGetEvent(UBlueprint *Blueprint, FName EventName, UClass *EventClassSignature);
static bool OpenEditorForAsset(const UObject *Asset);
static bool IsABlueprintClass(const UClass *Class) { return Cast<UBlueprintGeneratedClass>(Class) != nullptr; }
static bool GetAllChildClassesOf(const UClass *ParentClass, TArray<UClass*> &OutNativeClasses, TArray<UClass*> &OutBlueprintClasses)
{
// Iterate over UClass, this might be heavy on performance
for (TObjectIterator<UClass> It; It; ++It)
{
UClass *ChildClass = *It;
if (!ChildClass->IsChildOf(ParentClass))
{
continue;
}
// It is a child of the Parent Class
// make sure we don't include our parent class in the array
if (ChildClass == ParentClass)
{
continue;
}
if (FComboActionGraphEditorUtilities::IsABlueprintClass(ChildClass))
{
// Blueprint
OutBlueprintClasses.Add(ChildClass);
}
else
{
// Native
OutNativeClasses.Add(ChildClass);
}
}
return OutNativeClasses.Num() > 0 || OutBlueprintClasses.Num() > 0;
}
static bool OpenEditorAndJumpToGraphNode(TWeakPtr<class FAssetEditor_ComboActionGraph> DialogueEditorPtr, const UEdGraphNode *GraphNode, bool bFocusIfOpen = false);
static class UComboActionGraph *GetActionFromGraphNode(const UEdGraphNode *GraphNode);
static IAssetEditorInstance *FindEditorForAsset(UObject *Asset, bool bFocusIfOpen);
};

View File

@ -0,0 +1,28 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
struct FComboActionSearchFilter
{
public:
bool IsEmptyFilter() const
{
return SearchString.IsEmpty()
&& bIncludeNodeTitle == false
&& bIncludeNodeType == false
&& bIncludeNodeDecoratorsTypes == false
&& bIncludeNodeData == true
&& bIncludeNodeGUID == false;
}
public:
// Search term that the search items must match
FString SearchString;
bool bIncludeNodeTitle = true;
bool bIncludeNodeType = true;
bool bIncludeNodeDecoratorsTypes = true;
bool bIncludeNodeData = true;
bool bIncludeNodeGUID = false;
};

View File

@ -0,0 +1,275 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionSearchManager.h"
#include "ComboActionGraph.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Ed/EdComboActionGraph.h"
#include "Nodes/ComboActionGraphNode.h"
#include "Nodes/ComboActionGraphNode_ActionNodeBase.h"
#include "Search/ComboActionSearchFilter.h"
#define LOCTEXT_NAMESPACE "ComboActionSearchManager"
FComboActionSearchManager *FComboActionSearchManager::Instance = nullptr;
bool FComboActionSearchManager::QueryGraphNode(const FComboActionSearchFilter &SearchFilter, const UEdComboActionGraphNode *InGraphNode, const TSharedPtr<FComboActionSearchResult> &OutParentNode) const
{
if (SearchFilter.SearchString.IsEmpty() || !OutParentNode.IsValid() || !IsValid(InGraphNode))
{
return false;
}
bool bContainsSearchString = false;
const UComboActionGraphNode *Node = InGraphNode->ComboActionGraphNode;
if (Node == nullptr)
{
return false;
}
const FString NodeType = Node->NodeTypeName.ToString();
const FText DisplayText = FText::Format(LOCTEXT("ComboActionNodeCategory", "Found results in {0}"), FText::FromString(NodeType));
const TSharedPtr<FComboActionSearchResult_GraphNode> TreeGraphNode = MakeShared<FComboActionSearchResult_GraphNode>(DisplayText, OutParentNode);
TreeGraphNode->SetCategory(FText::FromString(NodeType));
TreeGraphNode->SetGraphNode(InGraphNode);
if (bContainsSearchString)
{
OutParentNode->AddChild(TreeGraphNode);
}
// Search by Title
if (SearchFilter.bIncludeNodeTitle)
{
if (Node->NodeTitle.ToString().Contains(SearchFilter.SearchString))
{
bContainsSearchString = true;
MakeChildTextNode
(
TreeGraphNode,
FText::FromName(FName(Node->NodeTitle.ToString() )),
LOCTEXT("NodeTitleKey", "Node Title"),
TEXT("Node Title")
);
}
}
// Search by NodeTypeName
if (SearchFilter.bIncludeNodeType)
{
if (Node->NodeTypeName.ToString().Contains(SearchFilter.SearchString))
{
bContainsSearchString = true;
this->MakeChildTextNode(
TreeGraphNode,
FText::FromName(FName(Node->NodeTypeName.ToString() )),
LOCTEXT("NodeTypeKey", "Node Type"),
TEXT("Node Type")
);
}
}
// Search by Decorators
if (SearchFilter.bIncludeNodeDecoratorsTypes)
{
const TArray<FComboActionDecorator> &NodeDecorators = Node->GetNodeDecorators();
for (int32 Index = 0, Num = NodeDecorators.Num(); Index < Num; Index++)
{
bContainsSearchString = this->QueryNodeDecorators(
SearchFilter,
NodeDecorators[Index],
TreeGraphNode,
Index,
TEXT("DecoratorType")
)
|| bContainsSearchString;
}
}
// Search by Node Data
if (SearchFilter.bIncludeNodeData)
{
if (const UComboActionGraphNode_ActionNodeBase *ActionNodeBase = Cast<UComboActionGraphNode_ActionNodeBase>(Node))
{
if (ActionNodeBase->GetRowName().ToString().Contains(SearchFilter.SearchString))
{
bContainsSearchString = true;
this->MakeChildTextNode(
TreeGraphNode,
FText::FromName(FName(Node->NodeTypeName.ToString() )),
LOCTEXT("NodeDataRowKey", "Node Data"),
TEXT("Node Data")
);
}
}
}
// Search by GUID
if (SearchFilter.bIncludeNodeGUID)
{
const FString FoundGUID = Node->GetNodeGUID().ToString();
if (FoundGUID.Contains(SearchFilter.SearchString))
{
bContainsSearchString = true;
MakeChildTextNode
(
TreeGraphNode,
FText::FromString(FoundGUID),
LOCTEXT("NodeGUID", "Node GUID"),
TEXT("Node GUID")
);
}
}
if (bContainsSearchString)
{
OutParentNode->AddChild(TreeGraphNode);
}
return bContainsSearchString;
}
bool FComboActionSearchManager::QueryNodeDecorators(const FComboActionSearchFilter &SearchFilter, const FComboActionDecorator &InDecorator, const TSharedPtr<FComboActionSearchResult> &OutParentNode, int32 DecoratorIndex, FName DecoratorMemberName) const
{
if (SearchFilter.SearchString.IsEmpty() || !OutParentNode.IsValid())
{
return false;
}
bool bContainsSearchString = false;
if (InDecorator.DecoratorType == nullptr) return false;
// Search by Decorator Name
if (InDecorator.DecoratorType->GetName().Contains(SearchFilter.SearchString))
{
bContainsSearchString = true;
FString DecoratorName = InDecorator.DecoratorType->GetClass()->GetName();
// Format Name
{
if (DecoratorName.Contains(TEXT("_GEN_VARIABLE")))
{
DecoratorName.ReplaceInline(TEXT("_GEN_VARIABLE"), TEXT(""));
}
if(DecoratorName.EndsWith(TEXT("_C")) && DecoratorName.StartsWith(TEXT("Default__")))
{
DecoratorName.RightChopInline(9);
DecoratorName.LeftChopInline(2);
}
if (DecoratorName.EndsWith(TEXT("_C")))
{
DecoratorName.LeftChopInline(2);
}
}
const FText Category = FText::Format
(
LOCTEXT("DecoratorName", "Node Decorator: {0} at Index: {1}"),
FText::FromString(DecoratorName), FText::AsNumber(DecoratorIndex)
);
MakeChildTextNode
(
OutParentNode,
FText::FromString(DecoratorName),
Category,
Category.ToString()
);
}
return bContainsSearchString;
}
bool FComboActionSearchManager::QuerySingleAction(const FComboActionSearchFilter &SearchFilter, const UComboActionGraph *InAction, TSharedPtr<FComboActionSearchResult> &OutParentNode)
{
if (SearchFilter.SearchString.IsEmpty() || !OutParentNode.IsValid() || !IsValid(InAction))
{
return false;
}
const UEdComboActionGraph *Graph = CastChecked<UEdComboActionGraph>(InAction->EdGraph);
const TSharedPtr<FComboActionSearchResult_ActionNode> TreeActionNode = MakeShared<FComboActionSearchResult_ActionNode>(FText::FromString(InAction->GetPathName()), OutParentNode);
TreeActionNode->SetActionGraph(Graph);
// Find in GraphNodes
bool bFoundInAction = false;
const TArray<UEdGraphNode*> &AllGraphNodes = Graph->Nodes;
for (UEdGraphNode *Node : AllGraphNodes)
{
bool bFoundInNode = false;
if (const UEdComboActionGraphNode *GraphNode = Cast<UEdComboActionGraphNode>(Node))
{
bFoundInNode = this->QueryGraphNode(SearchFilter, GraphNode, TreeActionNode);
}
// Found at least one match in one of the nodes.
bFoundInAction = bFoundInNode || bFoundInAction;
}
if (bFoundInAction)
{
OutParentNode->AddChild(TreeActionNode);
}
return bFoundInAction;
}
void FComboActionSearchManager::Initialize(TSharedPtr<FWorkspaceItem> ParentTabCategory)
{
// Must ensure we do not attempt to load the AssetRegistry Module while saving a package, however, if it is loaded already we can safely obtain it
this->AssetRegistry = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
this->OnAssetAddedHandle = this->AssetRegistry->OnAssetAdded().AddRaw(this, &FComboActionSearchManager::HandleOnAssetAdded);
this->OnAssetRemovedHandle = this->AssetRegistry->OnAssetRemoved().AddRaw(this, &FComboActionSearchManager::HandleOnAssetRemoved);
this->OnAssetRenamedHandle = this->AssetRegistry->OnAssetRenamed().AddRaw(this, &FComboActionSearchManager::HandleOnAssetRenamed);
if (this->AssetRegistry->IsLoadingAssets())
{
this->OnFilesLoadedHandle = this->AssetRegistry->OnFilesLoaded().AddRaw(this, &FComboActionSearchManager::HandleOnAssetRegistryFilesLoaded);
}
else
{
this->HandleOnAssetRegistryFilesLoaded();
}
this->OnAssetLoadedHandle = FCoreUObjectDelegates::OnAssetLoaded.AddRaw(this, &FComboActionSearchManager::HandleOnAssetLoaded);
}
void FComboActionSearchManager::UnInitialize()
{
if (this->AssetRegistry)
{
if (this->OnAssetAddedHandle.IsValid())
{
this->AssetRegistry->OnAssetAdded().Remove(this->OnAssetAddedHandle);
this->OnAssetAddedHandle.Reset();
}
if (this->OnAssetRemovedHandle.IsValid())
{
this->AssetRegistry->OnAssetRemoved().Remove(this->OnAssetRemovedHandle);
this->OnAssetRemovedHandle.Reset();
}
if (this->OnFilesLoadedHandle.IsValid())
{
this->AssetRegistry->OnFilesLoaded().Remove(this->OnFilesLoadedHandle);
this->OnFilesLoadedHandle.Reset();
}
if (this->OnAssetRenamedHandle.IsValid())
{
this->AssetRegistry->OnAssetRenamed().Remove(this->OnAssetRenamedHandle);
this->OnAssetRenamedHandle.Reset();
}
}
if (this->OnAssetLoadedHandle.IsValid())
{
FCoreUObjectDelegates::OnAssetLoaded.Remove(this->OnAssetLoadedHandle);
this->OnAssetLoadedHandle.Reset();
}
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,113 @@
// Copyright Dominik Pavlicek 2023. All Rights Reserved.
#pragma once
#include "Search/ComboActionSearchResult.h"
#include "ComboActionGraph.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "Ed/EdComboActionGraphNode.h"
struct FDialogueSearchData
{
TWeakObjectPtr<class UComboActionGraph> Dialogue;
};
class FComboActionSearchManager
{
public:
static FComboActionSearchManager *Get()
{
if (Instance == nullptr)
{
Instance = new FComboActionSearchManager();
}
return Instance;
}
public:
FComboActionSearchManager(){}
~FComboActionSearchManager() { this->UnInitialize(); }
/**
* Searches for InSearchString in the InGraphNode. Adds the result as a child in OutParentNode.
* @return True if found anything matching the InSearchString
*/
bool QueryGraphNode(const FComboActionSearchFilter &SearchFilter, const UEdComboActionGraphNode *InGraphNode, const TSharedPtr<class FComboActionSearchResult> &OutParentNode) const;
bool QueryNodeDecorators
(
const FComboActionSearchFilter &SearchFilter,
const FComboActionDecorator &InDecorator,
const TSharedPtr<class FComboActionSearchResult> &OutParentNode,
int32 DecoratorIndex,
FName DecoratorMemberName
) const;
/**
* Searches for InSearchString in the InAction. Adds the result as a child of OutParentNode.
* @return True if found anything matching the InSearchString
*/
bool QuerySingleAction
(
const FComboActionSearchFilter &SearchFilter,
const UComboActionGraph *InAction,
TSharedPtr<class FComboActionSearchResult> &OutParentNode
);
void Initialize(TSharedPtr<FWorkspaceItem> ParentTabCategory = nullptr);
void UnInitialize();
private:
// Helper method to make a Text Node and add it as a child to ParentNode
TSharedPtr<FComboActionSearchResult> MakeChildTextNode
(
const TSharedPtr<FComboActionSearchResult> &ParentNode,
const FText &DisplayName, const FText &Category,
const FString &CommentString
) const
{
TSharedPtr<FComboActionSearchResult> TextNode = MakeShared<FComboActionSearchResult>(DisplayName, ParentNode);
TextNode->SetCategory(Category);
if (!CommentString.IsEmpty())
{
TextNode->SetCommentString(CommentString);
}
ParentNode->AddChild(TextNode);
return TextNode;
}
// Callback hook from the Asset Registry when an asset is added
void HandleOnAssetAdded(const FAssetData &InAssetData){}
// Callback hook from the Asset Registry, marks the asset for deletion from the cache
void HandleOnAssetRemoved(const FAssetData &InAssetData){}
// Callback hook from the Asset Registry, marks the asset for deletion from the cache
void HandleOnAssetRenamed(const FAssetData &InAssetData, const FString &InOldName){}
// Callback hook from the Asset Registry when an asset is loaded
void HandleOnAssetLoaded(UObject *InAsset){}
// Callback when the Asset Registry loads all its assets
void HandleOnAssetRegistryFilesLoaded(){}
private:
static FComboActionSearchManager *Instance;
// Maps the Dialogue path => SearchData.
TMap<FName, FDialogueSearchData> SearchMap;
// Because we are unable to query for the module on another thread, cache it for use later
IAssetRegistry *AssetRegistry = nullptr;
// Handlers
FDelegateHandle OnAssetAddedHandle;
FDelegateHandle OnAssetRemovedHandle;
FDelegateHandle OnAssetRenamedHandle;
FDelegateHandle OnFilesLoadedHandle;
FDelegateHandle OnAssetLoadedHandle;
};

View File

@ -0,0 +1,73 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionSearchResult.h"
#include "ComboActionGraph.h"
#include "ComboActionSearchUtils.h"
#include "Helpers/ComboActionGraphEditorUtilities.h"
#define LOCTEXT_NAMESPACE "ComboActionSearchResult"
TSharedRef<SWidget> FComboActionSearchResult::CreateIcon() const
{
const FLinearColor IconColor = FLinearColor::White;
const FSlateBrush *Brush = nullptr;
return SNew(SImage)
.Image(Brush)
.ColorAndOpacity(IconColor)
.ToolTipText(GetCategory());
}
TWeakObjectPtr<const UComboActionGraph> FComboActionSearchResult::GetParentDialogue() const
{
if (this->Parent.IsValid())
{
return this->Parent.Pin()->GetParentDialogue();
}
return nullptr;
}
#pragma region Search_Actions
TWeakObjectPtr<const UComboActionGraph> FComboActionSearchResult_ActionNode::GetParentDialogue() const
{
if (this->ComboActionGraph.IsValid())
{
return this->ComboActionGraph;
}
return FComboActionSearchResult::GetParentDialogue();
}
#pragma endregion
#pragma region Search_Nodes
FReply FComboActionSearchResult_GraphNode::OnClick(TWeakPtr<FAssetEditor_ComboActionGraph> ActionEditorPtr)
{
if (this->GraphNode.IsValid())
{
return FComboActionGraphEditorUtilities::OpenEditorAndJumpToGraphNode(ActionEditorPtr, this->GraphNode.Get()) ? FReply::Handled() : FReply::Unhandled();
}
return FReply::Unhandled();
}
TSharedRef<SWidget> FComboActionSearchResult_GraphNode::CreateIcon() const
{
if (this->GraphNode.IsValid())
{
FLinearColor Color;
const FSlateIcon Icon = this->GraphNode.Get()->GetIconAndTint(Color);
return SNew(SImage)
.Image(Icon.GetOptionalIcon())
.ColorAndOpacity(Color)
.ToolTipText(GetCategory());
}
return FComboActionSearchResult::CreateIcon();
}
#pragma endregion
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,211 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Ed/EdComboActionGraph.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Widgets/Views/STreeView.h"
#define LOCTEXT_NAMESPACE "ComboActionSearchResult"
/**
* Template Tree Item Node class.
*/
template <class SelfType>
class FComboActionTreeItemNode : public TSharedFromThis<SelfType>
{
public:
FComboActionTreeItemNode(const FText &InDisplayText, const TSharedPtr<SelfType> &InParent) : Parent(InParent), DisplayText(InDisplayText){};
virtual ~FComboActionTreeItemNode(){};
#pragma region Click_Functions
virtual FReply OnClick(TWeakPtr<FAssetEditor_ComboActionGraph> DialogueEditorPtr)
{
// If there is a parent, handle it using the parent's functionality
if (Parent.IsValid())
{
return Parent.Pin()->OnClick(DialogueEditorPtr);
}
return FReply::Unhandled();
}
#pragma endregion
#pragma region DisplayText_Functions
FText GetDisplayText() const { return this->DisplayText; }
FName GetDisplayTextAsFName() const { return FName(*this->DisplayText.ToString()); }
void SetDisplayText(const FText &InText) { this->DisplayText = InText; }
bool DoesDisplayTextContains(const FString &InSearch, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const
{
return this->DisplayText.ToString().Contains(InSearch, SearchCase);
}
#pragma endregion
#pragma region Parent_Functions
bool HasParent() const { return this->Parent.IsValid(); }
TWeakPtr<SelfType> GetParent() const { return this->Parent; }
void SetParent(TWeakPtr<SelfType> InParentNode) { this->Parent = InParentNode; }
void ClearParent() { this->Parent.Reset(); }
#pragma endregion
#pragma region Children_Functions
public:
bool HasChildren() const { return this->Children.Num() > 0; }
const TArray<TSharedPtr<SelfType>> &GetChildren() const { return this->Children; }
void GetVisibleChildren(TArray<TSharedPtr<SelfType>> &OutChildren)
{
for (const TSharedPtr<SelfType> &Child : this->Children)
{
if (Child->IsVisible())
{
OutChildren.Add(Child);
}
}
}
virtual void AddChild(const TSharedPtr<SelfType> &ChildNode)
{
ensure(!ChildNode->IsRoot());
ChildNode->SetParent(this->AsShared());
this->Children.Add(ChildNode);
}
virtual void SetChildren(const TArray<TSharedPtr<SelfType>> &InChildren)
{
this->Children = InChildren;
for (const TSharedPtr<SelfType> &Child : this->Children)
{
ensure(!Child->IsRoot());
Child->SetParent(this->AsShared());
}
}
virtual void ClearChildren()
{
this->Children.Empty();
}
void ExpandAllChildren(const TSharedPtr<STreeView<TSharedPtr<SelfType>>> &TreeView, bool bRecursive = true)
{
static constexpr bool bShouldExpandItem = true;
if (!HasChildren())
{
return;
}
TreeView->SetItemExpansion(this->AsShared(), bShouldExpandItem);
for (const TSharedPtr<SelfType> &ChildNode : this->Children)
{
if (bRecursive)
{
// recursive on all children.
ChildNode->ExpandAllChildren(TreeView, bRecursive);
}
else
{
// Only direct children
TreeView->SetItemExpansion(ChildNode, bShouldExpandItem);
}
}
}
#pragma endregion
#pragma region Helper_Functions
public:
bool IsRoot() const { return !this->Parent.IsValid(); }
#pragma endregion
protected:
/** Any children listed under this node. */
TArray<TSharedPtr<SelfType>> Children;
/** The node that this is a direct child of (empty if this is a root node) */
TWeakPtr<SelfType> Parent;
/** The displayed text for this item. */
FText DisplayText;
/** Is this node displayed? */
bool bIsVisible = true;
};
class FComboActionSearchResult : public FComboActionTreeItemNode<FComboActionSearchResult>
{
public:
FComboActionSearchResult(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionTreeItemNode(InDisplayText, InParent){}
public:
// Create an icon to represent the result
virtual TSharedRef<SWidget> CreateIcon() const;
// Gets the Dialogue housing all these search results. Aka the Dialogue this search result belongs to.
virtual TWeakObjectPtr<const UComboActionGraph> GetParentDialogue() const;
// Category:
FText GetCategory() const { return this->Category; }
void SetCategory(const FText &InCategory) { this->Category = InCategory; }
// CommentString
FString GetCommentString() const { return this->CommentString; }
void SetCommentString(const FString &InCommentString) { this->CommentString = InCommentString; }
protected:
// The category of this node.
FText Category;
// Display text for comment information
FString CommentString;
};
// Root Node, should not be displayed.
class FComboActionSearchResult_RootNode : public FComboActionSearchResult
{
public:
FComboActionSearchResult_RootNode() : FComboActionSearchResult(FText::FromString(TEXT("INVALID")), nullptr) { this->Category = LOCTEXT("ComboActionSearchResult_RootNodeCategory", "Root"); }
};
// Tree Node result that represents the Node
class FComboActionSearchResult_ActionNode : public FComboActionSearchResult
{
public:
FComboActionSearchResult_ActionNode(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionSearchResult(InDisplayText, InParent) { this->Category = LOCTEXT("ComboAcitonSearchResult_ActionNodeCategory", "Action Node"); }
virtual FReply OnClick(TWeakPtr<class FAssetEditor_ComboActionGraph> DialogueEditorPtr) override { return FReply::Unhandled(); }
virtual TSharedRef<SWidget> CreateIcon() const override { return FComboActionSearchResult::CreateIcon(); }
virtual TWeakObjectPtr<const UComboActionGraph> GetParentDialogue() const override;
void SetActionGraph(TWeakObjectPtr<const UEdComboActionGraph> InDialogueGraph) { this->ComboActionGraph = InDialogueGraph->GetComboActionGraph(); }
protected:
TWeakObjectPtr<const UComboActionGraph> ComboActionGraph;
};
// Tree Node result that represents the GraphNode
class FComboActionSearchResult_GraphNode : public FComboActionSearchResult
{
public:
FComboActionSearchResult_GraphNode(const FText &InDisplayText, const TSharedPtr<FComboActionSearchResult> &InParent) : FComboActionSearchResult(InDisplayText, InParent){}
virtual FReply OnClick(TWeakPtr<FAssetEditor_ComboActionGraph> ComboActionEditorPtr) override;
virtual TSharedRef<SWidget> CreateIcon() const override;
void SetGraphNode(TWeakObjectPtr<const UEdComboActionGraphNode> InGraphNode) { this->GraphNode = InGraphNode; }
protected:
TWeakObjectPtr<const UEdComboActionGraphNode> GraphNode;
};
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,13 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#include "ComboActionSearchUtils.h"
TSharedPtr<SDockTab> FComboActionSearchHelpers::InvokeTab(TSharedPtr<FTabManager> TabManager, const FTabId &TabID)
{
if (!TabManager.IsValid())
{
return nullptr;
}
return TabManager->TryInvokeTab(TabID);
}

View File

@ -0,0 +1,10 @@
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
#pragma once
class COMBOINPUTEDITOR_API FComboActionSearchHelpers
{
public:
static TSharedPtr<SDockTab> InvokeTab(TSharedPtr<FTabManager> TabManager, const FTabId &TabID);
};

View File

@ -0,0 +1,405 @@
// Copyright Dominik Pavlicek 2023. All Rights Reserved.
#include "SComboActionSearch.h"
#include "Ed/AssetEditor_ComboActionGraph.h"
#include "Framework/Commands/GenericCommands.h"
#include "Search/ComboActionSearchManager.h"
#include "Widgets/Input/SSearchBox.h"
#define LOCTEXT_NAMESPACE "SComboActionSearch"
void SComboActionSearch::Construct(const FArguments &InArgs, const TSharedPtr<FAssetEditor_ComboActionGraph> &InDialogueEditor)
{
this->ComboActionEditorPtr = InDialogueEditor;
this->HostTab = InArgs._ContainingTab;
if (this->HostTab.IsValid())
{
this->HostTab.Pin()->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateSP(this, &SComboActionSearch::HandleHostTabClosed));
}
this->ChildSlot
[
SAssignNew(this->MainVerticalBoxWidget, SVerticalBox)
// Top bar, search
+SVerticalBox::Slot()
.AutoHeight()
[
SNew(SHorizontalBox)
// Search field
+SHorizontalBox::Slot()
.FillWidth(1)
[
SAssignNew(this->SearchTextBoxWidget, SSearchBox)
.HintText(LOCTEXT("ActionSearchHint", "Enter searched text..."))
.OnTextChanged(this, &SComboActionSearch::HandleSearchTextChanged)
.OnTextCommitted(this, &SComboActionSearch::HandleSearchTextCommitted)
.Visibility(EVisibility::Visible)
]
// Filter Options
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 2.0f)
[
SNew(SComboButton)
.ComboButtonStyle(FAppStyle::Get(), "GenericFilters.ComboButtonStyle")
.ForegroundColor(FLinearColor::White)
.ContentPadding(0)
.ToolTipText(LOCTEXT("Filters_Tooltip", "Filter options"))
.OnGetMenuContent(this, &SComboActionSearch::FillFilterEntries)
.HasDownArrow(true)
.ContentPadding(FMargin(1, 0))
.ButtonContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "GenericFilters.TextStyle")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FText::FromString(FString(TEXT("\xf0b0"))) )
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2, 0, 0, 0)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "GenericFilters.TextStyle")
.Text(LOCTEXT("Filters", "Filters"))
]
]
]
]
// Results tree
+SVerticalBox::Slot()
.FillHeight(1.0f)
.Padding(0.0f, 4.0f, 0.0f, 0.0f)
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("Menu.Background"))
[
SAssignNew(this->TreeView, STreeView<TSharedPtr<FComboActionSearchResult>>)
.ItemHeight(24)
.TreeItemsSource(&this->ItemsFound)
.OnGenerateRow(this, &SComboActionSearch::HandleGenerateRow)
.OnGetChildren(this, &SComboActionSearch::HandleGetChildren)
.OnMouseButtonDoubleClick(this, &SComboActionSearch::HandleTreeSelectionDoubleClicked)
.SelectionMode(ESelectionMode::Multi)
.OnContextMenuOpening(this, &SComboActionSearch::HandleContextMenuOpening)
]
]
];
}
void SComboActionSearch::FocusForUse(const FComboActionSearchFilter &SearchFilter, bool bSelectFirstResult)
{
FWidgetPath FilterTextBoxWidgetPath;
FSlateApplication::Get().GeneratePathToWidgetUnchecked(SearchTextBoxWidget.ToSharedRef(), FilterTextBoxWidgetPath);
FSlateApplication::Get().SetKeyboardFocus(FilterTextBoxWidgetPath, EFocusCause::SetDirectly);
if (!SearchFilter.SearchString.IsEmpty())
{
SearchTextBoxWidget->SetText(FText::FromString(SearchFilter.SearchString));
MakeSearchQuery(SearchFilter);
if (bSelectFirstResult && this->ItemsFound.Num())
{
auto ItemToFocusOn = this->ItemsFound[0];
while (ItemToFocusOn->HasChildren())
{
ItemToFocusOn = ItemToFocusOn->GetChildren()[0];
}
this->TreeView->SetSelection(ItemToFocusOn);
ItemToFocusOn->OnClick(this->ComboActionEditorPtr);
}
}
}
void SComboActionSearch::MakeSearchQuery(const FComboActionSearchFilter &SearchFilter)
{
this->SearchTextBoxWidget->SetText(FText::FromString(SearchFilter.SearchString));
if (this->ItemsFound.Num())
{
this->TreeView->RequestScrollIntoView(this->ItemsFound[0]);
}
this->ItemsFound.Empty();
if (SearchFilter.SearchString.IsEmpty())
{
return;
}
this->HighlightText = FText::FromString(SearchFilter.SearchString);
this->RootSearchResult = MakeShared<FComboActionSearchResult_RootNode>();
if (this->ComboActionEditorPtr.IsValid())
{
FComboActionSearchManager::Get()->QuerySingleAction(SearchFilter, this->ComboActionEditorPtr.Pin()->GetEditingGraphSafe(), this->RootSearchResult);
const TArray<TSharedPtr<FComboActionSearchResult>> &Children = this->RootSearchResult->GetChildren();
if (Children.Num() == 1 && Children[0].IsValid())
{
// we must ensure reference is created so its not garbage collected, usually resulting in crash!
TSharedPtr<FComboActionSearchResult> TempChild = Children[0];
this->RootSearchResult = TempChild;
this->RootSearchResult->ClearParent();
}
}
this->ItemsFound = this->RootSearchResult->GetChildren();
if (this->ItemsFound.Num() == 0)
{
this->ItemsFound.Add(MakeShared<FComboActionSearchResult>(LOCTEXT("ActionSearchNoResults", "No Results found"), this->RootSearchResult));
this->HighlightText = FText::GetEmpty();\
}
else
{
this->RootSearchResult->ExpandAllChildren(this->TreeView);
}
this->TreeView->RequestTreeRefresh();
}
FName SComboActionSearch::GetHostTabId() const
{
const TSharedPtr<SDockTab> HostTabPtr = this->HostTab.Pin();
if (HostTabPtr.IsValid())
{
return HostTabPtr->GetLayoutIdentifier().TabType;
}
return NAME_None;
}
void SComboActionSearch::CloseHostTab()
{
const TSharedPtr<SDockTab> HostTabPtr = this->HostTab.Pin();
if (HostTabPtr.IsValid())
{
HostTabPtr->RequestCloseTab();
}
}
void SComboActionSearch::HandleHostTabClosed(TSharedRef<SDockTab> DockTab)
{
// Clear cache
}
void SComboActionSearch::HandleSearchTextChanged(const FText& Text)
{
this->CurrentFilter.SearchString = Text.ToString();
}
void SComboActionSearch::HandleSearchTextCommitted(const FText& Text, ETextCommit::Type CommitType)
{
if (Text.IsEmpty())
{
this->TreeView->RequestTreeRefresh();
}
if (CommitType == ETextCommit::OnEnter)
{
this->CurrentFilter.SearchString = Text.ToString();
MakeSearchQuery(this->CurrentFilter);
}
}
void SComboActionSearch::HandleGetChildren(TSharedPtr<FComboActionSearchResult> InItem, TArray<TSharedPtr<FComboActionSearchResult>> &OutChildren)
{
OutChildren += InItem->GetChildren();
}
void SComboActionSearch::HandleTreeSelectionDoubleClicked(TSharedPtr<FComboActionSearchResult> Item)
{
if (Item.IsValid())
{
Item->OnClick(this->ComboActionEditorPtr);
}
}
TSharedRef<ITableRow> SComboActionSearch::HandleGenerateRow(TSharedPtr<FComboActionSearchResult> InItem, const TSharedRef<STableViewBase> &OwnerTable)
{
// Normal entry
FText CommentText = FText::GetEmpty();
if (!InItem->GetCommentString().IsEmpty())
{
FFormatNamedArguments Args;
Args.Add(TEXT("Comment"), FText::FromString(InItem->GetCommentString()));
CommentText = FText::Format(LOCTEXT("NodeComment", "{Comment}"), Args);
}
FFormatNamedArguments Args;
Args.Add(TEXT("Category"), InItem->GetCategory());
Args.Add(TEXT("DisplayTitle"), InItem->GetDisplayText());
const FText Tooltip = FText::Format(LOCTEXT("DialogueResultSearchToolTip", "{Category} : {DisplayTitle}"), Args);
return SNew(STableRow<TSharedPtr<FComboActionSearchResult>>, OwnerTable)
[
SNew(SHorizontalBox)
// Icon
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
InItem->CreateIcon()
]
// Display text
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(2,0)
[
SNew(STextBlock)
.Text(InItem.Get(), &FComboActionSearchResult::GetDisplayText)
.HighlightText(HighlightText)
.ToolTipText(Tooltip)
]
// Comment Block
+SHorizontalBox::Slot()
.FillWidth(1)
.HAlign(HAlign_Right)
.VAlign(VAlign_Center)
.Padding(2,0)
[
SNew(STextBlock)
.Text(CommentText)
.ColorAndOpacity(FLinearColor::Yellow)
]
];
}
TSharedPtr<SWidget> SComboActionSearch::HandleContextMenuOpening()
{
const bool bShouldCloseWindowAfterMenuSelection = true;
FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, this->CommandList);
MenuBuilder.BeginSection("BasicOperations");
{
MenuBuilder.AddMenuEntry(FGenericCommands::Get().SelectAll);
MenuBuilder.AddMenuEntry(FGenericCommands::Get().Copy);
}
return MenuBuilder.MakeWidget();
}
TSharedRef<SWidget> SComboActionSearch::FillFilterEntries()
{
FMenuBuilder MenuBuilder(true, nullptr);
MenuBuilder.AddMenuEntry
(
LOCTEXT("IncludeNodeTitle", "Include Node Title"),
LOCTEXT("IncludeNodeTitle_ToolTip", "Include Node Titles in the search result"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateLambda([this]()
{
this->CurrentFilter.bIncludeNodeTitle = !this->CurrentFilter.bIncludeNodeTitle;
MakeSearchQuery(this->CurrentFilter);
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]() -> bool
{
return this->CurrentFilter.bIncludeNodeTitle;
})
),
NAME_None,
EUserInterfaceActionType::ToggleButton
);
MenuBuilder.AddMenuEntry
(
LOCTEXT("IncludeNodeType", "Include Node Type"),
LOCTEXT("IncludeNodeType_ToolTip", "Include Node Type in the search result"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateLambda([this]()
{
this->CurrentFilter.bIncludeNodeType = !this->CurrentFilter.bIncludeNodeType;
MakeSearchQuery(this->CurrentFilter);
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]() -> bool
{
return this->CurrentFilter.bIncludeNodeType;
})
),
NAME_None,
EUserInterfaceActionType::ToggleButton
);
MenuBuilder.AddMenuEntry
(
LOCTEXT("IncludeNodeDecoratorsTypes", "Include Node Decorators"),
LOCTEXT("IncludeNodeDecoratorsTypes_ToolTip", "Include Node Decorators Types (by name) in the search result"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateLambda([this]()
{
this->CurrentFilter.bIncludeNodeDecoratorsTypes = !this->CurrentFilter.bIncludeNodeDecoratorsTypes;
MakeSearchQuery(this->CurrentFilter);
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]() -> bool
{
return this->CurrentFilter.bIncludeNodeDecoratorsTypes;
})
),
NAME_None,
EUserInterfaceActionType::ToggleButton
);
MenuBuilder.AddMenuEntry
(
LOCTEXT("IncludeNodeData", "Include Node Data Row"),
LOCTEXT("IncludeNodeDecoratorsTypes_ToolTip", "Include Node Data Row in the search result"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateLambda([this]()
{
this->CurrentFilter.bIncludeNodeData = !this->CurrentFilter.bIncludeNodeData;
MakeSearchQuery(this->CurrentFilter);
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]() -> bool
{
return this->CurrentFilter.bIncludeNodeData;
})
),
NAME_None,
EUserInterfaceActionType::ToggleButton
);
MenuBuilder.AddMenuEntry
(
LOCTEXT("IncludeNodeGUID", "Include Node GUID"),
LOCTEXT("IncludeNodeGUID_ToolTip", "Include Node GUID in the search result"),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateLambda([this]()
{
this->CurrentFilter.bIncludeNodeGUID = !this->CurrentFilter.bIncludeNodeGUID;
MakeSearchQuery(this->CurrentFilter);
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]() -> bool
{
return this->CurrentFilter.bIncludeNodeGUID;
})
),
NAME_None,
EUserInterfaceActionType::ToggleButton
);
return MenuBuilder.MakeWidget();
}
#undef LOCTEXT_NAMESPACE

View File

@ -0,0 +1,106 @@
// Copyright Dominik Pavlicek 2023. All Rights Reserved.
#pragma once
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Views/STreeView.h"
#include "Framework/Commands/UICommandList.h"
#include "Search/ComboActionSearchFilter.h"
#include "Search/ComboActionSearchResult.h"
/**
* Widget handling Search in Combo Action Graph
*/
class SComboActionSearch : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SComboActionSearch)
: _bIsSearchWindow(true)
, _bHideSearchBar(false)
, _ContainingTab()
{}
SLATE_ARGUMENT(bool, bIsSearchWindow)
SLATE_ARGUMENT(bool, bHideSearchBar)
SLATE_ARGUMENT(TSharedPtr<SDockTab>, ContainingTab)
SLATE_END_ARGS()
void Construct(const FArguments &InArgs, const TSharedPtr<FAssetEditor_ComboActionGraph> &InDialogueEditor = nullptr);
/** Focuses this widget's search box, and changes the mode as well, and optionally the search terms */
void FocusForUse(const FComboActionSearchFilter &SearchFilter = FComboActionSearchFilter(), bool bSelectFirstResult = false);
/**
* Submits a search query
*
* @param SearchFilter Filter for search
* @param bInIsFindWithinDialogue TRUE if searching within the current Dialogue only
*/
void MakeSearchQuery(const FComboActionSearchFilter &SearchFilter);
/** If this is a global find results widget, returns the host tab's unique ID. Otherwise, returns NAME_None. */
FName GetHostTabId() const;
/** If this is a global find results widget, ask the host tab to close */
void CloseHostTab();
private:
/** Called when the host tab is closed (if valid) */
void HandleHostTabClosed(TSharedRef<SDockTab> DockTab);
/** Called when user changes the text they are searching for */
void HandleSearchTextChanged(const FText &Text);
/** Called when user changes commits text to the search box */
void HandleSearchTextCommitted(const FText &Text, ETextCommit::Type CommitType);
/* Get the children of a row */
void HandleGetChildren(TSharedPtr<FComboActionSearchResult> InItem, TArray<TSharedPtr<FComboActionSearchResult>> &OutChildren);
/* Called when user double clicks on a new result */
void HandleTreeSelectionDoubleClicked(TSharedPtr<FComboActionSearchResult> Item);
/* Called when a new row is being generated */
TSharedRef<ITableRow> HandleGenerateRow(TSharedPtr<FComboActionSearchResult> InItem, const TSharedRef<STableViewBase> &OwnerTable);
/** Callback to build the context menu when right clicking in the tree */
TSharedPtr<SWidget> HandleContextMenuOpening();
/** Fills in the filter menu. */
TSharedRef<SWidget> FillFilterEntries();
private:
/** Pointer back to the ComboAction editor that owns us */
TWeakPtr<FAssetEditor_ComboActionGraph> ComboActionEditorPtr;
/* The tree view displays the results */
TSharedPtr<STreeView<TSharedPtr<FComboActionSearchResult>>> TreeView;
/** The search text box */
TSharedPtr<SSearchBox> SearchTextBoxWidget;
/** Vertical box, used to add and remove widgets dynamically */
TWeakPtr<SVerticalBox> MainVerticalBoxWidget;
/** In Find Within Action mode, we need to keep a handle on the root result, because it won't show up in the tree. */
TSharedPtr<FComboActionSearchResult> RootSearchResult;
/* This buffer stores the currently displayed results */
TArray<TSharedPtr<FComboActionSearchResult>> ItemsFound;
/* The string to highlight in the results */
FText HighlightText;
/** The current searach filter */
FComboActionSearchFilter CurrentFilter;
/** Tab hosting this widget. May be invalid. */
TWeakPtr<SDockTab> HostTab;
/** Commands handled by this widget */
TSharedPtr<FUICommandList> CommandList;
};

View File

@ -90,7 +90,7 @@ public:
static bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("ComboInputEditor"); } static bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("ComboInputEditor"); }
virtual void StartupModule() override; virtual void StartupModule() override;
virtual void ShutdownModule() override{} virtual void ShutdownModule() override;
TSharedPtr<class FSlateStyleSet> GetComboInputEditorStyleSet() const { return this->ComboInputEditorStyleSet; } TSharedPtr<class FSlateStyleSet> GetComboInputEditorStyleSet() const { return this->ComboInputEditorStyleSet; }