예제 #1
0
void UMovieSceneShotTrack::FixupSurroundingShots( UMovieSceneSection& Section, bool bDelete )
{
	// Find the previous section and extend it to take the place of the section being deleted
	int32 SectionIndex = INDEX_NONE;
	if( SubMovieSceneSections.Find( &Section, SectionIndex ) )
	{
		int32 PrevSectionIndex = SectionIndex - 1;
		if( SubMovieSceneSections.IsValidIndex( PrevSectionIndex ) )
		{
			// Extend the previous section
			SubMovieSceneSections[PrevSectionIndex]->SetEndTime( bDelete ? Section.GetEndTime() : Section.GetStartTime() );
		}

		if( !bDelete )
		{
			int32 NextSectionIndex = SectionIndex + 1;
			if(SubMovieSceneSections.IsValidIndex(NextSectionIndex))
			{
				// Shift the next shot's start time so that it starts when the new shot ends
				SubMovieSceneSections[NextSectionIndex]->SetStartTime(Section.GetEndTime());
			}
		}
	}

	SortShots();
}
TOptional<FSectionHandle> FVirtualTrackArea::HitTestSection(FVector2D InPhysicalPosition) const
{
	TSharedPtr<FSequencerDisplayNode> Node = HitTestNode(InPhysicalPosition.Y);

	if (Node.IsValid())
	{
		TSharedPtr<FSequencerTrackNode> TrackNode = GetParentTrackNode(*Node);

		if (TrackNode.IsValid())
		{
			float Time = PixelToTime(InPhysicalPosition.X);

			const auto& Sections = TrackNode->GetSections();
			for (int32 Index = 0; Index < Sections.Num(); ++Index)
			{
				UMovieSceneSection* Section = Sections[Index]->GetSectionObject();
				if (Section->IsTimeWithinSection(Time))
				{
					return FSectionHandle(TrackNode.ToSharedRef(), Index);
				}
			}
		}
	}

	return TOptional<FSectionHandle>();
}
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 FMoveKeys::OnBeginDrag(const FVector2D& LocalMousePos, TSharedPtr<FTrackNode> SequencerNode)
{
	check( SelectedKeys.Num() > 0 )

	// Begin an editor transaction and mark the section as transactional so it's state will be saved
	GEditor->BeginTransaction( NSLOCTEXT("Sequencer", "MoveKeysTransaction", "Move Keys") );

	TSet<UMovieSceneSection*> ModifiedSections;
	for( FSelectedKey SelectedKey : SelectedKeys )
	{
		UMovieSceneSection* OwningSection = SelectedKey.Section;

		// Only modify sections once
		if( !ModifiedSections.Contains( OwningSection ) )
		{
			OwningSection->SetFlags( RF_Transactional );

			// Save the current state of the section
			OwningSection->Modify();

			// Section has been modified
			ModifiedSections.Add( OwningSection );
		}
	}
}
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() ) );
}
void FSequencerDragOperation::BeginTransaction( UMovieSceneSection& Section, const FText& TransactionDesc )
{
	// Begin an editor transaction and mark the section as transactional so it's state will be saved
	GEditor->BeginTransaction( TransactionDesc );
	Section.SetFlags( RF_Transactional );
	// Save the current state of the section
	Section.Modify();
}
예제 #7
0
TSharedRef<ISequencerSection> FMarginTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack* Track )
{
	check( SupportsType( SectionObject.GetOuter()->GetClass() ) );

	UClass* SectionClass = SectionObject.GetOuter()->GetClass();

	TSharedRef<ISequencerSection> NewSection = MakeShareable( new FMarginPropertySection( SectionObject, Track->GetTrackName() ) );

	return NewSection;
}
예제 #8
0
UMovieSceneSection* UMovieSceneAnimationTrack::GetAnimSectionAtTime(float Time)
{
	for (int32 i = 0; i < AnimationSections.Num(); ++i)
	{
		UMovieSceneSection* Section = AnimationSections[i];
		if( Section->IsTimeWithinSection( Time ) )
		{
			return Section;
		}
	}

	return NULL;
}
예제 #9
0
 virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
 {
     if (Sequencer.Pin()->IsShotFilteringOn())
     {
         TArray< TWeakObjectPtr<UMovieSceneSection> > FilterShots = Sequencer.Pin()->GetFilteringShotSections();
         // if there are filtering shots, continuously update the cached filter zones
         // we do this in tick, and cache it in order to make animation work properly
         CachedFilteredRanges.Empty();
         for (int32 i = 0; i < FilterShots.Num(); ++i)
         {
             UMovieSceneSection* Filter = FilterShots[i].Get();
             CachedFilteredRanges.Add(Filter->GetRange());
         }
     }
 }
UMovieSceneSection* MovieSceneHelpers::FindSectionAtTime( const TArray<UMovieSceneSection*>& Sections, float Time )
{
	for( int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex )
	{
		UMovieSceneSection* Section = Sections[SectionIndex];

		//@todo Sequencer - There can be multiple sections overlapping in time. Returning instantly does not account for that.
		if( Section->IsTimeWithinSection( Time ) && Section->IsActive() )
		{
			return Section;
		}
	}

	return NULL;
}
TSharedRef<ISequencerSection> FParticleTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack& Track )
{
	check( SupportsType( SectionObject.GetOuter()->GetClass() ) );

	const TSharedPtr<ISequencer> OwningSequencer = GetSequencer();
	return MakeShareable( new FParticleSection( SectionObject, OwningSequencer.ToSharedRef() ) );
}
UMovieSceneSection* MovieSceneHelpers::FindNearestSectionAtTime( const TArray<UMovieSceneSection*>& Sections, float Time )
{
	// Only update the section if the position is within the time span of the section
	// Or if there are no sections at the time, the left closest section to the time
	// Or in the case that Time is before all sections, take the section with the earliest start time
	UMovieSceneSection* ClosestSection = nullptr;
	float ClosestSectionTime = 0.f;
	UMovieSceneSection* EarliestSection = nullptr;
	float EarliestSectionTime = 0.f;
	for( int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex )
	{
		UMovieSceneSection* Section = Sections[SectionIndex];

		if (Section->IsActive())
		{
			//@todo Sequencer - There can be multiple sections overlapping in time. Returning instantly does not account for that.
			if( Section->IsTimeWithinSection( Time ) )
			{
				return Section;
			}

			float EndTime = Section->GetEndTime();
			if (EndTime < Time)
			{
				float ClosestTime = Time - EndTime;
				if (!ClosestSection || ClosestTime < ClosestSectionTime)
				{
					ClosestSection = Section;
					ClosestSectionTime = ClosestTime;
				}
			}

			float StartTime = Section->GetStartTime();
			if (!EarliestSection || StartTime < EarliestSectionTime)
			{
				EarliestSection = Section;
				EarliestSectionTime = StartTime;
			}
		}
	}

	// if we get here, we are off of any section
	// if ClosestSection, then we take the closest to left of this time
	// else, we take the EarliestSection
	// if that's nullptr, then there are no sections
	return ClosestSection ? ClosestSection : EarliestSection;
}
예제 #13
0
TSharedRef<ISequencerSection> FAnimationTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack* Track )
{
	check( SupportsType( SectionObject.GetOuter()->GetClass() ) );
	
	TSharedRef<ISequencerSection> NewSection( new FAnimationSection(SectionObject) );

	return NewSection;
}
FReply SAnimationOutlinerTreeNode::OnAddKeyClicked()
{
	FSequencer& Sequencer = DisplayNode->GetSequencer();
	float CurrentTime = Sequencer.GetCurrentLocalTime(*Sequencer.GetFocusedMovieScene());

	TSet<TSharedPtr<IKeyArea>> KeyAreas;
	GetAllKeyAreas(DisplayNode, KeyAreas);

	FScopedTransaction Transaction(LOCTEXT("AddKeys", "Add keys at current time"));
	for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
	{
		UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
		OwningSection->SetFlags(RF_Transactional);
		OwningSection->Modify();
		KeyArea->AddKeyUnique(CurrentTime);
	}
	return FReply::Handled();
}
void FNameCurveKeyArea::PasteKeys(const FMovieSceneClipboardKeyTrack& KeyTrack, const FMovieSceneClipboardEnvironment& SrcEnvironment, const FSequencerPasteEnvironment& DstEnvironment)
{
	float PasteAt = DstEnvironment.CardinalTime;

	KeyTrack.IterateKeys([&](const FMovieSceneClipboardKey& Key){
		UMovieSceneSection* Section = GetOwningSection();
		if (!Section)
		{
			return true;
		}

		if (Section->TryModify())
		{		
			float Time = PasteAt + Key.GetTime();
			if (Section->GetStartTime() > Time)
			{
				Section->SetStartTime(Time);
			}
			if (Section->GetEndTime() < Time)
			{
				Section->SetEndTime(Time);
			}

			FKeyHandle KeyHandle = Curve.UpdateOrAddKey(Time, Key.GetValue<FName>());
			DstEnvironment.ReportPastedKey(KeyHandle, *this);
		}
			
		return true;
	});
}
TArray<UMovieSceneSection*> MovieSceneHelpers::GetTraversedSections( const TArray<UMovieSceneSection*>& Sections, float CurrentTime, float PreviousTime )
{
	TArray<UMovieSceneSection*> TraversedSections;

	bool bPlayingBackwards = CurrentTime - PreviousTime < 0.0f;
	
	float MaxTime = bPlayingBackwards ? PreviousTime : CurrentTime;
	float MinTime = bPlayingBackwards ? CurrentTime : PreviousTime;

	TRange<float> SliderRange(MinTime, MaxTime);

	for( int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex )
	{
		UMovieSceneSection* Section = Sections[SectionIndex];
		if( Section->GetStartTime() == CurrentTime || SliderRange.Overlaps( TRange<float>( Section->GetRange() ) ) )
		{
			TraversedSections.Add( Section );
		}
	}

	return TraversedSections;
}
TSharedRef<ISequencerSection> F3DAttachTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack& Track, FGuid ObjectBinding )
{
	check( SupportsType( SectionObject.GetOuter()->GetClass() ) );

	return MakeShareable( new F3DAttachSection( SectionObject, this ) );
}
void FMoveKeys::OnDrag( const FPointerEvent& MouseEvent, const FVector2D& LocalMousePos, const FTimeToPixel& TimeToPixelConverter, TSharedPtr<FTrackNode> SequencerNode )
{
	// Convert the delta position to a delta time amount that was moved
	float MouseTime = TimeToPixelConverter.PixelToTime(LocalMousePos.X);
	float SelectedKeyTime = DraggedKey.KeyArea->GetKeyTime(DraggedKey.KeyHandle.GetValue());
	float DistanceMoved = MouseTime - SelectedKeyTime;

	if( DistanceMoved != 0.0f )
	{
		float TimeDelta = DistanceMoved;
		// Snapping
		if ( Settings->GetIsSnapEnabled() )
		{
			bool bSnappedToKeyTime = false;
			if ( Settings->GetSnapKeyTimesToKeys() )
			{
				TArray<float> OutSnapTimes;
				GetKeySnapTimes(OutSnapTimes, SequencerNode);

				TArray<float> InitialTimes;
				for ( FSelectedKey SelectedKey : SelectedKeys )
				{
					InitialTimes.Add(SelectedKey.KeyArea->GetKeyTime(SelectedKey.KeyHandle.GetValue()) + DistanceMoved);
				}
				float OutInitialTime = 0.f;
				float OutSnapTime = 0.f;
				if ( SnapToTimes( InitialTimes, OutSnapTimes, TimeToPixelConverter, OutInitialTime, OutSnapTime ) )
				{
					bSnappedToKeyTime = true;
					TimeDelta = OutSnapTime - (OutInitialTime - DistanceMoved);
				}
			}

			if ( bSnappedToKeyTime == false && Settings->GetSnapKeyTimesToInterval() )
			{
				TimeDelta = Settings->SnapTimeToInterval( MouseTime ) - SelectedKeyTime;
			}
		}

		for( FSelectedKey SelectedKey : SelectedKeys )
		{
			UMovieSceneSection* Section = SelectedKey.Section;

			TSharedPtr<IKeyArea>& KeyArea = SelectedKey.KeyArea;


			// Tell the key area to move the key.  We reset the key index as a result of the move because moving a key can change it's internal index 
			KeyArea->MoveKey( SelectedKey.KeyHandle.GetValue(), TimeDelta );

			// Update the key that moved
			float NewKeyTime = KeyArea->GetKeyTime( SelectedKey.KeyHandle.GetValue() );

			// If the key moves outside of the section resize the section to fit the key
			// @todo Sequencer - Doesn't account for hitting other sections 
			if( NewKeyTime > Section->GetEndTime() )
			{
				Section->SetEndTime( NewKeyTime );
			}
			else if( NewKeyTime < Section->GetStartTime() )
			{
				Section->SetStartTime( NewKeyTime );
			}
		}
	}
}
TSharedRef<ISequencerSection> FFaceFXAnimationTrackEditor::MakeSectionInterface(UMovieSceneSection& SectionObject, UMovieSceneTrack& Track)
{
	check(SupportsType(SectionObject.GetOuter()->GetClass()));
	return MakeShareable(new FFaceFXAnimationSection(SectionObject));
}
TSharedRef<ISequencerSection> FCameraCutTrackEditor::MakeSectionInterface(UMovieSceneSection& SectionObject, UMovieSceneTrack& Track, FGuid ObjectBinding)
{
	check(SupportsType(SectionObject.GetOuter()->GetClass()));

	return MakeShareable(new FCameraCutSection(GetSequencer(), ThumbnailPool, SectionObject));
}
UMovieSceneSection* UMovieScenePropertyTrack::FindOrAddSection( float Time )
{
	// Find a spot for the section so that they are sorted by start time
	for( int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex )
	{
		UMovieSceneSection* Section = Sections[SectionIndex];

		if( Section->IsTimeWithinSection( Time ) )
		{
			return Section;
		}

		// Check if there are no more sections that would overlap the time 
		if( !Sections.IsValidIndex( SectionIndex+1 ) || Sections[SectionIndex+1]->GetStartTime() > Time )
		{
			// No sections overlap the time
		
			if( SectionIndex > 0 )
			{
				// Append and grow the previous section
				UMovieSceneSection* PreviousSection = Sections[ SectionIndex ? SectionIndex-1 : 0 ];
		
				PreviousSection->SetEndTime( Time );
				return PreviousSection;
			}
			else if( Sections.IsValidIndex( SectionIndex+1 ) )
			{
				// Prepend and grow the next section because there are no sections before this one
				UMovieSceneSection* NextSection = Sections[SectionIndex+1];
				NextSection->SetStartTime( Time );
				return NextSection;
			}	
			else
			{
				// SectionIndex == 0 
				UMovieSceneSection* PreviousSection = Sections[0];
				if( PreviousSection->GetEndTime() < Time )
				{
					// Append and grow the section
					PreviousSection->SetEndTime( Time );
				}
				else
				{
					// Prepend and grow the section
					PreviousSection->SetStartTime( Time );
				}
				return PreviousSection;
			}
		}

	}

	check( Sections.Num() == 0 );

	// Add a new section that starts and ends at the same time
	UMovieSceneSection* NewSection = CreateNewSection();
	NewSection->SetStartTime( Time );
	NewSection->SetEndTime( Time );

	Sections.Add( NewSection );

	return NewSection;
}
FSequencerSelectedKey FVirtualTrackArea::HitTestKey(FVector2D InPhysicalPosition) const
{
	TSharedPtr<FSequencerDisplayNode> Node = HitTestNode(InPhysicalPosition.Y);

	if (!Node.IsValid())
	{
		return FSequencerSelectedKey();
	}

	const float KeyLeft  = PixelToTime(InPhysicalPosition.X - SequencerSectionConstants::KeySize.X/2);
	const float KeyRight = PixelToTime(InPhysicalPosition.X + SequencerSectionConstants::KeySize.X/2);

	TArray<TSharedRef<IKeyArea>> KeyAreas;

	// First check for a key area node on the hit-tested node
	TSharedPtr<FSequencerSectionKeyAreaNode> KeyAreaNode;
	switch (Node->GetType())
	{
		case ESequencerNode::KeyArea: 	KeyAreaNode = StaticCastSharedPtr<FSequencerSectionKeyAreaNode>(Node); break;
		case ESequencerNode::Track:		KeyAreaNode = StaticCastSharedPtr<FSequencerTrackNode>(Node)->GetTopLevelKeyNode(); break;
	}

	if (KeyAreaNode.IsValid())
	{
		for (auto& KeyArea : KeyAreaNode->GetAllKeyAreas())
		{
			UMovieSceneSection* Section = KeyArea->GetOwningSection();
			if (Section->GetStartTime() <= KeyRight && Section->GetEndTime() >= KeyLeft)
			{
				KeyAreas.Add(KeyArea);
			}
		}
	}
	// Failing that, and the node is collapsed, we check for key groupings
	else if (!Node->IsExpanded())
	{
		TSharedPtr<FSequencerTrackNode> TrackNode = GetParentTrackNode(*Node);
		const TArray< TSharedRef<ISequencerSection> >& Sections = TrackNode->GetSections();

		for ( int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex )
		{
			UMovieSceneSection* Section = Sections[SectionIndex]->GetSectionObject();
			if (Section->GetStartTime() <= KeyRight && Section->GetEndTime() >= KeyLeft)
			{
				KeyAreas.Add(Node->GetKeyGrouping(SectionIndex));
			}
		}
	}

	// Search for any key that matches the position
	// todo: investigate if this would be faster as a sort + binary search, rather than linear search
	for (auto& KeyArea : KeyAreas)
	{
		for (FKeyHandle Key : KeyArea->GetUnsortedKeyHandles())
		{
			const float Time = KeyArea->GetKeyTime(Key);
			if (Time >= KeyLeft && Time <= KeyRight)
			{
				return FSequencerSelectedKey(*KeyArea->GetOwningSection(), KeyArea, Key);
			}
		}
	}

	return FSequencerSelectedKey();
}
TSharedRef<ISequencerSection> FBytePropertyTrackEditor::MakeSectionInterface( UMovieSceneSection& SectionObject, UMovieSceneTrack* Track )
{
	return MakeShareable( new FBytePropertySection( SectionObject, Track->GetTrackName(), Cast<UMovieSceneByteTrack>( SectionObject.GetOuter() )->GetEnum() ) );
}