You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#proj core #branch UE4 #summary Rename Trunc, Round, Floor, Ceil to TruncToInt, RoundToInt, FloorToInt, CeilToInt. Added *ToFloat versions. Repeated for FGenericPlatformMath and all derived classes for all platforms wherever applicable. Corrected comment in Fractional and added Frac() which does HLSL-style fractional (x - floor(x)). Checked for compilation on all projects (with cooking levels wherever applicable). Didn't change Fractional to Frac, this will be done in second commit. #codereview robert.manuszewski [CL 2064306 by Mikolaj Sieluzycki in Main branch]
483 lines
15 KiB
C++
483 lines
15 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SequencerPrivatePCH.h"
|
|
#include "SectionDragOperations.h"
|
|
#include "MovieSceneSection.h"
|
|
#include "ISequencerSection.h"
|
|
#include "IKeyArea.h"
|
|
#include "CommonMovieSceneTools.h"
|
|
#include "MovieScene.h"
|
|
#include "MovieSceneTrack.h"
|
|
#include "MovieSceneDirectorTrack.h"
|
|
|
|
/** How many pixels near the mouse has to be before snapping occurs */
|
|
const float PixelSnapWidth = 10.f;
|
|
|
|
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();
|
|
}
|
|
|
|
void FSequencerDragOperation::EndTransaction()
|
|
{
|
|
// End the transaction if one was active
|
|
if( GEditor->IsTransactionActive() )
|
|
{
|
|
GEditor->EndTransaction();
|
|
}
|
|
}
|
|
|
|
TRange<float> FSequencerDragOperation::GetSectionBoundaries(UMovieSceneSection* Section, TSharedPtr<FTrackNode> SequencerNode) const
|
|
{
|
|
// Find the borders of where you can drag to
|
|
float LowerBound = -FLT_MAX, UpperBound = FLT_MAX;
|
|
|
|
// Also get the closest borders on either side
|
|
const TArray< TSharedRef<ISequencerSection> >& Sections = SequencerNode->GetSections();
|
|
for (int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex)
|
|
{
|
|
const UMovieSceneSection* InSection = Sections[SectionIndex]->GetSectionObject();
|
|
if (Section != InSection && Section->GetRowIndex() == InSection->GetRowIndex())
|
|
{
|
|
if (InSection->GetEndTime() <= Section->GetStartTime() && InSection->GetEndTime() > LowerBound)
|
|
{
|
|
LowerBound = InSection->GetEndTime();
|
|
}
|
|
if (InSection->GetStartTime() >= Section->GetEndTime() && InSection->GetStartTime() < UpperBound)
|
|
{
|
|
UpperBound = InSection->GetStartTime();
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRange<float>(LowerBound, UpperBound);
|
|
}
|
|
|
|
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* DirectorTrack = MovieScene->FindMasterTrack(UMovieSceneDirectorTrack::StaticClass());
|
|
if (DirectorTrack && OuterTrack != DirectorTrack)
|
|
{
|
|
TArray<UMovieSceneSection*> ShotSections = DirectorTrack->GetAllSections();
|
|
for (int32 SectionIndex = 0; SectionIndex < ShotSections.Num(); ++SectionIndex)
|
|
{
|
|
auto Shot = ShotSections[SectionIndex];
|
|
Shot->GetSnapTimes(OutSnapTimes, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FSequencerDragOperation::SnapToTimes(TArray<float> InitialTimes, const TArray<float>& SnapTimes, const FTimeToPixel& TimeToPixelConverter, float& OutInitialTime, float& OutSnapTime)
|
|
{
|
|
bool bSuccess = false;
|
|
float ClosestTimePixelDistance = PixelSnapWidth;
|
|
|
|
for (int32 InitialTimeIndex = 0; InitialTimeIndex < InitialTimes.Num(); ++InitialTimeIndex)
|
|
{
|
|
float InitialTime = InitialTimes[InitialTimeIndex];
|
|
float PixelXOfTime = TimeToPixelConverter.TimeToPixel(InitialTime);
|
|
|
|
for (int32 SnapTimeIndex = 0; SnapTimeIndex < SnapTimes.Num(); ++SnapTimeIndex)
|
|
{
|
|
float SnapTime = SnapTimes[SnapTimeIndex];
|
|
float PixelXOfSnapTime = TimeToPixelConverter.TimeToPixel(SnapTime);
|
|
|
|
float PixelDistance = FMath::Abs(PixelXOfTime - PixelXOfSnapTime);
|
|
if (PixelDistance < ClosestTimePixelDistance)
|
|
{
|
|
ClosestTimePixelDistance = PixelDistance;
|
|
OutInitialTime = InitialTime;
|
|
OutSnapTime = SnapTime;
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
TOptional<float> FSequencerDragOperation::SnapToTimes(float InitialTime, const TArray<float>& SnapTimes, const FTimeToPixel& TimeToPixelConverter)
|
|
{
|
|
TArray<float> InitialTimes;
|
|
InitialTimes.Add(InitialTime);
|
|
|
|
float OutSnapTime = 0.f;
|
|
float OutInitialTime = 0.f;
|
|
bool bSuccess = SnapToTimes(InitialTimes, SnapTimes, TimeToPixelConverter, OutInitialTime, OutSnapTime);
|
|
if (bSuccess)
|
|
{
|
|
return TOptional<float>(OutSnapTime);
|
|
}
|
|
return TOptional<float>();
|
|
}
|
|
|
|
|
|
|
|
void FResizeSection::OnBeginDrag(const FVector2D& LocalMousePos, TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
if( Section.IsValid() )
|
|
{
|
|
BeginTransaction( *Section, NSLOCTEXT("Sequencer", "DragSectionEdgeTransaction", "Resize section") );
|
|
}
|
|
}
|
|
|
|
void FResizeSection::OnEndDrag(TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
EndTransaction();
|
|
}
|
|
|
|
void FResizeSection::OnDrag( const FPointerEvent& MouseEvent, const FVector2D& LocalMousePos, const FTimeToPixel& TimeToPixelConverter, TSharedPtr<FTrackNode> SequencerNode )
|
|
{
|
|
bool bIsDilating = MouseEvent.IsControlDown();
|
|
|
|
if( Section.IsValid() )
|
|
{
|
|
// Convert the current mouse position to a time
|
|
float NewTime = TimeToPixelConverter.PixelToTime( LocalMousePos.X );
|
|
|
|
// Find the borders of where you can drag to
|
|
TRange<float> SectionBoundaries = GetSectionBoundaries(Section.Get(), SequencerNode);
|
|
|
|
// Snapping
|
|
{
|
|
TArray<float> TimesToSnapTo;
|
|
GetSectionSnapTimes(TimesToSnapTo, Section.Get(), SequencerNode, bIsDilating);
|
|
|
|
TOptional<float> NewSnappedTime = SnapToTimes(NewTime, TimesToSnapTo, TimeToPixelConverter);
|
|
|
|
if (NewSnappedTime.IsSet())
|
|
{
|
|
NewTime = NewSnappedTime.GetValue();
|
|
}
|
|
}
|
|
|
|
if( bDraggingByEnd )
|
|
{
|
|
// Dragging the end of a section
|
|
// Ensure we aren't shrinking past the start time
|
|
NewTime = FMath::Clamp( NewTime, Section->GetStartTime(), SectionBoundaries.GetUpperBoundValue() );
|
|
|
|
if (bIsDilating)
|
|
{
|
|
float NewSize = NewTime - Section->GetStartTime();
|
|
float DilationFactor = NewSize / Section->GetTimeSize();
|
|
Section->DilateSection(DilationFactor, Section->GetStartTime());
|
|
}
|
|
else
|
|
{
|
|
Section->SetEndTime( NewTime );
|
|
}
|
|
}
|
|
else if( !bDraggingByEnd )
|
|
{
|
|
// Dragging the start of a section
|
|
// Ensure we arent expanding past the end time
|
|
NewTime = FMath::Clamp( NewTime, SectionBoundaries.GetLowerBoundValue(), Section->GetEndTime() );
|
|
|
|
if (bIsDilating)
|
|
{
|
|
float NewSize = Section->GetEndTime() - NewTime;
|
|
float DilationFactor = NewSize / Section->GetTimeSize();
|
|
Section->DilateSection(DilationFactor, Section->GetEndTime());
|
|
}
|
|
else
|
|
{
|
|
Section->SetStartTime( NewTime );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMoveSection::OnBeginDrag(const FVector2D& LocalMousePos, TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
if( Section.IsValid() )
|
|
{
|
|
BeginTransaction( *Section, NSLOCTEXT("Sequencer", "MoveSectionTransaction", "Move Section") );
|
|
|
|
DragOffset = LocalMousePos;
|
|
}
|
|
}
|
|
|
|
void FMoveSection::OnEndDrag(TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
if( GEditor->IsTransactionActive() )
|
|
{
|
|
GEditor->EndTransaction();
|
|
}
|
|
|
|
if (Section.IsValid())
|
|
{
|
|
SequencerNode->FixRowIndices();
|
|
}
|
|
}
|
|
|
|
void FMoveSection::OnDrag( const FPointerEvent& MouseEvent, const FVector2D& LocalMousePos, const FTimeToPixel& TimeToPixelConverter, TSharedPtr<FTrackNode> SequencerNode )
|
|
{
|
|
if( Section.IsValid() )
|
|
{
|
|
auto Sections = SequencerNode->GetSections();
|
|
TArray<UMovieSceneSection*> MovieSceneSections;
|
|
for (int32 i = 0; i < Sections.Num(); ++i)
|
|
{
|
|
MovieSceneSections.Add(Sections[i]->GetSectionObject());
|
|
}
|
|
|
|
|
|
FVector2D TotalDelta = LocalMousePos - DragOffset;
|
|
float DistanceMoved = TotalDelta.X / TimeToPixelConverter.GetPixelsPerInput();
|
|
|
|
float DeltaTime = DistanceMoved;
|
|
// Snapping
|
|
{
|
|
TArray<float> TimesToSnapTo;
|
|
GetSectionSnapTimes(TimesToSnapTo, Section.Get(), SequencerNode, true);
|
|
|
|
TArray<float> TimesToSnap;
|
|
TimesToSnap.Add(DistanceMoved + Section->GetStartTime());
|
|
TimesToSnap.Add(DistanceMoved + Section->GetEndTime());
|
|
|
|
float OutSnappedTime = 0.f;
|
|
float OutNewTime = 0.f;
|
|
bool bSuccess = SnapToTimes(TimesToSnap, TimesToSnapTo, TimeToPixelConverter, OutSnappedTime, OutNewTime);
|
|
if (bSuccess)
|
|
{
|
|
DeltaTime = OutNewTime - (OutSnappedTime - DistanceMoved);
|
|
}
|
|
}
|
|
|
|
int32 TargetRowIndex = Section->GetRowIndex();
|
|
|
|
// vertical dragging - master tracks only
|
|
if (SequencerNode->GetTrack()->SupportsMultipleRows() && Sections.Num() > 1)
|
|
{
|
|
float TrackHeight = Sections[0]->GetSectionHeight();
|
|
|
|
if (LocalMousePos.Y < 0.f || LocalMousePos.Y > TrackHeight)
|
|
{
|
|
int32 MaxRowIndex = 0;
|
|
for (int32 i = 0; i < Sections.Num(); ++i)
|
|
{
|
|
if (Sections[i]->GetSectionObject() != Section.Get())
|
|
{
|
|
MaxRowIndex = FMath::Max(MaxRowIndex, Sections[i]->GetSectionObject()->GetRowIndex());
|
|
}
|
|
}
|
|
|
|
TargetRowIndex = FMath::Clamp(Section->GetRowIndex() + FMath::FloorToInt(LocalMousePos.Y / TrackHeight),
|
|
0, MaxRowIndex + 1);
|
|
}
|
|
}
|
|
|
|
bool bDeltaX = !FMath::IsNearlyZero(TotalDelta.X);
|
|
bool bDeltaY = TargetRowIndex != Section->GetRowIndex();
|
|
|
|
if (bDeltaX && bDeltaY &&
|
|
!Section->OverlapsWithSections(MovieSceneSections, TargetRowIndex - Section->GetRowIndex(), DeltaTime))
|
|
{
|
|
Section->MoveSection(DeltaTime);
|
|
Section->SetRowIndex(TargetRowIndex);
|
|
}
|
|
else
|
|
{
|
|
if (bDeltaY &&
|
|
!Section->OverlapsWithSections(MovieSceneSections, TargetRowIndex - Section->GetRowIndex(), 0.f))
|
|
{
|
|
Section->SetRowIndex(TargetRowIndex);
|
|
}
|
|
|
|
if (bDeltaX)
|
|
{
|
|
if (!Section->OverlapsWithSections(MovieSceneSections, 0, DeltaTime))
|
|
{
|
|
Section->MoveSection(DeltaTime);
|
|
}
|
|
else
|
|
{
|
|
// Find the borders of where you can move to
|
|
TRange<float> SectionBoundaries = GetSectionBoundaries(Section.Get(), SequencerNode);
|
|
|
|
float LeftMovementMaximum = SectionBoundaries.GetLowerBoundValue() - Section->GetStartTime();
|
|
float RightMovementMaximum = SectionBoundaries.GetUpperBoundValue() - Section->GetEndTime();
|
|
|
|
// Tell the section to move itself and any data it has
|
|
Section->MoveSection( FMath::Clamp(DeltaTime, LeftMovementMaximum, RightMovementMaximum) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FMoveSection::IsSectionAtNewLocationValid(UMovieSceneSection* InSection, int32 RowIndex, float DeltaTime, TSharedPtr<FTrackNode> SequencerNode) const
|
|
{
|
|
// Also get the closest borders on either side
|
|
const TArray< TSharedRef<ISequencerSection> >& Sections = SequencerNode->GetSections();
|
|
for (int32 SectionIndex = 0; SectionIndex < Sections.Num(); ++SectionIndex)
|
|
{
|
|
const UMovieSceneSection* MovieSection = Sections[SectionIndex]->GetSectionObject();
|
|
if (InSection != MovieSection && MovieSection->GetRowIndex() == RowIndex)
|
|
{
|
|
TRange<float> OffsetSectionRange = TRange<float>(
|
|
InSection->GetRange().GetLowerBoundValue() + DeltaTime,
|
|
InSection->GetRange().GetUpperBoundValue() + DeltaTime);
|
|
if (OffsetSectionRange.Overlaps(MovieSection->GetRange()))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
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( auto It = SelectedKeys.CreateIterator(); It; ++It )
|
|
{
|
|
FSelectedKey& SelectedKey = *It;
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMoveKeys::OnEndDrag(TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
if( GEditor->IsTransactionActive() )
|
|
{
|
|
GEditor->EndTransaction();
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
TArray<float> OutSnapTimes;
|
|
GetKeySnapTimes(OutSnapTimes, SequencerNode);
|
|
|
|
TArray<float> InitialTimes;
|
|
for (TSet<FSelectedKey>::TConstIterator It(SelectedKeys); It; ++It)
|
|
{
|
|
const FSelectedKey& SelectedKey = *It;
|
|
InitialTimes.Add(SelectedKey.KeyArea->GetKeyTime(SelectedKey.KeyHandle.GetValue()) + DistanceMoved);
|
|
}
|
|
float OutInitialTime = 0.f;
|
|
float OutSnapTime = 0.f;
|
|
bool bSuccess = SnapToTimes(InitialTimes, OutSnapTimes, TimeToPixelConverter, OutInitialTime, OutSnapTime);
|
|
|
|
if (bSuccess)
|
|
{
|
|
TimeDelta = OutSnapTime - (OutInitialTime - DistanceMoved);
|
|
}
|
|
}
|
|
|
|
for( auto It = SelectedKeys.CreateIterator(); It; ++It )
|
|
{
|
|
FSelectedKey& SelectedKey = *It;
|
|
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMoveKeys::GetKeySnapTimes(TArray<float>& OutSnapTimes, TSharedPtr<FTrackNode> SequencerNode)
|
|
{
|
|
// snap to non-selected keys
|
|
TArray< TSharedRef<FSectionKeyAreaNode> > KeyAreaNodes;
|
|
SequencerNode->GetChildKeyAreaNodesRecursively(KeyAreaNodes);
|
|
|
|
for (int32 NodeIndex = 0; NodeIndex < KeyAreaNodes.Num(); ++NodeIndex)
|
|
{
|
|
TArray< TSharedRef<IKeyArea> > KeyAreas = KeyAreaNodes[NodeIndex]->GetAllKeyAreas();
|
|
for (int32 KeyAreaIndex = 0; KeyAreaIndex < KeyAreas.Num(); ++KeyAreaIndex)
|
|
{
|
|
auto KeyArea = KeyAreas[KeyAreaIndex];
|
|
|
|
TArray<FKeyHandle> KeyHandles = KeyArea->GetUnsortedKeyHandles();
|
|
for( int32 KeyIndex = 0; KeyIndex < KeyHandles.Num(); ++KeyIndex )
|
|
{
|
|
FKeyHandle KeyHandle = KeyHandles[KeyIndex];
|
|
bool bKeyIsSnappable = true;
|
|
for (TSet<FSelectedKey>::TConstIterator It(SelectedKeys); It; ++It)
|
|
{
|
|
const FSelectedKey& SelectedKey = *It;
|
|
if (SelectedKey.KeyArea == KeyArea && SelectedKey.KeyHandle.GetValue() == KeyHandle)
|
|
{
|
|
bKeyIsSnappable = false;
|
|
break;
|
|
}
|
|
}
|
|
if (bKeyIsSnappable)
|
|
{
|
|
OutSnapTimes.Add(KeyArea->GetKeyTime(KeyHandle));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|