Files
UnrealEngine/Engine/Source/Editor/Persona/Private/SPoseWatchManager.h
2025-05-18 13:04:45 +08:00

416 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "EditorUndoClient.h"
#include "Framework/Commands/UICommandList.h"
#include "Framework/Views/ITypedTableView.h"
#include "Input/Reply.h"
#include "Layout/Visibility.h"
#include "Misc/Attribute.h"
#include "Misc/TextFilter.h"
#include "SlateFwd.h"
#include "Styling/SlateColor.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SWidget.h"
#include "Widgets/Views/STableRow.h"
#include "Widgets/Views/STableViewBase.h"
#include "Delegates/DelegateCombinations.h"
#include "Framework/Views/ITypedTableView.h"
#include "Types/SlateEnums.h"
#include "BlueprintEditor.h"
#include "Engine/PoseWatch.h"
#include "PoseWatchManagerFolderTreeItem.h"
#include "IPoseWatchManager.h"
#include "PoseWatchManagerFwd.h"
#include "SPoseWatchManagerTreeView.h"
#include "PoseWatchManagerPublicTypes.h"
#include "PoseWatchManagerStandaloneTypes.h"
#include "PoseWatchManagerDragDrop.h"
class FMenuBuilder;
class UToolMenu;
class IPoseWatchManagerColumn;
class FPoseWatchManagerDefaultHierarchy;
class SComboButton;
template<typename ItemType> class STreeView;
namespace PoseWatchManager
{
DECLARE_EVENT_OneParam(SPoseWatchManager, FTreeItemPtrEvent, FPoseWatchManagerTreeItemPtr);
DECLARE_EVENT_TwoParams(SPoseWatchManager, FOnItemSelectionChanged, FPoseWatchManagerTreeItemPtr, ESelectInfo::Type);
typedef TTextFilter<const IPoseWatchManagerTreeItem&> TreeItemTextFilter;
/** Structure that defines an operation that should be applied to the tree */
struct FPendingTreeOperation
{
enum EType { Added, Removed, Moved };
FPendingTreeOperation(EType InType, TSharedRef<IPoseWatchManagerTreeItem> InItem) : Type(InType), Item(InItem) { }
/** The type of operation that is to be applied */
EType Type;
/** The tree item to which this operation relates */
FPoseWatchManagerTreeItemRef Item;
};
/** Set of actions to apply to new tree items */
namespace ENewItemAction
{
enum Type
{
/** Do nothing when it is created */
None = 0,
/** Select the item when it is created */
Select = 1 << 0,
/** Scroll the item into view when it is created */
ScrollIntoView = 1 << 1,
/** Interactively rename the item when it is created (implies the above) */
Rename = 1 << 2,
};
}
}
class SPoseWatchManager : public IPoseWatchManager, public FGCObject
{
public:
SLATE_BEGIN_ARGS(SPoseWatchManager)
{}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs, const FPoseWatchManagerInitializationOptions& InitOptions);
SPoseWatchManager();
virtual ~SPoseWatchManager();
// SWidget interface
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
virtual bool SupportsKeyboardFocus() const override;
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
/** Sends a requests to refresh the next chance it gets */
virtual void Refresh() override;
void RefreshSelection();
/** Get a const reference to the actual tree hierarchy */
virtual const STreeView<FPoseWatchManagerTreeItemPtr>& GetTree() const override
{
return *PoseWatchManagerTreeView;
}
virtual const TSharedPtr<SPoseWatchManagerTreeView>& GetTreeView() const
{
return PoseWatchManagerTreeView;
}
/** @return Returns a string to use for highlighting results in the list */
virtual TAttribute<FText> GetFilterHighlightText() const;
/** Set the keyboard focus to the manager */
virtual void SetKeyboardFocus() override;
void SetColumnVisibility(FName ColumnId, bool bIsVisible);
/** Returns the current sort mode of the specified column */
virtual EColumnSortMode::Type GetColumnSortMode(const FName ColumnId) const;
/** Request that the tree be sorted at a convenient time */
virtual void RequestSort();
/** Requests a full refresh, which will clear the entire tree and rebuild it from scratch */
virtual void FullRefresh() override;
public:
/** Event to react to a user double click on a item */
PoseWatchManager::FTreeItemPtrEvent& GetDoubleClickEvent() { return OnDoubleClickOnTreeEvent; }
PoseWatchManager::FOnItemSelectionChanged& GetOnItemSelectionChanged() { return OnItemSelectionChanged; }
/** Set the item selection of the manager based on a selector function. Any items which return true will be added */
virtual void SetSelection(const TFunctionRef<bool(IPoseWatchManagerTreeItem&)> Selector) override;
/** Set the selection status of a set of items in the scene manager */
void SetItemSelection(const TArray<FPoseWatchManagerTreeItemPtr>& InItems, bool bSelected, ESelectInfo::Type SelectInfo = ESelectInfo::Direct);
/** Set the selection status of a single item in the scene manager */
void SetItemSelection(const FPoseWatchManagerTreeItemPtr& InItem, bool bSelected, ESelectInfo::Type SelectInfo = ESelectInfo::Direct);
virtual FPoseWatchManagerTreeItemPtr GetSelection() const { return PoseWatchManagerTreeView->GetSelectedItems().Num() == 1 ? PoseWatchManagerTreeView->GetSelectedItems()[0] : nullptr; }
FPoseWatchManagerTreeItemPtr FindParent(const IPoseWatchManagerTreeItem& InItem) const;
/** Deselect all selected items */
void ClearSelection();
/** Sets the next item to rename */
void SetPendingRenameItem(const FPoseWatchManagerTreeItemPtr& InItem) { PendingRenameItem = InItem; Refresh(); }
/** Retrieve an IPoseWatchManagerTreeItem by its ID if it exists in the tree */
FPoseWatchManagerTreeItemPtr GetTreeItem(FObjectKey, bool bIncludePending = false);
/** Create a drag drop operation */
TSharedPtr<FDragDropOperation> CreateDragDropOperation(const TArray<FPoseWatchManagerTreeItemPtr>& InTreeItems) const;
/** Parse a drag drop operation into a payload */
bool ParseDragDrop(FPoseWatchManagerDragDropPayload& OutPayload, const FDragDropOperation& Operation) const;
/** Validate a drag drop operation on a drop target */
FPoseWatchManagerDragValidationInfo ValidateDrop(const IPoseWatchManagerTreeItem& DropTarget, const FPoseWatchManagerDragDropPayload& Payload) const;
/** Called when a payload is dropped onto a target */
void OnDropPayload(IPoseWatchManagerTreeItem& DropTarget, const FPoseWatchManagerDragDropPayload& Payload, const FPoseWatchManagerDragValidationInfo& ValidationInfo) const;
/** Called when a payload is dragged over an item */
FReply OnDragOverItem(const FDragDropEvent& Event, const IPoseWatchManagerTreeItem& Item) const;
virtual uint32 GetTypeSortPriority(const IPoseWatchManagerTreeItem& Item) const;
/** Used to test if manager related selection changes have already been handled */
bool GetIsReentrant() const { return bIsReentrant; }
private:
/** Empty all the tree item containers maintained by this manager */
void EmptyTreeItems();
/** Apply incremental changes to, or a complete repopulation of the tree */
void Populate();
/** Repopulates the entire tree */
void RepopulateEntireTree();
/** Adds a single new item to the pending map and creates an add operation for it */
void AddPendingItem(FPoseWatchManagerTreeItemPtr Item);
/** Adds a new item and all of its children to the pending items. */
void AddPendingItemAndChildren(FPoseWatchManagerTreeItemPtr Item);
/** Attempts to add a pending item to the current tree. Will add any parents if required. */
bool AddItemToTree(FPoseWatchManagerTreeItemRef InItem);
/** Add an item to the tree, even if it doesn't match the filter terms. Used to add parent's that would otherwise be filtered out */
void AddUnfilteredItemToTree(FPoseWatchManagerTreeItemRef Item);
/** Ensure that the specified item's parent is added to the tree, if applicable */
FPoseWatchManagerTreeItemPtr EnsureParentForItem(FPoseWatchManagerTreeItemRef Item);
public:
// Test the filters using stack-allocated data to prevent unnecessary heap allocations
template <typename TreeItemType, typename TreeItemData>
FPoseWatchManagerTreeItemPtr CreateItemFor(const TreeItemData& Data, bool bForce = false)
{
const TreeItemType Temporary(Data);
if (bForce || SearchBoxFilter->PassesFilter(Temporary))
{
FPoseWatchManagerTreeItemPtr Result = MakeShareable(new TreeItemType(Data));
return Result;
}
return nullptr;
}
/** Instruct the manager to perform an action on the specified item when it is created */
void OnItemAdded(const FObjectKey& ItemID, uint8 ActionMask);
void OnPoseWatchesChanged(UAnimBlueprint* InAnimBlueprint, UEdGraphNode* InNode);
virtual void Rename_Execute() override;
virtual void Delete_Execute();
/** Get the columns to be displayed in this manager */
const TMap<FName, TSharedPtr<IPoseWatchManagerColumn>>& GetColumns() const
{
return Columns;
}
/** @return Returns true if the text filter is currently active */
bool IsTextFilterActive() const;
bool PassesTextFilter(const FPoseWatchManagerTreeItemPtr& Item) const
{
return SearchBoxFilter->PassesFilter(*Item);
}
bool HasSelectorFocus(FPoseWatchManagerTreeItemPtr Item) const
{
return PoseWatchManagerTreeView->Private_HasSelectorFocus(Item);
}
private:
/** Map of columns that are shown on this manager. */
TMap<FName, TSharedPtr<IPoseWatchManagerColumn>> Columns;
/** Set up the columns required for this manager */
void SetupColumns(SHeaderRow& HeaderRow);
/** Refresh the scene manager for when a column was added or removed */
void RefreshColumns();
/** Populates OutSearchStrings with the strings associated with TreeItem that should be used in searching */
void PopulateSearchStrings(const IPoseWatchManagerTreeItem& Item, TArray< FString >& OutSearchStrings) const;
public:
/** Scroll the specified item into view */
void ScrollItemIntoView(const FPoseWatchManagerTreeItemPtr& Item);
private:
/** Called by STreeView to generate a table row for the specified item */
TSharedRef< ITableRow > OnGenerateRowForManagerTree(FPoseWatchManagerTreeItemPtr Item, const TSharedRef< STableViewBase >& OwnerTable);
/** Called by STreeView to get child items for the specified parent item */
void OnGetChildrenForManagerTree(FPoseWatchManagerTreeItemPtr InParent, TArray< FPoseWatchManagerTreeItemPtr >& OutChildren);
/** Called by STreeView when the tree's selection has changed */
void OnManagerTreeSelectionChanged(FPoseWatchManagerTreeItemPtr TreeItem, ESelectInfo::Type SelectInfo);
/** Called by STreeView when an item is scrolled into view */
void OnManagerTreeItemScrolledIntoView(FPoseWatchManagerTreeItemPtr TreeItem, const TSharedPtr<ITableRow>& Widget);
void OnManagerTreeDoubleClick(FPoseWatchManagerTreeItemPtr TreeItem);
/** Called when an item in the tree has been collapsed or expanded */
void OnItemExpansionChanged(FPoseWatchManagerTreeItemPtr TreeItem, bool bIsExpanded) const;
private:
/** Event required to keep the pose watch manager up to date */
void OnHierarchyChangedEvent(FPoseWatchManagerHierarchyChangedData Event);
private:
/** Called by the editable text control when the filter text is changed by the user */
void OnFilterTextChanged(const FText& InFilterText);
/** Called by the filter button to get the image to display in the button */
const FSlateBrush* GetFilterButtonGlyph() const;
/** @return The filter button tool-tip text */
FString GetFilterButtonToolTip() const;
/** @return Returns whether the filter status line should be drawn */
EVisibility GetFilterStatusVisibility() const;
/** Returns the current visibility of the Empty label */
EVisibility GetEmptyLabelVisibility() const;
/** Returns the selection mode*/
ESelectionMode::Type GetSelectionMode() const;
private:
/** Called when the user right clicks in the tree view */
TSharedPtr<SWidget> OnOpenContextMenu();
/** Called when the user has clicked the button to add a new folder */
FReply OnCreateFolderClicked();
/** Requests a new folder be created, confirmation received with OnHierarchyChangedEvent */
void CreateFolder();
/** Binds our UI commands to delegates. */
void BindCommands();
private:
/** Context menu opening delegate provided by the client */
FOnContextMenuOpening OnContextMenuOpening;
/** List of pending operations to be applied to the tree */
TArray<PoseWatchManager::FPendingTreeOperation> PendingOperations;
/** Map of actions to apply to new tree items */
TMap<FObjectKey, uint8> NewItemActions;
/** Our tree view */
TSharedPtr< SPoseWatchManagerTreeView > PoseWatchManagerTreeView;
/** A map of all items we have in the tree */
FPoseWatchManagerTreeItemMap TreeItemMap;
/** Pending tree items that are yet to be added the tree */
FPoseWatchManagerTreeItemMap PendingTreeItemMap;
/** Root level tree items */
TArray<FPoseWatchManagerTreeItemPtr> RootTreeItems;
TSharedPtr<FUICommandList> CommandList;
private:
/** true if the manager needs to be repopulated at the next appropriate opportunity */
uint8 bNeedsRefresh : 1;
/** Processing a full refresh until pending items are processed */
uint8 bProcessingFullRefresh : 1;
/** true if should do a full refresh */
uint8 bFullRefresh : 1;
/** true if should refresh selection */
uint8 bSelectionDirty : 1;
uint8 bNeedsColumnRefresh : 1;
/** Reentrancy guard */
bool bIsReentrant;
/* Widget containing the filtering text box */
TSharedPtr< SSearchBox > FilterTextBoxWidget;
/** The header row of the manager */
TSharedPtr< SHeaderRow > HeaderRowWidget;
/** The TextFilter attached to the SearchBox widget */
TSharedPtr< PoseWatchManager::TreeItemTextFilter > SearchBoxFilter;
/** True if the search box will take keyboard focus next frame */
bool bPendingFocusNextFrame;
/** The tree item that is currently pending a rename */
TWeakPtr<IPoseWatchManagerTreeItem> PendingRenameItem;
TUniquePtr<FPoseWatchManagerDefaultHierarchy> Hierarchy;
PoseWatchManager::FTreeItemPtrEvent OnDoubleClickOnTreeEvent;
PoseWatchManager::FOnItemSelectionChanged OnItemSelectionChanged;
private:
virtual void AddReferencedObjects(FReferenceCollector& Collector) override {};
virtual FString GetReferencerName() const override
{
return TEXT("PoseWatchManager::SPoseWatchManager");
}
bool bDisableIntermediateSorting;
/** true if currently needs to be sorted */
bool bSortDirty;
/** Specify which column to sort with */
FName SortByColumn;
/** Currently selected sorting mode */
EColumnSortMode::Type SortMode;
FBlueprintEditor* BlueprintEditor;
/** Handles column sorting mode change */
void OnColumnSortModeChanged(const EColumnSortPriority::Type SortPriority, const FName& ColumnId, const EColumnSortMode::Type InSortMode);
/** Sort the specified array of items based on the current sort column */
void SortItems(TArray<FPoseWatchManagerTreeItemPtr>& Items) const;
/** Handler for recursively expanding/collapsing items */
void SetItemExpansionRecursive(FPoseWatchManagerTreeItemPtr Model, bool bInExpansionState);
};