// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "SlateFwd.h" #include "Misc/Attribute.h" #include "Animation/Skeleton.h" #include "Styling/SlateColor.h" #include "Input/Reply.h" #include "Widgets/SWidget.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "EditableSkeleton.h" #include "AssetRegistry/AssetData.h" #include "Engine/SkeletalMeshSocket.h" #include "ISkeletonTree.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "Widgets/Views/STreeView.h" #include "Preferences/PersonaOptions.h" #include "ISkeletonTreeBuilder.h" #include "ISkeletonTreeItem.h" #include "SkeletonTreeBuilder.h" #include "Widgets/Input/SSearchBox.h" #include "EditorUndoClient.h" #include "UObject/GCObject.h" class FMenuBuilder; class FSkeletonTreeAttachedAssetItem; class FSkeletonTreeBoneItem; class FSkeletonTreeSocketItem; class FSkeletonTreeVirtualBoneItem; class FTextFilterExpressionEvaluator; class FUICommandList_Pinnable; class IPersonaPreviewScene; class SBlendProfilePicker; class SComboButton; class UBlendProfile; class UToolMenu; struct FNotificationInfo; class IPinnedCommandList; class FPackageReloadedEvent; enum class EPackageReloadPhase : uint8; enum class EBlendProfileMode : uint8; ////////////////////////////////////////////////////////////////////////// // SSkeletonTree PRAGMA_DISABLE_DEPRECATION_WARNINGS class SSkeletonTree : public ISkeletonTree, public FSelfRegisteringEditorUndoClient { public: SLATE_BEGIN_ARGS( SSkeletonTree ) : _IsEditable(true) {} SLATE_ATTRIBUTE( bool, IsEditable ) SLATE_ARGUMENT( TSharedPtr, Builder ) SLATE_END_ARGS() public: SSkeletonTree() : bSelecting(false) {} ~SSkeletonTree(); void Construct(const FArguments& InArgs, const TSharedRef& InEditableSkeleton, const FSkeletonTreeArgs& InSkeletonTreeArgs); /** ISkeletonTree interface */ virtual void Refresh() override; virtual void RefreshFilter() override; virtual TSharedRef GetEditableSkeleton() const override { return EditableSkeleton.Pin().ToSharedRef(); } virtual TSharedPtr GetPreviewScene() const override { return PreviewScene.Pin(); } virtual void SetSkeletalMesh(USkeletalMesh* NewSkeletalMesh) override; virtual void SetSelectedSocket(const struct FSelectedSocketInfo& InSocketInfo) override; virtual void SetSelectedBone(const FName& InBoneName, ESelectInfo::Type InSelectInfo) override; virtual void SetSelectedBones(const TArray& InBoneNames, ESelectInfo::Type InSelectInfo) override; virtual void DeselectAll() override; virtual TArray> GetSelectedItems() const override { return SkeletonTreeView->GetSelectedItems(); } virtual void SelectItemsBy(TFunctionRef&, bool&)> Predicate, const ESelectInfo::Type SelectInfo) const override; virtual void DuplicateAndSelectSocket(const FSelectedSocketInfo& SocketInfoToDuplicate, const FName& NewParentBoneName = FName()) override; virtual void ResetBoneTransforms(const bool bSelectedOnly) override; virtual FDelegateHandle RegisterOnSelectionChanged(const FOnSkeletonTreeSelectionChanged& Delegate) override { return OnSelectionChangedMulticast.Add(Delegate); } virtual void UnregisterOnSelectionChanged(FDelegateHandle DelegateHandle) override { OnSelectionChangedMulticast.Remove(DelegateHandle); } virtual UBlendProfile* GetSelectedBlendProfile() override; virtual void AttachAssets(const TSharedRef& TargetItem, const TArray& AssetData) override; virtual TSharedPtr GetSearchWidget() const override { return NameFilterBox; } virtual TSharedPtr GetPinnedCommandList() const override { return PinnedCommands; } /** FSelfRegisteringEditorUndoClient interface */ virtual void PostUndo(bool bSuccess) override; virtual void PostRedo(bool bSuccess) override; /** Creates the tree control and then populates */ void CreateTreeColumns(); /** Function to build the skeleton tree widgets from the source skeleton tree */ void CreateFromSkeleton(); /** Apply filtering to the tree */ void ApplyFilter(); /** Set the initial expansion state of the tree items */ void SetInitialExpansionState(); /** Utility function to print notifications to the user */ void NotifyUser( FNotificationInfo& NotificationInfo ); /** Callback when an item is scrolled into view, handling calls to rename items */ void OnItemScrolledIntoView( TSharedPtr InItem, const TSharedPtr& InWidget); /** Callback for when the user double-clicks on an item in the tree */ void OnTreeDoubleClick( TSharedPtr InItem ); /** Handle recursive expansion/contraction of the tree */ void SetTreeItemExpansionRecursive(TSharedPtr< ISkeletonTreeItem > TreeItem, bool bInExpansionState) const; /** Set Bone Translation Retargeting Mode for bone selection, and their children. */ void SetBoneTranslationRetargetingModeRecursive(EBoneTranslationRetargetingMode::Type NewRetargetingMode); /** Remove the selected bones from LOD of LODIndex when using simplygon **/ void RemoveFromLOD(int32 LODIndex, bool bIncludeSelected, bool bIncludeBelowLODs); /** Called when the preview mesh is changed - simply rebuilds the skeleton tree for the new mesh */ void OnLODSwitched(); /** Called when the preview mesh is changed */ void OnPreviewMeshChanged(USkeletalMesh* InOldSkeletalMesh, USkeletalMesh* InNewSkeletalMesh); /** Get the name of the currently selected blend profile */ FName GetSelectedBlendProfileName() const; /** Delegate handler for when the tree needs refreshing */ void HandleTreeRefresh(); /** Get a shared reference to the skeleton tree that owns us */ TSharedRef GetEditableSkeletonInternal() const { return EditableSkeleton.Pin().ToSharedRef(); } /** Update preview scene and tree after a socket rename */ void PostRenameSocket(UObject* InAttachedObject, const FName& InOldName, const FName& InNewName); /** Update preview scene and tree after a socket duplication */ void PostDuplicateSocket(UObject* InAttachedObject, const FName& InSocketName); /** Update tree after a socket changes parent */ void PostSetSocketParent(); private: /** Binds the commands in FSkeletonTreeCommands to functions in this class */ void BindCommands(); /** Create a widget for an entry in the tree from an info */ TSharedRef MakeTreeRowWidget(TSharedPtr InInfo, const TSharedRef& OwnerTable); /** Get all children for a given entry in the list */ void GetFilteredChildren(TSharedPtr InInfo, TArray< TSharedPtr >& OutChildren); /** Called to display context menu when right clicking on the widget */ TSharedPtr< SWidget > CreateContextMenu(); /** Called to display the add new menu */ TSharedRef< SWidget > CreateNewMenuWidget(); /** Called to create the add new menu */ void RegisterNewMenu(); /** Called to display the filter menu */ TSharedRef< SWidget > CreateFilterMenuWidget(); /** Called to create the filter menu */ void RegisterFilterMenu(); /** Function to copy selected bone name to the clipboard */ void OnCopyBoneNames(); /** Function to reset the transforms of selected bones */ void OnResetBoneTransforms(const bool bSelectedOnly = true); /** Function to copy selected sockets to the clipboard */ void OnCopySockets() const; /** Whether we can copy sockets */ bool CanCopySockets() const; /** Function to serialize a single socket to a string */ FString SerializeSocketToString( class USkeletalMeshSocket* Socket, ESocketParentType ParentType ) const; /** Function to paste selected sockets from the clipboard */ void OnPasteSockets(bool bPasteToSelectedBone); /** Whether we can paste sockets */ bool CanPasteSockets() const; /** Function to add a socket to the selected bone (skeleton, not mesh) */ void OnAddSocket(); /** Function to check if it is possible to rename the selected item */ bool CanRenameSelected() const; /** Function to start renaming the selected item */ void OnRenameSelected(); /** Function to customize a socket - this essentially copies a socket from the skeleton to the mesh */ void OnCustomizeSocket(); /** Function to promote a socket - this essentially copies a socket from the mesh to the skeleton */ void OnPromoteSocket(); /** Create sub menu to allow users to pick a target bone for the new space switching bone(s) */ static TSharedRef CreateVirtualBoneMenu(SSkeletonTree* InSkeletonTree); /** Handler for user picking a target bone */ void OnVirtualTargetBonePicked(FName TargetBoneName, TArray> SourceBones); /** Create content picker sub menu to allow users to pick an asset to attach */ void FillAttachAssetSubmenu(FMenuBuilder& MenuBuilder, const TSharedPtr TargetItem); /** Helper function for asset picker that handles users choice */ void OnAssetSelectedFromPicker(const FAssetData& AssetData, const TSharedPtr TargetItem); /** Context menu function to remove all attached assets */ void OnRemoveAllAssets(); /** Context menu function to control enabled/disabled status of remove all assets menu item */ bool CanRemoveAllAssets() const; /** Functions to copy sockets from the skeleton to the mesh */ void OnCopySocketToMesh() {}; /** Callback function to be called when selection changes to check if the next item is selectable or navigable. */ bool OnIsSelectableOrNavigable(TSharedPtr InItem) const; /** Callback function to be called when selection changes in the tree view widget. */ void OnSelectionChanged(TSharedPtr Selection, ESelectInfo::Type SelectInfo); /** Filters the SListView when the user changes the search text box (NameFilterBox) */ void OnFilterTextChanged( const FText& SearchText ); /** Sets which types of bone to show */ void SetBoneFilter(EBoneFilter InBoneFilter ); /** Queries the bone filter */ bool IsBoneFilter(EBoneFilter InBoneFilter ) const; /** Sets which types of socket to show */ void SetSocketFilter(ESocketFilter InSocketFilter ); /** Queries the bone filter */ bool IsSocketFilter(ESocketFilter InSocketFilter ) const; /** Returns the current text for the filter button tooltip - "All", "Mesh" or "Weighted" etc. */ FText GetFilterMenuTooltip() const; /** We can only add sockets in Active, Skeleton or All mode (otherwise they just disappear) */ bool IsAddingSocketsAllowed() const; /** Handler for "Show Retargeting Options" check box IsChecked functionality */ bool IsShowingAdvancedOptions() const; /** Handler for when we change the "Show Retargeting Options" check box */ void OnChangeShowingAdvancedOptions(); /** Handler for "Show Debug Visualization Options" check box IsChecked functionality */ bool IsShowingDebugVisualizationOptions() const; /** Handler for when we change the "Show Debug Visualization Options" check box */ void OnChangeShowingDebugVisualizationOptions(); /** This replicates the socket filter to the previewcomponent so that the viewport can use the same settings */ void SetPreviewComponentSocketFilter() const; /** Override OnKeyDown */ virtual FReply OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ); /** Check whether we can delete all the selected sockets/assets */ bool CanDeleteSelectedRows() const; /** Function to delete all the selected sockets/assets */ void OnDeleteSelectedRows(); /** Function to remove attached assets from the skeleton/mesh */ void DeleteAttachedAssets(const TArray>& InDisplayedAttachedAssetInfos ); /** Function to remove sockets from the skeleton/mesh */ void DeleteSockets(const TArray>& InDisplayedSocketInfos ); /** Function to remove virtual bones from the skeleton/mesh */ void DeleteVirtualBones(const TArray>& InDisplayedVirtualBonestInfos); /** Called when the user selects a blend profile to edit */ void OnBlendProfileSelected(UBlendProfile* NewProfile); /** Sets the blend scale for the selected bones and all of their children */ void RecursiveSetBlendProfileScales(float InScaleToSet); /** Submenu creator handler for the given skeleton */ static void CreateMenuForBoneReduction(FMenuBuilder& MenuBuilder, SSkeletonTree* SkeletonTree, int32 LODIndex, bool bIncludeSelected); /** Handle focusing the camera on the current selection */ void HandleFocusCamera(); /** Handle framing the selected item in the tree */ void HandleFrameSelection(); /** Handle filtering the tree */ ESkeletonTreeFilterResult HandleFilterSkeletonTreeItem(const FSkeletonTreeFilterArgs& InArgs, const TSharedPtr& InItem); // Called when bone tree queries reference skeleton const FReferenceSkeleton& OnGetReferenceSkeleton() const { return GetEditableSkeletonInternal()->GetSkeleton().GetReferenceSkeleton(); } /** Handle bone selection changing externally */ void HandleSelectedBoneChanged(const FName& InBoneName, ESelectInfo::Type InSelectInfo); void HandleSelectedBonesChanged(const TArray& InBoneNames, ESelectInfo::Type InSelectInfo); /** Handle socket selection changing externally */ void HandleSelectedSocketChanged(const FSelectedSocketInfo& InSocketInfo); /** Handle external deselection event */ void HandleDeselectAll(); /** Handle package reloading (might be our skeleton) */ void HandlePackageReloaded(const EPackageReloadPhase InPackageReloadPhase, FPackageReloadedEvent* InPackageReloadedEvent); /** Creates a new Blend Profile */ void OnCreateBlendProfile(const EBlendProfileMode InMode); /** Removes the active Blend Profile */ void OnDeleteCurrentBlendProfile(); /** Removes the active Blend Profile */ void OnRenameBlendProfile(); /** Register Blend Profile Menu */ void RegisterBlendProfileMenu(); /** Create Blend Profile Menu */ static void CreateBlendProfileMenu(UToolMenu* InMenu); TSharedRef GetBlendProfileColumnMenuContent(); void ExpandTreeOnSelection(TSharedPtr RowToExpand, bool bForce = false); private: /** Pointer back to the skeleton tree that owns us */ TWeakPtr EditableSkeleton; /** Link to a preview scene */ TWeakPtr PreviewScene; /** SSearchBox to filter the tree */ TSharedPtr NameFilterBox; /** The blend profile picker displaying the selected profile */ TSharedPtr BlendProfilePicker; /** Blend Profile Header Label. Also used to name new blend profiles */ TSharedPtr BlendProfileHeader; /** Widget user to hold the skeleton tree */ TSharedPtr TreeHolder; /** Widget used to display the skeleton hierarchy */ TSharedPtr>> SkeletonTreeView; /** A tree of unfiltered items */ TArray> Items; /** A "mirror" of the tree as a flat array for easier searching */ TArray> LinearItems; /** Filtered view of the skeleton tree. This is what is actually used in the tree widget */ TArray> FilteredItems; /** Is this view editable */ TAttribute IsEditable; /** Current text typed into NameFilterBox */ FText FilterText; /** Commands that are bound to delegates*/ TSharedPtr UICommandList; /** Current type of blend profile no create. We shouldn't need to hold state for this, but blend profile creation is tied to its header text committed*/ EBlendProfileMode NewBlendProfileMode; /** Whether we are creating or renaming a BlendProfile, so the EditBox know what to do */ bool bIsCreateNewBlendProfile = false; /** Current type of bones to show */ EBoneFilter BoneFilter; /** Current type of sockets to show */ ESocketFilter SocketFilter; /** Points to an item that is being requested to be renamed */ TSharedPtr DeferredRenameRequest; /** Last Cached Preview Mesh Component LOD */ int32 LastCachedLODForPreviewMeshComponent; /** Delegate for when an item is selected */ FOnSkeletonTreeSelectionChangedMulticast OnSelectionChangedMulticast; /** Selection recursion guard flag */ bool bSelecting; /** Hold onto the filter combo button to set its foreground color */ TSharedPtr FilterComboButton; /** Add virtual bones to the skeleton tree */ void AddVirtualBones(const TArray& VirtualBones); /** Checks if the named profile is the currently selected/active one */ bool IsBlendProfileSelected(FName ProfileName) const; /** The builder we use to construct the tree */ TSharedPtr Builder; /** Compiled filter search terms. */ TSharedPtr TextFilterPtr; /** Whether to allow operations that modify the mesh */ bool bAllowMeshOperations; /** Whether to allow operations that modify the mesh */ bool bAllowSkeletonOperations; /** Whether to show the filter option to allow filtering of debug draw elements in the viewport. */ bool bShowDebugVisualizationOptions; /** Extenders for menus */ TSharedPtr Extenders; /** Delegate that allows custom filtering text to be shown on the filter button */ FOnGetFilterText OnGetFilterText; /** The mode that this skeleton tree is in */ ESkeletonTreeMode Mode; /** Pinned commands panel */ TSharedPtr PinnedCommands; /** Context name used to persist settings */ FName ContextName; friend struct FScopedSavedSelection; }; PRAGMA_ENABLE_DEPRECATION_WARNINGS