Files
UnrealEngineUWP/Engine/Plugins/Runtime/StateTree/Source/StateTreeEditorModule/Private/SStateTreeView.cpp
mieszko zielinski c019c2635f Moved GameplayBehaviors out of restricted folder over to Experimental
Moved SmartObjects out of restricted folder
Moved StateTree out of restricted folder
Moved ZoneGraph out of restricted folder
Moved ZoneGraphAnnotations out of restricted folder

#jira UE-115297

#ROBOMERGE-OWNER: mieszko.zielinski
#ROBOMERGE-AUTHOR: mieszko.zielinski
#ROBOMERGE-SOURCE: CL 17648223 via CL 17648246 via CL 17648261 via CL 17648385 via CL 17648390 via CL 17648742
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Test -> Main) (v875-17642767)

[CL 17648750 by mieszko zielinski in ue5-main branch]
2021-09-28 13:33:17 -04:00

425 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SStateTreeView.h"
#include "Framework/Commands/Commands.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "ScopedTransaction.h"
#include "Templates/SharedPointer.h"
#include "EditorStyleSet.h"
#include "EditorFontGlyphs.h"
#include "StateTreeEditorStyle.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SScrollBorder.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/SInlineEditableTextBlock.h"
#include "Widgets/Layout/SScrollBox.h"
#include "SStateTreeViewRow.h"
#include "StateTreeViewModel.h"
#include "StateTreeState.h"
#define LOCTEXT_NAMESPACE "StateTreeEditor"
SStateTreeView::SStateTreeView()
: RequestedRenameState(nullptr)
, bItemsDirty(false)
, bUpdatingSelection(false)
{
}
SStateTreeView::~SStateTreeView()
{
if (StateTreeViewModel)
{
StateTreeViewModel->GetOnAssetChanged().RemoveAll(this);
StateTreeViewModel->GetOnStatesRemoved().RemoveAll(this);
StateTreeViewModel->GetOnStatesMoved().RemoveAll(this);
StateTreeViewModel->GetOnStateAdded().RemoveAll(this);
StateTreeViewModel->GetOnStatesChanged().RemoveAll(this);
StateTreeViewModel->GetOnSelectionChanged().RemoveAll(this);
}
}
void SStateTreeView::Construct(const FArguments& InArgs, TSharedRef<FStateTreeViewModel> InStateTreeViewModel)
{
StateTreeViewModel = InStateTreeViewModel;
StateTreeViewModel->GetOnAssetChanged().AddSP(this, &SStateTreeView::HandleModelAssetChanged);
StateTreeViewModel->GetOnStatesRemoved().AddSP(this, &SStateTreeView::HandleModelStatesRemoved);
StateTreeViewModel->GetOnStatesMoved().AddSP(this, &SStateTreeView::HandleModelStatesMoved);
StateTreeViewModel->GetOnStateAdded().AddSP(this, &SStateTreeView::HandleModelStateAdded);
StateTreeViewModel->GetOnStatesChanged().AddSP(this, &SStateTreeView::HandleModelStatesChanged);
StateTreeViewModel->GetOnSelectionChanged().AddSP(this, &SStateTreeView::HandleModelSelectionChanged);
bUpdatingSelection = false;
TreeView = SNew(STreeView<UStateTreeState*>)
.OnGenerateRow(this, &SStateTreeView::HandleGenerateRow)
.OnGetChildren(this, &SStateTreeView::HandleGetChildren)
.TreeItemsSource(StateTreeViewModel->GetRoutines())
.ItemHeight(32)
.OnSelectionChanged(this, &SStateTreeView::HandleTreeSelectionChanged)
.OnContextMenuOpening(this, &SStateTreeView::HandleContextMenuOpening);
ExternalScrollbar = SNew(SScrollBar)
.AlwaysShowScrollbar(true);
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
.AutoHeight()
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.Padding(2.0f)
[
SNew(SHorizontalBox)
// New State
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.Padding(4.0f, 2.0f)
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(FEditorStyle::Get(), "FlatButton.Success")
.ToolTipText(LOCTEXT("AddRoutineToolTip", "Add New Routine"))
.OnClicked(this, &SStateTreeView::HandleAddRoutine)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
.AutoWidth()
[
SNew(STextBlock)
.Text(FEditorFontGlyphs::File)
.TextStyle(FEditorStyle::Get(), "FlatButton.DefaultTextStyle")
.Font(FEditorStyle::Get().GetFontStyle("FontAwesome.11"))
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("AddRoutine", "Add Routine"))
.TextStyle(FEditorStyle::Get(), "FlatButton.DefaultTextStyle")
]
]
]
]
]
+SVerticalBox::Slot()
.FillHeight(1.0f)
.Padding(0.0f, 6.0f, 0.0f, 0.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(0.0f)
[
SNew(SScrollBox)
.Orientation(Orient_Horizontal)
+ SScrollBox::Slot()
.HAlign(HAlign_Fill)
[
SNew(SBorder)
.HAlign(HAlign_Fill)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.Padding(0.0f)
[
TreeView.ToSharedRef()
]
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(0.0f)
[
SNew(SBox)
.WidthOverride(FOptionalSize(13.0f))
[
ExternalScrollbar.ToSharedRef()
]
]
]
];
UpdateTree(true);
}
void SStateTreeView::SavePersistentExpandedStates()
{
if (!StateTreeViewModel)
{
return;
}
TSet<UStateTreeState*> ExpandedStates;
TreeView->GetExpandedItems(ExpandedStates);
StateTreeViewModel->SetPersistentExpandedStates(ExpandedStates);
}
void SStateTreeView::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
if (bItemsDirty)
{
UpdateTree();
}
if (RequestedRenameState && !TreeView->IsPendingRefresh())
{
if (TSharedPtr<SStateTreeViewRow> Row = StaticCastSharedPtr<SStateTreeViewRow>(TreeView->WidgetFromItem(RequestedRenameState)))
{
Row->RequestRename();
}
RequestedRenameState = nullptr;
}
}
void SStateTreeView::UpdateTree(bool bExpandPersistent)
{
if (!StateTreeViewModel)
{
return;
}
TSet<UStateTreeState*> ExpandedStates;
if (bExpandPersistent)
{
// Get expanded state from the tree data.
StateTreeViewModel->GetPersistentExpandedStates(ExpandedStates);
}
else
{
// Restore current expanded state.
TreeView->GetExpandedItems(ExpandedStates);
}
// Remember selection
TArray<UStateTreeState*> SelectedStates;
StateTreeViewModel->GetSelectedStates(SelectedStates);
// Regenerate items
TreeView->SetTreeItemsSource(StateTreeViewModel->GetRoutines());
// Restore expanded state
for (UStateTreeState* State : ExpandedStates)
{
TreeView->SetItemExpansion(State, true);
}
// Restore selected state
TreeView->ClearSelection();
TreeView->SetItemSelection(SelectedStates, true);
bItemsDirty = false;
}
void SStateTreeView::HandleModelAssetChanged()
{
bItemsDirty = true;
}
void SStateTreeView::HandleModelStatesRemoved(const TSet<UStateTreeState*>& AffectedParents)
{
bItemsDirty = true;
}
void SStateTreeView::HandleModelStatesMoved(const TSet<UStateTreeState*>& AffectedParents, const TSet<UStateTreeState*>& MovedStates)
{
bItemsDirty = true;
}
void SStateTreeView::HandleModelStateAdded(UStateTreeState* ParentState, UStateTreeState* NewState)
{
bItemsDirty = true;
HandleRenameState(NewState);
}
void SStateTreeView::HandleModelStatesChanged(const TSet<UStateTreeState*>& AffectedStates, const FPropertyChangedEvent& PropertyChangedEvent)
{
bool bArraysChanged = false;
// The purpose of the rebuild below is to update the evaluator and task visualization (number of widgets change).
// This method is called when anything in a state changes, make sure to only rebuild when needed.
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UStateTreeState, Evaluators))
{
bArraysChanged = true;
}
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UStateTreeState, Evaluators2))
{
bArraysChanged = true;
}
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UStateTreeState, Tasks))
{
bArraysChanged = true;
}
if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UStateTreeState, Tasks2))
{
bArraysChanged = true;
}
if (bArraysChanged)
{
TreeView->RebuildList();
}
}
void SStateTreeView::HandleModelSelectionChanged(const TArray<UStateTreeState*>& SelectedStates)
{
if (bUpdatingSelection)
{
return;
}
TreeView->ClearSelection();
if (SelectedStates.Num() > 0)
{
TreeView->SetItemSelection(SelectedStates, true);
}
}
TSharedRef<ITableRow> SStateTreeView::HandleGenerateRow(UStateTreeState* InState, const TSharedRef<STableViewBase>& InOwnerTableView)
{
return SNew(SStateTreeViewRow, InOwnerTableView, InState, StateTreeViewModel.ToSharedRef());
}
void SStateTreeView::HandleGetChildren(UStateTreeState* InParent, TArray<UStateTreeState*>& OutChildren)
{
if (InParent)
{
OutChildren.Append(InParent->Children);
}
}
void SStateTreeView::HandleTreeSelectionChanged(UStateTreeState* InSelectedItem, ESelectInfo::Type SelectionType)
{
if (!StateTreeViewModel)
{
return;
}
// Do not report code based selection changes.
if (SelectionType == ESelectInfo::Direct)
{
return;
}
TArray<UStateTreeState*> SelectedItems = TreeView->GetSelectedItems();
bUpdatingSelection = true;
StateTreeViewModel->SetSelection(SelectedItems);
bUpdatingSelection = false;
}
TSharedPtr<SWidget> SStateTreeView::HandleContextMenuOpening()
{
if (!StateTreeViewModel)
{
return nullptr;
}
TArray<UStateTreeState*> SelectedStates;
StateTreeViewModel->GetSelectedStates(SelectedStates);
UStateTreeState* FirstSelectedState = SelectedStates.Num() > 0 ? SelectedStates[0] : nullptr;
FMenuBuilder MenuBuilder(true, nullptr);
MenuBuilder.AddMenuEntry(
LOCTEXT("AddState", "Add State"),
FText(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SStateTreeView::HandleAddState, FirstSelectedState)));
if (FirstSelectedState)
{
MenuBuilder.AddMenuEntry(
LOCTEXT("AddChildState", "Add Child State"),
FText(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SStateTreeView::HandleAddChildState, FirstSelectedState)));
MenuBuilder.AddSeparator();
MenuBuilder.AddMenuEntry(
LOCTEXT("RenameNodeGroup", "Rename"),
FText(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SStateTreeView::HandleRenameState, FirstSelectedState)));
MenuBuilder.AddMenuEntry(
LOCTEXT("DeleteState", "Delete Selected"),
FText(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SStateTreeView::HandleDeleteItems)));
}
return MenuBuilder.MakeWidget();
}
FReply SStateTreeView::HandleAddRoutine()
{
if (StateTreeViewModel)
{
StateTreeViewModel->AddState(nullptr);
}
return FReply::Handled();
}
void SStateTreeView::HandleAddState(UStateTreeState* AfterState)
{
if (StateTreeViewModel)
{
StateTreeViewModel->AddState(AfterState);
}
}
void SStateTreeView::HandleRenameState(UStateTreeState* State)
{
RequestedRenameState = State;
}
void SStateTreeView::HandleAddChildState(UStateTreeState* ParentState)
{
if (StateTreeViewModel && ParentState)
{
StateTreeViewModel->AddChildState(ParentState);
TreeView->SetItemExpansion(ParentState, true);
}
}
void SStateTreeView::HandleDeleteItems()
{
if (StateTreeViewModel)
{
StateTreeViewModel->RemoveSelectedStates();
}
}
#undef LOCTEXT_NAMESPACE