// Copyright Epic Games, Inc. All Rights Reserved. #include "MovieSceneObjectBindingIDCustomization.h" #include "IPropertyUtilities.h" #include "MovieSceneBindingOwnerInterface.h" #include "MovieSceneSequence.h" #include "MovieScene.h" #include "PropertyHandle.h" #include "PropertyHandle.h" #include "DetailWidgetRow.h" #include "IDetailChildrenBuilder.h" #include "SDropTarget.h" #include "ISequencer.h" #include "Widgets/Input/SComboButton.h" #include "Widgets/Text/STextBlock.h" #include "ScopedTransaction.h" #include "SequencerObjectBindingDragDropOp.h" #define LOCTEXT_NAMESPACE "MovieSceneObjectBindingIDCustomization" void FMovieSceneObjectBindingIDCustomization::BindTo(TSharedRef OuterSequencer) { OuterSequencer->OnInitializeDetailsPanel().AddStatic( [](TSharedRef DetailsView, TSharedRef InSequencer) { TWeakPtr WeakSequencer = InSequencer; FOnGetPropertyTypeCustomizationInstance BindingIDCustomizationFactory = FOnGetPropertyTypeCustomizationInstance::CreateLambda( [WeakSequencer] { return MakeShared(WeakSequencer.Pin()->GetFocusedTemplateID(), WeakSequencer); } ); // Register an object binding ID customization that can use the current sequencer interface DetailsView->RegisterInstancedCustomPropertyTypeLayout("MovieSceneObjectBindingID", BindingIDCustomizationFactory); } ); } void FMovieSceneObjectBindingIDCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) { using namespace UE::Sequencer; StructProperty = PropertyHandle; Initialize(); auto IsAcceptable = [](TSharedPtr Operation) { using namespace UE::Sequencer; if (!Operation->IsOfType()) { return false; } FSequencerObjectBindingDragDropOp* DragDropOp = static_cast(Operation.Get()); return DragDropOp->GetDraggedRebindableBindings().Num() == 1; }; HeaderRow .NameContent() [ StructProperty->CreatePropertyNameWidget() ] .ValueContent() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() [ SNew(SDropTarget) .OnDropped(this, &FMovieSceneObjectBindingIDCustomization::OnDrop) .OnAllowDrop_Static(IsAcceptable) .OnIsRecognized_Static(IsAcceptable) [ SNew(SComboButton) .ToolTipText(this, &FMovieSceneObjectBindingIDCustomization::GetToolTipText) .OnGetMenuContent(this, &FMovieSceneObjectBindingIDCustomization::GetPickerMenu) .ContentPadding(FMargin(4.0, 2.0)) .ButtonContent() [ GetCurrentItemWidget( SNew(STextBlock) .Font(CustomizationUtils.GetRegularFont()) ) ] ] ] + SHorizontalBox::Slot() .AutoWidth() .Padding(FMargin(4.f, 0.f, 0.f, 0.f)) [ GetWarningWidget() ] ]; } FReply FMovieSceneObjectBindingIDCustomization::OnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent) { using namespace UE::Sequencer; TSharedPtr SequencerOp = InDragDropEvent.GetOperationAs(); if (SequencerOp) { TArray Bindings = SequencerOp->GetDraggedRebindableBindings(); if (Bindings.Num() == 1) { SetBindingId(Bindings[0]); } } return FReply::Handled(); } UMovieSceneSequence* FMovieSceneObjectBindingIDCustomization::GetSequence() const { TArray OuterObjects; StructProperty->GetOuterObjects(OuterObjects); if (OuterObjects.Num() != 1) { return nullptr; } for ( UObject* NextOuter = OuterObjects[0]; NextOuter; NextOuter = NextOuter->GetOuter() ) { if (IMovieSceneBindingOwnerInterface* Result = Cast(NextOuter)) { return Result->RetrieveOwnedSequence(); } } return nullptr; } bool FMovieSceneObjectBindingIDCustomization::HasMultipleValues() const { TArray Ptrs; StructProperty->AccessRawData(Ptrs); return Ptrs.Num() > 1; } FMovieSceneObjectBindingID FMovieSceneObjectBindingIDCustomization::GetCurrentValue() const { TArray Ptrs; StructProperty->AccessRawData(Ptrs); FMovieSceneObjectBindingID Value = Ptrs.Num() > 0 ? *static_cast(Ptrs[0]) : FMovieSceneObjectBindingID(); // If more than one value and not all equal, return empty for (int32 Index = 1; Index < Ptrs.Num(); ++Index) { if (*static_cast(Ptrs[Index]) != Value) { return FMovieSceneObjectBindingID(); } } return Value; } void FMovieSceneObjectBindingIDCustomization::SetCurrentValue(const FMovieSceneObjectBindingID& InObjectBinding) { FScopedTransaction Transaction(LOCTEXT("SetBinding", "Set Binding")); StructProperty->NotifyPreChange(); TArray Objects; StructProperty->GetOuterObjects(Objects); for (UObject* Object : Objects) { Object->Modify(); } TArray Ptrs; StructProperty->AccessRawData(Ptrs); for (int32 Index = 0; Index < Ptrs.Num(); ++Index) { *static_cast(Ptrs[Index]) = InObjectBinding; } StructProperty->NotifyPostChange(EPropertyChangeType::ValueSet); StructProperty->NotifyFinishedChangingProperties(); } #undef LOCTEXT_NAMESPACE