// Copyright Epic Games, Inc. All Rights Reserved. #include "DragOperation_Stretch.h" #include "MVVM/ViewModels/ViewModel.h" #include "MVVM/ViewModels/SequencerEditorViewModel.h" #include "MVVM/Selection/Selection.h" #include "SequencerSettings.h" #include "ISequencer.h" #include "Sequencer.h" #include "MVVM/ViewModels/SectionModel.h" #include "MVVM/ViewModels/VirtualTrackArea.h" #define LOCTEXT_NAMESPACE "FEditToolDragOperation_Stretch" namespace UE { namespace Sequencer { FEditToolDragOperation_Stretch::FEditToolDragOperation_Stretch(ISequencer* InSequencer, EStretchConstraint InStretchConstraint, FFrameNumber InDragStartPosition) : Sequencer(InSequencer) , DragStartPosition(InDragStartPosition) , StretchConstraint(InStretchConstraint) { GlobalParameters.Anchor = GlobalParameters.Handle = InDragStartPosition.Value; } bool FEditToolDragOperation_Stretch::InitiateStretch(TSharedPtr Controller, TSharedPtr Target, int32 Priority, const FStretchParameters& InParams) { if (!ensure(InParams.IsValid())) { return false; } if (FStretchTarget* ExistingTarget = StretchTargets.Find(Target)) { if (ExistingTarget->Priority < Priority) { ExistingTarget->Params = InParams; return true; } } else { StretchTargets.Add(Target, FStretchTarget{ InParams, Priority }); return true; } return false; } void FEditToolDragOperation_Stretch::DoNotSnapTo(TSharedPtr Model) { if (FSectionModel* SectionModel = Model->CastThis()) { SnapExclusion.Add(SectionModel->GetSection()); } } void FEditToolDragOperation_Stretch::OnBeginDrag(const FPointerEvent& MouseEvent, FVector2D LocalMousePos, const FVirtualTrackArea& VirtualTrackArea) { TArray AllStretchables; for (FViewModelPtr SelectedModel : Sequencer->GetViewModel()->GetSelection()->TrackArea) { if (TViewModelPtr Stretchable = SelectedModel.ImplicitCast()) { Stretchable->OnInitiateStretch(*this, StretchConstraint, &GlobalParameters); } } Transaction = MakeUnique(LOCTEXT("StretchTransaction", "Stretch")); FStretchScreenParameters ScreenParameters; ScreenParameters.DragStartPosition = DragStartPosition; ScreenParameters.CurrentDragPosition = DragStartPosition; ScreenParameters.LocalMousePos = LocalMousePos; ScreenParameters.MouseEvent = &MouseEvent; ScreenParameters.VirtualTrackArea = &VirtualTrackArea; FStretchParameters TempParams; const bool bUseGlobalParams = MouseEvent.IsAltDown() == false; for (auto TargetIt = StretchTargets.CreateIterator(); TargetIt; ++TargetIt) { FStretchParameters* Params = &TargetIt.Value().Params; if (bUseGlobalParams) { // Ensure the TempParams match the global ones (in-case something overwrote them) TempParams = GlobalParameters; Params = &TempParams; } EStretchResult Result = TargetIt.Key()->OnBeginStretch(*this, ScreenParameters, Params); // Don't drag if the parameters are invalid if (Result == EStretchResult::Failure) { TargetIt.RemoveCurrent(); } } SnapField = MakeUnique(); SnapField->Initialize(*static_cast(Sequencer), *this); SnapField->AddExplicitSnap(FSnapPoint{FSnapPoint::CustomSection, DragStartPosition }); SnapField->Finalize(); } void FEditToolDragOperation_Stretch::OnDrag(const FPointerEvent& MouseEvent, FVector2D LocalMousePos, const FVirtualTrackArea& VirtualTrackArea) { UE::MovieScene::FScopedSignedObjectModifyDefer DeferMarkAsChanged(true); FFrameTime CurrentTime = VirtualTrackArea.PixelToFrame(LocalMousePos.X); if (Sequencer->GetSequencerSettings()->GetIsSnapEnabled()) { const float PixelSnapWidth = 10.f; const float SnapThresholdPx = VirtualTrackArea.PixelToSeconds(PixelSnapWidth) - VirtualTrackArea.PixelToSeconds(0.f); const int32 SnapThreshold = (SnapThresholdPx * Sequencer->GetFocusedTickResolution()).FloorToFrame().Value; TOptional SnappedResult = SnapField->Snap(CurrentTime.RoundToFrame(), SnapThreshold); if (SnappedResult.IsSet()) { CurrentTime = SnappedResult->SnappedTime; } } if (Sequencer->GetSequencerSettings()->GetForceWholeFrames()) { CurrentTime = FFrameRate::Snap(CurrentTime, Sequencer->GetFocusedTickResolution(), Sequencer->GetFocusedDisplayRate()); } FStretchScreenParameters ScreenParameters; ScreenParameters.DragStartPosition = DragStartPosition; ScreenParameters.CurrentDragPosition = CurrentTime; ScreenParameters.LocalMousePos = LocalMousePos; ScreenParameters.MouseEvent = &MouseEvent; ScreenParameters.VirtualTrackArea = &VirtualTrackArea; FStretchParameters TempParams; const bool bUseGlobalParams = MouseEvent.IsAltDown() == false; for (TPair, FStretchTarget> Pair : StretchTargets) { FStretchParameters* Params = &Pair.Value.Params; if (bUseGlobalParams) { // Ensure the TempParams match the global ones (in-case something overwrote them) TempParams = GlobalParameters; Params = &TempParams; } Pair.Key->OnStretch(*this, ScreenParameters, Params); } } void FEditToolDragOperation_Stretch::OnEndDrag( const FPointerEvent& MouseEvent, FVector2D LocalMousePos, const FVirtualTrackArea& VirtualTrackArea) { FFrameTime CurrentTime = VirtualTrackArea.PixelToFrame(LocalMousePos.X); if (Sequencer->GetSequencerSettings()->GetIsSnapEnabled()) { const float PixelSnapWidth = 10.f; const float SnapThresholdPx = VirtualTrackArea.PixelToSeconds(PixelSnapWidth) - VirtualTrackArea.PixelToSeconds(0.f); const int32 SnapThreshold = (SnapThresholdPx * Sequencer->GetFocusedTickResolution()).FloorToFrame().Value; TOptional SnappedResult = SnapField->Snap(CurrentTime.RoundToFrame(), SnapThreshold); if (SnappedResult.IsSet()) { CurrentTime = SnappedResult->SnappedTime; } } if (Sequencer->GetSequencerSettings()->GetForceWholeFrames()) { CurrentTime = FFrameRate::Snap(CurrentTime, Sequencer->GetFocusedTickResolution(), Sequencer->GetFocusedDisplayRate()); } FStretchScreenParameters ScreenParameters; ScreenParameters.DragStartPosition = DragStartPosition; ScreenParameters.CurrentDragPosition = VirtualTrackArea.PixelToFrame(LocalMousePos.X); ScreenParameters.LocalMousePos = LocalMousePos; ScreenParameters.MouseEvent = &MouseEvent; ScreenParameters.VirtualTrackArea = &VirtualTrackArea; FStretchParameters TempParams; const bool bUseGlobalParams = MouseEvent.IsAltDown() == false; for (TPair, FStretchTarget> Pair : StretchTargets) { FStretchParameters* Params = &Pair.Value.Params; if (bUseGlobalParams) { // Ensure the TempParams match the global ones (in-case something overwrote them) TempParams = GlobalParameters; Params = &TempParams; } Pair.Key->OnEndStretch(*this, ScreenParameters, Params); } Transaction.Reset(); } bool FEditToolDragOperation_Stretch::IsKeyApplicable(FKeyHandle KeyHandle, const FViewModelPtr& Owner) const { TSharedPtr Channel = Owner.ImplicitCast(); return !Channel || !SnapExclusion.Contains(Channel->GetSection()); } bool FEditToolDragOperation_Stretch::AreSectionBoundsApplicable(UMovieSceneSection* Section) const { return !SnapExclusion.Contains(Section); } bool FEditToolDragOperation_Stretch::AreSectionCustomSnapsApplicable(UMovieSceneSection* Section) const { return !SnapExclusion.Contains(Section); } FCursorReply FEditToolDragOperation_Stretch::GetCursor() const { return FCursorReply::Cursor(EMouseCursor::ResizeLeftRight); } int32 FEditToolDragOperation_Stretch::OnPaint(const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId) const { return LayerId; } } // namespace Sequencer } // namespace UE #undef LOCTEXT_NAMESPACE