Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Public/SSkeletonWidget.h
2025-05-18 13:04:45 +08:00

461 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Animation/Skeleton.h"
#include "CoreMinimal.h"
#include "IContentBrowserSingleton.h"
#include "Input/Reply.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SWidget.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/SWindow.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Views/STableViewBase.h"
#include "Widgets/Views/STableRow.h"
#include "Widgets/Views/SListView.h"
#include "Styling/AppStyle.h"
#include "AssetRegistry/AssetData.h"
#include "Widgets/Layout/SUniformGridPanel.h"
#include "PreviewScene.h"
#include "EditorViewportClient.h"
#include "SEditorViewport.h"
#include "EditorAnimUtils.h"
class UAnimSet;
class USkeletalMesh;
using namespace EditorAnimUtils;
/**
* This below code is to select skeleton from the list
*/
#define LOCTEXT_NAMESPACE "SkeletonWidget"
struct FBoneTrackPair
{
FName Bone1;
FName Bone2;
FBoneTrackPair(FName InBone1, FName InBone2)
: Bone1(InBone1)
, Bone2(InBone2)
{
}
};
class SBonePairRow : public SMultiColumnTableRow< TSharedPtr<FBoneTrackPair> >
{
public:
SLATE_BEGIN_ARGS(SBonePairRow){}
SLATE_ARGUMENT( TSharedPtr<FBoneTrackPair>, BonePair)
SLATE_END_ARGS()
/**
* Construct child widgets that comprise this widget.
*
* @param InArgs Declaration from which to construct this widget
*/
void Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView )
{
this->BonePair = InArgs._BonePair;
SMultiColumnTableRow< TSharedPtr<FBoneTrackPair> >::Construct( FSuperRowType::FArguments(), InOwnerTableView );
}
virtual TSharedRef<SWidget> GenerateWidgetForColumn( const FName& ColumnName ) override
{
TSharedPtr<SBorder> Border1, Border2;
if (ColumnName == TEXT("Curretly Selected"))
{
return SAssignNew(Border1, SBorder) .Padding(2.f)
.Content()
[
SNew(STextBlock)
.Text(FText::FromName(BonePair->Bone1))
];
}
else
{
if (BonePair->Bone2 == NAME_None)
{
return SAssignNew(Border2, SBorder) .Padding(2.f)
.ColorAndOpacity(FLinearColor(1.f, 0.f, 0.f))
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("MissingBone", "Missing"))
];
}
else
{
return SAssignNew(Border2, SBorder) .Padding(2.f)
.Content()
[
SNew(STextBlock)
.Text(FText::FromName(BonePair->Bone2))
];
}
}
}
private:
TSharedPtr<FBoneTrackPair> BonePair;
};
class SSkeletonWidget : public SCompoundWidget
{
public:
USkeleton* GetSelectedSkeleton() const
{
return CurSelectedSkeleton;
}
protected:
USkeleton* CurSelectedSkeleton;
};
/** 1 columns - just show bone list **/
class SSkeletonListWidget : public SSkeletonWidget
{
public:
SLATE_BEGIN_ARGS( SSkeletonListWidget ){}
SLATE_ARGUMENT(bool, ShowBones)
SLATE_ARGUMENT(EAssetViewType::Type, InitialViewType)
SLATE_END_ARGS()
public:
// WIDGETS
void Construct(const FArguments& InArgs);
void SkeletonSelectionChanged(const FAssetData& AssetData);
TSharedRef<ITableRow> GenerateSkeletonRow( USkeleton* InSkeleton, const TSharedRef<STableViewBase>& OwnerTable )
{
return
SNew( STableRow< USkeleton* >, OwnerTable )
. Content()
[
SNew(STextBlock)
.Text(FText::FromString(InSkeleton->GetFullName()))
];
}
TSharedRef<ITableRow> GenerateSkeletonBoneRow( TSharedPtr<FName> InBoneName, const TSharedRef<STableViewBase>& OwnerTable )
{
return
SNew( STableRow< TSharedPtr<FName> >, OwnerTable )
. Content()
[
SNew(STextBlock)
.Text(FText::FromName(*InBoneName))
];
}
private:
bool bShowBones = true;
EAssetViewType::Type InitialViewType = EAssetViewType::Column;
SVerticalBox::FSlot* BoneListSlot;
TArray< TSharedPtr<FName> > BoneList;
};
/** 2 columns - bone pair widget **/
class SSkeletonCompareWidget : public SSkeletonWidget
{
public:
SLATE_BEGIN_ARGS( SSkeletonCompareWidget )
: _Object(NULL)
{}
SLATE_ARGUMENT( UObject*, Object )
SLATE_ARGUMENT( TArray<FName>*, BoneNames )
SLATE_END_ARGS()
public:
// WIDGETS
void Construct(const FArguments& InArgs);
void SkeletonSelectionChanged(const FAssetData& AssetData);
TSharedRef<ITableRow> GenerateBonePairRow( TSharedPtr<FBoneTrackPair> InBonePair, const TSharedRef<STableViewBase>& OwnerTable )
{
return
SNew( SBonePairRow, OwnerTable )
.BonePair(InBonePair);
}
private:
TArray<FName> BoneNames;
SVerticalBox::FSlot * BonePairSlot;
TArray< TSharedPtr<FBoneTrackPair> > BonePairList;
};
class SSkeletonSelectorWindow : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS( SSkeletonSelectorWindow )
: _Object(NULL)
{}
SLATE_ARGUMENT( UObject*, Object )
SLATE_ARGUMENT( TSharedPtr<SWindow>, WidgetWindow )
SLATE_END_ARGS()
public:
UNREALED_API void Construct(const FArguments& InArgs);
void ConstructWindowFromAnimSet(UAnimSet* InAnimSet);
void ConstructWindowFromMesh(USkeletalMesh* InSkeletalMesh);
void ConstructWindowFromAnimBlueprint(UAnimBlueprint* AnimBlueprint);
void ConstructWindow();
void ConstructButtons(TSharedRef<SVerticalBox> ParentBox)
{
ParentBox->AddSlot()
.AutoHeight()
.HAlign(HAlign_Right)
.VAlign(VAlign_Bottom)
[
SNew(SUniformGridPanel)
.SlotPadding(FAppStyle::GetMargin("StandardDialog.SlotPadding"))
.MinDesiredSlotWidth(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
.MinDesiredSlotHeight(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotHeight"))
+SUniformGridPanel::Slot(0,0)
[
SNew(SButton)
.Text(LOCTEXT("Accept", "Accept"))
.HAlign(HAlign_Center)
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
.OnClicked_Raw( this, &SSkeletonSelectorWindow::OnAccept )
]
+SUniformGridPanel::Slot(1,0)
[
SNew(SButton)
.Text(LOCTEXT("Cancel", "Cancel"))
.HAlign(HAlign_Center)
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
.OnClicked_Raw( this, &SSkeletonSelectorWindow::OnCancel )
]
];
}
FReply OnAccept()
{
SelectedSkeleton = SkeletonWidget->GetSelectedSkeleton();
if (SelectedSkeleton!=NULL && WidgetWindow.IsValid())
{
WidgetWindow.Pin()->RequestDestroyWindow();
}
return FReply::Handled();
}
FReply OnCancel()
{
if ( WidgetWindow.IsValid() )
{
WidgetWindow.Pin()->RequestDestroyWindow();
}
return FReply::Handled();
}
USkeleton* GetSelectedSkeleton()
{
return SelectedSkeleton;
}
private:
TSharedPtr<SSkeletonWidget> SkeletonWidget;
TWeakPtr<SWindow> WidgetWindow;
USkeleton * SelectedSkeleton;
};
//////////////////////////
class SBasePoseViewport: public /*SCompoundWidget*/SEditorViewport
{
public:
SLATE_BEGIN_ARGS(SBasePoseViewport)
{}
SLATE_ARGUMENT(USkeleton*, Skeleton)
SLATE_END_ARGS()
public:
SBasePoseViewport();
void Construct(const FArguments& InArgs);
void SetSkeleton(USkeleton* Skeleton);
protected:
/** SEditorViewport interface */
virtual TSharedRef<FEditorViewportClient> MakeEditorViewportClient() override;
virtual TSharedPtr<SWidget> MakeViewportToolbar() override;
private:
/** Skeleton */
USkeleton* TargetSkeleton;
FPreviewScene PreviewScene;
class UDebugSkelMeshComponent* PreviewComponent;
bool IsVisible() const override;
};
//////////////////////////////////////////////////////////////////////////
class FDisplayedAssetEntryInfo
{
public:
USkeleton* NewSkeleton;
UObject* AnimAsset;
UObject* RemapAsset;
static TSharedRef<FDisplayedAssetEntryInfo> Make(UObject* InAsset, USkeleton* InNewSkeleton);
protected:
FDisplayedAssetEntryInfo(){};
FDisplayedAssetEntryInfo(UObject* InAsset, USkeleton* InNewSkeleton);
};
/////////////////////////////////////////////
/**
* Slate panel for choose displaying bones to remove
*/
class SSkeletonBoneRemoval : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SSkeletonBoneRemoval){}
/** The bones to remove (for list display) */
SLATE_ARGUMENT( TArray<FName>, BonesToRemove )
/** The window this panel has been placed in */
SLATE_ARGUMENT( TSharedPtr<SWindow>, WidgetWindow )
/** Message to display to the user */
SLATE_ARGUMENT( FText, WarningMessage )
SLATE_END_ARGS()
/**
* Constructs this widget
*
* @param InArgs The declaration data for this widget
*/
void Construct( const FArguments& InArgs );
/** Reference to our window */
TWeakPtr<SWindow> WidgetWindow;
/** Button Handlers */
FReply OnOk();
FReply OnCancel();
/** Handle closing to dialog window */
void CloseWindow();
/** Create an individual row for the bone name list */
TSharedRef<ITableRow> GenerateSkeletonBoneRow( TSharedPtr<FName> InBoneName, const TSharedRef<STableViewBase>& OwnerTable )
{
return
SNew( STableRow< TSharedPtr<FName> >, OwnerTable )
. Content()
[
SNew(STextBlock)
.Text(FText::FromName(*InBoneName))
];
}
/**
* Show Modal window
*
* @param BonesToRemove List of bones that will be removed
* @param WarningMessage Message to display to the user so they know what is going on
*
* @return true if successfully selected new skeleton
*/
static UNREALED_API bool ShowModal(const TArray<FName> BonesToRemove, const FText& WarningMessage);
/** Did the user choose to continue */
bool bShouldContinue;
/** List of bone names that will be removed */
TArray< TSharedPtr<FName> > BoneNames;
};
class SSelectFolderDlg: public SWindow
{
public:
SLATE_BEGIN_ARGS(SSelectFolderDlg)
{
}
SLATE_ARGUMENT(FText, DefaultAssetPath)
SLATE_END_ARGS()
SSelectFolderDlg()
: UserResponse(EAppReturnType::Cancel)
{
}
void Construct(const FArguments& InArgs);
public:
/** Displays the dialog in a blocking fashion */
EAppReturnType::Type ShowModal();
/** Gets the resulting asset path */
FString GetAssetPath();
protected:
void OnPathChange(const FString& NewPath);
FReply OnButtonClick(EAppReturnType::Type ButtonID);
EAppReturnType::Type UserResponse;
FText AssetPath;
};
class SReplaceMissingSkeletonDialog : public SWindow
{
public:
SLATE_BEGIN_ARGS(SReplaceMissingSkeletonDialog)
{
}
SLATE_ARGUMENT(TArray<TWeakObjectPtr<UObject>>, AnimAssets)
SLATE_END_ARGS()
void UNREALED_API Construct(const FArguments& InArgs);
SReplaceMissingSkeletonDialog()
: UserResponse(EAppReturnType::Cancel)
, bWasSkeletonReplaced(false)
{
}
bool UNREALED_API ShowModal();
protected:
void OnSkeletonSelected(const FAssetData& Replacement);
FReply OnButtonClick(EAppReturnType::Type ButtonID);
EAppReturnType::Type UserResponse;
FAssetData SelectedAsset;
TArray<TWeakObjectPtr<UObject>> AssetsToReplaceSkeletonOn;
bool bWasSkeletonReplaced;
};
#undef LOCTEXT_NAMESPACE