Files
UnrealEngineUWP/Engine/Source/Editor/SkeletonEditor/Private/SkeletonTreeVirtualBoneItem.cpp
jose villarroel 262e9e63d3 Added virtual bone support to blend profiles
#jira none
[at]Louise.Rasmussen, [at]Thomas.Sarkanen
[FYI] Ray.Arnett, Aaron.Cox
#preflight 61b1084a5c61dba07bfe212c

#ROBOMERGE-AUTHOR: jose.villarroel
#ROBOMERGE-SOURCE: CL 18421025 in //UE5/Release-5.0/... via CL 18422624
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v897-18405271)

[CL 18422907 by jose villarroel in ue5-release-engine-test branch]
2021-12-09 14:52:34 -05:00

266 lines
8.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SkeletonTreeVirtualBoneItem.h"
#include "Widgets/Text/STextBlock.h"
#include "SSkeletonTreeRow.h"
#include "IPersonaPreviewScene.h"
#include "EditorStyleSet.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/SInlineEditableTextBlock.h"
#include "Containers/UnrealString.h"
#include "Animation/DebugSkelMeshComponent.h"
#include "Animation/BlendProfile.h"
#include "UObject/Package.h"
#define LOCTEXT_NAMESPACE "FSkeletonTreeVirtualBoneItem"
FSkeletonTreeVirtualBoneItem::FSkeletonTreeVirtualBoneItem(const FName& InBoneName, const TSharedRef<class ISkeletonTree>& InSkeletonTree)
: FSkeletonTreeItem(InSkeletonTree)
, BoneName(InBoneName)
{
static const FString BoneProxyPrefix(TEXT("VIRTUALBONEPROXY_"));
BoneProxy = NewObject<UBoneProxy>(GetTransientPackage(), *(BoneProxyPrefix + FString::Printf(TEXT("%p"), &InSkeletonTree.Get()) + InBoneName.ToString()));
BoneProxy->SetFlags(RF_Transactional);
BoneProxy->BoneName = InBoneName;
TSharedPtr<IPersonaPreviewScene> PreviewScene = InSkeletonTree->GetPreviewScene();
if (PreviewScene.IsValid())
{
BoneProxy->SkelMeshComponent = PreviewScene->GetPreviewMeshComponent();
}
}
EVisibility FSkeletonTreeVirtualBoneItem::GetLODIconVisibility() const
{
return EVisibility::Visible;
}
void FSkeletonTreeVirtualBoneItem::GenerateWidgetForNameColumn(TSharedPtr< SHorizontalBox > Box, const TAttribute<FText>& FilterText, FIsSelected InIsSelected)
{
const FSlateBrush* LODIcon = FAppStyle::Get().GetBrush("SkeletonTree.Bone");
Box->AddSlot()
.AutoWidth()
.Padding(FMargin(0.0f, 2.0f))
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SImage)
.ColorAndOpacity(this, &FSkeletonTreeVirtualBoneItem::GetBoneTextColor, InIsSelected)
.Image(LODIcon)
.Visibility(this, &FSkeletonTreeVirtualBoneItem::GetLODIconVisibility)
];
FText ToolTip = GetBoneToolTip();
TAttribute<FText> NameAttr = TAttribute<FText>::Create(TAttribute<FText>::FGetter::CreateSP(this, &FSkeletonTreeVirtualBoneItem::GetVirtualBoneNameAsText));
InlineWidget = SNew(SInlineEditableTextBlock)
.ColorAndOpacity(this, &FSkeletonTreeVirtualBoneItem::GetBoneTextColor, InIsSelected)
.Text(NameAttr)
.HighlightText(FilterText)
.Font(this, &FSkeletonTreeVirtualBoneItem::GetBoneTextFont)
.ToolTipText(ToolTip)
.OnEnterEditingMode(this, &FSkeletonTreeVirtualBoneItem::OnVirtualBoneNameEditing)
.OnVerifyTextChanged(this, &FSkeletonTreeVirtualBoneItem::OnVerifyBoneNameChanged)
.OnTextCommitted(this, &FSkeletonTreeVirtualBoneItem::OnCommitVirtualBoneName)
.IsSelected(InIsSelected);
OnRenameRequested.BindSP(InlineWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);
Box->AddSlot()
.AutoWidth()
.Padding(4, 0, 0, 0)
[
SNew(STextBlock)
.ColorAndOpacity(this, &FSkeletonTreeVirtualBoneItem::GetBoneTextColor, InIsSelected)
.Text(FText::FromString(VirtualBoneNameHelpers::VirtualBonePrefix))
.Font(this, &FSkeletonTreeVirtualBoneItem::GetBoneTextFont)
.Visibility(this, &FSkeletonTreeVirtualBoneItem::GetVirtualBonePrefixVisibility)
];
Box->AddSlot()
.Padding(4, 0, 0, 0)
.AutoWidth()
[
InlineWidget.ToSharedRef()
];
}
TSharedRef< SWidget > FSkeletonTreeVirtualBoneItem::GenerateWidgetForDataColumn(const FName& DataColumnName, FIsSelected InIsSelected)
{
if (DataColumnName == ISkeletonTree::Columns::BlendProfile)
{
return SNew(SBox)
.Padding(0.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SNew(SSpinBox<float>)
.Visibility(this, &FSkeletonTreeVirtualBoneItem::GetBoneBlendProfileVisibility)
.Style(&FAppStyle::Get(), "SkeletonTree.HyperlinkSpinBox")
.Font(FAppStyle::Get().GetFontStyle("SmallFont"))
.ContentPadding(0.0f)
.Delta(0.01f)
.MinValue(0.0f)
.MinSliderValue(this, &FSkeletonTreeVirtualBoneItem::GetBlendProfileMinSliderValue)
.MaxSliderValue(this, &FSkeletonTreeVirtualBoneItem::GetBlendProfileMaxSliderValue)
.Value(this, &FSkeletonTreeVirtualBoneItem::GetBoneBlendProfileScale)
.OnValueCommitted(this, &FSkeletonTreeVirtualBoneItem::OnBlendSliderCommitted)
.OnValueChanged(this, &FSkeletonTreeVirtualBoneItem::OnBlendSliderCommitted, ETextCommit::OnEnter)
];
}
return SNullWidget::NullWidget;
}
EVisibility FSkeletonTreeVirtualBoneItem::GetBoneBlendProfileVisibility() const
{
return GetSkeletonTree()->GetSelectedBlendProfile() ? EVisibility::Visible : EVisibility::Collapsed;
}
float FSkeletonTreeVirtualBoneItem::GetBoneBlendProfileScale() const
{
if (UBlendProfile* CurrentProfile = GetSkeletonTree()->GetSelectedBlendProfile())
{
return CurrentProfile->GetBoneBlendScale(BoneName);
}
return 0.0;
}
TOptional<float> FSkeletonTreeVirtualBoneItem::GetBlendProfileMaxSliderValue() const
{
if (UBlendProfile* CurrentProfile = GetSkeletonTree()->GetSelectedBlendProfile())
{
return (CurrentProfile->GetMode() == EBlendProfileMode::WeightFactor) ? 10.0f : 1.0f;
}
return 1.0f;
}
TOptional<float> FSkeletonTreeVirtualBoneItem::GetBlendProfileMinSliderValue() const
{
if (UBlendProfile* CurrentProfile = GetSkeletonTree()->GetSelectedBlendProfile())
{
return (CurrentProfile->GetMode() == EBlendProfileMode::WeightFactor) ? 1.0f : 0.0f;
}
return 0.0f;
}
void FSkeletonTreeVirtualBoneItem::OnBlendSliderCommitted(float NewValue, ETextCommit::Type CommitType)
{
SetBoneBlendProfileScale(NewValue, false);
}
void FSkeletonTreeVirtualBoneItem::SetBoneBlendProfileScale(float NewScale, bool bRecurse)
{
FName BlendProfileName = GetSkeletonTree()->GetSelectedBlendProfile()->GetFName();
GetEditableSkeleton()->SetBlendProfileScale(BlendProfileName, BoneName, NewScale, bRecurse);
}
FSlateFontInfo FSkeletonTreeVirtualBoneItem::GetBoneTextFont() const
{
return FEditorStyle::GetWidgetStyle<FTextBlockStyle>("SkeletonTree.NormalFont").Font;
}
FSlateColor FSkeletonTreeVirtualBoneItem::GetBoneTextColor(FIsSelected InIsSelected) const
{
bool bIsSelected = false;
if (InIsSelected.IsBound())
{
bIsSelected = InIsSelected.Execute();
}
if(bIsSelected)
{
return FSlateColor::UseForeground();
}
else
{
return FSlateColor(FLinearColor(0.4f, 0.4f, 1.f));
}
}
FText FSkeletonTreeVirtualBoneItem::GetBoneToolTip()
{
return LOCTEXT("VirtualBone_ToolTip", "Virtual Bones are added in editor and allow space switching between two different bones in the skeleton.");
}
void FSkeletonTreeVirtualBoneItem::OnItemDoubleClicked()
{
OnRenameRequested.ExecuteIfBound();
}
void FSkeletonTreeVirtualBoneItem::RequestRename()
{
OnRenameRequested.ExecuteIfBound();
}
void FSkeletonTreeVirtualBoneItem::OnVirtualBoneNameEditing()
{
CachedBoneNameForRename = BoneName;
BoneName = VirtualBoneNameHelpers::RemoveVirtualBonePrefix(BoneName.ToString());
}
bool FSkeletonTreeVirtualBoneItem::OnVerifyBoneNameChanged(const FText& InText, FText& OutErrorMessage)
{
bool bVerifyName = true;
FString InTextTrimmed = FText::TrimPrecedingAndTrailing(InText).ToString();
FString NewName = VirtualBoneNameHelpers::AddVirtualBonePrefix(InTextTrimmed);
if (InTextTrimmed.IsEmpty())
{
OutErrorMessage = LOCTEXT("EmptyVirtualBoneName_Error", "Virtual bones must have a name!");
bVerifyName = false;
}
else
{
if(InTextTrimmed != BoneName.ToString())
{
bVerifyName = !GetEditableSkeleton()->DoesVirtualBoneAlreadyExist(NewName);
// Needs to be checked on verify.
if (!bVerifyName)
{
// Tell the user that the name is a duplicate
OutErrorMessage = LOCTEXT("DuplicateVirtualBone_Error", "Name in use!");
bVerifyName = false;
}
}
}
return bVerifyName;
}
void FSkeletonTreeVirtualBoneItem::OnCommitVirtualBoneName(const FText& InText, ETextCommit::Type CommitInfo)
{
FString NewNameString = VirtualBoneNameHelpers::AddVirtualBonePrefix(FText::TrimPrecedingAndTrailing(InText).ToString());
FName NewName(*NewNameString);
// Notify skeleton tree of rename
GetEditableSkeleton()->RenameVirtualBone(CachedBoneNameForRename, NewName);
BoneName = NewName;
}
EVisibility FSkeletonTreeVirtualBoneItem::GetVirtualBonePrefixVisibility() const
{
return InlineWidget->IsInEditMode() ? EVisibility::Visible : EVisibility::Collapsed;
}
void FSkeletonTreeVirtualBoneItem::EnableBoneProxyTick(bool bEnable)
{
BoneProxy->bIsTickable = bEnable;
}
void FSkeletonTreeVirtualBoneItem::AddReferencedObjects( FReferenceCollector& Collector )
{
Collector.AddReferencedObject(BoneProxy);
}
#undef LOCTEXT_NAMESPACE