// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Channels/MovieSceneChannelData.h" #include "Channels/MovieSceneChannelHandle.h" #include "Channels/MovieSceneChannelTraits.h" #include "Containers/Array.h" #include "Containers/ArrayView.h" #include "CoreTypes.h" #include "Curves/KeyHandle.h" #include "Evaluation/MovieSceneRootOverridePath.h" #include "Evaluation/MovieSceneTimeTransform.h" #include "ISequencer.h" #include "ISequencerChannelInterface.h" #include "Math/Range.h" #include "Misc/FrameNumber.h" #include "Misc/FrameRate.h" #include "Misc/FrameTime.h" #include "Misc/Guid.h" #include "Misc/Optional.h" #include "MovieSceneClipboard.h" #include "MovieSceneSection.h" #include "MVVM/Views/KeyDrawParams.h" #include "SequencerClipboardReconciler.h" #include "SequencerKeyStructGenerator.h" #include "Templates/Decay.h" #include "Templates/SharedPointer.h" #include "Templates/UniquePtr.h" #include "UObject/NameTypes.h" #include "UObject/WeakObjectPtr.h" #include "UObject/WeakObjectPtrTemplates.h" #include "Widgets/SNullWidget.h" #include "TimeToPixel.h" class FCurveModel; class FMenuBuilder; class FSequencerSectionPainter; class FStructOnScope; class FTrackInstancePropertyBindings; class SWidget; class UMovieSceneTrack; class UObject; struct FGeometry; struct FKeyDrawParams; struct FMovieSceneChannel; template struct TMovieSceneExternalValue; template struct TMovieSceneChannelData; /** Utility struct representing a number of selected keys on a single channel */ template struct TExtendKeyMenuParams { /** The section on which the channel resides */ TWeakObjectPtr Section; /** The owning object. Probably the same as Section, but can be different. */ TWeakObjectPtr WeakOwner; /** The channel on which the keys reside */ TMovieSceneChannelHandle Channel; /** An array of key handles to operante on */ TArray Handles; }; struct FSequencerChannelPaintArgs { FSlateWindowElementList& DrawElements; const FPaintArgs& WidgetPaintArgs; const FGeometry& Geometry; const FSlateRect& MyCullingRect; const FWidgetStyle& WidgetStyle; FTimeToPixel TimeToPixel; bool bParentEnabled = true; }; namespace UE::Sequencer { class FChannelModel; class STrackAreaLaneView; struct FCreateTrackLaneViewParams; } /** * Stub/default implementations for ISequencerChannelInterface functions. * Custom behaviour should be implemented by overloading the relevant function with the necessary channel/data types. * For example, to overload how to draw keys for FMyCustomChannelType, implement the following function in the same namespace as FMyCustomChannelType: * * void DrawKeys(FMyCustomChannelType* Channel, TArrayView InHandles, TArrayView OutKeyDrawParams) * { * ... * } */ namespace Sequencer { /** * Extend the specified selected section context menu * * @param MenuBuilder The menu builder that will construct the section context menu * @param Channels An array of all channels that are currently selected, in no particular order * @param Sections An array of all sections that the selected channels reside in * @param InSequencer The sequencer that is currently active */ template void ExtendSectionMenu(FMenuBuilder& MenuBuilder , TSharedPtr InMenuExtender , TArray>&& InChannels , const TArray>& InWeakSections , TWeakPtr InWeakSequencer) {} /** * Extend the specified selected sidebar menu * * @param MenuBuilder The menu builder that will construct the section context menu * @param InMenuExtender The extender for the menu * @param InChannels An array of all channels that are currently selected, in no particular order * @param InWeakSections An array of all sections that the selected channels reside in * @param InWeakSequencer The sequencer that is currently active */ template TSharedPtr ExtendSidebarMenu(FMenuBuilder& MenuBuilder , TSharedPtr InMenuExtender , TArray>&& InChannels , const TArray>& InWeakSections , TWeakPtr InWeakSequencer) { return nullptr; } /** * Extend the specified selected key context menu * * @param MenuBuilder The menu builder that will construct the section context menu * @param Channels An array of all channels that are currently selected, in no particular order * @param Sections An array of all sections that the selected channels reside in * @param InSequencer The sequencer that is currently active */ template void ExtendKeyMenu(FMenuBuilder& MenuBuilder, TSharedPtr MenuExtender, TArray>&& InChannels, TWeakPtr InSequencer) {} /** * Get a transient key structure that can be added to a details panel to enable editing of a single key * * @param ChannelHandle Handle to the channel in which the key resides * @param KeyHandle A handle to the key to edit * @return A shared struct object, or nullptr */ template TSharedPtr GetKeyStruct(const TMovieSceneChannelHandle& ChannelHandle, FKeyHandle KeyHandle) { return FSequencerKeyStructGenerator::Get().CreateKeyStructInstance(ChannelHandle, KeyHandle); } /** * Check whether the specified channel can create a key editor widget that should be placed on the sequencer node tree * * @param InChannel The channel to check * @return true if a key editor can be created, false otherwise */ inline bool CanCreateKeyEditor(const FMovieSceneChannel* InChannel) { return false; } /** * Create a key editor widget for the specified channel with the channel's specialized editor data. Such widgets are placed on the sequencer node tree for a given key area node. * * @param InChannel The channel to create a key editor for * @param Params Creation parameters containing all the necessary structures for creating the key editor * @return The key editor widget */ inline TSharedRef CreateKeyEditor(const FMovieSceneChannelHandle& InChannel,const UE::Sequencer::FCreateKeyEditorParams& Params) { return SNullWidget::NullWidget; } /** * Add a key at the specified time (or update an existing key) with the channel's current value at that time * * @param InChannel The channel to create a key for * @param InChannelData The channel's data * @param InTime The time at which to add a key * @param InSequencer The currently active sequencer * @param InDefaultValue The default value to use if evaluation of the channel failed * @return A handle to the added (or updated) key */ template FKeyHandle EvaluateAndAddKey(ChannelType* InChannel, const TMovieSceneChannelData& InChannelData, FFrameNumber InTime, ISequencer& InSequencer, ValueType InDefaultValue = ValueType{}) { using namespace UE::MovieScene; ValueType ValueAtTime = InDefaultValue; EvaluateChannel(InChannel, InTime, ValueAtTime); EMovieSceneKeyInterpolation InterpolationMode = GetInterpolationMode(InChannel, InTime, InSequencer.GetKeyInterpolation()); return AddKeyToChannel(InChannel, InTime, ValueAtTime, InterpolationMode); } /** * Retrieve a channel's external value, and add it to the channel as a new key (or update an existing key with its value) * * @param InChannel The channel to create a key for * @param InExternalValue The external value definition * @param InTime The time at which to add a key * @param InSequencer The currently active sequencer * @param InObjectBindingID The object binding ID that this section's track is bound to * @param InPropertyBindings Optionally supplied helper for accessing an object's property pertaining to this channel * @return (Optional) A handle to the added (or updated) key */ template TOptional AddKeyForExternalValue( ChannelType* InChannel, const TMovieSceneExternalValue& InExternalValue, FFrameNumber InTime, ISequencer& InSequencer, const FGuid& InObjectBindingID, FTrackInstancePropertyBindings* InPropertyBindings ) { using namespace UE::MovieScene; // Add a key for the current value of the valid first object we can find if (InExternalValue.OnGetExternalValue && InObjectBindingID.IsValid()) { for (TWeakObjectPtr<> WeakObject : InSequencer.FindBoundObjects(InObjectBindingID, InSequencer.GetFocusedTemplateID())) { UObject* Object = WeakObject.Get(); if (Object) { TOptional Value = InExternalValue.OnGetExternalValue(*Object, InPropertyBindings); if (Value.IsSet()) { EMovieSceneKeyInterpolation InterpolationMode = GetInterpolationMode(InChannel, InTime, InSequencer.GetKeyInterpolation()); return AddKeyToChannel(InChannel, InTime, Value.GetValue(), InterpolationMode); } } } } return TOptional(); } /** * Add or update a key for this channel's current value * * @param InChannel The channel to create a key for * @param InSectionToKey The Section to key * @param InTime The time at which to add a key * @param InSequencer The currently active sequencer * @param InObjectBindingID The object binding ID that this section's track is bound to * @param InPropertyBindings Optionally supplied helper for accessing an object's property pertaining to this channel * @return A handle to the added (or updated) key */ template FKeyHandle AddOrUpdateKey( ChannelType* InChannel, UMovieSceneSection* InSectionToKey, FFrameNumber InTime, ISequencer& InSequencer, const FGuid& InObjectBindingID, FTrackInstancePropertyBindings* InPropertyBindings ) { return EvaluateAndAddKey(InChannel, InChannel->GetData(), InTime, InSequencer); } /** * Add or update a key for this channel's current value, using an external value if possible * * @param InChannel The channel to create a key for * @param InSectionToKey The Section to key * @param InExternalValue The external value definition * @param InTime The time at which to add a key * @param InSequencer The currently active sequencer * @param InObjectBindingID The object binding ID that this section's track is bound to * @param InPropertyBindings Optionally supplied helper for accessing an object's property pertaining to this channel * @return A handle to the added (or updated) key */ template FKeyHandle AddOrUpdateKey( ChannelType* InChannel, UMovieSceneSection* SectionToKey, const TMovieSceneExternalValue& InExternalValue, FFrameNumber InTime, ISequencer& InSequencer, const FGuid& InObjectBindingID, FTrackInstancePropertyBindings* InPropertyBindings) { using namespace UE::MovieScene; TOptional Handle = AddKeyForExternalValue(InChannel, InExternalValue, InTime, InSequencer, InObjectBindingID, InPropertyBindings); if (!Handle.IsSet()) { ValueType ValueAtTime{}; EvaluateChannel(InChannel, InTime, ValueAtTime); EMovieSceneKeyInterpolation InterpolationMode = GetInterpolationMode(InChannel, InTime, InSequencer.GetKeyInterpolation()); Handle = AddKeyToChannel(InChannel, InTime, ValueAtTime, InterpolationMode); } return Handle.GetValue(); } /** * Gather key draw information from a channel for a specific set of keys * * @param InChannel The channel to draw keys * @param InHandles Array of key handles that should be displayed * @param InOwner The owning movie scene section for this channel * @param OutKeyDrawParams Array to receive key draw information. Must be exactly the size of InHandles */ SEQUENCER_API void DrawKeys(FMovieSceneChannel* Channel, TArrayView InHandles, const UMovieSceneSection* InOwner, TArrayView OutKeyDrawParams); /** * Draw additional content in addition to keys for a particular channel * * @param InChannel The channel to draw extra display information for * @param InOwner The owning movie scene section for this channel * @param PaintArgs Paint arguments containing the draw element list, time-to-pixel converter and other structures * @param LayerId The slate layer to paint onto * @return The new slate layer ID for subsequent elements to paint onto */ SEQUENCER_API int32 DrawExtra(FMovieSceneChannel* InChannel, const UMovieSceneSection* InOwner, const FSequencerChannelPaintArgs& PaintArgs, int32 LayerId); /** * Delete the specified keys. If all keys are removed, the current value at that time will be set as the default value for the channel * * @param Channel The channel to remove the keys from * @param InHandles The key handles to delete * @param InTime The time at which to evaluate for the default value if there are no keys remaining */ template typename TEnableIf::SupportsDefaults>::Type DeleteKeys(ChannelType* InChannel, TArrayView InHandles, FFrameNumber InTime) { using namespace UE::MovieScene; using CurveValueType = typename ChannelType::CurveValueType; CurveValueType Value; EvaluateChannel(InChannel, InTime, Value); InChannel->DeleteKeys(InHandles); if (InChannel->GetNumKeys() == 0) { InChannel->SetDefault(Value); } } template typename TEnableIf::SupportsDefaults>::Type DeleteKeys(ChannelType* InChannel, TArrayView InHandles, FFrameNumber InTime) { InChannel->DeleteKeys(InHandles); } /** * Copy the specified keys from a channel * * @param InChannel The channel to duplicate keys in * @param InSection The section that owns this channel * @param KeyAreaName The name of the key area representing this channel * @param ClipboardBuilder Structure for populating the clipboard * @param InHandles Array of key handles that should be copied */ template void CopyKeys(ChannelType* InChannel, const UMovieSceneSection* InSection, FName KeyAreaName, FMovieSceneClipboardBuilder& ClipboardBuilder, TArrayView InHandles) { UMovieSceneTrack* Track = InSection ? InSection->GetTypedOuter() : nullptr; if (!Track) { return; } FMovieSceneClipboardKeyTrack* KeyTrack = nullptr; auto ChannelData = InChannel->GetData(); TArrayView Times = ChannelData.GetTimes(); auto Values = ChannelData.GetValues(); for (FKeyHandle Handle : InHandles) { const int32 KeyIndex = ChannelData.GetIndex(Handle); if (KeyIndex != INDEX_NONE) { FFrameNumber KeyTime = Times[KeyIndex]; auto KeyValue = Values[KeyIndex]; if (!KeyTrack) { KeyTrack = &ClipboardBuilder.FindOrAddKeyTrack(KeyAreaName, *Track); } KeyTrack->AddKey(KeyTime, KeyValue); } } } /** * Paste the clipboard contents onto a channel * * @param InChannel The channel to duplicate keys in * @param Section The section that owns this channel * @param KeyTrack The clipboard track to paste * @param SrcEnvironment The source clipboard environment that was originally copied * @param DstEnvironment The destination clipboard environment that we're copying to * @param OutPastedKeys Array of key handles that should receive any pasted keys */ template void PasteKeys(ChannelType* InChannel, UMovieSceneSection* Section, const FMovieSceneClipboardKeyTrack& KeyTrack, const FMovieSceneClipboardEnvironment& SrcEnvironment, const FSequencerPasteEnvironment& DstEnvironment, TArray& OutPastedKeys) { FFrameTime PasteAt = DstEnvironment.CardinalTime; auto ChannelData = InChannel->GetData(); TRange NewRange = Section->GetRange(); auto ForEachKey = [Section, PasteAt, &NewRange, &ChannelData, &OutPastedKeys, &SrcEnvironment, &DstEnvironment](const FMovieSceneClipboardKey& Key) { FFrameTime SrcTime = Key.GetTime(); SrcTime = SrcTime * SrcEnvironment.TimeTransform.Inverse(); FFrameTime DstTime = FFrameRate::TransformTime(SrcTime, SrcEnvironment.TickResolution, DstEnvironment.TickResolution); DstTime = DstTime * DstEnvironment.TimeTransform; FFrameNumber Time = (PasteAt + DstTime).FloorToFrame(); NewRange = TRange::Hull(NewRange, TRange(Time)); typedef typename TDecay::Type KeyType; KeyType NewKey = Key.GetValue(); FKeyHandle KeyHandle = ChannelData.UpdateOrAddKey(Time, NewKey); OutPastedKeys.Add(KeyHandle); return true; }; KeyTrack.IterateKeys(ForEachKey); Section->SetRange(NewRange); } /** * Whether the specified channel handle supports curve models or not */ SEQUENCER_API bool SupportsCurveEditorModels(const FMovieSceneChannelHandle& ChannelHandle); /** * Create a new model for the specified channel that can be used on the curve editor interface * * @return (Optional) A new model to be added to a curve editor */ SEQUENCER_API TUniquePtr CreateCurveEditorModel(const FMovieSceneChannelHandle& ChannelHandle, const UE::Sequencer::FCreateCurveEditorModelParams& Params); /** * Create a new channel model for this type of channel * * @param InChannelHandle The channel handle to create a model for * @param InSectionModel The section that owns this channel model * @param InChannelName The identifying name of this channel * @return (Optional) A new model to be used as part of the Sequencer MVVM framework */ inline TSharedPtr CreateChannelModel(const FMovieSceneChannelHandle& InChannelHandle, const UE::Sequencer::FSectionModel& InSection, FName InChannelName) { return nullptr; } /** * Create a new channel view for this type of channel * * @param InChannelHandle The channel handle to create a model for * @param InWeakModel The model that is creating the view. Should not be Pinned persistently. * @param Parameters View construction parameters * @return (Optional) A new view to be shown on the track area */ inline TSharedPtr CreateChannelView(const FMovieSceneChannelHandle& InChannelHandle, TWeakPtr InWeakModel, const UE::Sequencer::FCreateTrackLaneViewParams& Parameters) { return nullptr; } /** * Whether this channel should draw a curve on its editor UI * * @param Channel The channel to query * @param InSection The section that owns the channel * @return true to show the curve on the UI, false otherwise */ inline bool ShouldShowCurve(const FMovieSceneChannel* Channel, UMovieSceneSection* InSection) { return false; } } // namespace Sequencer