Files
UnrealEngine/Engine/Plugins/Experimental/SceneState/Source/SceneStateGameplayEditor/Private/SceneStateSequencerSchema.cpp
2025-05-18 13:04:45 +08:00

170 lines
4.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SceneStateSequencerSchema.h"
#include "ISequencerModule.h"
#include "MVVM/ObjectBindingModelStorageExtension.h"
#include "MVVM/Selection/Selection.h"
#include "MVVM/Selection/SequencerSelectionEventSuppressor.h"
#include "MVVM/ViewModels/ObjectBindingModel.h"
#include "SceneStateComponent.h"
#include "SceneStateObject.h"
#include "ScopedTransaction.h"
#define LOCTEXT_NAMESPACE "SceneStateSequencerSchema"
namespace UE::SceneState::Editor
{
UObject* FSequencerSchema::GetParentObject(UObject* InObject) const
{
if (const USceneStateObject* SceneState = Cast<USceneStateObject>(InObject))
{
return SceneState->GetTypedOuter<USceneStateComponent>();
}
if (const USceneStateComponent* Component = Cast<USceneStateComponent>(InObject))
{
return Component->GetOwner();
}
return nullptr;
}
UE::Sequencer::FObjectSchemaRelevancy FSequencerSchema::GetRelevancy(const UObject* InObject) const
{
if (InObject->IsA<USceneStateObject>())
{
return USceneStateObject::StaticClass();
}
if (InObject->IsA<USceneStateComponent>())
{
return USceneStateComponent::StaticClass();
}
return UE::Sequencer::FObjectSchemaRelevancy();
}
TSharedPtr<FExtender> FSequencerSchema::ExtendObjectBindingMenu(TSharedRef<FUICommandList> InCommandList
, TWeakPtr<ISequencer> InSequencerWeak
, TConstArrayView<UObject*> InContextSensitiveObjects) const
{
TArray<TWeakObjectPtr<USceneStateComponent>> SceneStateComponents;
for (UObject* Object : InContextSensitiveObjects)
{
if (USceneStateComponent* SceneStateComponent = Cast<USceneStateComponent>(Object))
{
SceneStateComponents.Add(SceneStateComponent);
}
}
// No Scene State Components nothing to add
if (SceneStateComponents.IsEmpty())
{
return nullptr;
}
TSharedRef<FExtender> Extender = MakeShared<FExtender>();
Extender->AddMenuExtension(SequencerMenuExtensionPoints::AddTrackMenu_PropertiesSection
, EExtensionHook::Before
, InCommandList
, FMenuExtensionDelegate::CreateStatic(&FSequencerSchema::OnAddTrackMenuExtension
, InSequencerWeak
, SceneStateComponents));
return Extender;
}
void FSequencerSchema::OnAddTrackMenuExtension(FMenuBuilder& InMenuBuilder
, TWeakPtr<ISequencer> InSequencerWeak
, TArray<TWeakObjectPtr<USceneStateComponent>> InComponents)
{
InMenuBuilder.BeginSection(TEXT("Scene State"), LOCTEXT("SceneStateSection", "Scene State"));
{
InMenuBuilder.AddMenuEntry(LOCTEXT("AddSceneStateLabel", "Scene State")
, LOCTEXT("AddSceneStateTooltip", "Add Scene State Object(s)")
, FSlateIcon()
, FExecuteAction::CreateStatic(&FSequencerSchema::AddSceneStateComponents
, InSequencerWeak
, InComponents));
}
InMenuBuilder.EndSection();
}
void FSequencerSchema::AddSceneStateComponents(TWeakPtr<ISequencer> InSequencerWeak
, TArray<TWeakObjectPtr<USceneStateComponent>> InComponents)
{
using namespace UE::Sequencer;
TSharedPtr<ISequencer> Sequencer = InSequencerWeak.Pin();
if (!Sequencer)
{
return;
}
const TSharedPtr<FSequencerEditorViewModel> SequencerViewModel = Sequencer->GetViewModel();
if (!ensure(SequencerViewModel.IsValid()))
{
return;
}
FObjectBindingModelStorageExtension* const ObjectStorage = SequencerViewModel->GetRootModel()->CastDynamic<FObjectBindingModelStorageExtension>();
if (!ensure(ObjectStorage))
{
return;
}
const TSharedPtr<FSequencerSelection> Selection = SequencerViewModel->GetSelection();
if (!ensure(Selection.IsValid()))
{
return;
}
TArray<USceneStateObject*> SceneStateObjects;
SceneStateObjects.Reserve(InComponents.Num());
for (const TWeakObjectPtr<USceneStateComponent>& ComponentWeak : InComponents)
{
USceneStateComponent* ResolvedComponent = ComponentWeak.Get();
if (!ResolvedComponent)
{
continue;
}
if (USceneStateObject* SceneStateObject = ResolvedComponent->GetSceneState())
{
SceneStateObjects.Add(SceneStateObject);
}
}
if (SceneStateObjects.IsEmpty())
{
return;
}
const FScopedTransaction Transaction(LOCTEXT("AddSceneState", "Add Scene State"));
FSelectionEventSuppressor SupressEvents = Selection->SuppressEvents();
Selection->Outliner.Empty();
for (USceneStateObject* SceneStateObject : SceneStateObjects)
{
const FGuid ObjectId = Sequencer->GetHandleToObject(SceneStateObject);
if (TSharedPtr<FObjectBindingModel> Model = ObjectStorage->FindModelForObjectBinding(ObjectId))
{
Selection->Outliner.Select(Model);
}
// Break on first element.
// This is to be consistent with the behavior with how Components are added in FActorSchema
// see: FActorSchema::HandleAddComponentActionExecute
break;
}
}
} // UE::SceneState::Editor
#undef LOCTEXT_NAMESPACE