Files
UnrealEngine/Engine/Source/Editor/Sequencer/Private/SequencerModule.cpp
2025-05-18 13:04:45 +08:00

791 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "Textures/SlateIcon.h"
#include "EditorModeRegistry.h"
#include "Toolkits/AssetEditorToolkit.h"
#include "IMovieRendererInterface.h"
#include "ISequencer.h"
#include "ISequencerModule.h"
#include "SequencerCommands.h"
#include "ISequencerObjectChangeListener.h"
#include "Sequencer.h"
#include "SequencerCustomizationManager.h"
#include "SequencerEdMode.h"
#include "SequencerObjectChangeListener.h"
#include "IDetailKeyframeHandler.h"
#include "IDetailTreeNode.h"
#include "IDetailsView.h"
#include "Tree/CurveEditorTreeFilter.h"
#include "AnimatedPropertyKey.h"
#include "MovieSceneSignedObject.h"
#include "MovieSceneSequence.h"
#include "Sections/MovieSceneSubSection.h"
#include "MVVM/CurveEditorExtension.h"
#include "MVVM/CurveEditorIntegrationExtension.h"
#include "MVVM/FolderModelStorageExtension.h"
#include "MVVM/ObjectBindingModelStorageExtension.h"
#include "MVVM/SectionModelStorageExtension.h"
#include "MVVM/TrackModelStorageExtension.h"
#include "MVVM/TrackRowModelStorageExtension.h"
#include "MVVM/ViewModels/SequenceModel.h"
#include "MVVM/ViewModels/SequencerEditorViewModel.h"
#include "MVVM/ViewModels/OutlinerColumns/OutlinerIndicatorColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/DeactivateOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/LockOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/MuteOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/PinOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/SoloOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/LabelOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/EditOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/AddOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/NavOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/KeyFrameOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerColumns/ColorPickerOutlinerColumn.h"
#include "MVVM/ViewModels/OutlinerIndicators/ConditionOutlinerIndicatorBuilder.h"
#include "MVVM/ViewModels/OutlinerIndicators/TimeWarpOutlinerIndicatorBuilder.h"
#include "ToolMenus.h"
#include "ContentBrowserMenuContexts.h"
#include "SequencerUtilities.h"
#include "FileHelpers.h"
#include "LevelSequence.h"
#include "ActorObjectSchema.h"
#include "SkeletalMeshComponentSchema.h"
#include "Misc/CoreDelegates.h"
#include "UnrealEdGlobals.h"
#include "Editor/UnrealEdEngine.h"
#include "PropertyEditorModule.h"
#include "PropertyHandle.h"
#include "Algo/RemoveIf.h"
#include "Engine/Font.h"
#include "CanvasTypes.h"
namespace UE::Sequencer::Private
{
static const TMap<EPropertyKeyedStatus, FName> KeyedStatusStyleNames =
{
{ EPropertyKeyedStatus::NotKeyed, "Sequencer.KeyedStatus.NotKeyed" },
{ EPropertyKeyedStatus::KeyedInOtherFrame, "Sequencer.KeyedStatus.Animated" },
{ EPropertyKeyedStatus::KeyedInFrame, "Sequencer.KeyedStatus.Keyed" },
{ EPropertyKeyedStatus::PartiallyKeyed, "Sequencer.KeyedStatus.PartialKey" },
};
}
#define LOCTEXT_NAMESPACE "SequencerEditor"
// Destructor defined in CPP to avoid having to #include SequencerChannelInterface.h in the main module definition
ISequencerModule::~ISequencerModule()
{
}
ECurveEditorTreeFilterType ISequencerModule::GetSequencerSelectionFilterType()
{
static ECurveEditorTreeFilterType FilterType = FCurveEditorTreeFilter::RegisterFilterType();
return FilterType;
}
static TSharedPtr<IDetailKeyframeHandler> GetKeyframeHandler(TWeakPtr<IDetailTreeNode> OwnerTreeNode)
{
TSharedPtr<IDetailTreeNode> OwnerTreeNodePtr = OwnerTreeNode.Pin();
if (!OwnerTreeNodePtr.IsValid())
{
return TSharedPtr<IDetailKeyframeHandler>();
}
TSharedPtr<IDetailsView> DetailsView = OwnerTreeNodePtr->GetNodeDetailsViewSharedPtr();
if (DetailsView == nullptr)
{
return TSharedPtr<IDetailKeyframeHandler>();
}
return DetailsView->GetKeyframeHandler();
}
static FSlateIcon GetKeyframeIcon(TWeakPtr<IDetailTreeNode> OwnerTreeNode, TSharedPtr<IPropertyHandle> PropertyHandle)
{
if (!PropertyHandle.IsValid())
{
return FSlateIcon();
}
EPropertyKeyedStatus KeyedStatus = EPropertyKeyedStatus::NotKeyed;
if (TSharedPtr<IDetailKeyframeHandler> KeyframeHandler = GetKeyframeHandler(OwnerTreeNode))
{
KeyedStatus = KeyframeHandler->GetPropertyKeyedStatus(*PropertyHandle);
}
return FSlateIcon(FAppStyle::GetAppStyleSetName(), UE::Sequencer::Private::KeyedStatusStyleNames[KeyedStatus]);
}
static bool IsKeyframeButtonVisible(TWeakPtr<IDetailTreeNode> OwnerTreeNode, TSharedPtr<IPropertyHandle> PropertyHandle)
{
TSharedPtr<IDetailKeyframeHandler> KeyframeHandler = GetKeyframeHandler(OwnerTreeNode);
if (!KeyframeHandler.IsValid() || !PropertyHandle.IsValid())
{
return false;
}
const UClass* ObjectClass = PropertyHandle->GetOuterBaseClass();
if (ObjectClass == nullptr)
{
return false;
}
return KeyframeHandler->IsPropertyKeyable(ObjectClass, *PropertyHandle);
}
static bool IsKeyframeButtonEnabled(TWeakPtr<IDetailTreeNode> OwnerTreeNode)
{
TSharedPtr<IDetailKeyframeHandler> KeyframeHandler = GetKeyframeHandler(OwnerTreeNode);
if (!KeyframeHandler.IsValid())
{
return false;
}
return KeyframeHandler->IsPropertyKeyingEnabled();
}
static void OnAddKeyframeClicked(TWeakPtr<IDetailTreeNode> OwnerTreeNode, TSharedPtr<IPropertyHandle> PropertyHandle)
{
TSharedPtr<IDetailKeyframeHandler> KeyframeHandler = GetKeyframeHandler(OwnerTreeNode);
if (!KeyframeHandler.IsValid() || !PropertyHandle.IsValid())
{
return;
}
KeyframeHandler->OnKeyPropertyClicked(*PropertyHandle);
}
static void RegisterKeyframeExtensionHandler(const FOnGenerateGlobalRowExtensionArgs& Args, TArray<FPropertyRowExtensionButton>& OutExtensionButtons)
{
// local copy for capturing in handlers below
TSharedPtr<IPropertyHandle> PropertyHandle = Args.PropertyHandle;
if (!PropertyHandle.IsValid())
{
return;
}
TWeakPtr<IDetailTreeNode> OwnerTreeNode = Args.OwnerTreeNode;
FPropertyRowExtensionButton& CreateKey = OutExtensionButtons.AddDefaulted_GetRef();
CreateKey.Icon = TAttribute<FSlateIcon>::Create(TAttribute<FSlateIcon>::FGetter::CreateStatic(&GetKeyframeIcon, OwnerTreeNode, PropertyHandle));
CreateKey.Label = NSLOCTEXT("PropertyEditor", "CreateKey", "Create Key");
CreateKey.ToolTip = NSLOCTEXT("PropertyEditor", "CreateKeyToolTip", "Add a keyframe for this property.");
CreateKey.UIAction = FUIAction(
FExecuteAction::CreateStatic(&OnAddKeyframeClicked, OwnerTreeNode, PropertyHandle),
FCanExecuteAction::CreateStatic(&IsKeyframeButtonEnabled, OwnerTreeNode),
FGetActionCheckState(),
FIsActionButtonVisible::CreateStatic(&IsKeyframeButtonVisible, OwnerTreeNode, PropertyHandle)
);
}
namespace UE::SequencerModule::Private
{
int32 RenderTimecode(FCanvas* Canvas, int32 X, int32 Y, const FTimecode& Timecode, const FString& SequenceName)
{
UFont* Font = FPlatformProperties::SupportsWindowedMode() ? GEngine->GetSmallFont() : GEngine->GetMediumFont();
const int32 RowHeight = FMath::TruncToInt(Font->GetMaxCharHeight());
const bool bForceSignDisplay = false;
const bool bAlwaysDisplaySubframe = true;
FString TimecodeStr = Timecode.ToString(bForceSignDisplay, bAlwaysDisplaySubframe);
float CharWidth, CharHeight;
Font->GetCharSize(TEXT(' '), CharWidth, CharHeight);
int32 NewX = X - Font->GetStringSize(*SequenceName) - (int32)CharWidth*14;
Canvas->DrawShadowedString(NewX, Y, *FString::Printf(TEXT("%s TC: %s"), *SequenceName, *TimecodeStr), Font, FColor::Green);
Y += RowHeight;
return Y;
};
int32 RenderTimeForSequences(FCanvas* Canvas, int32 X, int32 Y, TSharedPtr<ISequencer>& InSequencer)
{
const FFrameRate RootDisplayRate = InSequencer->GetRootDisplayRate();
const FFrameRate LocalDisplayRate = InSequencer->GetFocusedDisplayRate();
const FQualifiedFrameTime LocalCurrentTime = InSequencer->GetLocalTime();
const FQualifiedFrameTime RootCurrentTime = InSequencer->GetGlobalTime();
const FTimecode LocalTimecode = FTimecode::FromFrameTime(LocalCurrentTime.ConvertTo(LocalDisplayRate), LocalDisplayRate);
const FTimecode RootTimecode = FTimecode::FromFrameTime(RootCurrentTime.ConvertTo(RootDisplayRate), RootDisplayRate);
const TArray<FMovieSceneSequenceID>& SubSequenceHierarchy = InSequencer->GetSubSequenceHierarchy();
if (SubSequenceHierarchy.Num() > 0)
{
// The first one is the root sequence.
UMovieSceneSequence* Sequence = FSequencerUtilities::GetMovieSceneSequence(InSequencer, SubSequenceHierarchy[0]);
check(Sequence);
FString SequenceName = Sequence->GetDisplayName().ToString();
Y = RenderTimecode(Canvas, X, Y, RootTimecode, SequenceName);
if (SubSequenceHierarchy.Num() > 1)
{
// The current sequence is always the first in the list.
Sequence = FSequencerUtilities::GetMovieSceneSequence(InSequencer, SubSequenceHierarchy.Last());
check(Sequence);
SequenceName = Sequence->GetDisplayName().ToString();
Y = RenderTimecode(Canvas, X, Y, LocalTimecode, SequenceName);
}
}
return Y;
}
static FOpenSequencerWatcher SequencerWatcher;
/** Render the sequencer time to the viewport HUD. */
int32 RenderStatSequencerTime(UWorld* World, FViewport* Viewport, FCanvas* Canvas, int32 X, int32 Y, const FVector* ViewLocation, const FRotator* ViewRotation)
{
for (const FOpenSequencerWatcher::FOpenSequencerData& OpenSequencer : SequencerWatcher.OpenSequencers)
{
if (TSharedPtr<ISequencer> Sequencer = OpenSequencer.WeakSequencer.Pin())
{
Y = RenderTimeForSequences(Canvas, X, Y, Sequencer);
}
}
return Y;
}
void InitStatCommands()
{
auto StartupComplete = []()
{
check(GEngine);
if (GIsEditor)
{
const bool bIsRHS = true;
GEngine->AddEngineStat(TEXT("STAT_SequencerTimecode"), TEXT("STATCAT_Sequencer"),
LOCTEXT("SequencerTimeDisplay", "Displays current timecode, rate, and frame for active sequencer editor."),
UEngine::FEngineStatRender::CreateStatic(&RenderStatSequencerTime),
nullptr, bIsRHS);
}
};
SequencerWatcher.DoStartup(StartupComplete);
}
}
/**
* SequencerModule implementation (private)
*/
class FSequencerModule
: public ISequencerModule
{
public:
// ISequencerModule interface
virtual TSharedRef<ISequencer> CreateSequencer(const FSequencerInitParams& InitParams) override
{
using namespace UE::Sequencer;
TSharedRef<FSequencer> Sequencer = MakeShared<FSequencer>();
TSharedRef<ISequencerObjectChangeListener> ObjectChangeListener = MakeShared<FSequencerObjectChangeListener>(Sequencer);
OnPreSequencerInit.Broadcast(Sequencer, ObjectChangeListener, InitParams);
Sequencer->InitSequencer(InitParams, ObjectChangeListener, TrackEditorDelegates, EditorObjectBindingDelegates, OutlinerColumnDelegates, OutlinerIndicatorDelegates);
OnSequencerCreated.Broadcast(Sequencer);
return Sequencer;
}
virtual FDelegateHandle RegisterTrackEditor( FOnCreateTrackEditor InOnCreateTrackEditor, TArrayView<FAnimatedPropertyKey> AnimatedPropertyTypes ) override
{
TrackEditorDelegates.Add( InOnCreateTrackEditor );
FDelegateHandle Handle = TrackEditorDelegates.Last().GetHandle();
for (const FAnimatedPropertyKey& Key : AnimatedPropertyTypes)
{
PropertyAnimators.Add(Key);
}
if (AnimatedPropertyTypes.Num() > 0)
{
FAnimatedTypeCache CachedTypes;
CachedTypes.FactoryHandle = Handle;
for (const FAnimatedPropertyKey& Key : AnimatedPropertyTypes)
{
CachedTypes.AnimatedTypes.Add(Key);
}
AnimatedTypeCache.Add(CachedTypes);
}
return Handle;
}
virtual void UnRegisterTrackEditor( FDelegateHandle InHandle ) override
{
TrackEditorDelegates.RemoveAll( [=](const FOnCreateTrackEditor& Delegate){ return Delegate.GetHandle() == InHandle; } );
int32 CacheIndex = AnimatedTypeCache.IndexOfByPredicate([=](const FAnimatedTypeCache& In) { return In.FactoryHandle == InHandle; });
if (CacheIndex != INDEX_NONE)
{
for (const FAnimatedPropertyKey& Key : AnimatedTypeCache[CacheIndex].AnimatedTypes)
{
PropertyAnimators.Remove(Key);
}
AnimatedTypeCache.RemoveAtSwap(CacheIndex);
}
}
virtual FDelegateHandle RegisterTrackModel(FOnCreateTrackModel InCreator) override
{
TrackModelDelegates.Add(InCreator);
return TrackModelDelegates.Last().GetHandle();
}
virtual void UnregisterTrackModel(FDelegateHandle InHandle) override
{
TrackModelDelegates.RemoveAll([=](const FOnCreateTrackModel& Delegate) { return Delegate.GetHandle() == InHandle; });
}
virtual FDelegateHandle RegisterOutlinerColumn(FOnCreateOutlinerColumn InCreator) override {
OutlinerColumnDelegates.Add(InCreator);
return OutlinerColumnDelegates.Last().GetHandle();
}
virtual void UnregisterOutlinerColumn(FDelegateHandle InHandle) override {
OutlinerColumnDelegates.RemoveAll([=](const FOnCreateOutlinerColumn& Delegate) { return Delegate.GetHandle() == InHandle; });
}
virtual FDelegateHandle RegisterOutlinerIndicator(FOnCreateOutlinerIndicator InCreator) override {
OutlinerIndicatorDelegates.Add(InCreator);
return OutlinerIndicatorDelegates.Last().GetHandle();
}
virtual void UnregisterOutlinerIndicator(FDelegateHandle InHandle) override {
OutlinerIndicatorDelegates.RemoveAll([=](const FOnCreateOutlinerIndicator& Delegate) { return Delegate.GetHandle() == InHandle; });
}
virtual FDelegateHandle RegisterOnSequencerCreated(FOnSequencerCreated::FDelegate InOnSequencerCreated) override
{
return OnSequencerCreated.Add(InOnSequencerCreated);
}
virtual void UnregisterOnSequencerCreated(FDelegateHandle InHandle) override
{
OnSequencerCreated.Remove(InHandle);
}
virtual FDelegateHandle RegisterOnPreSequencerInit(FOnPreSequencerInit::FDelegate InOnPreSequencerInit) override
{
return OnPreSequencerInit.Add(InOnPreSequencerInit);
}
virtual void UnregisterOnPreSequencerInit(FDelegateHandle InHandle) override
{
OnPreSequencerInit.Remove(InHandle);
}
virtual FDelegateHandle RegisterEditorObjectBinding(FOnCreateEditorObjectBinding InOnCreateEditorObjectBinding) override
{
EditorObjectBindingDelegates.Add(InOnCreateEditorObjectBinding);
return EditorObjectBindingDelegates.Last().GetHandle();
}
virtual void UnRegisterEditorObjectBinding(FDelegateHandle InHandle) override
{
EditorObjectBindingDelegates.RemoveAll([=](const FOnCreateEditorObjectBinding& Delegate) { return Delegate.GetHandle() == InHandle; });
}
void RegisterMenus()
{
UToolMenus* ToolMenus = UToolMenus::Get();
UToolMenu* Menu = ToolMenus->ExtendMenu("ContentBrowser.AssetContextMenu.LevelSequence");
if (!Menu)
{
return;
}
FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions");
Section.AddDynamicEntry("SequencerActions", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
{
UContentBrowserAssetContextMenuContext* Context = InSection.FindContext<UContentBrowserAssetContextMenuContext>();
if (!Context)
{
return;
}
if (Context->SelectedAssets.Num() == 1 && Context->SelectedAssets[0].IsInstanceOf(ULevelSequence::StaticClass()))
{
const FAssetData LevelSequenceAsset = Context->SelectedAssets[0];
// if this LevelSequence has associated maps, offer to load them
TArray<FString> AssociatedMaps = FSequencerUtilities::GetAssociatedLevelSequenceMapPackages(LevelSequenceAsset.PackageName);
if (AssociatedMaps.Num() > 0)
{
InSection.AddSubMenu(
"SequencerOpenMap_Label",
LOCTEXT("SequencerOpenMap_Label", "Open Map"),
LOCTEXT("SequencerOpenMap_Tooltip", "Open a map associated with this Level Sequence Asset"),
FNewMenuDelegate::CreateLambda(
[AssociatedMaps](FMenuBuilder& SubMenuBuilder)
{
for (const FString& AssociatedMap : AssociatedMaps)
{
SubMenuBuilder.AddMenuEntry(
FText::FromString(FPaths::GetBaseFilename(AssociatedMap)),
FText(),
FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Levels"),
FExecuteAction::CreateLambda(
[AssociatedMap]
{
FEditorFileUtils::LoadMap(AssociatedMap);
}
)
);
}
}
),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Levels")
);
}
}
}));
}
void RegisterObjectSchemas()
{
RegisterObjectSchema(MakeShared<UE::Sequencer::FActorSchema>());
RegisterObjectSchema(MakeShared<UE::Sequencer::FSkeletalMeshComponentSchema>());
}
virtual void StartupModule() override
{
using namespace UE::Sequencer;
using namespace UE::MovieScene;
if (GIsEditor)
{
FEditorModeRegistry::Get().RegisterMode<FSequencerEdMode>(
FSequencerEdMode::EM_SequencerMode,
NSLOCTEXT("Sequencer", "SequencerEditMode", "Sequencer Mode"),
FSlateIcon(),
false);
if (UToolMenus::TryGet())
{
FSequencerCommands::Register();
RegisterMenus();
}
else
{
FCoreDelegates::OnPostEngineInit.AddStatic(&FSequencerCommands::Register);
FCoreDelegates::OnPostEngineInit.AddRaw(this, &FSequencerModule::RegisterMenus);
}
UE::SequencerModule::Private::InitStatCommands();
FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
OnGetGlobalRowExtensionHandle = EditModule.GetGlobalRowExtensionDelegate().AddStatic(&RegisterKeyframeExtensionHandler);
// Register far left gutter columns
OutlinerIndicatorColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([] { return TSharedRef<IOutlinerColumn>(MakeShared<FOutlinerIndicatorColumn>()); }));
// Register left gutter columns
PinOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FPinOutlinerColumn>()); }));
LockOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FLockOutlinerColumn>()); }));
DeactivateOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FDeactivateOutlinerColumn>()); }));
// Register left gutter columns
MuteOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FMuteOutlinerColumn>()); }));
SoloOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FSoloOutlinerColumn>()); }));
// Register center columns
LabelOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FLabelOutlinerColumn>()); }));
EditOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FEditOutlinerColumn>()); }));
AddOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FAddOutlinerColumn>()); }));
// Register right gutter columns
KeyFrameOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FKeyFrameOutlinerColumn>()); }));
NavOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FNavOutlinerColumn>()); }));
ColorPickerOutlinerColumnHandle = RegisterOutlinerColumn(FOnCreateOutlinerColumn::CreateStatic([]{ return TSharedRef<IOutlinerColumn>(MakeShared<FColorPickerOutlinerColumn>()); }));
// Register outliner indicator items
ConditionOutlinerIndicatorHandle = RegisterOutlinerIndicator(FOnCreateOutlinerIndicator::CreateStatic([] { return TSharedRef<IOutlinerIndicatorBuilder>(MakeShared<FConditionOutlinerIndicatorBuilder>()); }));
TimeWarpOutlinerIndicatorHandle = RegisterOutlinerIndicator(FOnCreateOutlinerIndicator::CreateStatic([] { return TSharedRef<IOutlinerIndicatorBuilder>(MakeShared<FTimeWarpOutlinerIndicatorBuilder>()); }));
RegisterObjectSchemas();
}
FSequenceModel::CreateExtensionsEvent.AddLambda(
[&](TSharedPtr<FEditorViewModel> InEditor, TSharedPtr<FSequenceModel> InModel)
{
InModel->AddDynamicExtension(FFolderModelStorageExtension::ID);
InModel->AddDynamicExtension(FObjectBindingModelStorageExtension::ID);
InModel->AddDynamicExtension(FTrackModelStorageExtension::ID, TrackModelDelegates);
InModel->AddDynamicExtension(FTrackRowModelStorageExtension::ID);
InModel->AddDynamicExtension(FSectionModelStorageExtension::ID);
// If the editor supports a curve editor, add an integration extension to
// sync view-model hierarchies between the outliner and curve editor.
if (InEditor->CastDynamic<FCurveEditorExtension>())
{
InModel->AddDynamicExtension(FCurveEditorIntegrationExtension::ID);
}
}
);
ObjectBindingContextMenuExtensibilityManager = MakeShareable( new FExtensibilityManager );
AddTrackMenuExtensibilityManager = MakeShareable( new FExtensibilityManager );
ToolBarExtensibilityManager = MakeShareable(new FExtensibilityManager);
ActionsMenuExtensibilityManager = MakeShareable(new FExtensibilityManager);
ViewMenuExtensibilityManager = MakeShareable(new FExtensibilityManager);
SidebarExtensibilityManager = MakeShareable(new FExtensibilityManager);
SequencerCustomizationManager = MakeShareable(new FSequencerCustomizationManager);
}
virtual void ShutdownModule() override
{
if (GIsEditor)
{
UMovieSceneSignedObject::SetDeferredHandler(nullptr);
FSequencerCommands::Unregister();
if (FPropertyEditorModule* EditModulePtr = FModuleManager::Get().GetModulePtr<FPropertyEditorModule>("PropertyEditor"))
{
EditModulePtr->GetGlobalRowExtensionDelegate().Remove(OnGetGlobalRowExtensionHandle);
}
FEditorModeRegistry::Get().UnregisterMode(FSequencerEdMode::EM_SequencerMode);
// unregister outliner columns
UnregisterOutlinerColumn(OutlinerIndicatorColumnHandle);
UnregisterOutlinerColumn(DeactivateOutlinerColumnHandle);
UnregisterOutlinerColumn(PinOutlinerColumnHandle);
UnregisterOutlinerColumn(MuteOutlinerColumnHandle);
UnregisterOutlinerColumn(LockOutlinerColumnHandle);
UnregisterOutlinerColumn(SoloOutlinerColumnHandle);
UnregisterOutlinerColumn(LabelOutlinerColumnHandle);
UnregisterOutlinerColumn(EditOutlinerColumnHandle);
UnregisterOutlinerColumn(AddOutlinerColumnHandle);
UnregisterOutlinerColumn(KeyFrameOutlinerColumnHandle);
UnregisterOutlinerColumn(NavOutlinerColumnHandle);
UnregisterOutlinerColumn(ColorPickerOutlinerColumnHandle);
// unregister outliner indicator items
UnregisterOutlinerIndicator(ConditionOutlinerIndicatorHandle);
UnregisterOutlinerIndicator(TimeWarpOutlinerIndicatorHandle);
}
}
virtual void RegisterPropertyAnimator(FAnimatedPropertyKey Key) override
{
PropertyAnimators.Add(Key);
}
virtual void UnRegisterPropertyAnimator(FAnimatedPropertyKey Key) override
{
PropertyAnimators.Remove(Key);
}
virtual bool CanAnimateProperty(FProperty* Property) override
{
if (PropertyAnimators.Contains(FAnimatedPropertyKey::FromProperty(Property)))
{
return true;
}
FObjectPropertyBase* ObjectProperty = CastField<FObjectPropertyBase>(Property);
// Check each level of the property hierarchy
FFieldClass* PropertyType = Property->GetClass();
while (PropertyType && PropertyType != FProperty::StaticClass())
{
FAnimatedPropertyKey Key = FAnimatedPropertyKey::FromPropertyTypeName(PropertyType->GetFName());
// For object properties, check each parent type of the object (ie, so a track that animates UBaseClass ptrs can be used with a UDerivedClass property)
UClass* ClassType = (ObjectProperty && ObjectProperty->PropertyClass) ? ObjectProperty->PropertyClass->GetSuperClass() : nullptr;
while (ClassType)
{
Key.ObjectTypeName = ClassType->GetFName();
if (PropertyAnimators.Contains(Key))
{
return true;
}
ClassType = ClassType->GetSuperClass();
}
Key.ObjectTypeName = NAME_None;
if (PropertyAnimators.Contains(Key))
{
return true;
}
// Look at the property's super class
PropertyType = PropertyType->GetSuperClass();
}
return false;
}
virtual TSharedPtr<FExtensibilityManager> GetObjectBindingContextMenuExtensibilityManager() const override { return ObjectBindingContextMenuExtensibilityManager; }
virtual TSharedPtr<FExtensibilityManager> GetAddTrackMenuExtensibilityManager() const override { return AddTrackMenuExtensibilityManager; }
virtual TSharedPtr<FExtensibilityManager> GetToolBarExtensibilityManager() const override { return ToolBarExtensibilityManager; }
virtual TSharedPtr<FExtensibilityManager> GetActionsMenuExtensibilityManager() const override { return ActionsMenuExtensibilityManager; }
virtual TSharedPtr<FExtensibilityManager> GetViewMenuExtensibilityManager() const override { return ViewMenuExtensibilityManager; }
virtual TSharedPtr<FExtensibilityManager> GetSidebarExtensibilityManager() const override { return SidebarExtensibilityManager; }
virtual TSharedPtr<FSequencerCustomizationManager> GetSequencerCustomizationManager() const override { return SequencerCustomizationManager; }
virtual void RegisterObjectSchema(TSharedPtr<UE::Sequencer::IObjectSchema> InSchema) override
{
ObjectSchemas.Add(InSchema);
}
virtual void UnregisterObjectSchema(TSharedPtr<UE::Sequencer::IObjectSchema> InSchema) override
{
ObjectSchemas.Remove(InSchema);
}
virtual TSharedPtr<UE::Sequencer::IObjectSchema> FindObjectSchema(const UObject* Object) const override
{
using namespace UE::Sequencer;
FObjectSchemaRelevancy Relevancy;
TSharedPtr<IObjectSchema> RelevantSchema;
for (const TSharedPtr<IObjectSchema>& Schema : ObjectSchemas)
{
FObjectSchemaRelevancy ThisRelevancy = Schema->GetRelevancy(Object);
if (ThisRelevancy > Relevancy)
{
Relevancy = ThisRelevancy;
RelevantSchema = Schema;
}
}
return RelevantSchema;
}
virtual FDelegateHandle RegisterMovieRenderer(TUniquePtr<IMovieRendererInterface>&& InMovieRenderer) override
{
FDelegateHandle NewHandle(FDelegateHandle::GenerateNewHandle);
MovieRenderers.Add(FMovieRendererEntry{ NewHandle, MoveTemp(InMovieRenderer) });
return NewHandle;
}
virtual void UnregisterMovieRenderer(FDelegateHandle InDelegateHandle) override
{
MovieRenderers.RemoveAll([InDelegateHandle](const FMovieRendererEntry& In){ return In.Handle == InDelegateHandle; });
}
virtual IMovieRendererInterface* GetMovieRenderer(const FString& InMovieRendererName) override
{
for (const FMovieRendererEntry& MovieRenderer : MovieRenderers)
{
if (MovieRenderer.Renderer->GetDisplayName() == InMovieRendererName)
{
return MovieRenderer.Renderer.Get();
}
}
return nullptr;
}
virtual TArray<FString> GetMovieRendererNames() override
{
TArray<FString> MovieRendererNames;
for (const FMovieRendererEntry& MovieRenderer : MovieRenderers)
{
MovieRendererNames.Add(MovieRenderer.Renderer->GetDisplayName());
}
return MovieRendererNames;
}
TArrayView<const TSharedPtr<UE::Sequencer::IObjectSchema>> GetObjectSchemas() const override
{
return ObjectSchemas;
}
private:
TSet<FAnimatedPropertyKey> PropertyAnimators;
/** List of auto-key handler delegates sequencers will execute when they are created */
TArray< FOnCreateTrackEditor > TrackEditorDelegates;
/** List of object binding handler delegates sequencers will execute when they are created */
TArray< FOnCreateEditorObjectBinding > EditorObjectBindingDelegates;
/** List of track model creators */
TArray<FOnCreateTrackModel> TrackModelDelegates;
/** List of outliner column creators */
TArray<FOnCreateOutlinerColumn> OutlinerColumnDelegates;
/** List of outliner indicator item creators */
TArray<FOnCreateOutlinerIndicator> OutlinerIndicatorDelegates;
TArray<TSharedPtr<UE::Sequencer::IObjectSchema>> ObjectSchemas;
/** Global details row extension delegate; */
FDelegateHandle OnGetGlobalRowExtensionHandle;
/** Multicast delegate used to notify others of sequencer initialization params and allow modification. */
FOnPreSequencerInit OnPreSequencerInit;
/** Multicast delegate used to notify others of sequencer creations */
FOnSequencerCreated OnSequencerCreated;
struct FAnimatedTypeCache
{
FDelegateHandle FactoryHandle;
TArray<FAnimatedPropertyKey, TInlineAllocator<4>> AnimatedTypes;
};
/** Map of all track editor factories to property types that they have registered to animated */
TArray<FAnimatedTypeCache> AnimatedTypeCache;
TSharedPtr<FExtensibilityManager> ObjectBindingContextMenuExtensibilityManager;
TSharedPtr<FExtensibilityManager> AddTrackMenuExtensibilityManager;
TSharedPtr<FExtensibilityManager> ToolBarExtensibilityManager;
TSharedPtr<FExtensibilityManager> ActionsMenuExtensibilityManager;
TSharedPtr<FExtensibilityManager> ViewMenuExtensibilityManager;
TSharedPtr<FExtensibilityManager> SidebarExtensibilityManager;
TSharedPtr<FSequencerCustomizationManager> SequencerCustomizationManager;
struct FMovieRendererEntry
{
FDelegateHandle Handle;
TUniquePtr<IMovieRendererInterface> Renderer;
};
/** Array of movie renderers */
TArray<FMovieRendererEntry> MovieRenderers;
// Outliner Column Delegate Handles
FDelegateHandle OutlinerIndicatorColumnHandle;
FDelegateHandle DeactivateOutlinerColumnHandle;
FDelegateHandle PinOutlinerColumnHandle;
FDelegateHandle MuteOutlinerColumnHandle;
FDelegateHandle LockOutlinerColumnHandle;
FDelegateHandle SoloOutlinerColumnHandle;
FDelegateHandle LabelOutlinerColumnHandle;
FDelegateHandle EditOutlinerColumnHandle;
FDelegateHandle AddOutlinerColumnHandle;
FDelegateHandle KeyFrameOutlinerColumnHandle;
FDelegateHandle NavOutlinerColumnHandle;
FDelegateHandle ColorPickerOutlinerColumnHandle;
// Outliner Indicator Item Delegate Handles
FDelegateHandle ConditionOutlinerIndicatorHandle;
FDelegateHandle TimeWarpOutlinerIndicatorHandle;
};
IMPLEMENT_MODULE(FSequencerModule, Sequencer);
#undef LOCTEXT_NAMESPACE