void FSequencer::DeleteSection(class UMovieSceneSection* Section) { UMovieScene* MovieScene = GetFocusedMovieScene(); bool bAnythingRemoved = false; UMovieSceneTrack* Track = CastChecked<UMovieSceneTrack>( Section->GetOuter() ); // If this check fails then the section is outered to a type that doesnt know about the section //checkSlow( Track->HasSection(Section) ); Track->SetFlags( RF_Transactional ); FScopedTransaction DeleteSectionTransaction( NSLOCTEXT("Sequencer", "DeleteSection_Transaction", "Delete Section") ); Track->Modify(); Track->RemoveSection(Section); bAnythingRemoved = true; if( bAnythingRemoved ) { UpdateRuntimeInstances(); } }
UMovieSceneTrack* UMovieScene::FindTrack( TSubclassOf<UMovieSceneTrack> TrackClass, const FGuid& ObjectGuid, FName UniqueTrackName ) const { UMovieSceneTrack* FoundTrack = NULL; check( UniqueTrackName != NAME_None && ObjectGuid.IsValid() ) for( int32 ObjectBindingIndex = 0; ObjectBindingIndex < ObjectBindings.Num(); ++ObjectBindingIndex ) { const FMovieSceneObjectBinding& ObjectBinding = ObjectBindings[ObjectBindingIndex]; if( ObjectBinding.GetObjectGuid() == ObjectGuid ) { const TArray<UMovieSceneTrack*>& Tracks = ObjectBinding.GetTracks(); for( int32 TrackIndex = 0; TrackIndex < Tracks.Num(); ++TrackIndex ) { UMovieSceneTrack* Track = Tracks[TrackIndex]; if( Track->GetClass() == TrackClass && Track->GetTrackName() == UniqueTrackName ) { FoundTrack = Track; break; } } } } return FoundTrack; }
UMovieSceneSection* UMovieSceneSection::SplitSection(float SplitTime) { if (!IsTimeWithinSection(SplitTime)) { return nullptr; } SetFlags(RF_Transactional); if (TryModify()) { float SectionEndTime = GetEndTime(); // Trim off the right SetEndTime(SplitTime); // Create a new section UMovieSceneTrack* Track = CastChecked<UMovieSceneTrack>(GetOuter()); Track->Modify(); UMovieSceneSection* NewSection = DuplicateObject<UMovieSceneSection>(this, Track); check(NewSection); NewSection->SetStartTime(SplitTime); NewSection->SetEndTime(SectionEndTime); Track->AddSection(*NewSection); return NewSection; } return nullptr; }
void FSequencerDragOperation::GetSectionSnapTimes(TArray<float>& OutSnapTimes, UMovieSceneSection* Section, TSharedPtr<FTrackNode> SequencerNode, bool bIgnoreOurSectionCustomSnaps) { // @todo Sequencer handle dilation snapping better // Collect all the potential snap times from other section borders const TArray< TSharedRef<ISequencerSection> >& Sections = SequencerNode->GetSections(); for (int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex) { const UMovieSceneSection* InSection = Sections[SectionIndex]->GetSectionObject(); bool bIsThisSection = Section == InSection; if (!bIgnoreOurSectionCustomSnaps || !bIsThisSection) { InSection->GetSnapTimes(OutSnapTimes, Section != InSection); } } // snap to director track if it exists, and we are not the director track UMovieSceneTrack* OuterTrack = Cast<UMovieSceneTrack>(Section->GetOuter()); UMovieScene* MovieScene = Cast<UMovieScene>(OuterTrack->GetOuter()); UMovieSceneTrack* ShotTrack = MovieScene->FindMasterTrack(UMovieSceneShotTrack::StaticClass()); if (ShotTrack && OuterTrack != ShotTrack) { const TArray<UMovieSceneSection*>& ShotSections = ShotTrack->GetAllSections(); for (int32 SectionIndex = 0; SectionIndex < ShotSections.Num(); ++SectionIndex) { auto Shot = ShotSections[SectionIndex]; Shot->GetSnapTimes(OutSnapTimes, true); } } }
void FSlomoTrackEditor::HandleAddSlomoTrackMenuEntryExecute() { UMovieScene* MovieScene = GetFocusedMovieScene(); if (MovieScene == nullptr) { return; } UMovieSceneTrack* SlomoTrack = MovieScene->FindMasterTrack<UMovieSceneSlomoTrack>(); if (SlomoTrack != nullptr) { return; } const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "AddSlomoTrack_Transaction", "Add Play Rate Track")); MovieScene->Modify(); SlomoTrack = FindOrCreateMasterTrack<UMovieSceneSlomoTrack>().Track; ensure(SlomoTrack); UMovieSceneSection* NewSection = SlomoTrack->CreateNewSection(); ensure(NewSection); SlomoTrack->AddSection(*NewSection); GetSequencer()->NotifyMovieSceneDataChanged(); }
bool F3DAttachTrackEditor::AddKeyInternal( float KeyTime, const TArray<TWeakObjectPtr<UObject>> Objects, const FName SocketName, const FName ComponentName, AActor* ParentActor) { bool bHandleCreated = false; bool bTrackCreated = false; bool bTrackModified = false; FGuid ParentActorId; if (ParentActor != nullptr) { FFindOrCreateHandleResult HandleResult = FindOrCreateHandleToObject(ParentActor); ParentActorId = HandleResult.Handle; bHandleCreated |= HandleResult.bWasCreated; } if (!ParentActorId.IsValid()) { return false; } for( int32 ObjectIndex = 0; ObjectIndex < Objects.Num(); ++ObjectIndex ) { UObject* Object = Objects[ObjectIndex].Get(); FFindOrCreateHandleResult HandleResult = FindOrCreateHandleToObject( Object ); FGuid ObjectHandle = HandleResult.Handle; bHandleCreated |= HandleResult.bWasCreated; if (ObjectHandle.IsValid()) { FFindOrCreateTrackResult TrackResult = FindOrCreateTrackForObject( ObjectHandle, UMovieScene3DAttachTrack::StaticClass()); UMovieSceneTrack* Track = TrackResult.Track; bTrackCreated |= TrackResult.bWasCreated; if (ensure(Track)) { // Clamp to next attach section's start time or the end of the current sequencer view range float AttachEndTime = GetSequencer()->GetViewRange().GetUpperBoundValue(); for (int32 AttachSectionIndex = 0; AttachSectionIndex < Track->GetAllSections().Num(); ++AttachSectionIndex) { float StartTime = Track->GetAllSections()[AttachSectionIndex]->GetStartTime(); float EndTime = Track->GetAllSections()[AttachSectionIndex]->GetEndTime(); if (KeyTime < StartTime) { if (AttachEndTime > StartTime) { AttachEndTime = StartTime; } } } Cast<UMovieScene3DAttachTrack>(Track)->AddConstraint( KeyTime, AttachEndTime, SocketName, ComponentName, ParentActorId ); bTrackModified = true; } } } return bHandleCreated || bTrackCreated || bTrackModified; }
void FMovieSceneSequenceInstance::RefreshInstanceMap( const TArray<UMovieSceneTrack*>& Tracks, const TArray<TWeakObjectPtr<UObject>>& RuntimeObjects, FMovieSceneInstanceMap& TrackInstances, IMovieScenePlayer& Player ) { // All the tracks we found during this pass TSet< UMovieSceneTrack* > FoundTracks; // For every track, check if it has an instance, if not create one, otherwise refresh that instance for( int32 TrackIndex = 0; TrackIndex < Tracks.Num(); ++TrackIndex ) { UMovieSceneTrack* Track = Tracks[TrackIndex]; // A new track has been encountered FoundTracks.Add( Track ); // See if the track has an instance TSharedPtr<IMovieSceneTrackInstance> Instance = TrackInstances.FindRef( Track ); if ( !Instance.IsValid() ) { // The track does not have an instance, create one Instance = Track->CreateInstance(); Instance->RefreshInstance( RuntimeObjects, Player, *this ); Instance->SaveState(RuntimeObjects, Player, *this); TrackInstances.Add( Track, Instance ); } else { // The track has an instance, refresh it Instance->RefreshInstance( RuntimeObjects, Player, *this ); Instance->SaveState(RuntimeObjects, Player, *this); } } // Remove entries which no longer have a track associated with them FMovieSceneInstanceMap::TIterator It = TrackInstances.CreateIterator(); for( ; It; ++It ) { if( !FoundTracks.Contains( It.Key().Get() ) ) { It.Value()->ClearInstance( Player, *this ); // This track was not found in the moviescene's track list so it was removed. It.RemoveCurrent(); } } // Sort based on evaluation order TrackInstances.ValueSort(FTrackInstanceEvalSorter()); }
UMovieSceneTrack* UMovieScene::FindMasterTrack( TSubclassOf<UMovieSceneTrack> TrackClass ) const { UMovieSceneTrack* FoundTrack = NULL; for( int32 TrackIndex = 0; TrackIndex < MasterTracks.Num(); ++TrackIndex ) { UMovieSceneTrack* Track = MasterTracks[TrackIndex]; if( Track->GetClass() == TrackClass ) { FoundTrack = Track; break; } } return FoundTrack; }
TSharedRef<ISequencerSection> F2DTransformTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack& Track ) { check( SupportsType( SectionObject.GetOuter()->GetClass() ) ); UClass* SectionClass = SectionObject.GetOuter()->GetClass(); return MakeShareable( new F2DTransformSection( SectionObject, Track.GetTrackName() ) ); }
UMovieSceneSubSection* UMovieSceneSubSection::GetRecordingSection() { // check if the section is still valid and part of a track (i.e. it has not been deleted or GCed) if(TheRecordingSection.IsValid()) { UMovieSceneTrack* TrackOuter = Cast<UMovieSceneTrack>(TheRecordingSection->GetOuter()); if(TrackOuter) { if(TrackOuter->HasSection(*TheRecordingSection.Get())) { return TheRecordingSection.Get(); } } } return nullptr; }
void FMoveSection::OnEndDrag(TSharedPtr<FTrackNode> SequencerNode) { DraggedKeyHandles.Empty(); if (Section.IsValid()) { SequencerNode->FixRowIndices(); UMovieSceneTrack* OuterTrack = Cast<UMovieSceneTrack>(Section->GetOuter()); if (OuterTrack) { OuterTrack->Modify(); OuterTrack->OnSectionMoved(*Section); } } EndTransaction(); }
void FSequencerNodeTree::MakeSectionInterfaces( UMovieSceneTrack& Track, TSharedRef<FTrackNode>& SectionAreaNode ) { const TArray<UMovieSceneSection*>& MovieSceneSections = Track.GetAllSections(); TSharedRef<FMovieSceneTrackEditor> Editor = FindOrAddTypeEditor( Track ); for (int32 SectionIndex = 0; SectionIndex < MovieSceneSections.Num(); ++SectionIndex ) { UMovieSceneSection* SectionObject = MovieSceneSections[SectionIndex]; TSharedRef<ISequencerSection> Section = Editor->MakeSectionInterface( *SectionObject, &Track ); // Ask the section to generate it's inner layout FSectionLayoutBuilder Builder( SectionAreaNode ); Section->GenerateSectionLayout( Builder ); SectionAreaNode->AddSection( Section ); } SectionAreaNode->FixRowIndices(); }
TSharedRef<FMovieSceneTrackEditor> FSequencerNodeTree::FindOrAddTypeEditor( UMovieSceneTrack& InTrack ) { TSharedPtr<FMovieSceneTrackEditor> Editor = EditorMap.FindRef( &InTrack ); if( !Editor.IsValid() ) { const TArray< TSharedPtr<FMovieSceneTrackEditor> >& TrackEditors = Sequencer.GetTrackEditors(); // Get a tool for each track // @todo Sequencer - Should probably only need to get this once and it shouldnt be done here. It depends on when movie scene tool modules are loaded TSharedPtr<FMovieSceneTrackEditor> SupportedTool; for( int32 EditorIndex = 0; EditorIndex < TrackEditors.Num(); ++EditorIndex ) { if( TrackEditors[EditorIndex]->SupportsType( InTrack.GetClass() ) ) { Editor = TrackEditors[EditorIndex]; EditorMap.Add( &InTrack, Editor ); break; } } } return Editor.ToSharedRef(); }
TSharedRef<ISequencerSection> FColorPropertyTrackEditor::MakeSectionInterface(UMovieSceneSection& SectionObject, UMovieSceneTrack& Track, FGuid ObjectBinding) { UMovieScenePropertyTrack* PropertyTrack = Cast<UMovieScenePropertyTrack>(&Track); checkf(PropertyTrack != nullptr, TEXT("Incompatible track in FColorPropertyTrackEditor")); return MakeShareable(new FColorPropertySection(GetSequencer().Get(), ObjectBinding, PropertyTrack->GetPropertyName(), PropertyTrack->GetPropertyPath(), SectionObject, Track.GetDisplayName())); }
TSharedRef<ISequencerSection> FSubMovieSceneTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack& Track ) { return MakeShareable( new FSubMovieSceneSection( GetSequencer(), SectionObject, Track.GetTrackName() ) ); }
TSharedRef<ISequencerSection> FBytePropertyTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack& Track ) { return MakeShareable( new FBytePropertySection( SectionObject, Track.GetTrackName(), Cast<UMovieSceneByteTrack>( SectionObject.GetOuter() )->GetEnum() ) ); }
void FSequencerNodeTree::Update() { // @todo Sequencer - This update pass is too aggressive. Some nodes may still be valid Empty(); UMovieScene* MovieScene = Sequencer.GetFocusedMovieSceneSequence()->GetMovieScene(); TArray< TSharedRef<FSequencerDisplayNode> > NewRootNodes; // Get the master tracks so we can get sections from them const TArray<UMovieSceneTrack*>& MasterTracks = MovieScene->GetMasterTracks(); for( UMovieSceneTrack* Track : MasterTracks ) { UMovieSceneTrack& TrackRef = *Track; TSharedRef<FTrackNode> SectionNode = MakeShareable( new FTrackNode( TrackRef.GetTrackName(), TrackRef, NULL, *this ) ); NewRootNodes.Add( SectionNode ); MakeSectionInterfaces( TrackRef, SectionNode ); SectionNode->PinNode(); } const TArray<FMovieSceneBinding>& Bindings = MovieScene->GetBindings(); TMap<FGuid, const FMovieSceneBinding*> GuidToBindingMap; for (const FMovieSceneBinding& Binding : Bindings) { GuidToBindingMap.Add(Binding.GetObjectGuid(), &Binding); } // Make nodes for all object bindings TArray< TSharedRef<FSequencerDisplayNode> > NewObjectNodes; for( const FMovieSceneBinding& Binding : Bindings ) { TSharedRef<FObjectBindingNode> ObjectBindingNode = AddObjectBinding( Binding.GetName(), Binding.GetObjectGuid(), GuidToBindingMap, NewObjectNodes ); const TArray<UMovieSceneTrack*>& Tracks = Binding.GetTracks(); for( UMovieSceneTrack* Track : Tracks ) { UMovieSceneTrack& TrackRef = *Track; FName SectionName = TrackRef.GetTrackName(); check( SectionName != NAME_None ); TSharedRef<FTrackNode> SectionAreaNode = ObjectBindingNode->AddSectionAreaNode( SectionName, TrackRef ); MakeSectionInterfaces( TrackRef, SectionAreaNode ); } } struct FObjectNodeSorter { bool operator()( const TSharedRef<FSequencerDisplayNode>& A, const TSharedRef<FSequencerDisplayNode>& B ) const { if (A->GetType() == ESequencerNode::Object && B->GetType() != ESequencerNode::Object) { return true; } if (A->GetType() != ESequencerNode::Object && B->GetType() == ESequencerNode::Object) { return false; } return A->GetDisplayName().ToString() < B->GetDisplayName().ToString(); } }; NewObjectNodes.Sort( FObjectNodeSorter() ); for (TSharedRef<FSequencerDisplayNode> NewObjectNode : NewObjectNodes) { NewObjectNode->SortChildNodes(FObjectNodeSorter()); } NewRootNodes.Append(NewObjectNodes); // Look for a shot track. It will always come first if it exists UMovieSceneTrack* ShotTrack = MovieScene->GetShotTrack(); if( ShotTrack ) { TSharedRef<FTrackNode> SectionNode = MakeShareable( new FTrackNode( ShotTrack->GetTrackName(), *ShotTrack, NULL, *this ) ); // Shot track always comes first RootNodes.Add( SectionNode ); MakeSectionInterfaces( *ShotTrack, SectionNode ); SectionNode->PinNode(); } // Add all other nodes after the shot track RootNodes.Append( NewRootNodes ); // Set up virtual offsets, and expansion states float VerticalOffset = 0.f; for (auto& Node : RootNodes) { Node->Traverse_ParentFirst([&](FSequencerDisplayNode& InNode){ float VerticalTop = VerticalOffset; VerticalOffset += InNode.GetNodeHeight() + InNode.GetNodePadding().Combined(); InNode.Initialize(VerticalTop, VerticalOffset); return true; }); } // Re-filter the tree after updating // @todo Sequencer - Newly added sections may need to be visible even when there is a filter FilterNodes( FilterString ); }
FMovieSceneSequenceInstance::FMovieSceneSequenceInstance(const UMovieSceneTrack& InMovieSceneTrack) { TimeRange = CastChecked<UMovieScene>(InMovieSceneTrack.GetOuter())->GetPlaybackRange(); }
TSharedRef<FPropertySection> FBoolPropertyTrackEditor::MakePropertySectionInterface(UMovieSceneSection& SectionObject, UMovieSceneTrack& Track) { return MakeShareable(new FBoolPropertySection(SectionObject, Track.GetDisplayName(), GetSequencer().Get())); }
FSequencerTrackNode::FSequencerTrackNode(UMovieSceneTrack& InAssociatedTrack, ISequencerTrackEditor& InAssociatedEditor, bool bInCanBeDragged, TSharedPtr<FSequencerDisplayNode> InParentNode, FSequencerNodeTree& InParentTree) : FSequencerDisplayNode(InAssociatedTrack.GetTrackName(), InParentNode, InParentTree) , AssociatedEditor(InAssociatedEditor) , AssociatedTrack(&InAssociatedTrack) , bCanBeDragged(bInCanBeDragged) { }