// Copyright Epic Games, Inc. All Rights Reserved. #include "SequencerAddKeyOperation.h" #include "ISequencer.h" #include "ISequencerTrackEditor.h" #include "DisplayNodes/SequencerDisplayNode.h" #include "DisplayNodes/SequencerTrackNode.h" #include "DisplayNodes/SequencerSectionKeyAreaNode.h" #include "Algo/Find.h" namespace UE { namespace Sequencer { FAddKeyOperation FAddKeyOperation::FromNodes(const TSet>& InNodes) { FAddKeyOperation Operation; TArray> FilteredNodes; // Remove any child nodes that have a parent also included in the set for (const TSharedRef& ProspectiveNode : InNodes) { TSharedPtr Parent = ProspectiveNode->GetParent(); while (Parent) { if (InNodes.Contains(Parent.ToSharedRef())) { goto Continue; } Parent = Parent->GetParent(); } FilteredNodes.Add(ProspectiveNode); Continue: continue; } Operation.AddPreFilteredNodes(FilteredNodes); return Operation; } FAddKeyOperation FAddKeyOperation::FromNode(TSharedRef InNode) { FAddKeyOperation Operation; Operation.AddPreFilteredNodes(MakeArrayView(&InNode, 1)); return Operation; } FAddKeyOperation FAddKeyOperation::FromKeyAreas(ISequencerTrackEditor* TrackEditor, const TArrayView> InKeyAreas) { FAddKeyOperation Operation; if (ensure(TrackEditor)) { for (const TSharedRef& KeyArea : InKeyAreas) { Operation.ProcessKeyArea(TrackEditor, KeyArea); } } return Operation; } void FAddKeyOperation::AddPreFilteredNodes(TArrayView> FilteredNodes) { auto KeyChildTrackArea = [this](FSequencerDisplayNode& InNode) { if (InNode.GetType() == ESequencerNode::Track) { FSequencerTrackNode* TrackNode = static_cast(&InNode); if (TrackNode->GetSubTrackMode() != FSequencerTrackNode::ESubTrackMode::ParentTrack) { // Consider everything underneath this track for keying this->ConsiderKeyableAreas(TrackNode, TrackNode); } } return true; }; for (const TSharedRef& Node : FilteredNodes) { if (TSharedPtr ParentTrack = Node->FindParentTrackNode()) { ConsiderKeyableAreas(ParentTrack.Get(), &Node.Get()); } else { Node->Traverse_ParentFirst(KeyChildTrackArea); } } } bool FAddKeyOperation::ConsiderKeyableAreas(FSequencerTrackNode* InTrackNode, FSequencerDisplayNode* KeyAnythingBeneath) { bool bKeyedAnything = false; auto Traversal = [this, InTrackNode, &bKeyedAnything](FSequencerDisplayNode& InNode) { if (InNode.GetType() == ESequencerNode::Track) { FSequencerTrackNode* ThisTrackNode = static_cast(&InNode); if (TSharedPtr KeyAreaNode = ThisTrackNode->GetTopLevelKeyNode()) { bKeyedAnything |= this->ProcessKeyAreaNode(ThisTrackNode, KeyAreaNode.Get()); } } if (InNode.GetType() == ESequencerNode::KeyArea) { bKeyedAnything |= this->ProcessKeyAreaNode(InTrackNode, static_cast(&InNode)); } return true; }; KeyAnythingBeneath->Traverse_ParentFirst(Traversal, true); return bKeyedAnything; } bool FAddKeyOperation::ProcessKeyAreaNode(FSequencerTrackNode* InTrackNode, const FSequencerSectionKeyAreaNode* KeyAreaNode) { bool bKeyedAnything = false; for (const TSharedRef& KeyArea : KeyAreaNode->GetAllKeyAreas()) { bKeyedAnything |= ProcessKeyArea(InTrackNode, KeyArea); } return bKeyedAnything; } bool FAddKeyOperation::ProcessKeyArea(FSequencerTrackNode* InTrackNode, TSharedPtr InKeyArea) { ISequencerTrackEditor* TrackEditor = &InTrackNode->GetTrackEditor(); return ProcessKeyArea(TrackEditor, InKeyArea); } bool FAddKeyOperation::ProcessKeyArea(ISequencerTrackEditor* InTrackEditor, TSharedPtr InKeyArea) { TSharedPtr Section = InKeyArea->GetSectionInterface(); UMovieSceneSection* SectionObject = Section ? Section->GetSectionObject() : nullptr; UMovieSceneTrack* TrackObject = SectionObject ? SectionObject->GetTypedOuter() : nullptr; if (TrackObject) { GetTrackOperation(InTrackEditor).Populate(TrackObject, Section, InKeyArea); return true; } return false; } void FAddKeyOperation::Commit(FFrameNumber KeyTime, ISequencer& InSequencer) { for (TTuple& Pair : OperationsByTrackEditor) { Pair.Value.InitializeOperation(KeyTime); Pair.Key->ProcessKeyOperation(KeyTime, Pair.Value, InSequencer); } InSequencer.UpdatePlaybackRange(); InSequencer.NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::TrackValueChanged); } FKeyOperation& FAddKeyOperation::GetTrackOperation(ISequencerTrackEditor* TrackEditor) { return OperationsByTrackEditor.FindOrAdd(TrackEditor); } } // namespace Sequencer } // namespace UE