You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
267 lines
8.4 KiB
C++
267 lines
8.4 KiB
C++
|
|
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||
|
|
|
||
|
|
#include "SAnimationModifierContentBrowserWindow.h"
|
||
|
|
#include "AnimationModifierHelpers.h"
|
||
|
|
#include "Widgets/SOverlay.h"
|
||
|
|
#include "Widgets/SBoxPanel.h"
|
||
|
|
#include "Widgets/Layout/SBorder.h"
|
||
|
|
#include "Widgets/Layout/SUniformGridPanel.h"
|
||
|
|
#include "Widgets/Input/SComboButton.h"
|
||
|
|
#include "Widgets/Text/STextBlock.h"
|
||
|
|
|
||
|
|
#include "EditorStyleSet.h"
|
||
|
|
#include "SModifierListview.h"
|
||
|
|
#include "PropertyEditorModule.h"
|
||
|
|
|
||
|
|
#include "Animation/AnimSequence.h"
|
||
|
|
#include "AnimationModifiersAssetUserData.h"
|
||
|
|
#include "Dialogs/Dialogs.h"
|
||
|
|
#include "ScopedTransaction.h"
|
||
|
|
|
||
|
|
#define LOCTEXT_NAMESPACE "AnimationModifierContentBrowserWindow"
|
||
|
|
|
||
|
|
void SAnimationModifierContentBrowserWindow::Construct(const FArguments& InArgs)
|
||
|
|
{
|
||
|
|
CreateInstanceDetailsView();
|
||
|
|
|
||
|
|
WidgetWindow = InArgs._WidgetWindow;
|
||
|
|
AnimSequences = InArgs._AnimSequences;
|
||
|
|
|
||
|
|
FOnGetContent GetContent = FOnGetContent::CreateLambda(
|
||
|
|
[this]()
|
||
|
|
{
|
||
|
|
return FAnimationModifierHelpers::GetModifierPicker(FOnClassPicked::CreateRaw(this, &SAnimationModifierContentBrowserWindow::OnModifierPicked));
|
||
|
|
});
|
||
|
|
|
||
|
|
this->ChildSlot
|
||
|
|
[
|
||
|
|
SNew(SOverlay)
|
||
|
|
+SOverlay::Slot()
|
||
|
|
[
|
||
|
|
SNew(SVerticalBox)
|
||
|
|
+ SVerticalBox::Slot()
|
||
|
|
.AutoHeight()
|
||
|
|
[
|
||
|
|
SNew(SBorder)
|
||
|
|
.Padding(2.0f)
|
||
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
||
|
|
[
|
||
|
|
SNew(SHorizontalBox)
|
||
|
|
+ SHorizontalBox::Slot()
|
||
|
|
.Padding(3.0f, 3.0f)
|
||
|
|
.AutoWidth()
|
||
|
|
[
|
||
|
|
SAssignNew(AddModifierCombobox, SComboButton)
|
||
|
|
.OnGetMenuContent(GetContent)
|
||
|
|
.ButtonContent()
|
||
|
|
[
|
||
|
|
SNew(STextBlock)
|
||
|
|
.Text(LOCTEXT("AnimationModifierWindow_AddModifier", "Add Modifier"))
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]
|
||
|
|
|
||
|
|
+ SVerticalBox::Slot()
|
||
|
|
[
|
||
|
|
SNew(SBorder)
|
||
|
|
.Padding(2.0f)
|
||
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
||
|
|
[
|
||
|
|
SNew(SSplitter)
|
||
|
|
.Orientation(EOrientation::Orient_Vertical)
|
||
|
|
|
||
|
|
+ SSplitter::Slot()
|
||
|
|
.Value(.5f)
|
||
|
|
[
|
||
|
|
SNew(SBox)
|
||
|
|
.Padding(2.0f)
|
||
|
|
[
|
||
|
|
SAssignNew(ModifierListView, SModifierListView)
|
||
|
|
.Items(&ModifierItems)
|
||
|
|
.InstanceDetailsView(ModifierInstanceDetailsView)
|
||
|
|
.OnRemoveModifier(FOnModifierArray::CreateSP(this, &SAnimationModifierContentBrowserWindow::RemoveModifiersCallback))
|
||
|
|
]
|
||
|
|
]
|
||
|
|
|
||
|
|
+ SSplitter::Slot()
|
||
|
|
.Value(.5f)
|
||
|
|
[
|
||
|
|
SNew(SBox)
|
||
|
|
.Padding(2.0f)
|
||
|
|
[
|
||
|
|
ModifierInstanceDetailsView->AsShared()
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]
|
||
|
|
|
||
|
|
+ SVerticalBox::Slot()
|
||
|
|
.AutoHeight()
|
||
|
|
.HAlign(HAlign_Right)
|
||
|
|
.Padding(2)
|
||
|
|
[
|
||
|
|
SNew(SUniformGridPanel)
|
||
|
|
.SlotPadding(2)
|
||
|
|
+ SUniformGridPanel::Slot(0, 0)
|
||
|
|
[
|
||
|
|
SNew(SButton)
|
||
|
|
.HAlign(HAlign_Center)
|
||
|
|
.Text(LOCTEXT("AnimationModifierWindow_Import", "Apply"))
|
||
|
|
.ToolTipText(LOCTEXT("AnimationModifierWindow_Import_ToolTip", "Apply adding modifiers(s)."))
|
||
|
|
.IsEnabled(this, &SAnimationModifierContentBrowserWindow::CanApply)
|
||
|
|
.OnClicked(this, &SAnimationModifierContentBrowserWindow::OnApply)
|
||
|
|
]
|
||
|
|
+ SUniformGridPanel::Slot(1, 0)
|
||
|
|
[
|
||
|
|
SNew(SButton)
|
||
|
|
.HAlign(HAlign_Center)
|
||
|
|
.Text(LOCTEXT("AnimationModifierWindow_Cancel", "Cancel"))
|
||
|
|
.ToolTipText(LOCTEXT("AnimationModifierWindow_Cancel_ToolTip", "Cancels adding modifiers(s)."))
|
||
|
|
.OnClicked(this, &SAnimationModifierContentBrowserWindow::OnCancel)
|
||
|
|
]
|
||
|
|
]
|
||
|
|
]
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
FReply SAnimationModifierContentBrowserWindow::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
|
||
|
|
{
|
||
|
|
if (InKeyEvent.GetKey() == EKeys::Escape)
|
||
|
|
{
|
||
|
|
return OnCancel();
|
||
|
|
}
|
||
|
|
|
||
|
|
return FReply::Unhandled();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SAnimationModifierContentBrowserWindow::RemoveModifiersCallback(const TArray<TWeakObjectPtr<UAnimationModifier>>& ModifiersToRemove)
|
||
|
|
{
|
||
|
|
Modifiers.RemoveAll([&ModifiersToRemove](UAnimationModifier* Modifier) { return ModifiersToRemove.Contains(Modifier); });
|
||
|
|
ModifierItems.RemoveAll([&ModifiersToRemove](TSharedPtr<FModifierListviewItem> ModifierItem) { return ModifiersToRemove.Contains(ModifierItem->Instance); });
|
||
|
|
ModifierListView->Refresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SAnimationModifierContentBrowserWindow::OnModifierPicked(UClass* PickedClass)
|
||
|
|
{
|
||
|
|
UAnimationModifier* Processor = FAnimationModifierHelpers::CreateModifierInstance(GetTransientPackage(), PickedClass);
|
||
|
|
|
||
|
|
Modifiers.Add(Processor);
|
||
|
|
|
||
|
|
FModifierListviewItem* Item = new FModifierListviewItem();
|
||
|
|
Item->Instance = Processor;
|
||
|
|
Item->Class = Processor->GetClass();
|
||
|
|
Item->Index = Modifiers.Num() - 1;
|
||
|
|
Item->OuterClass = nullptr;
|
||
|
|
ModifierItems.Add(ModifierListviewItem(Item));
|
||
|
|
|
||
|
|
// Close the combo box
|
||
|
|
AddModifierCombobox->SetIsOpen(false);
|
||
|
|
|
||
|
|
ModifierListView->Refresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SAnimationModifierContentBrowserWindow::CreateInstanceDetailsView()
|
||
|
|
{
|
||
|
|
// Create a property view
|
||
|
|
FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
||
|
|
|
||
|
|
FDetailsViewArgs DetailsViewArgs(
|
||
|
|
/*bUpdateFromSelection=*/ false,
|
||
|
|
/*bLockable=*/ false,
|
||
|
|
/*bAllowSearch=*/ false,
|
||
|
|
FDetailsViewArgs::HideNameArea,
|
||
|
|
/*bHideSelectionTip=*/ true,
|
||
|
|
/*InNotifyHook=*/ nullptr,
|
||
|
|
/*InSearchInitialKeyFocus=*/ false,
|
||
|
|
/*InViewIdentifier=*/ NAME_None);
|
||
|
|
DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Automatic;
|
||
|
|
DetailsViewArgs.bShowOptions = false;
|
||
|
|
|
||
|
|
ModifierInstanceDetailsView = EditModule.CreateDetailView(DetailsViewArgs);
|
||
|
|
ModifierInstanceDetailsView->SetDisableCustomDetailLayouts(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
FReply SAnimationModifierContentBrowserWindow::OnApply()
|
||
|
|
{
|
||
|
|
const FScopedTransaction Transaction(LOCTEXT("UndoAction_ApplyModifiers", "Applying Animation Modifier(s) to Animation Sequence(s)"));
|
||
|
|
|
||
|
|
TArray<UAnimationModifiersAssetUserData*> AssetUserData;
|
||
|
|
|
||
|
|
bool bCloseWindow = true;
|
||
|
|
|
||
|
|
// Retrieve or create asset user data
|
||
|
|
for (UAnimSequence* AnimationSequence : AnimSequences)
|
||
|
|
{
|
||
|
|
UAnimationModifiersAssetUserData* UserData = AnimationSequence->GetAssetUserData<UAnimationModifiersAssetUserData>();
|
||
|
|
if (!UserData)
|
||
|
|
{
|
||
|
|
UserData = NewObject<UAnimationModifiersAssetUserData>(AnimationSequence, UAnimationModifiersAssetUserData::StaticClass());
|
||
|
|
checkf(UserData, TEXT("Unable to instantiate AssetUserData class"));
|
||
|
|
UserData->SetFlags(RF_Transactional);
|
||
|
|
AnimationSequence->AddAssetUserData(UserData);
|
||
|
|
}
|
||
|
|
|
||
|
|
AssetUserData.Add(UserData);
|
||
|
|
}
|
||
|
|
|
||
|
|
// For each added modifier create add a new instance to each of the user data entries, using the one(s) set up in the window as template(s)
|
||
|
|
for (UAnimationModifier* Modifier : Modifiers)
|
||
|
|
{
|
||
|
|
for (UAnimationModifiersAssetUserData* UserData : AssetUserData)
|
||
|
|
{
|
||
|
|
const bool bAlreadyContainsModifier = UserData->GetAnimationModifierInstances().ContainsByPredicate([Modifier](UAnimationModifier* TestModifier) { return Modifier->GetClass() == TestModifier->GetClass(); });
|
||
|
|
static const FText MessageFormat = LOCTEXT("AnimationModifierWindow_AlreadyContainsModifierDialogText", "{0} already contains Animation Modifier {1}, are you sure you want to add another instance?");
|
||
|
|
|
||
|
|
const bool bUserInputResult = bAlreadyContainsModifier ? OpenMsgDlgInt(EAppMsgType::YesNo, FText::FormatOrdered(MessageFormat, FText::FromString(UserData->GetOuter()->GetName()), FText::FromString(Modifier->GetClass()->GetName())), LOCTEXT("AnimationModifierWindow_AlreadyContainsModifierTitle", "Already contains Animation Modifier!")) == EAppReturnType::Yes : true;
|
||
|
|
bCloseWindow = bUserInputResult;
|
||
|
|
if (!bAlreadyContainsModifier || bUserInputResult)
|
||
|
|
{
|
||
|
|
UObject* Outer = UserData;
|
||
|
|
UAnimationModifier* Processor = FAnimationModifierHelpers::CreateModifierInstance(Outer, Modifier->GetClass(), Modifier);
|
||
|
|
UserData->Modify();
|
||
|
|
UserData->AddAnimationModifier(Processor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** For each user data retrieve all modifiers and apply them */
|
||
|
|
for (int32 Index = 0; Index < AssetUserData.Num(); ++Index)
|
||
|
|
{
|
||
|
|
UAnimationModifiersAssetUserData* UserData = AssetUserData[Index];
|
||
|
|
if (UserData)
|
||
|
|
{
|
||
|
|
UAnimSequence* AnimSequence = AnimSequences[Index];
|
||
|
|
AnimSequence->Modify();
|
||
|
|
|
||
|
|
const TArray<UAnimationModifier*>& ModifierInstances = UserData->GetAnimationModifierInstances();
|
||
|
|
for (UAnimationModifier* Modifier : ModifierInstances)
|
||
|
|
{
|
||
|
|
Modifier->ApplyToAnimationSequence(AnimSequence);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bCloseWindow && WidgetWindow.IsValid())
|
||
|
|
{
|
||
|
|
WidgetWindow.Pin()->RequestDestroyWindow();
|
||
|
|
}
|
||
|
|
|
||
|
|
return FReply::Handled();
|
||
|
|
}
|
||
|
|
|
||
|
|
FReply SAnimationModifierContentBrowserWindow::OnCancel()
|
||
|
|
{
|
||
|
|
if (WidgetWindow.IsValid())
|
||
|
|
{
|
||
|
|
WidgetWindow.Pin()->RequestDestroyWindow();
|
||
|
|
}
|
||
|
|
return FReply::Handled();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SAnimationModifierContentBrowserWindow::CanApply() const
|
||
|
|
{
|
||
|
|
return Modifiers.Num() > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#undef LOCTEXT_NAMESPACE // "AnimationModifierContentBrowserWindow"
|