405 lines
11 KiB
C++
405 lines
11 KiB
C++
// 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 |