760 lines
29 KiB
C++
760 lines
29 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Components/ActorComponent.h"
|
|
#include "Components/SceneComponent.h"
|
|
#include "SubobjectDataSubsystem.h"
|
|
|
|
#include "Widgets/SCompoundWidget.h"
|
|
#include "Widgets/Views/STableRow.h"
|
|
#include "Widgets/Views/STreeView.h"
|
|
#include "Framework/Commands/UICommandList.h"
|
|
#include "SComponentClassCombo.h"
|
|
|
|
#include "BlueprintEditor.h" // FComponentEventConstructionData
|
|
|
|
#include "ScopedTransaction.h"
|
|
|
|
class SSubobjectEditor;
|
|
class SToolTip;
|
|
class SExtensionPanel;
|
|
class AActor;
|
|
class FSubobjectEditorTreeNode;
|
|
class SInlineEditableTextBlock;
|
|
class ISCSEditorUICustomization;
|
|
class UBlueprint;
|
|
class UToolMenu;
|
|
class UPrimitiveComponent;
|
|
|
|
// Tree node pointer types
|
|
using FSubobjectEditorTreeNodePtrType = TSharedPtr<class FSubobjectEditorTreeNode>;
|
|
|
|
/////////////////////////////////////////////////////
|
|
// FSubobjectEditorTreeNode
|
|
|
|
/**
|
|
* Wrapper struct that represents access an singe subobject that is used
|
|
* by slate as a layout for columns/rows should look like
|
|
*/
|
|
class SUBOBJECTEDITOR_API FSubobjectEditorTreeNode : public TSharedFromThis<FSubobjectEditorTreeNode>
|
|
{
|
|
public:
|
|
|
|
/** Delegate for when the context menu requests a rename */
|
|
DECLARE_DELEGATE(FOnRenameRequested);
|
|
|
|
explicit FSubobjectEditorTreeNode(const FSubobjectDataHandle& DataSource, bool InbIsSeperator = false);
|
|
|
|
~FSubobjectEditorTreeNode() = default;
|
|
|
|
bool IsSeperator() const { return bIsSeperator; }
|
|
|
|
// If this subobject is an actor component, then return its template. Otherwise it will
|
|
// return null
|
|
const UActorComponent* GetComponentTemplate() const;
|
|
|
|
const UObject* GetObject(bool bEvenIfPendingKill = false) const;
|
|
|
|
// Get a pointer to the subobject data that this slate node is representing
|
|
FSubobjectData* GetDataSource() const;
|
|
|
|
// Get the subobject handle that this slate node is representing
|
|
FSubobjectDataHandle GetDataHandle() const { return DataHandle; }
|
|
|
|
/** Get the slate parent of this single tree node */
|
|
FSubobjectEditorTreeNodePtrType GetParent() const { return ParentNodePtr; }
|
|
|
|
/** Get the display name of this single tree node */
|
|
FString GetDisplayString() const;
|
|
|
|
bool IsComponentNode() const;
|
|
|
|
// Returns true if this is the root actor node of the tree
|
|
bool IsRootActorNode() const;
|
|
|
|
bool CanReparent() const;
|
|
|
|
FName GetVariableName() const;
|
|
|
|
// Returns true if this subobject data handle is valid
|
|
bool IsValid() const { return bIsSeperator || DataHandle.IsValid(); }
|
|
|
|
bool IsChildSubtreeNode() const;
|
|
|
|
bool IsNativeComponent() const;
|
|
|
|
// Returns true if this node is attached to the given slate node
|
|
bool IsAttachedTo(FSubobjectEditorTreeNodePtrType InNodePtr) const;
|
|
|
|
/**
|
|
* @return Whether or not this node is a direct child of the given node.
|
|
*/
|
|
bool IsDirectlyAttachedTo(FSubobjectEditorTreeNodePtrType InNodePtr) const;
|
|
|
|
bool CanDelete() const;
|
|
|
|
bool CanRename() const;
|
|
|
|
/**
|
|
* @return The set of nodes which are parented to this node (read-only).
|
|
*/
|
|
const TArray<FSubobjectEditorTreeNodePtrType>& GetChildren() const { return Children; }
|
|
|
|
// Add the given slate node to our child array and set it's parent to us
|
|
// This had no effect on the actual structure of the subobjects this node represents
|
|
// it is purely visual
|
|
void AddChild(FSubobjectEditorTreeNodePtrType AttachToPtr);
|
|
|
|
// Remove the given slate node from our children array
|
|
void RemoveChild(FSubobjectEditorTreeNodePtrType InChildNodePtr);
|
|
|
|
// Attempts to find the given subobject handle in the slate children on this node. Nullptr if none are found.
|
|
FSubobjectEditorTreeNodePtrType FindChild(const FSubobjectDataHandle& InHandle);
|
|
|
|
/** Query that determines if this item should be filtered out or not */
|
|
bool IsFlaggedForFiltration() const;
|
|
|
|
/** Sets this item's filtration state. Use bUpdateParent to make sure the parent's EFilteredState::ChildMatches flag is properly updated based off the new state */
|
|
void SetCachedFilterState(bool bMatchesFilter, bool bUpdateParent);
|
|
|
|
/** Used to update the EFilteredState::ChildMatches flag for parent nodes, when this item's filtration state has changed */
|
|
void ApplyFilteredStateToParent();
|
|
|
|
/** Updates the EFilteredState::ChildMatches flag, based off of children's current state */
|
|
void RefreshCachedChildFilterState(bool bUpdateParent);
|
|
|
|
/** Refreshes this item's filtration state. Set bRecursive to 'true' to refresh any child nodes as well */
|
|
bool RefreshFilteredState(const UClass* InFilterType, const TArray<FString>& InFilterTerms, bool bRecursive);
|
|
|
|
/** Returns whether the node will match the given type (for filtering) */
|
|
bool MatchesFilterType(const UClass* InFilterType) const;
|
|
|
|
void SetOngoingCreateTransaction(TUniquePtr<FScopedTransaction> InTransaction);
|
|
void CloseOngoingCreateTransaction();
|
|
void GetOngoingCreateTransaction(TUniquePtr<FScopedTransaction>& OutPtr) { OutPtr = MoveTemp(OngoingCreateTransaction); }
|
|
bool HasOngoingTransaction() const { return OngoingCreateTransaction.IsValid(); }
|
|
|
|
/** Sets up the delegate for a rename operation */
|
|
void SetRenameRequestedDelegate(FOnRenameRequested InRenameRequested) { RenameRequestedDelegate = InRenameRequested; }
|
|
FOnRenameRequested GetRenameRequestedDelegate() { return RenameRequestedDelegate; }
|
|
|
|
protected:
|
|
|
|
/** Pointer to the parent of this subobject */
|
|
FSubobjectEditorTreeNodePtrType ParentNodePtr;
|
|
|
|
// Scope the creation of a node which ends when the initial 'name' is given/accepted by the user, which can be several frames after the node was actually created.
|
|
TUniquePtr<FScopedTransaction> OngoingCreateTransaction;
|
|
|
|
/** Handles rename requests */
|
|
FOnRenameRequested RenameRequestedDelegate;
|
|
|
|
/**
|
|
* Any children that this subobject has in the hierarchy, used to
|
|
* collapsed things within in the tree
|
|
*/
|
|
TArray<FSubobjectEditorTreeNodePtrType> Children;
|
|
|
|
/** The data source of this subobject */
|
|
FSubobjectDataHandle DataHandle;
|
|
|
|
enum EFilteredState
|
|
{
|
|
FilteredOut = 0x00,
|
|
MatchesFilter = (1 << 0),
|
|
ChildMatches = (1 << 1),
|
|
|
|
FilteredInMask = (MatchesFilter | ChildMatches),
|
|
Unknown = 0xFC // ~FilteredInMask
|
|
};
|
|
uint8 FilterFlags;
|
|
|
|
/** A flag that indicates that this is a separator slate node and has no valid data */
|
|
uint8 bIsSeperator : 1;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////
|
|
// SSubobjectEditorDragDropTree
|
|
|
|
/** Implements the specific node type and add drag/drop functionality */
|
|
class SSubobjectEditorDragDropTree : public STreeView<FSubobjectEditorTreeNodePtrType>
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS(SSubobjectEditorDragDropTree)
|
|
: _SubobjectEditor(nullptr)
|
|
, _OnGenerateRow()
|
|
, _OnGetChildren()
|
|
, _OnSetExpansionRecursive()
|
|
, _TreeItemsSource(static_cast<TArray<FSubobjectEditorTreeNodePtrType>*>(nullptr))
|
|
, _ItemHeight(16)
|
|
, _OnContextMenuOpening()
|
|
, _OnMouseButtonDoubleClick()
|
|
, _OnSelectionChanged()
|
|
, _SelectionMode(ESelectionMode::Multi)
|
|
, _ClearSelectionOnClick(true)
|
|
, _ExternalScrollbar()
|
|
, _OnTableViewBadState()
|
|
{
|
|
_Clipping = EWidgetClipping::ClipToBounds;
|
|
}
|
|
|
|
SLATE_ARGUMENT(SSubobjectEditor*, SubobjectEditor)
|
|
|
|
SLATE_EVENT(FOnGenerateRow, OnGenerateRow)
|
|
|
|
SLATE_EVENT(FOnItemScrolledIntoView, OnItemScrolledIntoView)
|
|
|
|
SLATE_EVENT(FOnGetChildren, OnGetChildren)
|
|
|
|
SLATE_EVENT(FOnSetExpansionRecursive, OnSetExpansionRecursive)
|
|
|
|
SLATE_ARGUMENT(TArray<FSubobjectEditorTreeNodePtrType>*, TreeItemsSource)
|
|
|
|
SLATE_ATTRIBUTE_DEPRECATED(float, ItemHeight, 5.5, "The ItemHeight is only used for Tile. See ShouldArrangeAsTiles")
|
|
|
|
SLATE_EVENT(FOnContextMenuOpening, OnContextMenuOpening)
|
|
|
|
SLATE_EVENT(FOnMouseButtonDoubleClick, OnMouseButtonDoubleClick)
|
|
|
|
SLATE_EVENT(FOnSelectionChanged, OnSelectionChanged)
|
|
|
|
SLATE_ATTRIBUTE(ESelectionMode::Type, SelectionMode)
|
|
|
|
SLATE_ARGUMENT(TSharedPtr<SHeaderRow>, HeaderRow)
|
|
|
|
SLATE_ARGUMENT(bool, ClearSelectionOnClick)
|
|
|
|
SLATE_ARGUMENT(TSharedPtr<SScrollBar>, ExternalScrollbar)
|
|
|
|
SLATE_EVENT(FOnTableViewBadState, OnTableViewBadState)
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
/** Object construction - mostly defers to the base STreeView */
|
|
void Construct(const FArguments& InArgs);
|
|
|
|
// SWidget interface
|
|
virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
|
|
virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
|
|
// End SWidget interface
|
|
|
|
private:
|
|
|
|
SSubobjectEditor* SubobjectEditor;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////
|
|
// SSubobject_RowWidget
|
|
|
|
/**
|
|
* A row widget that represents a single subobject within the tree.
|
|
*/
|
|
class SSubobject_RowWidget : public SMultiColumnTableRow<FSubobjectEditorTreeNodePtrType>
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS(SSubobject_RowWidget) {}
|
|
SLATE_END_ARGS()
|
|
|
|
void Construct(const FArguments& InArgs, TWeakPtr<SSubobjectEditor> InEditor, FSubobjectEditorTreeNodePtrType InNodePtr, TSharedPtr<STableViewBase> InOwnerTableView);
|
|
|
|
// SMultiColumnTableRow<T> interface
|
|
virtual TSharedRef<SWidget> GenerateWidgetForColumn(const FName& ColumnName) override;
|
|
|
|
protected:
|
|
virtual ESelectionMode::Type GetSelectionMode() const override;
|
|
// End of SMultiColumnTableRow<T>
|
|
|
|
/** Drag-drop handlers */
|
|
void HandleOnDragEnter(const FDragDropEvent& DragDropEvent);
|
|
void HandleOnDragLeave(const FDragDropEvent& DragDropEvent);
|
|
FReply HandleOnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);
|
|
TOptional<EItemDropZone> HandleOnCanAcceptDrop(const FDragDropEvent& DragDropEvent, EItemDropZone DropZone, FSubobjectEditorTreeNodePtrType TargetItem);
|
|
FReply HandleOnAcceptDrop(const FDragDropEvent& DragDropEvent, EItemDropZone DropZone, FSubobjectEditorTreeNodePtrType TargetItem);
|
|
|
|
public:
|
|
/** Get the asset name of this subobject from the asset brokerage */
|
|
FText GetAssetName() const;
|
|
|
|
/** Get the asset path of this subobject from the asset brokerage */
|
|
FText GetAssetPath() const;
|
|
|
|
FText GetNameLabel() const;
|
|
|
|
/** Check if this asset is visible from the asset brokerage */
|
|
EVisibility GetAssetVisibility() const;
|
|
|
|
virtual const FSlateBrush* GetIconBrush() const;
|
|
|
|
FSlateColor GetColorTintForIcon() const;
|
|
|
|
FSubobjectEditorTreeNodePtrType GetSubobjectPtr() const { return SubobjectPtr; }
|
|
|
|
private:
|
|
|
|
static void AddToToolTipInfoBox(const TSharedRef<SVerticalBox>& InfoBox, const FText& Key, TSharedRef<SWidget> ValueIcon, const TAttribute<FText>& Value, bool bImportant);
|
|
|
|
/** Creates a tooltip for this row */
|
|
TSharedRef<SToolTip> CreateToolTipWidget() const;
|
|
|
|
/** Create the tooltip for component subobjects */
|
|
TSharedRef<SToolTip> CreateComponentTooltipWidget(const FSubobjectEditorTreeNodePtrType& InNode) const;
|
|
|
|
/** Create the tooltip for actor subobjects */
|
|
TSharedRef<SToolTip> CreateActorTooltipWidget(const FSubobjectEditorTreeNodePtrType& InNode) const;
|
|
|
|
FText GetTooltipText() const;
|
|
|
|
FText GetActorClassNameText() const;
|
|
FText GetActorSuperClassNameText() const;
|
|
FText GetActorMobilityText() const;
|
|
|
|
/** Returns a widget that represents the inheritance of this subobject which includes a hyperlink to edit the property */
|
|
TSharedRef<SWidget> GetInheritedLinkWidget();
|
|
|
|
/** Gets the context of this subobject, such as "(Self)" or "(Instance)" for actors. */
|
|
FText GetObjectContextText() const;
|
|
|
|
FString GetDocumentationLink() const;
|
|
FString GetDocumentationExcerptName() const;
|
|
|
|
/** Callback used when the user clicks on a blueprint inherited variable */
|
|
void OnEditBlueprintClicked();
|
|
|
|
EVisibility GetEditBlueprintVisibility() const;
|
|
EVisibility GetEditNativeCppVisibility() const;
|
|
|
|
/** Callback used when the user clicks on a native inherited variable */
|
|
void OnEditNativeCppClicked();
|
|
|
|
/**
|
|
* Retrieves tooltip text describing the specified component's mobility.
|
|
*
|
|
* @returns An FText object containing a description of the component's mobility
|
|
*/
|
|
FText GetMobilityToolTipText() const;
|
|
|
|
/**
|
|
* Retrieves an image brush signifying the specified component's mobility (could sometimes be NULL).
|
|
*
|
|
* @returns A pointer to the FSlateBrush to use (NULL for Static and Non-SceneComponents)
|
|
*/
|
|
FSlateBrush const* GetMobilityIconImage() const;
|
|
|
|
/**
|
|
* Retrieves tooltip text describing where the component was first introduced (for inherited components).
|
|
*
|
|
* @returns An FText object containing a description of when the component was first introduced
|
|
*/
|
|
FText GetIntroducedInToolTipText() const;
|
|
|
|
/**
|
|
* Retrieves tooltip text describing how the component was introduced
|
|
*
|
|
* @returns An FText object containing a description of when the component was first introduced
|
|
*/
|
|
FText GetComponentAddSourceToolTipText() const;
|
|
|
|
/**
|
|
* Retrieves a tooltip text describing if the component is marked Editor only or not
|
|
*
|
|
* @returns An FText object containing a description of if the component is marked Editor only or not
|
|
*/
|
|
FText GetComponentEditorOnlyTooltipText() const;
|
|
|
|
/**
|
|
* Retrieves tooltip text for the specified Native Component's underlying Name
|
|
*
|
|
* @returns An FText object containing the Component's Name
|
|
*/
|
|
FText GetNativeComponentNameToolTipText() const;
|
|
|
|
FText GetActorDisplayText() const;
|
|
|
|
/** Commits the new name of the component */
|
|
void OnNameTextCommit(const FText& InNewName, ETextCommit::Type InTextCommit);
|
|
|
|
/** Verifies the name of the component when changing it */
|
|
bool OnNameTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage);
|
|
|
|
bool IsReadOnly() const;
|
|
|
|
TWeakPtr<SSubobjectEditor> SubobjectEditor;
|
|
TSharedPtr<SInlineEditableTextBlock> InlineWidget;
|
|
|
|
FSubobjectEditorTreeNodePtrType SubobjectPtr;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////
|
|
// SSubobjectEditor
|
|
|
|
/**
|
|
* The base class viewer for subobject editing in Slate. This displays
|
|
* all subobjects of a given actor or blueprint. A subobject can be a native
|
|
* component on an actor or inherited components from a native or blueprint parent.
|
|
*/
|
|
class SUBOBJECTEDITOR_API SSubobjectEditor : public SCompoundWidget
|
|
{
|
|
public:
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnSelectionUpdated, const TArray<FSubobjectEditorTreeNodePtrType>&);
|
|
DECLARE_DELEGATE_OneParam(FOnItemDoubleClicked, const FSubobjectEditorTreeNodePtrType);
|
|
|
|
protected:
|
|
|
|
// Do not allow public construction of this widget!
|
|
SSubobjectEditor() = default;
|
|
|
|
virtual ~SSubobjectEditor() = default;
|
|
|
|
/** Delegate to invoke on selection update. */
|
|
FOnSelectionUpdated OnSelectionUpdated;
|
|
|
|
/** Delegate to invoke when an item in the tree is double clicked. */
|
|
FOnItemDoubleClicked OnItemDoubleClicked;
|
|
|
|
/** Attribute that provides access to the Object context for which we are viewing/editing. */
|
|
TAttribute<UObject*> ObjectContext;
|
|
|
|
/** Attribute to indicate whether or not editing is allowed. */
|
|
TAttribute<bool> AllowEditing;
|
|
|
|
/** Attribute to indicate whether or not the "Add Component" button is visible. If true, new components cannot be added to the Blueprint. */
|
|
TAttribute<bool> HideComponentClassCombo;
|
|
|
|
/** Attribute to limit visible nodes to a particular component type when filtering the tree view. */
|
|
TAttribute<TSubclassOf<UActorComponent>> ComponentTypeFilter;
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// Widget Callbacks
|
|
protected:
|
|
|
|
TSharedRef<ITableRow> MakeTableRowWidget(FSubobjectEditorTreeNodePtrType InNodePtr, const TSharedRef<STableViewBase>& OwnerTable);
|
|
|
|
/** @return The visibility of the components tree */
|
|
EVisibility GetComponentsTreeVisibility() const;
|
|
|
|
/** Used by tree control - get children for a specified subobject node */
|
|
void OnGetChildrenForTree(FSubobjectEditorTreeNodePtrType InNodePtr, TArray<FSubobjectEditorTreeNodePtrType>& OutChildren);
|
|
|
|
/** Update any associated selection (e.g. details view) from the passed in nodes */
|
|
void UpdateSelectionFromNodes(const TArray<FSubobjectEditorTreeNodePtrType>& SelectedNodes);
|
|
|
|
/** Called when selection in the tree changes */
|
|
void OnTreeSelectionChanged(FSubobjectEditorTreeNodePtrType InSelectedNodePtr, ESelectInfo::Type SelectInfo);
|
|
|
|
/** Callback when a component item is double clicked. */
|
|
void HandleItemDoubleClicked(FSubobjectEditorTreeNodePtrType InItem);
|
|
|
|
void OnFindReferences(bool bSearchAllBlueprints, const EGetFindReferenceSearchStringFlags Flags);
|
|
|
|
/** @return The visibility of the components filter box */
|
|
EVisibility GetComponentsFilterBoxVisibility() const;
|
|
|
|
/** Recursively updates the filtered state for each component item */
|
|
void OnFilterTextChanged(const FText& InFilterText);
|
|
|
|
/** Callback when a component item is scrolled into view */
|
|
void OnItemScrolledIntoView(FSubobjectEditorTreeNodePtrType InItem, const TSharedPtr<ITableRow>& InWidget);
|
|
|
|
/** SWidget interface */
|
|
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
|
|
|
|
public:
|
|
/** Select the given tree node */
|
|
void SelectNode(FSubobjectEditorTreeNodePtrType InNodeToSelect, bool bIsCntrlDown);
|
|
|
|
/** Select the given tree node if there is on that matches the given handle */
|
|
void SelectNodeFromHandle(const FSubobjectDataHandle& InHandle, bool bIsCntrlDown);
|
|
|
|
/** Update the contents of the Subobject Tree based on the current context */
|
|
void UpdateTree(bool bRegenerateTreeNodes = true);
|
|
|
|
/** Dumps out the tree view contents to the log (used to assist with debugging widget hierarchy issues) */
|
|
void DumpTree();
|
|
|
|
/** Forces the details panel to refresh on the same objects */
|
|
void RefreshSelectionDetails();
|
|
|
|
/** Clears the current selection */
|
|
void ClearSelection();
|
|
|
|
/** Select the root of the tree */
|
|
void SelectRoot();
|
|
|
|
/** Get the tint color that any subobject editor icons should use. The default is the foreground color. */
|
|
virtual FSlateColor GetColorTintForIcon(FSubobjectEditorTreeNodePtrType Node) const;
|
|
|
|
/** Get the currently selected nodes from the tree sorted in order from parent to child */
|
|
TArray<FSubobjectEditorTreeNodePtrType> GetSelectedNodes() const;
|
|
|
|
/** Returns the number of currently selected nodes in the tree */
|
|
int32 GetNumSelectedNodes() const { return TreeWidget->GetSelectedItems().Num(); }
|
|
|
|
/** Get the currently selected handles from the tree sorted in order from parent to child */
|
|
TArray<FSubobjectDataHandle> GetSelectedHandles() const;
|
|
|
|
virtual FSubobjectEditorTreeNodePtrType GetSceneRootNode() const;
|
|
|
|
/** Try to handle a drag-drop operation */
|
|
FReply TryHandleAssetDragDropOperation(const FDragDropEvent& DragDropEvent);
|
|
|
|
/** Sets UI customizations of this SCSEditor. */
|
|
void SetUICustomization(TSharedPtr<ISCSEditorUICustomization> InUICustomization);
|
|
|
|
virtual bool IsEditingAllowed() const;
|
|
|
|
/** Return the button widgets that can add components or create/edit blueprints */
|
|
TSharedPtr<SWidget> GetToolButtonsBox() const;
|
|
|
|
TSharedPtr<FUICommandList> GetCommandList() const { return CommandList; }
|
|
|
|
TSharedPtr<SSubobjectEditorDragDropTree> GetDragDropTree() const { return TreeWidget; }
|
|
|
|
// Drag/drop operations
|
|
/** Handler for attaching a single node to this node */
|
|
void OnAttachToDropAction(FSubobjectEditorTreeNodePtrType DroppedOn, FSubobjectEditorTreeNodePtrType DroppedNodePtr)
|
|
{
|
|
TArray<FSubobjectEditorTreeNodePtrType> DroppedNodePtrs;
|
|
DroppedNodePtrs.Add(DroppedNodePtr);
|
|
OnAttachToDropAction(DroppedOn, DroppedNodePtrs);
|
|
}
|
|
|
|
virtual void OnAttachToDropAction(FSubobjectEditorTreeNodePtrType DroppedOn, const TArray<FSubobjectEditorTreeNodePtrType>& DroppedNodePtrs) = 0;
|
|
virtual void OnDetachFromDropAction(const TArray<FSubobjectEditorTreeNodePtrType>& DroppedNodePtrs) = 0;
|
|
virtual void OnMakeNewRootDropAction(FSubobjectEditorTreeNodePtrType DroppedNodePtr) = 0;
|
|
virtual void PostDragDropAction(bool bRegenerateTreeNodes) = 0;
|
|
|
|
/** Builds a context menu popup for dropping a child node onto the scene root node */
|
|
virtual TSharedPtr<SWidget> BuildSceneRootDropActionMenu(FSubobjectEditorTreeNodePtrType DroppedOntoNodePtr, FSubobjectEditorTreeNodePtrType DroppedNodePtr) = 0;
|
|
|
|
virtual bool CanMakeNewRootOnDrag(UBlueprint* DraggedFromBlueprint) const { return false; }
|
|
|
|
/** Provides access to the Blueprint context that's being edited */
|
|
UBlueprint* GetBlueprint() const;
|
|
|
|
// Attempt to find an existing slate node that matches the given handle
|
|
virtual FSubobjectEditorTreeNodePtrType FindSlateNodeForObject(const UObject* InObject, bool bIncludeAttachmentComponents = true) const;
|
|
|
|
/** Returns true if the specified component is currently selected */
|
|
bool IsComponentSelected(const UPrimitiveComponent* PrimComponent) const;
|
|
|
|
/** Assigns a selection override delegate to the specified component */
|
|
void SetSelectionOverride(UPrimitiveComponent* PrimComponent) const;
|
|
|
|
/**
|
|
* Fills the supplied array with the currently selected objects
|
|
* @param OutSelectedItems The array to fill.
|
|
*/
|
|
void GetSelectedItemsForContextMenu(TArray<FComponentEventConstructionData>& OutSelectedItems) const;
|
|
|
|
/** Return an array of the current slate node hierarchy in the tree */
|
|
const TArray<FSubobjectEditorTreeNodePtrType>& GetRootNodes() const { return RootNodes; };
|
|
|
|
// Attempt to find an existing slate node that matches the given handle
|
|
FSubobjectEditorTreeNodePtrType FindSlateNodeForHandle(const FSubobjectDataHandle& Handle, FSubobjectEditorTreeNodePtrType InStartNodePtr = FSubobjectEditorTreeNodePtrType()) const;
|
|
|
|
// Attempt to find an existing slate node that has a given variable name
|
|
FSubobjectEditorTreeNodePtrType FindSlateNodeForVariableName(FName InVariableName) const;
|
|
|
|
/** Pointer to the current object that is represented by the subobject editor */
|
|
UObject* GetObjectContext() const;
|
|
|
|
/** SubobjectHandle of the current object that is represented by the subobject editor */
|
|
FSubobjectDataHandle GetObjectContextHandle() const;
|
|
|
|
/** Refresh the type list presented by the add component button when clicked */
|
|
void RefreshComponentTypesList();
|
|
|
|
protected:
|
|
|
|
/** Restore the previous selection state when updating the tree */
|
|
virtual void RestoreSelectionState(TArray<FSubobjectEditorTreeNodePtrType>& SelectedTreeNodes, bool bFallBackToVariableName = true);
|
|
|
|
/** If true, then the blueprint should be modified on TryHandleAssetDragDropOperation */
|
|
virtual bool ShouldModifyBPOnAssetDrop() const { return false; }
|
|
|
|
bool CanCutNodes() const;
|
|
void CutSelectedNodes();
|
|
|
|
bool CanCopyNodes() const;
|
|
virtual void CopySelectedNodes() = 0;
|
|
|
|
/** Pastes previously copied node(s) */
|
|
virtual bool CanPasteNodes() const;
|
|
virtual void PasteNodes() = 0;
|
|
|
|
public:
|
|
/** Removes existing selected component nodes from the SCS */
|
|
virtual bool CanDeleteNodes() const;
|
|
virtual void OnDeleteNodes() = 0;
|
|
|
|
protected:
|
|
bool CanDuplicateComponent() const;
|
|
virtual void OnDuplicateComponent() = 0;
|
|
|
|
/** Checks to see if renaming is allowed on the selected component */
|
|
bool CanRenameComponent() const;
|
|
void OnRenameComponent();
|
|
void OnRenameComponent(TUniquePtr<FScopedTransaction> InComponentCreateTransaction);
|
|
|
|
/** Called at the end of each frame. */
|
|
void OnPostTick(float);
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// Widgets
|
|
|
|
/** Root set of tree that represents all subobjects for the current context */
|
|
TArray<FSubobjectEditorTreeNodePtrType> RootNodes;
|
|
|
|
/** Tree widget */
|
|
TSharedPtr<SSubobjectEditorDragDropTree> TreeWidget;
|
|
|
|
/** Command list for handling actions in the editor. */
|
|
TSharedPtr<FUICommandList> CommandList;
|
|
|
|
/** The filter box that handles filtering for the tree. */
|
|
TSharedPtr<SSearchBox> FilterBox;
|
|
|
|
/** The tools buttons box */
|
|
TSharedPtr<SHorizontalBox> ButtonBox;
|
|
|
|
/** The add component button / type selector */
|
|
TSharedPtr<SComponentClassCombo> ComponentClassCombo;
|
|
|
|
/** Gate to prevent changing the selection while selection change is being broadcast. */
|
|
bool bUpdatingSelection;
|
|
|
|
/** Controls whether or not to allow calls to UpdateTree() */
|
|
bool bAllowTreeUpdates;
|
|
|
|
/** SCSEditor UI customizations */
|
|
TSharedPtr<ISCSEditorUICustomization> UICustomization;
|
|
|
|
/** SCSEditor UI extension */
|
|
TSharedPtr<SExtensionPanel> ExtensionPanel;
|
|
|
|
/** Scope the creation of a component which ends when the initial component 'name' is given/accepted by the user, which can be several frames after the component was actually created. */
|
|
TUniquePtr<FScopedTransaction> DeferredOngoingCreateTransaction;
|
|
|
|
/** Used to unregister from the post tick event. */
|
|
FDelegateHandle PostTickHandle;
|
|
|
|
/** Name of a node that has been requested to be renamed */
|
|
FSubobjectDataHandle DeferredRenameRequest;
|
|
|
|
/**
|
|
* The handle to the current root context. If this is different in between
|
|
* UpdateTree calls, then we know the context has changed and we should clean up
|
|
* the subobject memory layout.
|
|
*/
|
|
FSubobjectDataHandle CachedRootHandle;
|
|
|
|
virtual FMenuBuilder CreateMenuBuilder();
|
|
|
|
/** Constructs the slate drag/drop tree for this subobject editor */
|
|
virtual void ConstructTreeWidget();
|
|
|
|
/** Creates a list of commands */
|
|
virtual void CreateCommandList();
|
|
|
|
/** Recursively visits the given node + its children and invokes the given function for each. */
|
|
void DepthFirstTraversal(const FSubobjectEditorTreeNodePtrType& InNodePtr, TSet<FSubobjectEditorTreeNodePtrType>& OutVisitedNodes, const TFunctionRef<void(const FSubobjectEditorTreeNodePtrType&)> InFunction) const;
|
|
|
|
/** Returns the set of expandable nodes that are currently collapsed in the UI */
|
|
void GetCollapsedNodes(const FSubobjectEditorTreeNodePtrType& InNodePtr, TSet<FSubobjectEditorTreeNodePtrType>& OutCollapsedNodes) const;
|
|
|
|
// Attempt to find an existing slate node that matches the given handle
|
|
static FSubobjectEditorTreeNodePtrType FindOrCreateSlateNodeForHandle(const FSubobjectDataHandle& Handle, TMap<FSubobjectDataHandle, FSubobjectEditorTreeNodePtrType>& ExistingNodes);
|
|
|
|
/**
|
|
* Set the expansion state of a node
|
|
*
|
|
* @param InNodeToChange The node to be expanded/collapsed
|
|
* @param bIsExpanded True to expand the node, false to collapse it
|
|
*/
|
|
void SetNodeExpansionState(FSubobjectEditorTreeNodePtrType InNodeToChange, const bool bIsExpanded);
|
|
|
|
/** Handler for recursively expanding/collapsing items */
|
|
void SetItemExpansionRecursive(FSubobjectEditorTreeNodePtrType Model, bool bInExpansionState);
|
|
|
|
/** Registers context menu by name for later access */
|
|
void RegisterContextMenu();
|
|
|
|
/** Called to display context menu when right clicking on the widget */
|
|
TSharedPtr<SWidget> CreateContextMenu();
|
|
|
|
/** Populate context menu on the fly */
|
|
void PopulateContextMenu(UToolMenu* InMenu);
|
|
|
|
/** Populate the context menu with implementation specific details */
|
|
virtual void PopulateContextMenuImpl(UToolMenu* InMenu, TArray<FSubobjectEditorTreeNodePtrType>& InSelectedItems, bool bIsChildActorSubtreeNodeSelected) = 0;
|
|
|
|
/** @return Type of component to filter the tree view with or nullptr if there's no filter. */
|
|
TSubclassOf<UActorComponent> GetComponentTypeFilterToApply() const;
|
|
|
|
/**
|
|
* Compares the filter bar's text with the item's component name. Use
|
|
* bRecursive to refresh the state of child nodes as well. Returns true if
|
|
* the node is set to be filtered out
|
|
*/
|
|
bool RefreshFilteredState(FSubobjectEditorTreeNodePtrType TreeNode, bool bRecursive);
|
|
|
|
/** Callback for the action trees to get the filter text */
|
|
FText GetFilterText() const;
|
|
|
|
/** Converts the current actor instance to a blueprint */
|
|
void PromoteToBlueprint() const;
|
|
|
|
/** Called when the promote to blueprint button is clicked */
|
|
FReply OnPromoteToBlueprintClicked();
|
|
|
|
/** Opens the blueprint editor for the blueprint being viewed by the scseditor */
|
|
void OnOpenBlueprintEditor(bool bForceCodeEditing) const;
|
|
|
|
/**
|
|
* Spawns a new SWindow giving the user options for creating a new C++ component class.
|
|
* The user will be prompted to pick a new subclass name and code will be recompiled
|
|
*
|
|
* @return The new class that was created
|
|
*/
|
|
UClass* SpawnCreateNewCppComponentWindow(TSubclassOf<UActorComponent> ComponentClass);
|
|
|
|
/**
|
|
* Spawns a new SWindow giving the user options for creating a new blueprint component class.
|
|
* The user will be prompted to pick a new subclass name and a blueprint asset will be created
|
|
*
|
|
* @return The new class that was created
|
|
*/
|
|
UClass* SpawnCreateNewBPComponentWindow(TSubclassOf<UActorComponent> ComponentClass);
|
|
|
|
/** Add a component from the selection in the combo box */
|
|
FSubobjectDataHandle PerformComboAddClass(TSubclassOf<UActorComponent> ComponentClass, EComponentCreateAction::Type ComponentCreateAction, UObject* AssetOverride);
|
|
|
|
/** @return The visibility of the promote to blueprint button (only visible with an actor instance that is not created from a blueprint)*/
|
|
virtual EVisibility GetPromoteToBlueprintButtonVisibility() const;
|
|
|
|
/** @return The visibility of the Edit Blueprint button (only visible with an actor instance that is created from a blueprint)*/
|
|
virtual EVisibility GetEditBlueprintButtonVisibility() const;
|
|
|
|
/** @return The visibility of the Add Component combo button */
|
|
virtual EVisibility GetComponentClassComboButtonVisibility() const;
|
|
|
|
/** If true, then the tree widget will clear selection on click. */
|
|
virtual bool ClearSelectionOnClick() const { return false; }
|
|
|
|
/** Indicates whether or not the search bar and inline buttons are visible. */
|
|
virtual bool ShowInlineSearchWithButtons() const { return false; }
|
|
|
|
/** Add a new subobject to the given parent via the subobject data subsystem */
|
|
virtual FSubobjectDataHandle AddNewSubobject(const FSubobjectDataHandle& ParentHandle, UClass* NewClass, UObject* AssetOverride, FText& OutFailReason, TUniquePtr<FScopedTransaction> InOngoingTransaction) = 0;
|
|
|
|
///////////////////////////////////////
|
|
// Utils
|
|
struct Utils
|
|
{
|
|
/** Populate an array of subobject handles based on an array of the slate node ptr */
|
|
static void PopulateHandlesArray(const TArray<FSubobjectEditorTreeNodePtrType>& SlateNodePtrs, TArray<FSubobjectDataHandle>& OutHandles);
|
|
};
|
|
}; |