2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "PersonaPrivatePCH.h"
# include "SSkeletonTree.h"
# include "ScopedTransaction.h"
# include "BoneDragDropOp.h"
# include "SocketDragDropOp.h"
# include "SkeletonTreeCommands.h"
# include "DragAndDrop/AssetDragDropOp.h"
# include "SAnimationEditorViewport.h"
# include "AnimationEditorViewportClient.h"
# include "AssetSelection.h"
# include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
# include "ComponentAssetBroker.h"
# include "ClassIconFinder.h"
# include "Editor/UnrealEd/Public/AssetNotifications.h"
# include "Animation/PreviewAssetAttachComponent.h"
# include "AnimPreviewInstance.h"
# include "Factories.h"
# include "Developer/MeshUtilities/Public/MeshUtilities.h"
2014-06-18 07:25:31 -04:00
# include "UnrealExporter.h"
2014-10-14 22:50:06 -04:00
# include "SSearchBox.h"
# include "SInlineEditableTextBlock.h"
# include "SNotificationList.h"
# include "NotificationManager.h"
# include "GenericCommands.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "SSkeletonTree"
static const FName ColumnID_BoneLabel ( " BoneName " ) ;
static const FName ColumnID_RetargetingLabel ( " TranslationRetargeting " ) ;
// see if mesh reduction is supported
static bool bMeshReductionSupported = false ;
DECLARE_DELEGATE_RetVal_TwoParams ( FReply , FOnDraggingBoneItem , const FGeometry & , const FPointerEvent & ) ;
//////////////////////////////////////////////////////////////////////////
// FSocketTextObjectFactory - constructs sockets from clipboard data
class FSocketTextObjectFactory : public FCustomizableTextObjectFactory
{
public :
FSocketTextObjectFactory ( USkeletalMeshSocket * * InDestinationSocket )
: FCustomizableTextObjectFactory ( GWarn )
, DestinationSocket ( InDestinationSocket )
{
} ;
private :
virtual bool CanCreateClass ( UClass * ObjectClass ) const { return true ; }
virtual void ProcessConstructedObject ( UObject * CreatedObject )
{
* DestinationSocket = ( USkeletalMeshSocket * ) CreatedObject ;
}
// Pointer back to the outside world that will hold the final imported socket
USkeletalMeshSocket * * DestinationSocket ;
} ;
//////////////////////////////////////////////////////////////////////////
// SSkeletonTreeRow
DECLARE_DELEGATE_RetVal_TwoParams ( FReply , FOnDraggingTreeItem , const FGeometry & , const FPointerEvent & ) ;
typedef TSharedPtr < FDisplayedTreeRowInfo > FDisplayedTreeRowInfoPtr ;
class SSkeletonTreeRow
: public SMultiColumnTableRow < FDisplayedTreeRowInfoPtr >
{
public :
SLATE_BEGIN_ARGS ( SSkeletonTreeRow ) { }
/** The item for this row **/
SLATE_ARGUMENT ( FDisplayedTreeRowInfoPtr , Item )
/** Pointer to the Skeleton so we can mark it dirty */
SLATE_ARGUMENT ( USkeleton * , TargetSkeleton ) ;
/** Pointer to the parent SSkeletonTree so we can request a tree refresh when needed */
SLATE_ARGUMENT ( TWeakPtr < SSkeletonTree > , SkeletonTree ) ;
/** Pointer to the owning Persona so it can be used to copy sockets/etc */
SLATE_ARGUMENT ( TWeakPtr < FPersona > , PersonaPtr ) ;
/** Filter text typed by the user into the parent tree's search widget */
SLATE_ARGUMENT ( FText , FilterText ) ;
/** Delegate for dragging items **/
SLATE_EVENT ( FOnDraggingTreeItem , OnDraggingItem ) ;
SLATE_END_ARGS ( )
void Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwnerTableView ) ;
/** Overridden from SMultiColumnTableRow. Generates a widget for this column of the tree row. */
2014-06-13 06:14:46 -04:00
virtual TSharedRef < SWidget > GenerateWidgetForColumn ( const FName & ColumnName ) override ;
2014-03-14 14:13:41 -04:00
/** Override OnDragEnter for drag and drop of sockets onto bones */
2014-06-13 06:14:46 -04:00
virtual void OnDragEnter ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Override OnDragLeave for drag and drop of sockets onto bones */
2014-06-13 06:14:46 -04:00
virtual void OnDragLeave ( const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
/** Override OnDrop for drag and drop of sockets and meshes onto bones */
2014-06-13 06:14:46 -04:00
virtual FReply OnDrop ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent ) override ;
2014-03-14 14:13:41 -04:00
protected :
/** Handler for starting a drag/drop action */
2014-06-13 06:14:46 -04:00
virtual FReply OnDragDetected ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent ) override ;
2014-03-14 14:13:41 -04:00
private :
/** The item this row is holding */
FDisplayedTreeRowInfoPtr Item ;
/** The skeleton the bone is part of */
USkeleton * TargetSkeleton ;
/** Text the user typed into the search box - used for text highlighting */
FText FilterText ;
/** Weak pointer to the parent skeleton tree */
TWeakPtr < SSkeletonTree > SkeletonTree ;
/** Weak pointer to the owning Persona */
TWeakPtr < FPersona > PersonaPtr ;
/** Item that we're dragging */
FOnDraggingTreeItem OnDraggingItem ;
/** Was the user pressing "Alt" when the drag was started? */
bool bIsAltDrag ;
} ;
void SSkeletonTreeRow : : Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & InOwnerTableView )
{
Item = InArgs . _Item ;
OnDraggingItem = InArgs . _OnDraggingItem ;
TargetSkeleton = InArgs . _TargetSkeleton ;
FilterText = InArgs . _FilterText ;
SkeletonTree = InArgs . _SkeletonTree ;
PersonaPtr = InArgs . _PersonaPtr ;
check ( Item . IsValid ( ) ) ;
SMultiColumnTableRow < FDisplayedTreeRowInfoPtr > : : Construct ( FSuperRowType : : FArguments ( ) , InOwnerTableView ) ;
}
TSharedRef < SWidget > SSkeletonTreeRow : : GenerateWidgetForColumn ( const FName & ColumnName )
{
if ( ColumnName = = ColumnID_BoneLabel )
{
TSharedPtr < SHorizontalBox > Box ;
SAssignNew ( Box , SHorizontalBox ) ;
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( SExpanderArrow , SharedThis ( this ) )
] ;
Item - > GenerateWidgetForNameColumn ( Box , FilterText , FIsSelected : : CreateSP ( this , & STableRow : : IsSelectedExclusively ) ) ;
return Box . ToSharedRef ( ) ;
}
else
{
return Item - > GenerateWidgetForDataColumn ( ) ;
}
}
void SSkeletonTreeRow : : OnDragEnter ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FSocketDragDropOp > DragConnectionOp = DragDropEvent . GetOperationAs < FSocketDragDropOp > ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:00:50 -04:00
// Is someone dragging a socket onto a bone?
if ( DragConnectionOp . IsValid ( ) )
{
2014-03-14 14:13:41 -04:00
if ( Item - > GetType ( ) = = ESkeletonTreeRowType : : Bone & &
( * static_cast < FName * > ( Item - > GetData ( ) ) ! = DragConnectionOp - > GetSocketInfo ( ) . Socket - > BoneName ) )
{
// The socket can be dropped here if we're a bone and NOT the socket's existing parent
DragConnectionOp - > SetIcon ( FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Ok " ) ) ) ;
}
else if ( Item - > GetType ( ) = = ESkeletonTreeRowType : : Bone & & DragConnectionOp - > IsAltDrag ( ) )
{
// For Alt-Drag, dropping onto the existing parent is fine, as we're going to copy, not move the socket
DragConnectionOp - > SetIcon ( FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Ok " ) ) ) ;
}
else
{
DragConnectionOp - > SetIcon ( FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Error " ) ) ) ;
}
}
}
void SSkeletonTreeRow : : OnDragLeave ( const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FSocketDragDropOp > DragConnectionOp = DragDropEvent . GetOperationAs < FSocketDragDropOp > ( ) ;
if ( DragConnectionOp . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
// Reset the drag/drop icon when leaving this row
DragConnectionOp - > SetIcon ( FEditorStyle : : GetBrush ( TEXT ( " Graph.ConnectorFeedback.Error " ) ) ) ;
}
}
FReply SSkeletonTreeRow : : OnDrop ( const FGeometry & MyGeometry , const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FSocketDragDropOp > DragConnectionOp = DragDropEvent . GetOperationAs < FSocketDragDropOp > ( ) ;
if ( DragConnectionOp . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
FSelectedSocketInfo SocketInfo = DragConnectionOp - > GetSocketInfo ( ) ;
if ( DragConnectionOp - > IsAltDrag ( ) & & Item - > GetType ( ) = = ESkeletonTreeRowType : : Bone )
{
// In an alt-drag, the socket can be dropped on any bone
// (including its existing parent) to create a uniquely named copy
if ( PersonaPtr . IsValid ( ) )
{
PersonaPtr . Pin ( ) - > DuplicateAndSelectSocket ( SocketInfo , * static_cast < FName * > ( Item - > GetData ( ) ) ) ;
}
}
else if ( Item - > GetType ( ) = = ESkeletonTreeRowType : : Bone & &
* static_cast < FName * > ( Item - > GetData ( ) ) ! = SocketInfo . Socket - > BoneName )
{
// The socket can be dropped here if we're a bone and NOT the socket's existing parent
// Create an undo transaction, re-parent the socket and rebuild the skeleton tree view
const FScopedTransaction Transaction ( LOCTEXT ( " ReparentSocket " , " Re-parent Socket " ) ) ;
SocketInfo . Socket - > SetFlags ( RF_Transactional ) ; // Undo doesn't work without this!
SocketInfo . Socket - > Modify ( ) ;
SocketInfo . Socket - > BoneName = * static_cast < FName * > ( Item - > GetData ( ) ) ;
SkeletonTree . Pin ( ) - > CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
return FReply : : Handled ( ) ;
}
}
2014-04-23 18:00:50 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:00:50 -04:00
if ( DragDropEvent . GetOperationAs < FAssetDragDropOp > ( ) . IsValid ( ) )
{
SkeletonTree . Pin ( ) - > OnDropAssetToSkeletonTree ( Item , DragDropEvent ) ;
}
2014-03-14 14:13:41 -04:00
}
return FReply : : Unhandled ( ) ;
}
FReply SSkeletonTreeRow : : OnDragDetected ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
if ( OnDraggingItem . IsBound ( ) )
{
return OnDraggingItem . Execute ( MyGeometry , MouseEvent ) ;
}
else
{
return FReply : : Unhandled ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
// FDisplayedMeshBoneInfo
TSharedRef < ITableRow > FDisplayedMeshBoneInfo : : MakeTreeRowWidget (
const TSharedRef < STableViewBase > & OwnerTable ,
FText FilterText )
{
return
SNew ( SSkeletonTreeRow , OwnerTable )
. Item ( SharedThis ( this ) )
. TargetSkeleton ( TargetSkeleton )
. FilterText ( FilterText )
. SkeletonTree ( SkeletonTree )
. PersonaPtr ( PersonaPtr )
. OnDraggingItem ( this , & FDisplayedMeshBoneInfo : : OnDragDetected ) ;
}
void FDisplayedMeshBoneInfo : : GenerateWidgetForNameColumn ( TSharedPtr < SHorizontalBox > Box , FText & FilterText , FIsSelected InIsSelected )
{
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
const FSlateFontInfo TextFont = GetBoneTextFont ( PreviewComponent ) ;
const FLinearColor TextColor = GetBoneTextColor ( PreviewComponent ) ;
2015-01-07 09:52:40 -05:00
FText ToolTip = GetBoneToolTip ( ) ;
2014-03-14 14:13:41 -04:00
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
. ColorAndOpacity ( TextColor )
2014-04-23 18:06:41 -04:00
. Text ( FText : : FromName ( BoneName ) )
2014-03-14 14:13:41 -04:00
. HighlightText ( FilterText )
. Font ( TextFont )
. ToolTipText ( ToolTip )
] ;
}
TSharedRef < SWidget > FDisplayedMeshBoneInfo : : GenerateWidgetForDataColumn ( )
{
return SNew ( SComboButton )
. ContentPadding ( 3 )
. OnGetMenuContent ( this , & FDisplayedMeshBoneInfo : : CreateBoneTranslationRetargetingModeMenu )
2014-07-23 08:25:37 -04:00
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip (
LOCTEXT ( " RetargetingToolTip " , " Set bone translation retargeting mode " ) ,
NULL ,
TEXT ( " Shared/Editors/Persona " ) ,
TEXT ( " TranslationRetargeting " ) ) )
2014-03-14 14:13:41 -04:00
. ButtonContent ( )
[
SNew ( STextBlock )
. Text ( this , & FDisplayedMeshBoneInfo : : GetTranslationRetargetingModeMenuTitle )
] ;
}
TSharedRef < SWidget > FDisplayedMeshBoneInfo : : CreateBoneTranslationRetargetingModeMenu ( )
{
FMenuBuilder MenuBuilder ( true , NULL ) ;
MenuBuilder . BeginSection ( " BoneTranslationRetargetingMode " , LOCTEXT ( " BoneTranslationRetargetingModeMenuHeading " , " Bone Translation Retargeting Mode " ) ) ;
{
2015-02-20 14:35:01 -05:00
UEnum * const Enum = FindObject < UEnum > ( ANY_PACKAGE , TEXT ( " EBoneTranslationRetargetingMode " ) , true ) ;
check ( Enum ) ;
2014-03-14 14:13:41 -04:00
FUIAction ActionRetargetingAnimation = FUIAction ( FExecuteAction : : CreateSP ( this , & FDisplayedMeshBoneInfo : : SetBoneTranslationRetargetingMode , EBoneTranslationRetargetingMode : : Animation ) ) ;
2015-02-20 14:35:01 -05:00
MenuBuilder . AddMenuEntry ( Enum - > GetDisplayNameText ( EBoneTranslationRetargetingMode : : Animation ) , LOCTEXT ( " BoneTranslationRetargetingAnimationToolTip " , " Use translation from animation. " ) , FSlateIcon ( ) , ActionRetargetingAnimation ) ;
2014-03-14 14:13:41 -04:00
FUIAction ActionRetargetingSkeleton = FUIAction ( FExecuteAction : : CreateSP ( this , & FDisplayedMeshBoneInfo : : SetBoneTranslationRetargetingMode , EBoneTranslationRetargetingMode : : Skeleton ) ) ;
2015-02-20 14:35:01 -05:00
MenuBuilder . AddMenuEntry ( Enum - > GetDisplayNameText ( EBoneTranslationRetargetingMode : : Skeleton ) , LOCTEXT ( " BoneTranslationRetargetingSkeletonToolTip " , " Use translation from Skeleton. " ) , FSlateIcon ( ) , ActionRetargetingSkeleton ) ;
2014-03-14 14:13:41 -04:00
FUIAction ActionRetargetingLengthScale = FUIAction ( FExecuteAction : : CreateSP ( this , & FDisplayedMeshBoneInfo : : SetBoneTranslationRetargetingMode , EBoneTranslationRetargetingMode : : AnimationScaled ) ) ;
2015-02-20 14:35:01 -05:00
MenuBuilder . AddMenuEntry ( Enum - > GetDisplayNameText ( EBoneTranslationRetargetingMode : : AnimationScaled ) , LOCTEXT ( " BoneTranslationRetargetingAnimationScaledToolTip " , " Use translation from animation, scale length by Skeleton's proportions. " ) , FSlateIcon ( ) , ActionRetargetingLengthScale ) ;
2014-10-10 16:03:02 -04:00
FUIAction ActionRetargetingAnimationRelative = FUIAction ( FExecuteAction : : CreateSP ( this , & FDisplayedMeshBoneInfo : : SetBoneTranslationRetargetingMode , EBoneTranslationRetargetingMode : : AnimationRelative ) ) ;
2015-02-20 14:35:01 -05:00
MenuBuilder . AddMenuEntry ( Enum - > GetDisplayNameText ( EBoneTranslationRetargetingMode : : AnimationRelative ) , LOCTEXT ( " BoneTranslationRetargetingAnimationRelativeToolTip " , " Use relative translation from animation similar to an additive animation. " ) , FSlateIcon ( ) , ActionRetargetingAnimationRelative ) ;
2014-03-14 14:13:41 -04:00
}
MenuBuilder . EndSection ( ) ;
return MenuBuilder . MakeWidget ( ) ;
}
2015-01-07 09:52:40 -05:00
FText FDisplayedMeshBoneInfo : : GetTranslationRetargetingModeMenuTitle ( ) const
2014-03-14 14:13:41 -04:00
{
const int32 BoneIndex = TargetSkeleton - > GetReferenceSkeleton ( ) . FindBoneIndex ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
const EBoneTranslationRetargetingMode : : Type RetargetingMode = TargetSkeleton - > GetBoneTranslationRetargetingMode ( BoneIndex ) ;
2015-02-20 14:35:01 -05:00
UEnum * const Enum = FindObject < UEnum > ( ANY_PACKAGE , TEXT ( " EBoneTranslationRetargetingMode " ) , true ) ;
if ( Enum )
{
return Enum - > GetDisplayNameText ( RetargetingMode ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-07 09:52:40 -05:00
return LOCTEXT ( " None " , " None " ) ;
2014-03-14 14:13:41 -04:00
}
void FDisplayedMeshBoneInfo : : SetBoneTranslationRetargetingMode ( EBoneTranslationRetargetingMode : : Type NewRetargetingMode )
{
const FScopedTransaction Transaction ( LOCTEXT ( " SetBoneTranslationRetargetingMode " , " Set Bone Translation Retargeting Mode " ) ) ;
TargetSkeleton - > Modify ( ) ;
const int32 BoneIndex = TargetSkeleton - > GetReferenceSkeleton ( ) . FindBoneIndex ( BoneName ) ;
TargetSkeleton - > SetBoneTranslationRetargetingMode ( BoneIndex , NewRetargetingMode ) ;
FAssetNotifications : : SkeletonNeedsToBeSaved ( TargetSkeleton ) ;
}
FSlateFontInfo FDisplayedMeshBoneInfo : : GetBoneTextFont ( UDebugSkelMeshComponent * PreviewComponent ) const
{
if ( PreviewComponent )
{
int32 BoneIndex = PreviewComponent - > GetBoneIndex ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
if ( SkeletonTree . Pin ( ) - > IsBoneWeighted ( BoneIndex , PreviewComponent ) )
{
//Bone is vertex weighted
FSlateFontInfo BoldFont ( FPaths : : EngineContentDir ( ) / TEXT ( " Slate/Fonts/Roboto-Bold.ttf " ) , 10 ) ;
return BoldFont ;
}
}
}
//Bone is not vertex weighted
FSlateFontInfo RegularFont ( FPaths : : EngineContentDir ( ) / TEXT ( " Slate/Fonts/Roboto-Regular.ttf " ) , 10 ) ;
return RegularFont ;
}
FLinearColor FDisplayedMeshBoneInfo : : GetBoneTextColor ( UDebugSkelMeshComponent * PreviewComponent ) const
{
if ( PreviewComponent )
{
//Check whether this bone in skeleton bone tree is present in skeletal mesh's reference bone list.
int32 BoneIndex = PreviewComponent - > GetBoneIndex ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
return FLinearColor : : White ;
}
}
return FLinearColor : : Gray ;
}
FReply FDisplayedMeshBoneInfo : : OnDragDetected ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
if ( MouseEvent . IsMouseButtonDown ( EKeys : : LeftMouseButton ) )
{
return FReply : : Handled ( ) . BeginDragDrop ( FBoneDragDropOp : : New ( TargetSkeleton , BoneName ) ) ;
}
return FReply : : Unhandled ( ) ;
}
2015-01-07 09:52:40 -05:00
FText FDisplayedMeshBoneInfo : : GetBoneToolTip ( )
2014-03-14 14:13:41 -04:00
{
bool bIsMeshBone = false ;
bool bIsWeightedBone = false ;
bool bMeshExists = false ;
FText ToolTip ;
if ( PersonaPtr . IsValid ( ) )
{
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
if ( PreviewComponent )
{
bMeshExists = true ;
int32 BoneIndex = PreviewComponent - > GetBoneIndex ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
bIsMeshBone = true ;
bIsWeightedBone = SkeletonTree . Pin ( ) - > IsBoneWeighted ( BoneIndex , PreviewComponent ) ;
}
}
}
if ( ! bMeshExists )
{
ToolTip = LOCTEXT ( " BoneToolTipNoMeshAvailable " , " This bone exists only on the skeleton as there is no current mesh set " ) ;
}
else
{
if ( ! bIsMeshBone )
{
ToolTip = LOCTEXT ( " BoneToolTipSkeletonOnly " , " This bone exists only on the skeleton, but not on the current mesh " ) ;
}
else
{
if ( ! bIsWeightedBone )
{
ToolTip = LOCTEXT ( " BoneToolTipSkeletonAndMesh " , " This bone is used by the current mesh, but has no vertices weighted against it " ) ;
}
else
{
ToolTip = LOCTEXT ( " BoneToolTipWeighted " , " This bone has vertices weighted against it " ) ;
}
}
}
2015-01-07 09:52:40 -05:00
return ToolTip ;
2014-03-14 14:13:41 -04:00
}
//////////////////////////////////////////////////////////////////////////
// FDisplayedSocketInfo
TSharedRef < ITableRow > FDisplayedSocketInfo : : MakeTreeRowWidget (
const TSharedRef < STableViewBase > & InOwnerTable ,
FText InFilterText )
{
return
SNew ( SSkeletonTreeRow , InOwnerTable )
. Item ( SharedThis ( this ) )
. FilterText ( InFilterText )
. SkeletonTree ( SkeletonTree )
. TargetSkeleton ( TargetSkeleton )
. OnDraggingItem ( this , & FDisplayedSocketInfo : : OnDragDetected ) ;
}
void FDisplayedSocketInfo : : GenerateWidgetForNameColumn ( TSharedPtr < SHorizontalBox > Box , FText & FilterText , FIsSelected InIsSelected )
{
const FSlateBrush * SocketIcon = ( ParentType = = ESocketParentType : : Mesh ) ?
FEditorStyle : : GetBrush ( " SkeletonTree.MeshSocket " ) :
FEditorStyle : : GetBrush ( " SkeletonTree.SkeletonSocket " ) ;
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( SImage )
. Image ( SocketIcon )
] ;
const FSlateFontInfo TextFont ( FPaths : : EngineContentDir ( ) / TEXT ( " Slate/Fonts/Roboto-Regular.ttf " ) , 10 ) ;
FLinearColor TextColor ;
if ( ParentType = = ESocketParentType : : Skeleton & & bIsCustomized )
{
TextColor = FLinearColor : : Gray ;
}
else
{
TextColor = FLinearColor : : White ;
}
2015-01-07 09:52:40 -05:00
FText ToolTip = GetSocketToolTip ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:05:38 -04:00
TAttribute < FText > SocketNameAttr = TAttribute < FText > : : Create ( TAttribute < FText > : : FGetter : : CreateSP ( this , & FDisplayedSocketInfo : : GetSocketNameAsText ) ) ;
2014-03-14 14:13:41 -04:00
TSharedPtr < SInlineEditableTextBlock > InlineWidget ;
Box - > AddSlot ( )
. AutoWidth ( )
[
SAssignNew ( InlineWidget , SInlineEditableTextBlock )
. ColorAndOpacity ( TextColor )
2014-04-23 18:05:38 -04:00
. Text ( SocketNameAttr )
2014-03-14 14:13:41 -04:00
. HighlightText ( FilterText )
. Font ( TextFont )
. ToolTipText ( ToolTip )
. OnVerifyTextChanged ( this , & FDisplayedSocketInfo : : OnVerifySocketNameChanged )
. OnTextCommitted ( this , & FDisplayedSocketInfo : : OnCommitSocketName )
. IsSelected ( InIsSelected )
] ;
OnRenameRequested . BindSP ( InlineWidget . Get ( ) , & SInlineEditableTextBlock : : EnterEditingMode ) ;
if ( ParentType = = ESocketParentType : : Mesh )
{
FText SocketSuffix = IsSocketCustomized ( ) ?
2014-07-15 15:01:05 -04:00
LOCTEXT ( " CustomizedSuffix " , " [Mesh] " ) :
LOCTEXT ( " MeshSuffix " , " [Mesh Only] " ) ;
2014-03-14 14:13:41 -04:00
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
. ColorAndOpacity ( FLinearColor : : Gray )
. Text ( SocketSuffix )
. Font ( TextFont )
. ToolTipText ( ToolTip )
] ;
}
}
TSharedRef < SWidget > FDisplayedSocketInfo : : GenerateWidgetForDataColumn ( )
{
return SNullWidget : : NullWidget ;
}
void FDisplayedSocketInfo : : OnItemDoubleClicked ( )
{
OnRenameRequested . ExecuteIfBound ( ) ;
}
void FDisplayedSocketInfo : : RequestRename ( )
{
OnRenameRequested . ExecuteIfBound ( ) ;
}
bool FDisplayedSocketInfo : : OnVerifySocketNameChanged ( const FText & InText , FText & OutErrorMessage )
{
// You can't have two sockets with the same name on the mesh, nor on the skeleton,
// but you can have a socket with the same name on the mesh *and* the skeleton.
bool bVerifyName = true ;
2014-05-08 05:30:05 -04:00
FText NewText = FText : : TrimPrecedingAndTrailing ( InText ) ;
if ( NewText . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
OutErrorMessage = LOCTEXT ( " EmptySocketName_Error " , " Sockets must have a name! " ) ;
bVerifyName = false ;
}
else if ( PersonaPtr . IsValid ( ) & & SkeletonTree . IsValid ( ) )
{
if ( ParentType = = ESocketParentType : : Mesh )
{
// If we're on the mesh, check the mesh for duplicates...
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
if ( Mesh )
{
2014-05-08 05:30:05 -04:00
bVerifyName = ! PersonaPtr . Pin ( ) - > DoesSocketAlreadyExist ( SocketData , NewText , Mesh - > GetMeshOnlySocketList ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
// ...and if we're on the skeleton, check the skeleton for dupes
2014-05-08 05:30:05 -04:00
bVerifyName = ! PersonaPtr . Pin ( ) - > DoesSocketAlreadyExist ( SocketData , NewText , TargetSkeleton - > Sockets ) ;
2014-03-14 14:13:41 -04:00
}
// Needs to be checked on verify.
if ( ! bVerifyName )
{
// Tell the user that the socket is a duplicate
OutErrorMessage = LOCTEXT ( " DuplicateSocket_Error " , " Socket name in use! " ) ;
}
}
return bVerifyName ;
}
void FDisplayedSocketInfo : : OnCommitSocketName ( const FText & InText , ETextCommit : : Type CommitInfo )
{
2014-05-08 05:30:05 -04:00
FText NewText = FText : : TrimPrecedingAndTrailing ( InText ) ;
const FScopedTransaction Transaction ( LOCTEXT ( " RenameSocket " , " Rename Socket " ) ) ;
2014-03-14 14:13:41 -04:00
SocketData - > SetFlags ( RF_Transactional ) ; // Undo doesn't work without this!
SocketData - > Modify ( ) ;
FName OldSocketName = SocketData - > SocketName ;
2014-05-08 05:30:05 -04:00
SocketData - > SocketName = FName ( * NewText . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
if ( SkeletonTree . IsValid ( ) )
{
// Notify skeleton tree of socket rename
SkeletonTree . Pin ( ) - > RenameSocketAttachments ( OldSocketName , SocketData - > SocketName ) ;
}
}
FReply FDisplayedSocketInfo : : OnDragDetected ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
{
if ( MouseEvent . IsMouseButtonDown ( EKeys : : LeftMouseButton ) )
{
FSelectedSocketInfo SocketInfo ( SocketData , ParentType = = ESocketParentType : : Skeleton ) ;
return FReply : : Handled ( ) . BeginDragDrop ( FSocketDragDropOp : : New ( SocketInfo , MouseEvent . IsAltDown ( ) ) ) ;
}
return FReply : : Unhandled ( ) ;
}
2015-01-07 09:52:40 -05:00
FText FDisplayedSocketInfo : : GetSocketToolTip ( )
2014-03-14 14:13:41 -04:00
{
FText ToolTip ;
if ( ParentType = = ESocketParentType : : Skeleton & & bIsCustomized = = false )
{
ToolTip = LOCTEXT ( " SocketToolTipSkeletonOnly " , " This socket is on the skeleton only. It is shared with all meshes that use this skeleton " ) ;
}
else if ( ParentType = = ESocketParentType : : Mesh & & bIsCustomized = = false )
{
ToolTip = LOCTEXT ( " SocketToolTipMeshOnly " , " This socket is on the current mesh only " ) ;
}
else if ( ParentType = = ESocketParentType : : Skeleton )
{
2014-07-15 15:01:05 -04:00
ToolTip = LOCTEXT ( " SocketToolTipSkeleton " , " This socket is on the skeleton (shared with all meshes that use the skeleton), and the current mesh has duplciated version of it " ) ;
2014-03-14 14:13:41 -04:00
}
else
{
ToolTip = LOCTEXT ( " SocketToolTipCustomized " , " This socket is on the current mesh, customizing the socket of the same name on the skeleton " ) ;
}
2015-01-07 09:52:40 -05:00
return ToolTip ;
2014-03-14 14:13:41 -04:00
}
//////////////////////////////////////////////////////////////////////////
// FDisplayedAttachedAssetInfo
TSharedRef < ITableRow > FDisplayedAttachedAssetInfo : : MakeTreeRowWidget (
const TSharedRef < STableViewBase > & InOwnerTable ,
FText InFilterText )
{
return
SNew ( SSkeletonTreeRow , InOwnerTable )
. Item ( SharedThis ( this ) )
. FilterText ( InFilterText )
. SkeletonTree ( SkeletonTree )
. TargetSkeleton ( TargetSkeleton ) ;
}
void FDisplayedAttachedAssetInfo : : GenerateWidgetForNameColumn ( TSharedPtr < SHorizontalBox > Box , FText & FilterText , FIsSelected InIsSelected )
{
UActorFactory * ActorFactory = FActorFactoryAssetProxy : : GetFactoryForAssetObject ( Asset ) ;
const FSlateBrush * IconBrush = FClassIconFinder : : FindIconForClass ( ActorFactory - > GetDefaultActorClass ( FAssetData ( ) ) ) ;
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( SImage )
. Image ( IconBrush )
] ;
const FSlateFontInfo TextFont ( FPaths : : EngineContentDir ( ) / TEXT ( " Slate/Fonts/Roboto-Regular.ttf " ) , 10 ) ;
const FLinearColor TextColor ( FLinearColor : : White ) ;
Box - > AddSlot ( )
. AutoWidth ( )
[
SNew ( STextBlock )
. ColorAndOpacity ( TextColor )
2015-01-07 09:52:40 -05:00
. Text ( FText : : FromString ( Asset - > GetName ( ) ) )
2014-03-14 14:13:41 -04:00
. HighlightText ( FilterText )
. Font ( TextFont )
] ;
Box - > AddSlot ( )
. AutoWidth ( )
. Padding ( 5.0f , 0.0f )
[
SNew ( STextBlock )
. ColorAndOpacity ( FLinearColor : : Gray )
2014-04-23 18:06:41 -04:00
. Text ( LOCTEXT ( " AttachedAssetPreviewText " , " [Preview Only] " ) )
2014-03-14 14:13:41 -04:00
. Font ( TextFont )
2014-04-23 18:06:41 -04:00
. ToolTipText ( LOCTEXT ( " AttachedAssetPreviewText_ToolTip " , " Attached assets in Persona are preview only and do not carry through to the game. " ) )
2014-03-14 14:13:41 -04:00
] ;
}
TSharedRef < SWidget > FDisplayedAttachedAssetInfo : : GenerateWidgetForDataColumn ( )
{
return SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. HAlign ( HAlign_Left )
[
SNew ( SCheckBox )
2014-04-23 18:06:41 -04:00
. ToolTipText ( LOCTEXT ( " TranslationCheckBoxToolTip " , " Click to toggle visibility of this asset " ) )
2014-03-14 14:13:41 -04:00
. OnCheckStateChanged ( this , & FDisplayedAttachedAssetInfo : : OnToggleAssetDisplayed )
. IsChecked ( this , & FDisplayedAttachedAssetInfo : : IsAssetDisplayed )
. Style ( FEditorStyle : : Get ( ) , " CheckboxLookToggleButtonCheckbox " )
[
SNew ( SImage )
. Image ( this , & FDisplayedAttachedAssetInfo : : OnGetAssetDisplayedButtonImage )
. ColorAndOpacity ( FLinearColor : : Black )
]
] ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState FDisplayedAttachedAssetInfo : : IsAssetDisplayed ( ) const
2014-03-14 14:13:41 -04:00
{
if ( AssetComponent . IsValid ( ) )
{
2014-12-10 14:24:09 -05:00
return AssetComponent - > IsVisible ( ) ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
return ECheckBoxState : : Undetermined ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
void FDisplayedAttachedAssetInfo : : OnToggleAssetDisplayed ( ECheckBoxState InCheckboxState )
2014-03-14 14:13:41 -04:00
{
if ( AssetComponent . IsValid ( ) )
{
2014-12-10 14:24:09 -05:00
AssetComponent - > SetVisibility ( InCheckboxState = = ECheckBoxState : : Checked ) ;
2014-03-14 14:13:41 -04:00
}
}
const FSlateBrush * FDisplayedAttachedAssetInfo : : OnGetAssetDisplayedButtonImage ( ) const
{
2014-12-10 14:24:09 -05:00
return IsAssetDisplayed ( ) = = ECheckBoxState : : Checked ?
2014-03-14 14:13:41 -04:00
FEditorStyle : : GetBrush ( " Kismet.VariableList.ExposeForInstance " ) :
FEditorStyle : : GetBrush ( " Kismet.VariableList.HideForInstance " ) ;
}
void FDisplayedAttachedAssetInfo : : OnItemDoubleClicked ( )
{
TArray < UObject * > AssetsToSync ;
AssetsToSync . Add ( Asset ) ;
FContentBrowserModule & ContentBrowserModule = FModuleManager : : Get ( ) . LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
ContentBrowserModule . Get ( ) . SyncBrowserToAssets ( AssetsToSync ) ;
}
//////////////////////////////////////////////////////////////////////////
// SSkeletonTree
const FString SSkeletonTree : : SocketCopyPasteHeader = TEXT ( " SocketCopyPasteBuffer " ) ;
void SSkeletonTree : : Construct ( const FArguments & InArgs )
{
static bool bMeshReductionSupportedInitialized = false ;
if ( ! bMeshReductionSupportedInitialized )
{
IMeshUtilities & MeshUtilities = FModuleManager : : Get ( ) . LoadModuleChecked < IMeshUtilities > ( " MeshUtilities " ) ;
IMeshReduction * MeshReduction = MeshUtilities . GetMeshReductionInterface ( ) ;
bMeshReductionSupported = MeshReduction & & MeshReduction - > IsSupported ( ) ;
bMeshReductionSupportedInitialized = true ;
}
BoneFilter = EBoneFilter : : All ;
SocketFilter = ESocketFilter : : Active ;
2015-02-16 11:22:48 -05:00
bShowingAdvancedOptions = false ;
2014-03-14 14:13:41 -04:00
PersonaPtr = InArgs . _Persona ;
IsEditable = InArgs . _IsEditable ;
TargetSkeleton = PersonaPtr . Pin ( ) - > GetSkeleton ( ) ;
SetPreviewComponentSocketFilter ( ) ;
// Register a few delegates with Persona
PersonaPtr . Pin ( ) - > RegisterOnPostUndo ( FPersona : : FOnPostUndo : : CreateSP ( this , & SSkeletonTree : : PostUndo ) ) ;
PersonaPtr . Pin ( ) - > RegisterOnPreviewMeshChanged ( FPersona : : FOnPreviewMeshChanged : : CreateSP ( this , & SSkeletonTree : : OnPreviewMeshChanged ) ) ;
PersonaPtr . Pin ( ) - > RegisterOnBoneSelected ( FPersona : : FOnBoneSelected : : CreateSP ( this , & SSkeletonTree : : OnExternalSelectBone ) ) ;
PersonaPtr . Pin ( ) - > RegisterOnSocketSelected ( FPersona : : FOnSocketSelected : : CreateSP ( this , & SSkeletonTree : : OnExternalSelectSocket ) ) ;
PersonaPtr . Pin ( ) - > RegisterOnDeselectAll ( FPersona : : FOnAllDeselected : : CreateSP ( this , & SSkeletonTree : : OnExternalDeselectAll ) ) ;
PersonaPtr . Pin ( ) - > RegisterOnChangeSkeletonTree ( FPersona : : FOnSkeletonTreeChanged : : CreateSP ( this , & SSkeletonTree : : PostUndo ) ) ;
// Register and bind all our menu commands
FSkeletonTreeCommands : : Register ( ) ;
BindCommands ( ) ;
this - > ChildSlot
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( FMargin ( 0.0f , 0.0f , 0.0f , 4.0f ) )
[
SAssignNew ( NameFilterBox , SSearchBox )
. SelectAllTextWhenFocused ( true )
. OnTextChanged ( this , & SSkeletonTree : : OnFilterTextChanged )
. HintText ( LOCTEXT ( " SearchBoxHint " , " Search Skeleton Tree... " ) )
2014-09-12 15:56:59 -04:00
. AddMetaData < FTagMetaData > ( TEXT ( " SkelTree.Search " ) )
2014-03-14 14:13:41 -04:00
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. Padding ( 0.0f , 0.0f , 2.0f , 0.0f )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SComboButton )
. ContentPadding ( 3 )
. OnGetMenuContent ( this , & SSkeletonTree : : CreateBoneFilterMenu )
2014-04-23 18:06:41 -04:00
. ToolTipText ( LOCTEXT ( " BoneFilterToolTip " , " Change which types of bones are shown " ) )
2014-09-12 15:56:59 -04:00
. AddMetaData < FTagMetaData > ( TEXT ( " SkelTree.Bones " ) )
2014-03-14 14:13:41 -04:00
. ButtonContent ( )
[
SNew ( STextBlock )
. Text ( this , & SSkeletonTree : : GetBoneFilterMenuTitle )
]
]
+ SHorizontalBox : : Slot ( )
. Padding ( 0.0f , 0.0f , 2.0f , 0.0f )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SComboButton )
. ContentPadding ( 3 )
. OnGetMenuContent ( this , & SSkeletonTree : : CreateSocketFilterMenu )
2014-04-23 18:06:41 -04:00
. ToolTipText ( LOCTEXT ( " SocketFilterToolTip " , " Change which types of sockets are shown " ) )
2014-09-12 15:56:59 -04:00
. AddMetaData < FTagMetaData > ( TEXT ( " SkelTree.Sockets " ) )
2014-03-14 14:13:41 -04:00
. ButtonContent ( )
[
SNew ( STextBlock )
. Text ( this , & SSkeletonTree : : GetSocketFilterMenuTitle )
]
]
2014-10-17 12:43:25 -04:00
+ SHorizontalBox : : Slot ( )
. Padding ( 0.0f , 0.0f , 2.0f , 0.0f )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SCheckBox )
2015-02-16 11:22:48 -05:00
. IsChecked ( this , & SSkeletonTree : : IsShowingAdvancedOptions )
2014-10-17 12:43:25 -04:00
. ToolTipText ( LOCTEXT ( " SocketFilterToolTip " , " Change which types of sockets are shown " ) )
2015-02-16 11:22:48 -05:00
. OnCheckStateChanged ( this , & SSkeletonTree : : OnChangeShowingAdvancedOptions )
2014-10-17 12:43:25 -04:00
[
SNew ( STextBlock )
2015-02-16 11:22:48 -05:00
. Text ( LOCTEXT ( " ShowAdvancedOptions " , " Show Advanced Options " ) )
2014-10-17 12:43:25 -04:00
]
]
2014-03-14 14:13:41 -04:00
]
+ SVerticalBox : : Slot ( )
. Padding ( FMargin ( 0.0f , 4.0f , 0.0f , 0.0f ) )
[
2014-10-17 12:43:25 -04:00
SAssignNew ( TreeHolder , SOverlay )
2014-03-14 14:13:41 -04:00
]
] ;
if ( PersonaPtr . IsValid ( ) )
{
2014-10-17 12:43:25 -04:00
CreateTreeColumns ( ) ;
2014-03-14 14:13:41 -04:00
}
}
SSkeletonTree : : ~ SSkeletonTree ( )
{
if ( PersonaPtr . IsValid ( ) )
{
PersonaPtr . Pin ( ) - > UnregisterOnPostUndo ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnPreviewMeshChanged ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnBoneSelected ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnSocketSelected ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnDeselectAll ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnChangeSkeletonTree ( this ) ;
PersonaPtr . Pin ( ) - > UnregisterOnCreateViewport ( this ) ;
}
}
void SSkeletonTree : : BindCommands ( )
{
// This should not be called twice on the same instance
check ( ! UICommandList . IsValid ( ) ) ;
UICommandList = MakeShareable ( new FUICommandList ) ;
FUICommandList & CommandList = * UICommandList ;
// Grab the list of menu commands to bind...
const FSkeletonTreeCommands & MenuActions = FSkeletonTreeCommands : : Get ( ) ;
// ...and bind them all
// Bone Filter commands
CommandList . MapAction (
MenuActions . ShowAllBones ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneFilter , EBoneFilter : : All ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsBoneFilter , EBoneFilter : : All ) ) ;
CommandList . MapAction (
MenuActions . ShowMeshBones ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneFilter , EBoneFilter : : Mesh ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsBoneFilter , EBoneFilter : : Mesh ) ) ;
CommandList . MapAction (
MenuActions . ShowWeightedBones ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneFilter , EBoneFilter : : Weighted ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsBoneFilter , EBoneFilter : : Weighted ) ) ;
CommandList . MapAction (
MenuActions . HideBones ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneFilter , EBoneFilter : : None ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsBoneFilter , EBoneFilter : : None ) ) ;
// Socket filter commands
CommandList . MapAction (
MenuActions . ShowActiveSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetSocketFilter , ESocketFilter : : Active ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsSocketFilter , ESocketFilter : : Active ) ) ;
CommandList . MapAction (
MenuActions . ShowMeshSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetSocketFilter , ESocketFilter : : Mesh ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsSocketFilter , ESocketFilter : : Mesh ) ) ;
CommandList . MapAction (
MenuActions . ShowSkeletonSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetSocketFilter , ESocketFilter : : Skeleton ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsSocketFilter , ESocketFilter : : Skeleton ) ) ;
CommandList . MapAction (
MenuActions . ShowAllSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetSocketFilter , ESocketFilter : : All ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsSocketFilter , ESocketFilter : : All ) ) ;
CommandList . MapAction (
MenuActions . HideSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetSocketFilter , ESocketFilter : : None ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SSkeletonTree : : IsSocketFilter , ESocketFilter : : None ) ) ;
// Socket manipulation commands
CommandList . MapAction (
MenuActions . AddSocket ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnAddSocket ) ,
FCanExecuteAction : : CreateSP ( this , & SSkeletonTree : : IsAddingSocketsAllowed ) ) ;
CommandList . MapAction (
FGenericCommands : : Get ( ) . Rename ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnRenameSocket ) ,
FCanExecuteAction : : CreateSP ( this , & SSkeletonTree : : CanRenameSelected ) ) ;
CommandList . MapAction (
2014-07-15 15:01:05 -04:00
MenuActions . CreateMeshSocket ,
2014-03-14 14:13:41 -04:00
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnCustomizeSocket ) ) ;
CommandList . MapAction (
2014-07-15 15:01:05 -04:00
MenuActions . RemoveMeshSocket ,
2014-03-14 14:13:41 -04:00
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnDeleteSelectedRows ) ) ; // Removing customization just deletes the mesh socket
CommandList . MapAction (
MenuActions . PromoteSocketToSkeleton ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnPromoteSocket ) ) ; // Adding customization just deletes the mesh socket
CommandList . MapAction (
MenuActions . DeleteSelectedRows ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnDeleteSelectedRows ) ) ;
CommandList . MapAction (
MenuActions . CopyBoneNames ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnCopyBoneNames ) ) ;
CommandList . MapAction (
MenuActions . ResetBoneTransforms ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnResetBoneTransforms ) ) ;
CommandList . MapAction (
MenuActions . CopySockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnCopySockets ) ) ;
CommandList . MapAction (
MenuActions . PasteSockets ,
FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnPasteSockets ) ) ;
}
TSharedRef < ITableRow > SSkeletonTree : : MakeTreeRowWidget ( TSharedPtr < FDisplayedTreeRowInfo > InInfo , const TSharedRef < STableViewBase > & OwnerTable )
{
check ( InInfo . IsValid ( ) ) ;
return InInfo - > MakeTreeRowWidget ( OwnerTable , FilterText ) ;
}
void SSkeletonTree : : GetChildrenForInfo ( TSharedPtr < FDisplayedTreeRowInfo > InInfo , TArray < TSharedPtr < FDisplayedTreeRowInfo > > & OutChildren )
{
check ( InInfo . IsValid ( ) ) ;
OutChildren = InInfo - > Children ;
}
bool SSkeletonTree : : AttachToParent ( TSharedRef < FDisplayedTreeRowInfo > ItemToAttach , FName ParentName , int32 ItemsToInclude )
{
// Find the parent info
for ( int32 BoneIndex = 0 ; BoneIndex < DisplayMirror . Num ( ) ; + + BoneIndex )
{
TSharedRef < FDisplayedTreeRowInfo > CurrentItem = DisplayMirror [ BoneIndex ] ;
// does the item match our filter
if ( ( ItemsToInclude & CurrentItem - > GetType ( ) ) ! = 0 )
{
if ( CurrentItem - > GetRowItemName ( ) = = ParentName )
{
CurrentItem - > Children . Insert ( ItemToAttach , 0 ) ;
return true ;
}
}
}
return false ;
}
2014-10-17 12:43:25 -04:00
void SSkeletonTree : : CreateTreeColumns ( )
{
TSharedRef < SHeaderRow > TreeHeaderRow = SNew ( SHeaderRow )
+ SHeaderRow : : Column ( ColumnID_BoneLabel )
. DefaultLabel ( LOCTEXT ( " SkeletonBoneNameLabel " , " Name " ) )
. FillWidth ( 0.75f ) ;
2015-02-16 11:22:48 -05:00
if ( bShowingAdvancedOptions )
2014-10-17 12:43:25 -04:00
{
TreeHeaderRow - > AddColumn (
SHeaderRow : : Column ( ColumnID_RetargetingLabel )
. DefaultLabel ( LOCTEXT ( " SkeletonBoneTranslationRetargetingLabel " , " Translation Retargeting " ) )
. FillWidth ( 0.25f )
) ;
}
TreeHolder - > ClearChildren ( ) ;
TreeHolder - > AddSlot ( )
[
SAssignNew ( SkeletonTreeView , SMeshSkeletonTreeRowType )
. TreeItemsSource ( & SkeletonRowList )
. OnGenerateRow ( this , & SSkeletonTree : : MakeTreeRowWidget )
. OnGetChildren ( this , & SSkeletonTree : : GetChildrenForInfo )
. OnContextMenuOpening ( this , & SSkeletonTree : : CreateContextMenu )
. OnSelectionChanged ( this , & SSkeletonTree : : OnSelectionChanged )
. OnItemScrolledIntoView ( this , & SSkeletonTree : : OnItemScrolledIntoView )
. OnMouseButtonDoubleClick ( this , & SSkeletonTree : : OnTreeDoubleClick )
. OnSetExpansionRecursive ( this , & SSkeletonTree : : SetTreeItemExpansionRecursive )
. ItemHeight ( 24 )
. HeaderRow
(
TreeHeaderRow
)
] ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
2014-03-14 14:13:41 -04:00
void SSkeletonTree : : CreateFromSkeleton ( const TArray < FBoneNode > & SourceSkeleton , USkeletalMeshSocket * SocketToRename )
{
SkeletonRowList . Empty ( ) ;
DisplayMirror . Empty ( SourceSkeleton . Num ( ) ) ;
if ( BoneFilter ! = EBoneFilter : : None )
{
2014-10-01 14:45:23 -04:00
const FReferenceSkeleton & RefSkeleton = TargetSkeleton - > GetReferenceSkeleton ( ) ;
2014-03-14 14:13:41 -04:00
for ( int32 BoneIndex = 0 ; BoneIndex < SourceSkeleton . Num ( ) ; + + BoneIndex )
{
2014-10-01 14:45:23 -04:00
const FName & BoneName = RefSkeleton . GetBoneName ( BoneIndex ) ;
2014-03-14 14:13:41 -04:00
if ( ! FilterText . IsEmpty ( ) & & ! BoneName . ToString ( ) . Contains ( FilterText . ToString ( ) ) )
{
continue ;
}
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
if ( PreviewComponent )
{
int32 BoneMeshIndex = PreviewComponent - > GetBoneIndex ( BoneName ) ;
// Remove non-mesh bones if we're filtering
if ( ( BoneFilter = = EBoneFilter : : Mesh | | BoneFilter = = EBoneFilter : : Weighted ) & &
BoneMeshIndex = = INDEX_NONE )
{
continue ;
}
// Remove non-vertex-weighted bones if we're filtering
if ( BoneFilter = = EBoneFilter : : Weighted & & ! IsBoneWeighted ( BoneMeshIndex , PreviewComponent ) )
{
continue ;
}
}
int32 ParentIndex = RefSkeleton . GetParentIndex ( BoneIndex ) ;
TSharedRef < FDisplayedMeshBoneInfo > DisplayBone = FDisplayedMeshBoneInfo : : Make ( RefSkeleton . GetBoneName ( BoneIndex ) , TargetSkeleton , PersonaPtr , SharedThis ( this ) ) ;
if ( BoneIndex > 0 & & FilterText . IsEmpty ( ) & & DisplayMirror . Num ( ) ! = 0 ) // No hierarchy when filtertext is non-empty
{
check ( ParentIndex < BoneIndex ) ;
// We support filtering the list, so ParentIndex isn't necessarily correct in the DisplayMirror any more, so we need to search for it by name
FName ParentName = RefSkeleton . GetBoneName ( ParentIndex ) ;
bool bFoundRemappedParentIndex = false ;
for ( int32 i = 0 ; i < DisplayMirror . Num ( ) ; + + i )
{
FDisplayedTreeRowInfoPtr TreeRowInfo = DisplayMirror [ i ] ;
// At this point, we can assume that *all* of DisplayMirror contains bones, not sockets
check ( TreeRowInfo - > GetType ( ) = = ESkeletonTreeRowType : : Bone ) ;
if ( * static_cast < FName * > ( TreeRowInfo - > GetData ( ) ) = = ParentName )
{
ParentIndex = i ;
bFoundRemappedParentIndex = true ;
break ;
}
}
if ( bFoundRemappedParentIndex )
{
DisplayMirror [ ParentIndex ] - > Children . Add ( DisplayBone ) ;
}
else
{
// The parent bone didn't pass the filter, so just add this bone to the base of the tree
SkeletonRowList . Add ( DisplayBone ) ;
}
}
else
{
SkeletonRowList . Add ( DisplayBone ) ;
}
DisplayMirror . Add ( DisplayBone ) ;
SkeletonTreeView - > SetItemExpansion ( DisplayBone , true ) ;
}
}
// Add the sockets for the skeleton
if ( SocketFilter = = ESocketFilter : : Active | | SocketFilter = = ESocketFilter : : All | | SocketFilter = = ESocketFilter : : Skeleton )
{
AddSocketsFromData ( TargetSkeleton - > Sockets , ESocketParentType : : Skeleton , SocketToRename ) ;
}
if ( SocketFilter = = ESocketFilter : : Active | | SocketFilter = = ESocketFilter : : All | | SocketFilter = = ESocketFilter : : Mesh )
{
// Add the sockets for the mesh
if ( PersonaPtr . IsValid ( ) )
{
if ( USkeletalMesh * SkeletalMesh = PersonaPtr . Pin ( ) - > GetMesh ( ) )
{
AddSocketsFromData ( SkeletalMesh - > GetMeshOnlySocketList ( ) , ESocketParentType : : Mesh , SocketToRename ) ;
}
}
}
//Add the attached mesh items last, these are the most child like of all the items that can go in the skeleton tree
// Mesh attached items...
if ( PersonaPtr . IsValid ( ) )
{
if ( USkeletalMesh * SkeletalMesh = PersonaPtr . Pin ( ) - > GetMesh ( ) )
{
AddAttachedAssets ( SkeletalMesh - > PreviewAttachedAssetContainer ) ;
}
}
// ...skeleton attached items
AddAttachedAssets ( TargetSkeleton - > PreviewAttachedAssetContainer ) ;
SkeletonTreeView - > RequestTreeRefresh ( ) ;
}
void SSkeletonTree : : AddSocketsFromData (
const TArray < USkeletalMeshSocket * > & SocketArray ,
ESocketParentType : : Type ParentType ,
USkeletalMeshSocket * SocketToRename )
{
for ( auto SocketIt = SocketArray . CreateConstIterator ( ) ; SocketIt ; + + SocketIt )
{
USkeletalMeshSocket * Socket = * ( SocketIt ) ;
if ( ! FilterText . IsEmpty ( ) & & ! Socket - > SocketName . ToString ( ) . Contains ( FilterText . ToString ( ) ) )
{
continue ;
}
bool bIsCustomized = false ;
if ( ParentType = = ESocketParentType : : Mesh )
{
bIsCustomized = PersonaPtr . Pin ( ) - > DoesSocketAlreadyExist ( NULL , FText : : FromName ( Socket - > SocketName ) , TargetSkeleton - > Sockets ) ;
}
else
{
if ( PersonaPtr . IsValid ( ) )
{
if ( USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) )
{
bIsCustomized = PersonaPtr . Pin ( ) - > DoesSocketAlreadyExist ( NULL , FText : : FromName ( Socket - > SocketName ) , Mesh - > GetMeshOnlySocketList ( ) ) ;
if ( SocketFilter = = ESocketFilter : : Active & & bIsCustomized )
{
// Don't add the skeleton socket if it's already added for the mesh
continue ;
}
}
}
}
TSharedRef < FDisplayedSocketInfo > DisplaySocket = FDisplayedSocketInfo : : Make ( Socket , ParentType , TargetSkeleton , PersonaPtr , SharedThis ( this ) , bIsCustomized ) ;
if ( Socket = = SocketToRename )
{
SkeletonTreeView - > SetSelection ( DisplaySocket ) ;
OnRenameSocket ( ) ;
}
DisplayMirror . Add ( DisplaySocket ) ;
if ( ! AttachToParent ( DisplaySocket , Socket - > BoneName , ESkeletonTreeRowType : : Bone ) )
{
// Just add it to the list if the parent bone isn't currently displayed
SkeletonRowList . Add ( DisplaySocket ) ;
}
SkeletonTreeView - > SetItemExpansion ( DisplaySocket , true ) ;
}
}
class FBoneTreeSelection
{
public :
TArray < TSharedPtr < FDisplayedTreeRowInfo > > SelectedItems ;
TArray < TSharedPtr < FDisplayedMeshBoneInfo > > SelectedBones ;
TArray < TSharedPtr < FDisplayedSocketInfo > > SelectedSockets ;
TArray < TSharedPtr < FDisplayedAttachedAssetInfo > > SelectedAssets ;
FBoneTreeSelection ( TArray < TSharedPtr < FDisplayedTreeRowInfo > > InSelectedItems ) : SelectedItems ( InSelectedItems )
{
for ( auto ItemIt = SelectedItems . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FDisplayedTreeRowInfoPtr Item = * ( ItemIt ) ;
switch ( Item - > GetType ( ) )
{
case ESkeletonTreeRowType : : Bone :
{
SelectedBones . Add ( StaticCastSharedPtr < FDisplayedMeshBoneInfo > ( Item ) ) ;
break ;
}
case ESkeletonTreeRowType : : Socket :
{
SelectedSockets . Add ( StaticCastSharedPtr < FDisplayedSocketInfo > ( Item ) ) ;
break ;
}
case ESkeletonTreeRowType : : AttachedAsset :
{
SelectedAssets . Add ( StaticCastSharedPtr < FDisplayedAttachedAssetInfo > ( Item ) ) ;
break ;
}
default :
{
check ( false ) ; // Unknown row type!
}
}
}
}
bool IsMultipleItemsSelected ( ) const
{
return SelectedItems . Num ( ) > 1 ;
}
bool IsSingleItemSelected ( ) const
{
return SelectedItems . Num ( ) = = 1 ;
}
bool IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Type ItemType ) const
{
if ( IsSingleItemSelected ( ) )
{
switch ( ItemType )
{
case ESkeletonTreeRowType : : Bone :
{
return SelectedBones . Num ( ) = = 1 ;
}
case ESkeletonTreeRowType : : Socket :
{
return SelectedSockets . Num ( ) = = 1 ;
}
case ESkeletonTreeRowType : : AttachedAsset :
{
return SelectedAssets . Num ( ) = = 1 ;
}
default :
{
check ( false ) ; // Unknown type
}
}
}
return false ;
}
TSharedPtr < FDisplayedTreeRowInfo > GetSingleSelectedItem ( )
{
check ( IsSingleItemSelected ( ) ) ;
return SelectedItems [ 0 ] ;
}
bool HasSelectedOfType ( ESkeletonTreeRowType : : Type ItemType ) const
{
switch ( ItemType )
{
case ESkeletonTreeRowType : : Bone :
{
return SelectedBones . Num ( ) > 0 ;
}
case ESkeletonTreeRowType : : Socket :
{
return SelectedSockets . Num ( ) > 0 ;
}
case ESkeletonTreeRowType : : AttachedAsset :
{
return SelectedAssets . Num ( ) > 0 ;
}
default :
{
check ( false ) ; // Unknown type
}
}
return false ;
}
} ;
TSharedPtr < SWidget > SSkeletonTree : : CreateContextMenu ( )
{
const FSkeletonTreeCommands & Actions = FSkeletonTreeCommands : : Get ( ) ;
FBoneTreeSelection BoneTreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
const bool CloseAfterSelection = true ;
FMenuBuilder MenuBuilder ( CloseAfterSelection , UICommandList ) ;
{
if ( BoneTreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : AttachedAsset ) | | BoneTreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : Socket ) )
{
MenuBuilder . BeginSection ( " SkeletonTreeSelectedItemsActions " , LOCTEXT ( " SelectedActions " , " Selected Item Actions " ) ) ;
MenuBuilder . AddMenuEntry ( Actions . DeleteSelectedRows ) ;
MenuBuilder . EndSection ( ) ;
}
if ( BoneTreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : Bone ) )
{
MenuBuilder . BeginSection ( " SkeletonTreeBonesAction " , LOCTEXT ( " BoneActions " , " Selected Bone Actions " ) ) ;
MenuBuilder . AddMenuEntry ( Actions . CopyBoneNames ) ;
MenuBuilder . AddMenuEntry ( Actions . ResetBoneTransforms ) ;
if ( BoneTreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Bone ) )
{
MenuBuilder . AddMenuEntry ( Actions . AddSocket ) ;
MenuBuilder . AddMenuEntry ( Actions . PasteSockets ) ;
}
MenuBuilder . EndSection ( ) ;
2015-02-16 11:22:48 -05:00
if ( bShowingAdvancedOptions )
2014-03-14 14:13:41 -04:00
{
2014-07-11 15:14:21 -04:00
MenuBuilder . BeginSection ( " SkeletonTreeBoneTranslationRetargeting " , LOCTEXT ( " BoneTranslationRetargetingHeader " , " Bone Translation Retargeting " ) ) ;
{
FUIAction RecursiveRetargetingSkeletonAction = FUIAction ( FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneTranslationRetargetingModeRecursive , EBoneTranslationRetargetingMode : : Skeleton ) ) ;
FUIAction RecursiveRetargetingAnimationAction = FUIAction ( FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneTranslationRetargetingModeRecursive , EBoneTranslationRetargetingMode : : Animation ) ) ;
FUIAction RecursiveRetargetingAnimationScaledAction = FUIAction ( FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneTranslationRetargetingModeRecursive , EBoneTranslationRetargetingMode : : AnimationScaled ) ) ;
2014-10-10 16:03:02 -04:00
FUIAction RecursiveRetargetingAnimationRelativeAction = FUIAction ( FExecuteAction : : CreateSP ( this , & SSkeletonTree : : SetBoneTranslationRetargetingModeRecursive , EBoneTranslationRetargetingMode : : AnimationRelative ) ) ;
2014-03-14 14:13:41 -04:00
2014-07-11 15:14:21 -04:00
MenuBuilder . AddMenuEntry
( LOCTEXT ( " SetTranslationRetargetingSkeletonChildrenAction " , " Recursively Set Translation Retargeting Skeleton " )
, LOCTEXT ( " BoneTranslationRetargetingSkeletonToolTip " , " Use translation from Skeleton. " )
, FSlateIcon ( )
, RecursiveRetargetingSkeletonAction
) ;
2014-03-14 14:13:41 -04:00
2014-07-11 15:14:21 -04:00
MenuBuilder . AddMenuEntry
( LOCTEXT ( " SetTranslationRetargetingAnimationChildrenAction " , " Recursively Set Translation Retargeting Animation " )
, LOCTEXT ( " BoneTranslationRetargetingAnimationToolTip " , " Use translation from animation. " )
, FSlateIcon ( )
, RecursiveRetargetingAnimationAction
) ;
2014-03-14 14:13:41 -04:00
2014-07-11 15:14:21 -04:00
MenuBuilder . AddMenuEntry
( LOCTEXT ( " SetTranslationRetargetingAnimationScaledChildrenAction " , " Recursively Set Translation Retargeting AnimationScaled " )
, LOCTEXT ( " BoneTranslationRetargetingAnimationScaledToolTip " , " Use translation from animation, scale length by Skeleton's proportions. " )
, FSlateIcon ( )
, RecursiveRetargetingAnimationScaledAction
) ;
2014-10-10 16:03:02 -04:00
MenuBuilder . AddMenuEntry
( LOCTEXT ( " SetTranslationRetargetingAnimationRelativeChildrenAction " , " Recursively Set Translation Retargeting AnimationRelative " )
, LOCTEXT ( " BoneTranslationRetargetingAnimationRelativeToolTip " , " Use relative translation from animation similar to an additive animation. " )
, FSlateIcon ( )
, RecursiveRetargetingAnimationRelativeAction
) ;
2014-07-11 15:14:21 -04:00
}
MenuBuilder . EndSection ( ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( BoneTreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : Socket ) )
{
MenuBuilder . BeginSection ( " SkeletonTreeSocketsActions " , LOCTEXT ( " SocketActions " , " Selected Socket Actions " ) ) ;
MenuBuilder . AddMenuEntry ( Actions . CopySockets ) ;
if ( BoneTreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Socket ) )
{
MenuBuilder . AddMenuEntry ( FGenericCommands : : Get ( ) . Rename , NAME_None , LOCTEXT ( " RenameSocket_Label " , " Rename Socket " ) , LOCTEXT ( " RenameSocket_Tooltip " , " Rename this socket " ) ) ;
FDisplayedSocketInfo * DisplayedSocketInfo = static_cast < FDisplayedSocketInfo * > ( BoneTreeSelection . GetSingleSelectedItem ( ) . Get ( ) ) ;
if ( DisplayedSocketInfo - > IsSocketCustomized ( ) & & DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Mesh )
{
2014-07-15 15:01:05 -04:00
MenuBuilder . AddMenuEntry ( Actions . RemoveMeshSocket ) ;
2014-03-14 14:13:41 -04:00
}
USkeletalMeshSocket * SelectedSocket = static_cast < USkeletalMeshSocket * > ( DisplayedSocketInfo - > GetData ( ) ) ;
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
// If the socket is on the skeleton, we have a valid mesh
// and there isn't one of the same name on the mesh, we can customize it
if ( Mesh & & ! DisplayedSocketInfo - > IsSocketCustomized ( ) )
{
if ( DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Skeleton )
{
2014-07-15 15:01:05 -04:00
MenuBuilder . AddMenuEntry ( Actions . CreateMeshSocket ) ;
2014-03-14 14:13:41 -04:00
}
else if ( DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Mesh )
{
// If a socket is on the mesh only, then offer to promote it to the skeleton
MenuBuilder . AddMenuEntry ( Actions . PromoteSocketToSkeleton ) ;
}
}
}
MenuBuilder . EndSection ( ) ;
}
MenuBuilder . BeginSection ( " SkeletonTreeAttachedAssets " , LOCTEXT ( " AttachedAssetsActionsHeader " , " Attached Assets Actions " ) ) ;
if ( BoneTreeSelection . IsSingleItemSelected ( ) )
{
MenuBuilder . AddSubMenu ( LOCTEXT ( " AttachNewAsset " , " Add Preview Asset " ) ,
LOCTEXT ( " AttachNewAsset_ToolTip " , " Attaches an asset to this part of the skeleton. Assets can also be dragged onto the skeleton from a content browser to attach " ) ,
FNewMenuDelegate : : CreateSP ( this , & SSkeletonTree : : FillAttachAssetSubmenu , BoneTreeSelection . GetSingleSelectedItem ( ) ) ) ;
}
FUIAction RemoveAllAttachedAssets = FUIAction ( FExecuteAction : : CreateSP ( this , & SSkeletonTree : : OnRemoveAllAssets ) ,
FCanExecuteAction : : CreateSP ( this , & SSkeletonTree : : CanRemoveAllAssets ) ) ;
MenuBuilder . AddMenuEntry ( LOCTEXT ( " RemoveAllAttachedAssets " , " Remove All Attached Assets " ) ,
LOCTEXT ( " RemoveAllAttachedAssets_ToolTip " , " Removes all the attached assets from the skeleton and mesh. " ) ,
FSlateIcon ( ) , RemoveAllAttachedAssets ) ;
MenuBuilder . EndSection ( ) ;
}
return MenuBuilder . MakeWidget ( ) ;
}
2014-07-08 06:02:36 -04:00
/*
2014-10-01 14:45:23 -04:00
void SSkeletonTree : : CreateMenuForBoneReduction ( FMenuBuilder & MenuBuilder , SSkeletonTree * Widget , USkeleton * Skeleton , bool bAdd )
2014-03-14 14:13:41 -04:00
{
if ( bMeshReductionSupported )
{
int32 LODSettingIndex = 0 ;
for ( ; LODSettingIndex < Skeleton - > BoneReductionSettingsForLODs . Num ( ) ; + + LODSettingIndex )
{
if ( Skeleton - > BoneReductionSettingsForLODs [ LODSettingIndex ] . BonesToRemove . Num ( ) > 0 )
{
if ( bAdd )
{
FUIAction AddBonesToLOD1Action = FUIAction ( FExecuteAction : : CreateSP ( Widget , & SSkeletonTree : : AddToLOD , LODSettingIndex + 1 ) ) ;
MenuBuilder . AddMenuEntry
( FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FSlateIcon ( )
, AddBonesToLOD1Action
) ;
}
else
{
FUIAction RemoveBonesFromLOD1Action = FUIAction ( FExecuteAction : : CreateSP ( Widget , & SSkeletonTree : : RemoveFromLOD , LODSettingIndex + 1 ) ) ;
MenuBuilder . AddMenuEntry
( FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FSlateIcon ( )
, RemoveBonesFromLOD1Action
) ;
}
}
}
if ( ! bAdd )
{
FUIAction RemoveBonesFromLOD1Action = FUIAction ( FExecuteAction : : CreateSP ( Widget , & SSkeletonTree : : RemoveFromLOD , LODSettingIndex + 1 ) ) ;
MenuBuilder . AddMenuEntry
( FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FText : : FromString ( FString : : Printf ( TEXT ( " LOD %d " ) , LODSettingIndex + 1 ) )
, FSlateIcon ( )
, RemoveBonesFromLOD1Action
) ;
}
}
}
2014-07-08 06:02:36 -04:00
*/
2014-03-14 14:13:41 -04:00
void SSkeletonTree : : SetBoneTranslationRetargetingModeRecursive ( EBoneTranslationRetargetingMode : : Type NewRetargetingMode )
{
const FScopedTransaction Transaction ( LOCTEXT ( " SetBoneTranslationRetargetingModeRecursive " , " Set Bone Translation Retargeting Mode Recursive " ) ) ;
TargetSkeleton - > Modify ( ) ;
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
for ( auto ItemIt = TreeSelection . SelectedBones . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FName BoneName = * static_cast < FName * > ( ( * ItemIt ) - > GetData ( ) ) ;
int32 BoneIndex = TargetSkeleton - > GetReferenceSkeleton ( ) . FindBoneIndex ( BoneName ) ;
TargetSkeleton - > SetBoneTranslationRetargetingMode ( BoneIndex , NewRetargetingMode , true ) ;
}
FAssetNotifications : : SkeletonNeedsToBeSaved ( TargetSkeleton ) ;
}
void SSkeletonTree : : RemoveFromLOD ( int32 LODIndex )
{
if ( bMeshReductionSupported )
{
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveBoneFromLOD " , " Remove Selected Bones from LOD " ) ) ;
TargetSkeleton - > Modify ( ) ;
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
for ( auto ItemIt = TreeSelection . SelectedBones . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FName BoneName = * static_cast < FName * > ( ( * ItemIt ) - > GetData ( ) ) ;
int32 BoneIndex = TargetSkeleton - > GetReferenceSkeleton ( ) . FindBoneIndex ( BoneName ) ;
TargetSkeleton - > RemoveBoneFromLOD ( LODIndex , BoneIndex ) ;
}
FAssetNotifications : : SkeletonNeedsToBeSaved ( TargetSkeleton ) ;
}
}
void SSkeletonTree : : AddToLOD ( int32 LODIndex )
{
if ( bMeshReductionSupported )
{
const FScopedTransaction Transaction ( LOCTEXT ( " AddBoneToLOD " , " Add Selected Bones to LOD " ) ) ;
TargetSkeleton - > Modify ( ) ;
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
for ( auto ItemIt = TreeSelection . SelectedBones . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FName BoneName = * static_cast < FName * > ( ( * ItemIt ) - > GetData ( ) ) ;
int32 BoneIndex = TargetSkeleton - > GetReferenceSkeleton ( ) . FindBoneIndex ( BoneName ) ;
TargetSkeleton - > AddBoneToLOD ( LODIndex , BoneIndex ) ;
}
FAssetNotifications : : SkeletonNeedsToBeSaved ( TargetSkeleton ) ;
}
}
void SSkeletonTree : : OnCopyBoneNames ( )
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
if ( TreeSelection . SelectedBones . Num ( ) > 0 )
{
FString BoneNames ;
for ( auto ItemIt = TreeSelection . SelectedBones . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
2014-10-01 14:45:23 -04:00
FName * BoneName = static_cast < FName * > ( ( * ItemIt ) - > GetData ( ) ) ;
2014-03-14 14:13:41 -04:00
BoneNames + = BoneName - > ToString ( ) ;
BoneNames + = " \r \n " ;
}
FPlatformMisc : : ClipboardCopy ( * BoneNames ) ;
}
}
void SSkeletonTree : : OnResetBoneTransforms ( )
{
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
check ( PreviewComponent ) ;
UAnimPreviewInstance * PreviewInstance = PreviewComponent - > PreviewInstance ;
check ( PreviewInstance ) ;
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
if ( TreeSelection . SelectedBones . Num ( ) > 0 )
{
bool bModified = false ;
GEditor - > BeginTransaction ( LOCTEXT ( " SkeletonTree_ResetBoneTransforms " , " Reset Bone Transforms " ) ) ;
for ( auto ItemIt = TreeSelection . SelectedBones . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
const FName * BoneName = static_cast < FName * > ( ( * ItemIt ) - > GetData ( ) ) ;
check ( BoneName ) ;
const FAnimNode_ModifyBone * ModifiedBone = PreviewInstance - > FindModifiedBone ( * BoneName ) ;
if ( ModifiedBone ! = nullptr )
{
if ( ! bModified )
{
PreviewInstance - > SetFlags ( RF_Transactional ) ;
PreviewInstance - > Modify ( ) ;
bModified = true ;
}
PreviewInstance - > RemoveBoneModification ( * BoneName ) ;
}
}
GEditor - > EndTransaction ( ) ;
}
}
void SSkeletonTree : : OnCopySockets ( ) const
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
int32 NumSocketsToCopy = TreeSelection . SelectedSockets . Num ( ) ;
if ( NumSocketsToCopy > 0 )
{
FString SocketsDataString ;
for ( auto ItemIt = TreeSelection . SelectedSockets . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FDisplayedSocketInfo * DisplayedSocketInfo = ( * ItemIt ) . Get ( ) ;
USkeletalMeshSocket * Socket = static_cast < USkeletalMeshSocket * > ( DisplayedSocketInfo - > GetData ( ) ) ;
SocketsDataString + = SerializeSocketToString ( Socket , DisplayedSocketInfo ) ;
}
FString CopyString = FString : : Printf ( TEXT ( " %s \n NumSockets=%d \n %s " ) , * SocketCopyPasteHeader , NumSocketsToCopy , * SocketsDataString ) ;
FPlatformMisc : : ClipboardCopy ( * CopyString ) ;
}
}
FString SSkeletonTree : : SerializeSocketToString ( USkeletalMeshSocket * Socket , const FDisplayedSocketInfo * DisplayedSocketInfo ) const
{
FString SocketString ;
SocketString + = FString : : Printf ( TEXT ( " IsOnSkeleton=%s \n " ) , DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Skeleton ? TEXT ( " 1 " ) : TEXT ( " 0 " ) ) ;
FStringOutputDevice Buffer ;
const FExportObjectInnerContext Context ;
UExporter : : ExportToOutputDevice ( & Context , Socket , NULL , Buffer , TEXT ( " copy " ) , 0 , PPF_Copy , false ) ;
SocketString + = Buffer ;
return SocketString ;
}
void SSkeletonTree : : OnPasteSockets ( )
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
// Pasting sockets should only work if there is just one bone selected
if ( TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Bone ) )
{
FName DestBoneName = * static_cast < FName * > ( TreeSelection . GetSingleSelectedItem ( ) - > GetData ( ) ) ;
FString PasteString ;
FPlatformMisc : : ClipboardPaste ( PasteString ) ;
const TCHAR * PastePtr = * PasteString ;
FString PasteLine ;
FParse : : Line ( & PastePtr , PasteLine ) ;
if ( PasteLine = = SocketCopyPasteHeader )
{
const FScopedTransaction Transaction ( LOCTEXT ( " PasteSockets " , " Paste sockets " ) ) ;
int32 NumSocketsToPaste ;
FParse : : Line ( & PastePtr , PasteLine ) ; // Need this to advance PastePtr, for multiple sockets
FParse : : Value ( * PasteLine , TEXT ( " NumSockets= " ) , NumSocketsToPaste ) ;
FParse : : Line ( & PastePtr , PasteLine ) ;
for ( int32 i = 0 ; i < NumSocketsToPaste ; + + i )
{
bool bIsOnSkeleton ;
FParse : : Bool ( * PasteLine , TEXT ( " IsOnSkeleton= " ) , bIsOnSkeleton ) ;
USkeletalMeshSocket * NewSocket ;
FSocketTextObjectFactory TextObjectFactory ( & NewSocket ) ;
if ( bIsOnSkeleton )
{
TargetSkeleton - > Modify ( ) ;
TextObjectFactory . ProcessBuffer ( TargetSkeleton , RF_Transactional , PastePtr ) ;
check ( NewSocket ) ;
}
else
{
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
Mesh - > Modify ( ) ;
TextObjectFactory . ProcessBuffer ( Mesh , RF_Transactional , PastePtr ) ;
check ( NewSocket ) ;
}
// Override the bone name to the one we pasted to
NewSocket - > BoneName = DestBoneName ;
// Check the socket name is unique
NewSocket - > SocketName = PersonaPtr . Pin ( ) - > GenerateUniqueSocketName ( NewSocket - > SocketName ) ;
// Skip ahead in the stream to the next socket (if there is one)
PastePtr = FCString : : Strstr ( PastePtr , TEXT ( " IsOnSkeleton= " ) ) ;
if ( bIsOnSkeleton )
{
TargetSkeleton - > Sockets . Add ( NewSocket ) ;
}
else
{
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
Mesh - > GetMeshOnlySocketList ( ) . Add ( NewSocket ) ;
}
}
}
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
}
void SSkeletonTree : : OnAddSocket ( )
{
// This adds a socket to the currently selected bone in the SKELETON, not the MESH.
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
// Can only add a socket to one bone
if ( TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Bone ) )
{
USkeletalMeshSocket * NewSocket ;
const FScopedTransaction Transaction ( LOCTEXT ( " AddSocket " , " Add Socket to Skeleton " ) ) ;
TargetSkeleton - > Modify ( ) ;
2015-02-03 05:40:57 -05:00
NewSocket = NewObject < USkeletalMeshSocket > ( TargetSkeleton ) ;
2014-03-14 14:13:41 -04:00
check ( NewSocket ) ;
NewSocket - > BoneName = * static_cast < FName * > ( TreeSelection . GetSingleSelectedItem ( ) - > GetData ( ) ) ;
2014-07-29 17:32:17 -04:00
FString SocketName = NewSocket - > BoneName . ToString ( ) + LOCTEXT ( " SocketPostfix " , " Socket " ) . ToString ( ) ;
NewSocket - > SocketName = PersonaPtr . Pin ( ) - > GenerateUniqueSocketName ( * SocketName ) ;
2014-03-14 14:13:41 -04:00
TargetSkeleton - > Sockets . Add ( NewSocket ) ;
2014-09-24 15:12:35 -04:00
FSelectedSocketInfo SocketInfo ( NewSocket , true ) ;
PersonaPtr . Pin ( ) - > SetSelectedSocket ( SocketInfo , false ) ;
2014-03-14 14:13:41 -04:00
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) , NewSocket ) ;
}
}
void SSkeletonTree : : OnCustomizeSocket ( )
{
// This should only be called on a skeleton socket, it copies the
// socket to the mesh so the user can edit it separately
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
if ( TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Socket ) )
{
USkeletalMeshSocket * SocketToCustomize = static_cast < USkeletalMeshSocket * > ( TreeSelection . GetSingleSelectedItem ( ) - > GetData ( ) ) ;
if ( PersonaPtr . IsValid ( ) )
{
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
if ( Mesh )
{
2014-07-15 15:01:05 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CreateMeshSocket " , " Create Mesh Socket " ) ) ;
2014-03-14 14:13:41 -04:00
Mesh - > Modify ( ) ;
2015-02-03 05:40:57 -05:00
USkeletalMeshSocket * NewSocket = NewObject < USkeletalMeshSocket > ( Mesh ) ;
2014-03-14 14:13:41 -04:00
check ( NewSocket ) ;
NewSocket - > BoneName = SocketToCustomize - > BoneName ;
NewSocket - > SocketName = SocketToCustomize - > SocketName ;
NewSocket - > RelativeLocation = SocketToCustomize - > RelativeLocation ;
NewSocket - > RelativeRotation = SocketToCustomize - > RelativeRotation ;
NewSocket - > RelativeScale = SocketToCustomize - > RelativeScale ;
Mesh - > GetMeshOnlySocketList ( ) . Add ( NewSocket ) ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
}
}
}
void SSkeletonTree : : OnPromoteSocket ( )
{
// This should only be called on a mesh socket, it copies the
// socket to the skeleton so all meshes can use it
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
// Can only customize one socket (CreateContextMenu() should prevent this firing!)
if ( TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Socket ) )
{
USkeletalMeshSocket * SocketToCustomize = static_cast < USkeletalMeshSocket * > ( TreeSelection . GetSingleSelectedItem ( ) - > GetData ( ) ) ;
const FScopedTransaction Transaction ( LOCTEXT ( " PromoteSocket " , " Promote Socket " ) ) ;
TargetSkeleton - > Modify ( ) ;
2015-02-03 05:40:57 -05:00
USkeletalMeshSocket * NewSocket = NewObject < USkeletalMeshSocket > ( TargetSkeleton ) ;
2014-03-14 14:13:41 -04:00
check ( NewSocket ) ;
NewSocket - > BoneName = SocketToCustomize - > BoneName ;
NewSocket - > SocketName = SocketToCustomize - > SocketName ;
NewSocket - > RelativeLocation = SocketToCustomize - > RelativeLocation ;
NewSocket - > RelativeRotation = SocketToCustomize - > RelativeRotation ;
NewSocket - > RelativeScale = SocketToCustomize - > RelativeScale ;
TargetSkeleton - > Sockets . Add ( NewSocket ) ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
}
void SSkeletonTree : : FillAttachAssetSubmenu ( FMenuBuilder & MenuBuilder , const FDisplayedTreeRowInfoPtr TargetItem )
{
FContentBrowserModule & ContentBrowserModule = FModuleManager : : Get ( ) . LoadModuleChecked < FContentBrowserModule > ( TEXT ( " ContentBrowser " ) ) ;
TArray < UClass * > FilterClasses = FComponentAssetBrokerage : : GetSupportedAssets ( USceneComponent : : StaticClass ( ) ) ;
2015-04-22 11:40:32 -04:00
//Clean up the selection so it is relevant to Persona
2015-04-27 03:55:19 -04:00
FilterClasses . RemoveSingleSwap ( UBlueprint : : StaticClass ( ) , false ) ; //Child actor components broker gives us blueprints which isn't wanted
2015-04-22 11:40:32 -04:00
FilterClasses . RemoveSingleSwap ( USoundBase : : StaticClass ( ) , false ) ; //No sounds wanted
2015-03-02 12:57:33 -05:00
2014-03-14 14:13:41 -04:00
FAssetPickerConfig AssetPickerConfig ;
AssetPickerConfig . Filter . bRecursiveClasses = true ;
for ( int i = 0 ; i < FilterClasses . Num ( ) ; + + i )
{
AssetPickerConfig . Filter . ClassNames . Add ( FilterClasses [ i ] - > GetFName ( ) ) ;
}
AssetPickerConfig . OnAssetSelected = FOnAssetSelected : : CreateSP ( this , & SSkeletonTree : : OnAssetSelectedFromPicker , TargetItem ) ;
TSharedRef < SWidget > MenuContent = SNew ( SBox )
. WidthOverride ( 384 )
. HeightOverride ( 500 )
[
ContentBrowserModule . Get ( ) . CreateAssetPicker ( AssetPickerConfig )
] ;
MenuBuilder . AddWidget ( MenuContent , FText : : GetEmpty ( ) , true ) ;
}
void SSkeletonTree : : OnAssetSelectedFromPicker ( const FAssetData & AssetData , const FDisplayedTreeRowInfoPtr TargetItem )
{
FSlateApplication : : Get ( ) . DismissAllMenus ( ) ;
TArray < FAssetData > Assets ;
Assets . Add ( AssetData ) ;
AttachAssetsToSkeletonTree ( TargetItem , Assets ) ;
}
void SSkeletonTree : : OnRemoveAllAssets ( )
{
FScopedTransaction Transaction ( LOCTEXT ( " AttachedAssetRemoveUndo " , " Remove All Attached Assets " ) ) ;
TargetSkeleton - > Modify ( ) ;
DeleteAttachedObjects ( TargetSkeleton - > PreviewAttachedAssetContainer ) ;
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
if ( Mesh )
{
Mesh - > Modify ( ) ;
DeleteAttachedObjects ( Mesh - > PreviewAttachedAssetContainer ) ;
}
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
bool SSkeletonTree : : CanRemoveAllAssets ( ) const
{
USkeletalMesh * SkeletalMesh = NULL ;
if ( PersonaPtr . IsValid ( ) )
{
SkeletalMesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
}
const bool bHasPreviewAttachedObjects = TargetSkeleton - > PreviewAttachedAssetContainer . Num ( ) > 0 ;
const bool bHasMeshPreviewAttachedObjects = ( SkeletalMesh & & SkeletalMesh - > PreviewAttachedAssetContainer . Num ( ) ) ;
return bHasPreviewAttachedObjects | | bHasMeshPreviewAttachedObjects ;
}
void SSkeletonTree : : DeleteAttachedObjects ( FPreviewAssetAttachContainer & AttachedAssets )
{
for ( auto Iter = AttachedAssets . CreateIterator ( ) ; Iter ; + + Iter )
{
FPreviewAttachedObjectPair & Pair = ( * Iter ) ;
2014-04-24 14:59:16 -04:00
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Pair . GetAttachedObject ( ) , Pair . AttachedTo ) ;
2014-03-14 14:13:41 -04:00
}
AttachedAssets . ClearAllAttachedObjects ( ) ;
}
bool SSkeletonTree : : CanRenameSelected ( ) const
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
return TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Socket ) ;
}
void SSkeletonTree : : OnRenameSocket ( )
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
if ( TreeSelection . IsSingleOfTypeSelected ( ESkeletonTreeRowType : : Socket ) )
{
SkeletonTreeView - > RequestScrollIntoView ( TreeSelection . GetSingleSelectedItem ( ) ) ;
DeferredRenameRequest = TreeSelection . GetSingleSelectedItem ( ) ;
}
}
void SSkeletonTree : : OnSelectionChanged ( TSharedPtr < FDisplayedTreeRowInfo > Selection , ESelectInfo : : Type SelectInfo )
{
if ( Selection . IsValid ( ) )
{
//Get all the selected items
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
if ( TreeSelection . SelectedItems . Num ( ) > 0 & & PreviewComponent )
{
// pick the first settable bone from the selection
for ( auto ItemIt = TreeSelection . SelectedItems . CreateConstIterator ( ) ; ItemIt ; + + ItemIt )
{
FDisplayedTreeRowInfoPtr Item = * ( ItemIt ) ;
// Test SelectInfo so we don't end up in an infinite loop due to delegates calling each other
if ( SelectInfo ! = ESelectInfo : : Direct & & Item - > GetType ( ) = = ESkeletonTreeRowType : : Bone )
{
FName BoneName = * static_cast < FName * > ( Item - > GetData ( ) ) ;
// Get bone index
int32 BoneIndex = PreviewComponent - > GetBoneIndex ( BoneName ) ;
if ( BoneIndex ! = INDEX_NONE )
{
PersonaPtr . Pin ( ) - > SetSelectedBone ( TargetSkeleton , BoneName , false ) ;
break ;
}
}
// Test SelectInfo so we don't end up in an infinite loop due to delegates calling each other
else if ( SelectInfo ! = ESelectInfo : : Direct & & Item - > GetType ( ) = = ESkeletonTreeRowType : : Socket )
{
FDisplayedSocketInfo * DisplayedSocketInfo = static_cast < FDisplayedSocketInfo * > ( Item . Get ( ) ) ;
USkeletalMeshSocket * Socket = static_cast < USkeletalMeshSocket * > ( Item - > GetData ( ) ) ;
FSelectedSocketInfo SocketInfo ( Socket , DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Skeleton ) ;
PersonaPtr . Pin ( ) - > SetSelectedSocket ( SocketInfo , false ) ;
}
else if ( Item - > GetType ( ) = = ESkeletonTreeRowType : : AttachedAsset )
{
PersonaPtr . Pin ( ) - > ClearSelectedBones ( ) ;
PersonaPtr . Pin ( ) - > ClearSelectedSocket ( ) ;
}
}
PreviewComponent - > PostInitMeshObject ( PreviewComponent - > MeshObject ) ;
}
}
else
{
// Tell Persona if the user ctrl-clicked the selected bone/socket to de-select it
PersonaPtr . Pin ( ) - > ClearSelectedBones ( ) ;
PersonaPtr . Pin ( ) - > ClearSelectedSocket ( ) ;
}
}
FReply SSkeletonTree : : OnDropAssetToSkeletonTree ( const FDisplayedTreeRowInfoPtr TargetItem , const FDragDropEvent & DragDropEvent )
{
2014-04-23 18:00:50 -04:00
TSharedPtr < FAssetDragDropOp > DragDropOp = DragDropEvent . GetOperationAs < FAssetDragDropOp > ( ) ;
if ( DragDropOp . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
//Do we have some assets to attach?
if ( DragDropOp - > AssetData . Num ( ) > 0 )
{
AttachAssetsToSkeletonTree ( TargetItem , DragDropOp - > AssetData ) ;
}
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
void SSkeletonTree : : AttachAssetsToSkeletonTree ( const FDisplayedTreeRowInfoPtr TargetItem , const TArray < FAssetData > & AssetData )
{
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
if ( PreviewComponent & & PreviewComponent - > SkeletalMesh & & PreviewComponent - > SkeletalMesh - > Skeleton )
{
bool bAllAssetWereLoaded = true ;
TArray < UObject * > DroppedObjects ;
for ( int32 AssetIdx = 0 ; AssetIdx < AssetData . Num ( ) ; + + AssetIdx )
{
UObject * Object = AssetData [ AssetIdx ] . GetAsset ( ) ;
if ( Object ! = NULL )
{
DroppedObjects . Add ( Object ) ;
}
else
{
bAllAssetWereLoaded = false ;
}
}
if ( bAllAssetWereLoaded )
{
FName AttachToName = TargetItem - > GetAttachName ( ) ;
for ( auto Iter = DroppedObjects . CreateIterator ( ) ; Iter ; + + Iter )
{
UObject * Object = ( * Iter ) ;
if ( TargetItem - > GetType ( ) = = ESkeletonTreeRowType : : Socket & &
static_cast < FDisplayedSocketInfo * > ( TargetItem . Get ( ) ) - > GetParentType ( ) = = ESocketParentType : : Mesh )
{
FScopedTransaction Transaction ( LOCTEXT ( " DragDropAttachMeshUndo " , " Attach Assets to Mesh " ) ) ;
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
Mesh - > Modify ( ) ;
PersonaPtr . Pin ( ) - > AttachObjectToPreviewComponent ( Object , AttachToName , & Mesh - > PreviewAttachedAssetContainer ) ;
}
else
{
FScopedTransaction Transaction ( LOCTEXT ( " DragDropAttachSkeletonUndo " , " Attach Assets to Skeleton " ) ) ;
TargetSkeleton - > Modify ( ) ;
PersonaPtr . Pin ( ) - > AttachObjectToPreviewComponent ( Object , AttachToName , & TargetSkeleton - > PreviewAttachedAssetContainer ) ;
}
}
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
}
}
void SSkeletonTree : : OnItemScrolledIntoView ( FDisplayedTreeRowInfoPtr InItem , const TSharedPtr < ITableRow > & InWidget )
{
if ( DeferredRenameRequest . IsValid ( ) )
{
DeferredRenameRequest - > RequestRename ( ) ;
DeferredRenameRequest . Reset ( ) ;
}
}
void SSkeletonTree : : OnTreeDoubleClick ( FDisplayedTreeRowInfoPtr InItem )
{
InItem - > OnItemDoubleClicked ( ) ;
}
2014-07-11 15:14:21 -04:00
void SSkeletonTree : : SetTreeItemExpansionRecursive ( TSharedPtr < FDisplayedTreeRowInfo > TreeItem , bool bInExpansionState ) const
{
SkeletonTreeView - > SetItemExpansion ( TreeItem , bInExpansionState ) ;
// Recursively go through the children.
for ( auto It = TreeItem - > Children . CreateIterator ( ) ; It ; + + It )
{
SetTreeItemExpansionRecursive ( * It , bInExpansionState ) ;
}
}
2014-03-14 14:13:41 -04:00
void SSkeletonTree : : PostUndo ( )
{
// Rebuild the tree view whenever we undo a change to the skeleton
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
PersonaPtr . Pin ( ) - > ClearSelectedBones ( ) ;
PersonaPtr . Pin ( ) - > ClearSelectedSocket ( ) ;
}
void SSkeletonTree : : OnFilterTextChanged ( const FText & SearchText )
{
FilterText = SearchText ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
void SSkeletonTree : : OnExternalSelectSocket ( const FSelectedSocketInfo & SocketInfo )
{
// This function is called when something else selects a socket (i.e. *NOT* the user clicking on a row in the treeview)
// For example, this would be called if user clicked a socket hit point in the preview window
// Firstly, find which row (if any) contains the socket requested
for ( auto SkeletonRowIt = DisplayMirror . CreateConstIterator ( ) ; SkeletonRowIt ; + + SkeletonRowIt )
{
FDisplayedTreeRowInfoPtr SkeletonRow = * ( SkeletonRowIt ) ;
if ( SkeletonRow - > GetType ( ) = = ESkeletonTreeRowType : : Socket & & SkeletonRow - > GetData ( ) = = SocketInfo . Socket )
{
SkeletonTreeView - > SetSelection ( SkeletonRow ) ;
SkeletonTreeView - > RequestScrollIntoView ( SkeletonRow ) ;
}
}
}
void SSkeletonTree : : OnExternalSelectBone ( const FName & BoneName )
{
// This function is called when something else selects a bone (i.e. *NOT* the user clicking on a row in the treeview)
// For example, this would be called if user clicked a bone hit point in the preview window
// Find which row (if any) contains the bone requested
for ( auto SkeletonRowIt = DisplayMirror . CreateConstIterator ( ) ; SkeletonRowIt ; + + SkeletonRowIt )
{
FDisplayedTreeRowInfoPtr SkeletonRow = * ( SkeletonRowIt ) ;
if ( SkeletonRow - > GetType ( ) = = ESkeletonTreeRowType : : Bone & &
2014-10-01 14:45:23 -04:00
* static_cast < FName * > ( SkeletonRow - > GetData ( ) ) = = BoneName )
2014-03-14 14:13:41 -04:00
{
SkeletonTreeView - > SetSelection ( SkeletonRow ) ;
SkeletonTreeView - > RequestScrollIntoView ( SkeletonRow ) ;
}
}
}
void SSkeletonTree : : OnExternalDeselectAll ( )
{
SkeletonTreeView - > ClearSelection ( ) ;
if ( PersonaPtr . IsValid ( ) )
{
PersonaPtr . Pin ( ) - > ClearSelectedBones ( ) ;
PersonaPtr . Pin ( ) - > ClearSelectedSocket ( ) ;
}
}
void SSkeletonTree : : NotifyUser ( FNotificationInfo & NotificationInfo )
{
TSharedPtr < SNotificationItem > Notification = FSlateNotificationManager : : Get ( ) . AddNotification ( NotificationInfo ) ;
if ( Notification . IsValid ( ) )
{
Notification - > SetCompletionState ( SNotificationItem : : CS_Fail ) ;
}
}
TSharedRef < SWidget > SSkeletonTree : : CreateBoneFilterMenu ( )
{
const FSkeletonTreeCommands & Actions = FSkeletonTreeCommands : : Get ( ) ;
const bool CloseAfterSelection = true ;
FMenuBuilder MenuBuilder ( CloseAfterSelection , UICommandList ) ;
MenuBuilder . BeginSection ( " Bones " , LOCTEXT ( " BonesMenuHeading " , " Bones " ) ) ;
{
MenuBuilder . AddMenuEntry ( Actions . ShowAllBones ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowMeshBones ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowWeightedBones ) ;
MenuBuilder . AddMenuEntry ( Actions . HideBones ) ;
}
MenuBuilder . EndSection ( ) ;
return MenuBuilder . MakeWidget ( ) ;
}
TSharedRef < SWidget > SSkeletonTree : : CreateSocketFilterMenu ( )
{
const FSkeletonTreeCommands & Actions = FSkeletonTreeCommands : : Get ( ) ;
const bool CloseAfterSelection = true ;
FMenuBuilder MenuBuilder ( CloseAfterSelection , UICommandList ) ;
MenuBuilder . BeginSection ( " Sockets " , LOCTEXT ( " SocketsMenuHeading " , " Sockets " ) ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowActiveSockets ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowMeshSockets ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowSkeletonSockets ) ;
MenuBuilder . AddMenuEntry ( Actions . ShowAllSockets ) ;
MenuBuilder . AddMenuEntry ( Actions . HideSockets ) ;
MenuBuilder . EndSection ( ) ;
return MenuBuilder . MakeWidget ( ) ;
}
void SSkeletonTree : : SetBoneFilter ( EBoneFilter : : Type InBoneFilter )
{
check ( InBoneFilter < EBoneFilter : : Count ) ;
BoneFilter = InBoneFilter ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
bool SSkeletonTree : : IsBoneFilter ( EBoneFilter : : Type InBoneFilter ) const
{
return BoneFilter = = InBoneFilter ;
}
void SSkeletonTree : : SetSocketFilter ( ESocketFilter : : Type InSocketFilter )
{
check ( InSocketFilter < ESocketFilter : : Count ) ;
SocketFilter = InSocketFilter ;
SetPreviewComponentSocketFilter ( ) ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
void SSkeletonTree : : SetPreviewComponentSocketFilter ( ) const
{
// Set the socket filter in the debug skeletal mesh component so the viewport can share the filter settings
UDebugSkelMeshComponent * PreviewComponent = PersonaPtr . Pin ( ) - > GetPreviewMeshComponent ( ) ;
bool bAllOrActive = ( SocketFilter = = ESocketFilter : : All | | SocketFilter = = ESocketFilter : : Active ) ;
if ( PreviewComponent )
{
PreviewComponent - > bMeshSocketsVisible = bAllOrActive | | SocketFilter = = ESocketFilter : : Mesh ;
PreviewComponent - > bSkeletonSocketsVisible = bAllOrActive | | SocketFilter = = ESocketFilter : : Skeleton ;
}
}
bool SSkeletonTree : : IsSocketFilter ( ESocketFilter : : Type InSocketFilter ) const
{
return SocketFilter = = InSocketFilter ;
}
bool SSkeletonTree : : IsBoneWeighted ( int32 MeshBoneIndex , UDebugSkelMeshComponent * PreviewComponent ) const
{
// MeshBoneIndex must be an index into the mesh's skeleton, *not* the source skeleton!!!
if ( ! PreviewComponent | | ! PreviewComponent - > SkeletalMesh | | ! PreviewComponent - > SkeletalMesh - > GetImportedResource ( ) - > LODModels . Num ( ) )
{
// If there's no mesh, then this bone can't possibly be weighted!
return false ;
}
//Get current LOD
const int32 LODIndex = FMath : : Clamp ( PreviewComponent - > PredictedLODLevel , 0 , PreviewComponent - > SkeletalMesh - > GetImportedResource ( ) - > LODModels . Num ( ) - 1 ) ;
FStaticLODModel & LODModel = PreviewComponent - > SkeletalMesh - > GetImportedResource ( ) - > LODModels [ LODIndex ] ;
//Check whether the bone is vertex weighted
int32 Index = LODModel . ActiveBoneIndices . Find ( MeshBoneIndex ) ;
return Index ! = INDEX_NONE ;
}
2015-01-07 09:52:40 -05:00
FText SSkeletonTree : : GetBoneFilterMenuTitle ( ) const
2014-03-14 14:13:41 -04:00
{
FText BoneFilterMenuText ;
switch ( BoneFilter )
{
case EBoneFilter : : All :
BoneFilterMenuText = LOCTEXT ( " BoneFilterMenuAll " , " All Bones " ) ;
break ;
case EBoneFilter : : Mesh :
BoneFilterMenuText = LOCTEXT ( " BoneFilterMenuMesh " , " Mesh Bones " ) ;
break ;
case EBoneFilter : : Weighted :
BoneFilterMenuText = LOCTEXT ( " BoneFilterMenuWeighted " , " Weighted Bones " ) ;
break ;
case EBoneFilter : : None :
BoneFilterMenuText = LOCTEXT ( " BoneFilterMenuHidden " , " Bones Hidden " ) ;
break ;
default :
// Unknown mode
check ( 0 ) ;
break ;
}
2015-01-07 09:52:40 -05:00
return BoneFilterMenuText ;
2014-03-14 14:13:41 -04:00
}
2015-01-07 09:52:40 -05:00
FText SSkeletonTree : : GetSocketFilterMenuTitle ( ) const
2014-03-14 14:13:41 -04:00
{
FText SocketFilterMenuText ;
switch ( SocketFilter )
{
case ESocketFilter : : Active :
SocketFilterMenuText = LOCTEXT ( " SocketFilterMenuActive " , " Active Sockets " ) ;
break ;
case ESocketFilter : : Mesh :
SocketFilterMenuText = LOCTEXT ( " SocketFilterMenuMesh " , " Mesh Sockets " ) ;
break ;
case ESocketFilter : : Skeleton :
SocketFilterMenuText = LOCTEXT ( " SocketFilterMenuSkeleton " , " Skeleton Sockets " ) ;
break ;
case ESocketFilter : : All :
SocketFilterMenuText = LOCTEXT ( " SocketFilterMenuAll " , " All Sockets " ) ;
break ;
case ESocketFilter : : None :
SocketFilterMenuText = LOCTEXT ( " SocketFilterMenuHidden " , " Sockets Hidden " ) ;
break ;
default :
// Unknown mode
check ( 0 ) ;
break ;
}
2015-01-07 09:52:40 -05:00
return SocketFilterMenuText ;
2014-03-14 14:13:41 -04:00
}
void SSkeletonTree : : OnPreviewMeshChanged ( USkeletalMesh * NewPreviewMesh )
{
// Simply rebuild the tree
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
void SSkeletonTree : : RenameSocketAttachments ( FName & OldSocketName , FName & NewSocketName )
{
const FScopedTransaction Transaction ( LOCTEXT ( " RenameSocketAttachments " , " Rename Socket Attachments " ) ) ;
2014-07-14 10:03:53 -04:00
bool bSkeletonModified = false ;
2014-03-14 14:13:41 -04:00
for ( int AttachedObjectIndex = 0 ; AttachedObjectIndex < TargetSkeleton - > PreviewAttachedAssetContainer . Num ( ) ; + + AttachedObjectIndex )
{
FPreviewAttachedObjectPair & Pair = TargetSkeleton - > PreviewAttachedAssetContainer [ AttachedObjectIndex ] ;
if ( Pair . AttachedTo = = OldSocketName )
{
2014-07-14 10:03:53 -04:00
// Only modify the skeleton if we actually intend to change something.
if ( ! bSkeletonModified )
{
TargetSkeleton - > Modify ( ) ;
bSkeletonModified = true ;
}
2014-03-14 14:13:41 -04:00
Pair . AttachedTo = NewSocketName ;
}
2014-04-24 14:59:16 -04:00
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Pair . GetAttachedObject ( ) , OldSocketName ) ;
PersonaPtr . Pin ( ) - > AttachObjectToPreviewComponent ( Pair . GetAttachedObject ( ) , Pair . AttachedTo ) ;
2014-03-14 14:13:41 -04:00
}
if ( PersonaPtr . IsValid ( ) )
{
USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
if ( Mesh )
{
2014-07-14 10:03:53 -04:00
bool bMeshModified = false ;
2014-03-14 14:13:41 -04:00
for ( int AttachedObjectIndex = 0 ; AttachedObjectIndex < Mesh - > PreviewAttachedAssetContainer . Num ( ) ; + + AttachedObjectIndex )
{
FPreviewAttachedObjectPair & Pair = Mesh - > PreviewAttachedAssetContainer [ AttachedObjectIndex ] ;
if ( Pair . AttachedTo = = OldSocketName )
{
2014-07-14 10:03:53 -04:00
// Only modify the mesh if we actually intend to change something. Avoids dirtying
// meshes when we don't actually update any data on them. (such as adding a new socket)
if ( ! bMeshModified )
{
Mesh - > Modify ( ) ;
bMeshModified = true ;
}
2014-03-14 14:13:41 -04:00
Pair . AttachedTo = NewSocketName ;
}
2014-04-24 14:59:16 -04:00
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Pair . GetAttachedObject ( ) , OldSocketName ) ;
PersonaPtr . Pin ( ) - > AttachObjectToPreviewComponent ( Pair . GetAttachedObject ( ) , Pair . AttachedTo ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
bool SSkeletonTree : : IsAddingSocketsAllowed ( ) const
{
if ( SocketFilter = = ESocketFilter : : Skeleton | |
SocketFilter = = ESocketFilter : : Active | |
SocketFilter = = ESocketFilter : : All )
{
return true ;
}
return false ;
}
2014-10-30 12:29:36 -04:00
FReply SSkeletonTree : : OnKeyDown ( const FGeometry & MyGeometry , const FKeyEvent & InKeyEvent )
2014-03-14 14:13:41 -04:00
{
2014-10-30 12:29:36 -04:00
if ( UICommandList - > ProcessCommandBindings ( InKeyEvent ) )
2014-03-14 14:13:41 -04:00
{
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
void SSkeletonTree : : OnDeleteSelectedRows ( )
{
FBoneTreeSelection TreeSelection ( SkeletonTreeView - > GetSelectedItems ( ) ) ;
if ( TreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : AttachedAsset ) | | TreeSelection . HasSelectedOfType ( ESkeletonTreeRowType : : Socket ) )
{
FScopedTransaction Transaction ( LOCTEXT ( " SkeletonTreeDeleteSelected " , " Delete selected sockets/meshes/bones from skeleton tree " ) ) ;
DeleteAttachedAssets ( TreeSelection . SelectedAssets ) ;
DeleteSockets ( TreeSelection . SelectedSockets ) ;
CreateFromSkeleton ( TargetSkeleton - > GetBoneTree ( ) ) ;
}
}
void SSkeletonTree : : DeleteAttachedAssets ( TArray < TSharedPtr < FDisplayedAttachedAssetInfo > > InDisplayedAttachedAssetInfos )
{
TargetSkeleton - > Modify ( ) ;
for ( auto Iter = InDisplayedAttachedAssetInfos . CreateIterator ( ) ; Iter ; + + Iter )
{
TSharedPtr < FDisplayedAttachedAssetInfo > AttachedAssetInfo = ( * Iter ) ;
UObject * Asset = AttachedAssetInfo - > GetAsset ( ) ;
const FName & AttachedTo = AttachedAssetInfo - > GetParentName ( ) ;
TargetSkeleton - > PreviewAttachedAssetContainer . RemoveAttachedObject ( Asset , AttachedTo ) ;
if ( PersonaPtr . IsValid ( ) )
{
if ( USkeletalMesh * Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) )
{
Mesh - > Modify ( ) ;
Mesh - > PreviewAttachedAssetContainer . RemoveAttachedObject ( Asset , AttachedTo ) ;
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Asset , AttachedTo ) ;
}
}
}
}
void SSkeletonTree : : DeleteSockets ( TArray < TSharedPtr < FDisplayedSocketInfo > > InDisplayedSocketInfos )
{
USkeletalMesh * Mesh = NULL ;
if ( PersonaPtr . IsValid ( ) )
{
// Reset the sockets of interest in the Preview Mesh so we don't leave a null pointer dangling
PersonaPtr . Pin ( ) - > ClearSelectedSocket ( ) ;
PersonaPtr . Pin ( ) - > DeselectAll ( ) ;
Mesh = PersonaPtr . Pin ( ) - > GetMesh ( ) ;
}
for ( auto Iter = InDisplayedSocketInfos . CreateIterator ( ) ; Iter ; + + Iter )
{
TSharedPtr < FDisplayedSocketInfo > DisplayedSocketInfo = ( * Iter ) ;
USkeletalMeshSocket * SocketToDelete = static_cast < USkeletalMeshSocket * > ( DisplayedSocketInfo - > GetData ( ) ) ;
FName SocketName = SocketToDelete - > SocketName ;
if ( DisplayedSocketInfo - > GetParentType ( ) = = ESocketParentType : : Skeleton )
{
TargetSkeleton - > Modify ( ) ;
TargetSkeleton - > Sockets . Remove ( SocketToDelete ) ;
}
else
{
if ( Mesh )
{
UObject * Object = Mesh - > PreviewAttachedAssetContainer . GetAttachedObjectByAttachName ( DisplayedSocketInfo - > GetRowItemName ( ) ) ;
if ( Object )
{
Mesh - > Modify ( ) ;
Mesh - > PreviewAttachedAssetContainer . RemoveAttachedObject ( Object , SocketName ) ;
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Object , SocketName ) ;
}
Mesh - > GetMeshOnlySocketList ( ) . Remove ( SocketToDelete ) ;
}
}
// Remove attached assets
while ( UObject * Object = TargetSkeleton - > PreviewAttachedAssetContainer . GetAttachedObjectByAttachName ( SocketName ) )
{
TargetSkeleton - > Modify ( ) ;
TargetSkeleton - > PreviewAttachedAssetContainer . RemoveAttachedObject ( Object , SocketName ) ;
PersonaPtr . Pin ( ) - > RemoveAttachedObjectFromPreviewComponent ( Object , SocketName ) ;
}
}
}
void SSkeletonTree : : AddAttachedAssets ( const FPreviewAssetAttachContainer & AttachedObjects )
{
for ( auto Iter = AttachedObjects . CreateConstIterator ( ) ; Iter ; + + Iter )
{
const FPreviewAttachedObjectPair & Pair = ( * Iter ) ;
2014-04-24 14:59:16 -04:00
if ( ! FilterText . IsEmpty ( ) & & ! Pair . GetAttachedObject ( ) - > GetName ( ) . Contains ( FilterText . ToString ( ) ) )
2014-03-14 14:13:41 -04:00
{
continue ;
}
2014-04-24 14:59:16 -04:00
TSharedRef < FDisplayedAttachedAssetInfo > DisplayInfo = FDisplayedAttachedAssetInfo : : Make ( Pair . AttachedTo , Pair . GetAttachedObject ( ) , TargetSkeleton , PersonaPtr , SharedThis ( this ) ) ;
2014-03-14 14:13:41 -04:00
DisplayMirror . Add ( DisplayInfo ) ;
// for now it is a failure to not find where the asset is attached. Its possible that this might have to be changed to unloading the asset
// if there is a valid reason why the attach parent would not exist
if ( ! AttachToParent ( DisplayInfo , Pair . AttachedTo , ( ESkeletonTreeRowType : : Bone | ESkeletonTreeRowType : : Socket ) ) )
{
// Just add it to the list if the parent bone isn't currently displayed
SkeletonRowList . Add ( DisplayInfo ) ;
}
}
}
2015-02-16 11:22:48 -05:00
void SSkeletonTree : : OnChangeShowingAdvancedOptions ( ECheckBoxState NewState )
2014-07-11 15:14:21 -04:00
{
2015-02-16 11:22:48 -05:00
bShowingAdvancedOptions = NewState = = ECheckBoxState : : Checked ;
2014-10-17 12:43:25 -04:00
CreateTreeColumns ( ) ;
}
2015-02-16 11:22:48 -05:00
ECheckBoxState SSkeletonTree : : IsShowingAdvancedOptions ( ) const
2014-10-17 12:43:25 -04:00
{
2015-02-16 11:22:48 -05:00
return bShowingAdvancedOptions ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-07-11 15:14:21 -04:00
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE