Files
UnrealEngineUWP/Engine/Source/Editor/Sequencer/Private/SSequencerTreeView.h
Marc Audy 01b7c9f4f5 Merge UE5/RES @ 15958325 to UE5/Main
This represents UE4/Main @ 15913390 and Dev-PerfTest @ 15913304

[CL 15958515 by Marc Audy in ue5-main branch]
2021-04-08 14:32:07 -04:00

306 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Misc/Attribute.h"
#include "Input/Reply.h"
#include "Widgets/SWidget.h"
#include "SequencerNodeTree.h"
#include "DisplayNodes/SequencerDisplayNode.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Views/STableViewBase.h"
#include "Widgets/Views/STableRow.h"
#include "Widgets/Views/STreeView.h"
#include "SSequencerTrackArea.h"
class SSequencerTrackLane;
class SSequencerTreeViewRow;
typedef TSharedRef<FSequencerDisplayNode> FDisplayNodeRef;
enum class ETreeRecursion
{
Recursive, NonRecursive
};
/** Structure to represent the top/bottom bounds of a highlight region */
struct FHighlightRegion
{
FHighlightRegion(float InTop, float InBottom) : Top(InTop), Bottom(InBottom) {}
float Top, Bottom;
};
/** Structure used to define a column in the tree view */
struct FSequencerTreeViewColumn
{
typedef TFunction<TSharedRef<SWidget>(const FDisplayNodeRef&, const TSharedRef<SSequencerTreeViewRow>&)> FOnGenerate;
FSequencerTreeViewColumn(const FOnGenerate& InOnGenerate, const TAttribute<float>& InWidth) : Generator(InOnGenerate), Width(InWidth) {}
FSequencerTreeViewColumn(FOnGenerate&& InOnGenerate, const TAttribute<float>& InWidth) : Generator(MoveTemp(InOnGenerate)), Width(InWidth) {}
/** Function used to generate a cell for this column */
FOnGenerate Generator;
/** Attribute specifying the width of this column */
TAttribute<float> Width;
};
/** A delegate that is executed when adding menu content. */
DECLARE_DELEGATE_OneParam(FOnGetContextMenuContent, FMenuBuilder& /*MenuBuilder*/);
/** The tree view used in the sequencer */
class SSequencerTreeView : public STreeView<FDisplayNodeRef>
{
public:
SLATE_BEGIN_ARGS(SSequencerTreeView){}
/** Externally supplied scroll bar */
SLATE_ARGUMENT( TSharedPtr<SScrollBar>, ExternalScrollbar )
/** Called to populate the context menu. */
SLATE_EVENT( FOnGetContextMenuContent, OnGetContextMenuContent )
SLATE_END_ARGS()
/** Construct this widget */
void Construct(const FArguments& InArgs, const TSharedRef<FSequencerNodeTree>& InNodeTree, const TSharedRef<SSequencerTrackArea>& InTrackArea);
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime );
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
/** Access the underlying tree data */
TSharedPtr<FSequencerNodeTree> GetNodeTree() { return SequencerNodeTree; }
/** @return the number of root nodes this tree contains */
int32 GetNumRootNodes() const { return RootNodes.Num(); }
/** @return an optional region specifying the vertical bounds in which a highlight should be drawn */
const TOptional<FHighlightRegion>& GetHighlightRegion() const { return HighlightRegion; }
public:
/** Get the display node at the specified physical vertical position */
TSharedPtr<FSequencerDisplayNode> HitTestNode(float InPhysical) const;
/** Convert the specified physical vertical position into an absolute virtual position, ignoring expanded states */
float PhysicalToVirtual(float InPhysical) const;
/** Convert the specified absolute virtual position into a physical position in the tree.
* @note: Will not work reliably for virtual positions that are outside of the physical space
*/
float VirtualToPhysical(float InVirtual) const;
public:
/** Refresh this tree as a result of the underlying tree data changing */
void Refresh();
/** Expand or collapse nodes */
void ToggleExpandCollapseNodes(ETreeRecursion Recursion = ETreeRecursion::Recursive, bool bExpandAll = false, bool bCollapseAll = false);
/** Scroll this tree view by the specified number of slate units */
void ScrollByDelta(float DeltaInSlateUnits);
protected:
/** Set the item's expansion state, including all of its children */
void ExpandCollapseNode(const FDisplayNodeRef& InNode, bool bExpansionState, ETreeRecursion Recursion);
/** Generate a row for a particular node */
TSharedRef<ITableRow> OnGenerateRow(FDisplayNodeRef InDisplayNode, const TSharedRef<STableViewBase>& OwnerTable);
/** Gather the children from the specified node */
void OnGetChildren(FDisplayNodeRef InParent, TArray<FDisplayNodeRef>& OutChildren) const;
/** Generate a widget for the specified Node and Column */
TSharedRef<SWidget> GenerateWidgetForColumn(const FDisplayNodeRef& Node, const FName& ColumnId, const TSharedRef<SSequencerTreeViewRow>& Row) const;
/** Called when a node has been expanded or collapsed */
void OnExpansionChanged(FDisplayNodeRef InItem, bool bIsExpanded);
// Tree selection methods which must be overriden to maintain selection consistency with the rest of sequencer.
virtual void Private_SetItemSelection( FDisplayNodeRef TheItem, bool bShouldBeSelected, bool bWasUserDirected = false ) override;
virtual void Private_ClearSelection() override;
virtual void Private_SelectRangeFromCurrentTo( FDisplayNodeRef InRangeSelectionEnd ) override;
virtual void Private_SignalSelectionChanged( ESelectInfo::Type SelectInfo ) override;
virtual void OnRightMouseButtonDown(const FPointerEvent& MouseEvent) override;
virtual void OnRightMouseButtonUp(const FPointerEvent& MouseEvent) override;
virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
public:
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
private:
/** Updates the tree selection to match the current sequencer selection. */
void SynchronizeTreeSelectionWithSequencerSelection();
/**
* Updates the sequencer selection to match the current tree selection.
* @returns Whether or not the sequencer selection was actually modified.
*/
bool SynchronizeSequencerSelectionWithTreeSelection();
/** Handles the context menu opening when right clicking on the tree view. */
TSharedPtr<SWidget> OnContextMenuOpening();
void SetItemExpansionRecursive(FDisplayNodeRef InItem, bool bIsExpanded);
FOnGetContextMenuContent OnGetContextMenuContent;
public:
/** Structure used to cache physical geometry for a particular node */
struct FCachedGeometry
{
FCachedGeometry(FDisplayNodeRef InNode, float InPhysicalTop, float InPhysicalHeight)
: Node(MoveTemp(InNode)), PhysicalTop(InPhysicalTop), PhysicalHeight(InPhysicalHeight)
{}
FDisplayNodeRef Node;
float PhysicalTop, PhysicalHeight;
};
/** Access all the physical nodes currently visible on the sequencer */
const TArray<FCachedGeometry>& GetAllVisibleNodes() const { return PhysicalNodes; }
/** Retrieve the last reported physical geometry for the specified node, if available */
TOptional<FCachedGeometry> GetPhysicalGeometryForNode(const FDisplayNodeRef& InNode) const;
/** Attempt to compute the physical position of the specified node */
TOptional<float> ComputeNodePosition(const FDisplayNodeRef& InNode) const;
/** Report geometry for a child row */
void ReportChildRowGeometry(const FDisplayNodeRef& InNode, const FGeometry& InGeometry);
/** Called when a child row widget has been added/removed */
void OnChildRowRemoved(const FDisplayNodeRef& InNode);
/** Ensure that the track area column is either show or hidden, depending on the visibility of the curve editor */
void UpdateTrackArea();
/** Add a SSequencerTreeView object that should be modified or updated when this Treeview is updated */
void AddSlaveTreeView(TSharedPtr<SSequencerTreeView> SlaveTreeView);
/** Set a SSequencerTreeView object this Treeview is slaved to, for operations that should happen on the master */
void SetMasterTreeView(TSharedPtr<SSequencerTreeView> InMasterTreeView) { MasterTreeView = InMasterTreeView; }
/** Set whether this TreeView should show only pinned nodes or only non-pinned nodes */
void SetShowPinned(bool bShowPinned) { bShowPinnedNodes = bShowPinned; }
protected:
/** Linear, sorted array of nodes that we currently have generated widgets for */
mutable TArray<FCachedGeometry> PhysicalNodes;
/** A flag indicating that the physical nodes need to be updated. */
mutable bool bPhysicalNodesNeedUpdate;
/** Map of cached geometries for visible nodes */
TMap<FDisplayNodeRef, FCachedGeometry> CachedRowGeometry;
protected:
/** Populate the map of column definitions, and add relevant columns to the header row */
void SetupColumns(const FArguments& InArgs);
private:
/** The tree view's header row (hidden) */
TSharedPtr<SHeaderRow> HeaderRow;
/** Pointer to the node tree data that is used to populate this tree */
TSharedPtr<FSequencerNodeTree> SequencerNodeTree;
/** Cached copy of the root nodes from the tree data */
TArray<FDisplayNodeRef> RootNodes;
/** Column definitions for each of the columns in the tree view */
TMap<FName, FSequencerTreeViewColumn> Columns;
/** Strong pointer to the track area so we can generate track lanes as we need them */
TSharedPtr<SSequencerTrackArea> TrackArea;
/** A global highlight for the currently hovered tree node hierarchy */
TOptional<FHighlightRegion> HighlightRegion;
/** SSequencerTreeView objects that should be modified or updated when this Treeview is updated */
TArray<TSharedPtr<SSequencerTreeView>> SlaveTreeViews;
/** The SSequencerTreeView object this SSequencerTreeView is slave to, or nullptr if not a slave */
TWeakPtr<SSequencerTreeView> MasterTreeView;
/** When true, the sequencer selection is being updated from a change in the tree seleciton. */
bool bUpdatingSequencerSelection;
/** When true, the tree selection is being updated from a change in the sequencer selection. */
bool bUpdatingTreeSelection;
/** Right mouse button is down, don't update sequencer selection. */
bool bRightMouseButtonDown;
/** Whether this tree is for pinned nodes or non-pinned nodes */
bool bShowPinnedNodes;
/**
* When true a sequencer selection change broadcast was suppressed when updating sequencer selection
* due to the tree selection changing.
*/
bool bSequencerSelectionChangeBroadcastWasSupressed;
};
/** Widget that represents a row in the sequencer's tree control. */
class SSequencerTreeViewRow : public SMultiColumnTableRow<FDisplayNodeRef>
{
public:
DECLARE_DELEGATE_RetVal_ThreeParams(TSharedRef<SWidget>, FOnGenerateWidgetForColumn, const FDisplayNodeRef&, const FName&, const TSharedRef<SSequencerTreeViewRow>&);
SLATE_BEGIN_ARGS(SSequencerTreeViewRow){}
/** Delegate to invoke to create a new column for this row */
SLATE_EVENT(FOnGenerateWidgetForColumn, OnGenerateWidgetForColumn)
SLATE_END_ARGS()
~SSequencerTreeViewRow();
/** Construct function for this widget */
void Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& OwnerTableView, const FDisplayNodeRef& InNode);
/** Get the dispolay node to which this row relates */
TSharedPtr<FSequencerDisplayNode> GetDisplayNode() const;
/** Add a reference to the specified track lane, keeping it alive until this row is destroyed */
void AddTrackAreaReference(const TSharedPtr<SSequencerTrackLane>& Lane);
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
virtual const FSlateBrush* GetBorder() const override;
/** Overridden from SMultiColumnTableRow. Generates a widget for this column of the tree row. */
virtual TSharedRef<SWidget> GenerateWidgetForColumn(const FName& ColumnId) override;
/** Called whenever a drag is detected by the tree view. */
FReply OnDragDetected(const FGeometry& InGeometry, const FPointerEvent& InPointerEvent);
/** Called to determine whether a current drag operation is valid for this row. */
TOptional<EItemDropZone> OnCanAcceptDrop( const FDragDropEvent& DragDropEvent, EItemDropZone ItemDropZone, FDisplayNodeRef DisplayNode);
/** Called to complete a drag and drop onto this drop. */
FReply OnAcceptDrop( const FDragDropEvent& DragDropEvent, EItemDropZone ItemDropZone, FDisplayNodeRef DisplayNode );
/** Gets the padding for this row based on whether it is a root node or not */
FMargin GetRowPadding() const;
private:
/** Cached reference to a track lane that we relate to. This keeps the track lane alive (it's a weak widget) as long as we are in view. */
TSharedPtr<SSequencerTrackLane> TrackLaneReference;
/** The item associated with this row of data */
mutable TWeakPtr<FSequencerDisplayNode> Node;
/** Delegate to call to create a new widget for a particular column. */
FOnGenerateWidgetForColumn OnGenerateWidgetForColumn;
};