You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Copying //Tasks/UE5/Dev-SequencerMVVM2 to Main (//UE5/Main) @20364093 #preflight 628866dfb94f739b152c1e29 #preflight 628866e4585e8f793ee80943 #rb ludovic.chabant, andrew.rodham #fyi ludovic.chabant, andrew.rodham, andrew.porter #jira UE-105322 [CL 20364493 by Max Chen in ue5-main branch]
333 lines
12 KiB
C++
333 lines
12 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "IKeyArea.h"
|
|
#include "ISequencerModule.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Widgets/SNullWidget.h"
|
|
#include "ISequencerChannelInterface.h"
|
|
#include "SequencerClipboardReconciler.h"
|
|
#include "Tracks/MovieScenePropertyTrack.h"
|
|
#include "Channels/MovieSceneChannel.h"
|
|
#include "Channels/MovieSceneChannelProxy.h"
|
|
#include "CurveModel.h"
|
|
#include "ISequencer.h"
|
|
#include "ISequencerSection.h"
|
|
#include "MovieSceneSequence.h"
|
|
#include "CurveEditorSettings.h"
|
|
|
|
IKeyArea::IKeyArea(TWeakPtr<ISequencerSection> InSection, FMovieSceneChannelHandle InChannel)
|
|
: TreeSerialNumber(0)
|
|
, ChannelHandle(InChannel)
|
|
{
|
|
Reinitialize(InSection, InChannel);
|
|
}
|
|
|
|
void IKeyArea::Reinitialize(TWeakPtr<ISequencerSection> InSection, FMovieSceneChannelHandle InChannel)
|
|
{
|
|
WeakSection = InSection;
|
|
ChannelHandle = InChannel;
|
|
Color = FLinearColor::White;
|
|
|
|
if (const FMovieSceneChannelMetaData* MetaData = ChannelHandle.GetMetaData())
|
|
{
|
|
Color = MetaData->Color;
|
|
ChannelName = MetaData->Name;
|
|
DisplayText = MetaData->DisplayText;
|
|
}
|
|
|
|
UMovieSceneSection* SectionObject = InSection.Pin()->GetSectionObject();
|
|
UMovieScenePropertyTrack* PropertyTrack = SectionObject->GetTypedOuter<UMovieScenePropertyTrack>();
|
|
if (PropertyTrack && PropertyTrack->GetPropertyPath() != NAME_None)
|
|
{
|
|
PropertyBindings = FTrackInstancePropertyBindings(PropertyTrack->GetPropertyName(), PropertyTrack->GetPropertyPath().ToString());
|
|
}
|
|
}
|
|
|
|
FMovieSceneChannel* IKeyArea::ResolveChannel() const
|
|
{
|
|
return ChannelHandle.Get();
|
|
}
|
|
|
|
UMovieSceneSection* IKeyArea::GetOwningSection() const
|
|
{
|
|
TSharedPtr<ISequencerSection> SectionInterface = WeakSection.Pin();
|
|
return SectionInterface ? SectionInterface->GetSectionObject() : nullptr;;
|
|
}
|
|
|
|
TSharedPtr<ISequencerSection> IKeyArea::GetSectionInterface() const
|
|
{
|
|
return WeakSection.Pin();
|
|
}
|
|
|
|
FName IKeyArea::GetName() const
|
|
{
|
|
return ChannelName;
|
|
}
|
|
|
|
void IKeyArea::SetName(FName InName)
|
|
{
|
|
ChannelName = InName;
|
|
}
|
|
|
|
ISequencerChannelInterface* IKeyArea::FindChannelEditorInterface() const
|
|
{
|
|
ISequencerModule& SequencerModule = FModuleManager::LoadModuleChecked<ISequencerModule>("Sequencer");
|
|
ISequencerChannelInterface* EditorInterface = SequencerModule.FindChannelEditorInterface(ChannelHandle.GetChannelTypeName());
|
|
ensureMsgf(EditorInterface, TEXT("No channel interface found for type '%s'. Did you forget to call ISequencerModule::RegisterChannelInterface<ChannelType>()?"), *ChannelHandle.GetChannelTypeName().ToString());
|
|
return EditorInterface;
|
|
}
|
|
|
|
FKeyHandle IKeyArea::AddOrUpdateKey(FFrameNumber Time, const FGuid& ObjectBindingID, ISequencer& InSequencer)
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
UMovieSceneSection* Section = GetOwningSection();
|
|
|
|
// The extended editor data may be null, but is passed to the interface regardless
|
|
const void* RawExtendedData = ChannelHandle.GetExtendedEditorData();
|
|
|
|
if (EditorInterface && Channel)
|
|
{
|
|
FTrackInstancePropertyBindings* BindingsPtr = PropertyBindings.IsSet() ? &PropertyBindings.GetValue() : nullptr;
|
|
return EditorInterface->AddOrUpdateKey_Raw(Channel, Section, RawExtendedData, Time, InSequencer, ObjectBindingID, BindingsPtr);
|
|
}
|
|
|
|
return FKeyHandle();
|
|
}
|
|
|
|
FKeyHandle IKeyArea::DuplicateKey(FKeyHandle InKeyHandle) const
|
|
{
|
|
FKeyHandle NewHandle = FKeyHandle::Invalid();
|
|
|
|
if (FMovieSceneChannel* Channel = ChannelHandle.Get())
|
|
{
|
|
Channel->DuplicateKeys(TArrayView<const FKeyHandle>(&InKeyHandle, 1), TArrayView<FKeyHandle>(&NewHandle, 1));
|
|
}
|
|
|
|
return NewHandle;
|
|
}
|
|
|
|
void IKeyArea::SetKeyTimes(TArrayView<const FKeyHandle> InKeyHandles, TArrayView<const FFrameNumber> InKeyTimes) const
|
|
{
|
|
check(InKeyHandles.Num() == InKeyTimes.Num());
|
|
|
|
if (FMovieSceneChannel* Channel = ChannelHandle.Get())
|
|
{
|
|
Channel->SetKeyTimes(InKeyHandles, InKeyTimes);
|
|
}
|
|
}
|
|
|
|
void IKeyArea::GetKeyTimes(TArrayView<const FKeyHandle> InKeyHandles, TArrayView<FFrameNumber> OutTimes) const
|
|
{
|
|
if (FMovieSceneChannel* Channel = ChannelHandle.Get())
|
|
{
|
|
Channel->GetKeyTimes(InKeyHandles, OutTimes);
|
|
}
|
|
}
|
|
|
|
void IKeyArea::GetKeyInfo(TArray<FKeyHandle>* OutHandles, TArray<FFrameNumber>* OutTimes, const TRange<FFrameNumber>& WithinRange) const
|
|
{
|
|
if (FMovieSceneChannel* Channel = ChannelHandle.Get())
|
|
{
|
|
Channel->GetKeys(WithinRange, OutTimes, OutHandles);
|
|
}
|
|
}
|
|
|
|
TSharedPtr<FStructOnScope> IKeyArea::GetKeyStruct(FKeyHandle KeyHandle) const
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
if (EditorInterface)
|
|
{
|
|
return EditorInterface->GetKeyStruct_Raw(ChannelHandle, KeyHandle);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void IKeyArea::DrawExtra(FSequencerSectionPainter& Painter, const FGeometry& KeyGeometry) const
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
if (EditorInterface)
|
|
{
|
|
FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
const UMovieSceneSection* OwningSection = GetOwningSection();
|
|
EditorInterface->DrawExtra_Raw(Channel,OwningSection, KeyGeometry,Painter);
|
|
}
|
|
}
|
|
|
|
void IKeyArea::DrawKeys(TArrayView<const FKeyHandle> InKeyHandles, TArrayView<FKeyDrawParams> OutKeyDrawParams)
|
|
{
|
|
check(InKeyHandles.Num() == OutKeyDrawParams.Num());
|
|
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
UMovieSceneSection* OwningSection = GetOwningSection();
|
|
|
|
if (EditorInterface && Channel && OwningSection)
|
|
{
|
|
return EditorInterface->DrawKeys_Raw(Channel, InKeyHandles, OwningSection, OutKeyDrawParams);
|
|
}
|
|
}
|
|
|
|
bool IKeyArea::CanCreateKeyEditor() const
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
const FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
|
|
return EditorInterface && Channel && EditorInterface->CanCreateKeyEditor_Raw(Channel);
|
|
}
|
|
|
|
TSharedRef<SWidget> IKeyArea::CreateKeyEditor(TWeakPtr<ISequencer> Sequencer, const FGuid& ObjectBindingID)
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
UMovieSceneSection* OwningSection = GetOwningSection();
|
|
|
|
TWeakPtr<FTrackInstancePropertyBindings> PropertyBindingsPtr;
|
|
if (PropertyBindings.IsSet())
|
|
{
|
|
PropertyBindingsPtr = TSharedPtr<FTrackInstancePropertyBindings>(AsShared(), &PropertyBindings.GetValue());
|
|
}
|
|
|
|
if (EditorInterface && OwningSection)
|
|
{
|
|
return EditorInterface->CreateKeyEditor_Raw(ChannelHandle, OwningSection, ObjectBindingID, PropertyBindingsPtr, Sequencer);
|
|
}
|
|
return SNullWidget::NullWidget;
|
|
}
|
|
|
|
void IKeyArea::CopyKeys(FMovieSceneClipboardBuilder& ClipboardBuilder, TArrayView<const FKeyHandle> KeyMask) const
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
UMovieSceneSection* OwningSection = GetOwningSection();
|
|
|
|
if (EditorInterface && Channel && OwningSection)
|
|
{
|
|
EditorInterface->CopyKeys_Raw(Channel, OwningSection, ChannelName, ClipboardBuilder, KeyMask);
|
|
}
|
|
}
|
|
|
|
TArray<FKeyHandle> IKeyArea::PasteKeys(const FMovieSceneClipboardKeyTrack& KeyTrack, const FMovieSceneClipboardEnvironment& SrcEnvironment, const FSequencerPasteEnvironment& DstEnvironment)
|
|
{
|
|
TArray<FKeyHandle> PastedKeys;
|
|
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
FMovieSceneChannel* Channel = ChannelHandle.Get();
|
|
UMovieSceneSection* OwningSection = GetOwningSection();
|
|
if (EditorInterface && Channel && OwningSection)
|
|
{
|
|
EditorInterface->PasteKeys_Raw(Channel, OwningSection, KeyTrack, SrcEnvironment, DstEnvironment, PastedKeys);
|
|
}
|
|
|
|
return PastedKeys;
|
|
}
|
|
|
|
FText GetOwningObjectBindingName(UMovieSceneTrack* InTrack, ISequencer& InSequencer)
|
|
{
|
|
check(InTrack);
|
|
|
|
UMovieSceneSequence* FocusedSequence = InSequencer.GetFocusedMovieSceneSequence();
|
|
UMovieScene* MovieScene = FocusedSequence->GetMovieScene();
|
|
|
|
FGuid PossessableGuid;
|
|
if (MovieScene->FindTrackBinding(*InTrack, PossessableGuid))
|
|
{
|
|
return MovieScene->GetObjectDisplayName(PossessableGuid);
|
|
}
|
|
|
|
// Couldn't find an owning track, so must not be nestled inside of something!
|
|
return FText();
|
|
}
|
|
|
|
TUniquePtr<FCurveModel> IKeyArea::CreateCurveEditorModel(TSharedRef<ISequencer> InSequencer) const
|
|
{
|
|
ISequencerChannelInterface* EditorInterface = FindChannelEditorInterface();
|
|
UMovieSceneSection* OwningSection = GetOwningSection();
|
|
if (EditorInterface && OwningSection && ChannelHandle.Get() != nullptr)
|
|
{
|
|
TUniquePtr<FCurveModel> CurveModel = EditorInterface->CreateCurveEditorModel_Raw(ChannelHandle, OwningSection, InSequencer);
|
|
if (CurveModel.IsValid())
|
|
{
|
|
// Build long, short and context names for this curve to maximize information shown in the Curve Editor UI.
|
|
UMovieSceneTrack* OwningTrack = OwningSection->GetTypedOuter<UMovieSceneTrack>();
|
|
FText OwningTrackName;
|
|
FText ObjectBindingName;
|
|
|
|
if (OwningTrack)
|
|
{
|
|
OwningTrackName = OwningTrack->GetDisplayName();
|
|
|
|
// This track might be inside an object binding and we'd like to prepend the object binding's name for more context.
|
|
ObjectBindingName = GetOwningObjectBindingName(OwningTrack, *InSequencer);
|
|
}
|
|
|
|
// Not all tracks have all the information so we need to format it differently depending on how many are valid.
|
|
TArray<FText> ValidNames;
|
|
|
|
if (!ObjectBindingName.IsEmptyOrWhitespace())
|
|
{
|
|
ValidNames.Add(ObjectBindingName);
|
|
}
|
|
if (!OwningTrackName.IsEmptyOrWhitespace())
|
|
{
|
|
ValidNames.Add(OwningTrackName);
|
|
}
|
|
if (!ChannelHandle.GetMetaData()->Group.IsEmptyOrWhitespace())
|
|
{
|
|
ValidNames.Add(ChannelHandle.GetMetaData()->Group);
|
|
}
|
|
if (!DisplayText.IsEmptyOrWhitespace())
|
|
{
|
|
ValidNames.Add(DisplayText);
|
|
}
|
|
|
|
// Now we loop through and string them together into one big format string.
|
|
FText LongDisplayNameFormatString;
|
|
for (int32 NameIndex = 0; NameIndex < ValidNames.Num(); NameIndex++)
|
|
{
|
|
const bool bLastEntry = NameIndex == ValidNames.Num() - 1;
|
|
if (!bLastEntry)
|
|
{
|
|
LongDisplayNameFormatString = FText::Format(NSLOCTEXT("SequencerIKeyArea", "CurveLongDisplayNameFormat", "{0}`{{1}`}."), LongDisplayNameFormatString, NameIndex);
|
|
}
|
|
else
|
|
{
|
|
LongDisplayNameFormatString = FText::Format(NSLOCTEXT("SequencerIKeyArea", "CurveLongDisplayNameFormatEnd", "{0}`{{1}`}"), LongDisplayNameFormatString, NameIndex);
|
|
}
|
|
}
|
|
|
|
FText LongDisplayName = FText::Format(LongDisplayNameFormatString, FFormatOrderedArguments(ValidNames));
|
|
const FText ShortDisplayName = DisplayText;
|
|
FString IntentName = ChannelHandle.GetMetaData()->IntentName.ToString();
|
|
if (IntentName.IsEmpty())
|
|
{
|
|
IntentName = ChannelHandle.GetMetaData()->Group.IsEmptyOrWhitespace() ? DisplayText.ToString() : FString::Format(TEXT("{0}.{1}"), { ChannelHandle.GetMetaData()->Group.ToString(), DisplayText.ToString() });
|
|
}
|
|
|
|
CurveModel->SetShortDisplayName(DisplayText);
|
|
CurveModel->SetLongDisplayName(LongDisplayName);
|
|
CurveModel->SetIntentionName(IntentName);
|
|
if (Color.IsSet())
|
|
{
|
|
CurveModel->SetColor(Color.GetValue());
|
|
}
|
|
|
|
//Use editor preference color if it's been set, this function is const so we can't set just Color optional
|
|
const UCurveEditorSettings* Settings = GetDefault<UCurveEditorSettings>();
|
|
UObject* Object = nullptr;
|
|
FString Name;
|
|
CurveModel->GetCurveColorObjectAndName(&Object, Name);
|
|
if (Object)
|
|
{
|
|
TOptional<FLinearColor> SettingColor = Settings->GetCustomColor(Object->GetClass(), Name);
|
|
if (SettingColor.IsSet())
|
|
{
|
|
CurveModel->SetColor(SettingColor.GetValue());
|
|
}
|
|
}
|
|
}
|
|
return CurveModel;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|