Files
UnrealEngine/Engine/Source/Editor/Sequencer/Private/MVVM/Views/SSequencerTrackAreaView.cpp
2025-05-18 13:04:45 +08:00

219 lines
8.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MVVM/Views/SSequencerTrackAreaView.h"
#include "MVVM/Extensions/IObjectBindingExtension.h"
#include "MVVM/Extensions/ITrackExtension.h"
#include "MVVM/ViewModels/OutlinerSpacer.h"
#include "MVVM/ViewModels/SequencerTrackAreaViewModel.h"
#include "MVVM/Views/SOutlinerView.h"
#include "ITimeSlider.h"
#include "SequencerTimeSliderController.h"
#include "Tools/SequencerEditTool_Selection.h"
#include "Sequencer.h"
#include "ISequencerTrackEditor.h"
#include "Framework/Application/SlateApplication.h"
namespace UE
{
namespace Sequencer
{
void SSequencerTrackAreaView::Construct(const FArguments& InArgs, TWeakPtr<FTrackAreaViewModel> InWeakViewModel, TSharedRef<ITimeSliderController> InTimeSliderController)
{
TimeSliderController = InTimeSliderController;
STrackAreaView::Construct(InArgs, InWeakViewModel);
// Add the time slider controller to the input stack
InputStack.AddHandler(TimeSliderController.Get());
}
int32 SSequencerTrackAreaView::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
TSharedPtr<FTrackAreaViewModel> ViewModel = WeakViewModel.Pin();
if (ViewModel)
{
FSequencerEditorViewModel* EditorViewModel = ViewModel->GetEditor()->CastThisChecked<FSequencerEditorViewModel>();
TSharedRef<FSequencer> Sequencer = StaticCastSharedRef<FSequencer>(EditorViewModel->GetSequencer().ToSharedRef());
// Give track editors a chance to paint
// @todo_sequencer_mvvm: move track editors' code to viewmodels.
//const TArray<TSharedPtr<ISequencerTrackEditor>>& TrackEditors = Sequencer->GetTrackEditors();
//for (const TSharedPtr<ISequencerTrackEditor>& TrackEditor : TrackEditors)
//{
// LayerId = TrackEditor->PaintTrackArea(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId + 1, InWidgetStyle);
//}
}
return STrackAreaView::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
FReply SSequencerTrackAreaView::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
//FContextMenuSuppressor SuppressContextMenus(TimeSliderController.ToSharedRef());
return STrackAreaView::OnMouseButtonUp(MyGeometry, MouseEvent);
}
void SSequencerTrackAreaView::UpdateHoverStates(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
STrackAreaView::UpdateHoverStates(MyGeometry, MouseEvent);
TSharedPtr<FTrackAreaViewModel> ViewModel = WeakViewModel.Pin();
TSharedPtr<ITrackAreaHotspot> Hotspot = ViewModel ? ViewModel->GetHotspot() : nullptr;
if (!Hotspot && ViewModel)
{
// Any other region implies selection mode
ViewModel->AttemptToActivateTool(FSequencerEditTool_Selection::Identifier);
}
}
void SSequencerTrackAreaView::OnResized(const FVector2D& OldSize, const FVector2D& NewSize)
{
// Zoom by the difference in horizontal size
const float Difference = OldSize.X - SizeLastFrame->X;
TRange<double> OldRange = TimeSliderController->GetViewRange().GetAnimationTarget();
double NewRangeMin = OldRange.GetLowerBoundValue();
double NewRangeMax = OldRange.GetUpperBoundValue() + (Difference * OldRange.Size<double>() / SizeLastFrame->X);
TRange<double> ClampRange = TimeSliderController->GetClampRange();
if (NewRangeMin < ClampRange.GetLowerBoundValue() || NewRangeMax > ClampRange.GetUpperBoundValue())
{
double NewClampRangeMin = NewRangeMin < ClampRange.GetLowerBoundValue() ? NewRangeMin : ClampRange.GetLowerBoundValue();
double NewClampRangeMax = NewRangeMax > ClampRange.GetUpperBoundValue() ? NewRangeMax : ClampRange.GetUpperBoundValue();
TimeSliderController->SetClampRange(NewClampRangeMin, NewClampRangeMax);
}
TimeSliderController->SetViewRange(
NewRangeMin, NewRangeMax,
EViewRangeInterpolation::Immediate
);
}
FReply SSequencerTrackAreaView::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
using namespace UE::Sequencer;
TSharedPtr<SOutlinerView> Outliner = WeakOutliner.Pin();
TViewModelPtr<IOutlinerExtension> DroppedItem = Outliner->HitTestNode(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).Y);
if (DroppedItem && DroppedItem.AsModel()->IsA<FOutlinerSpacer>())
{
DroppedItem = nullptr;
}
WeakDroppedItem = DroppedItem;
bAllowDrop = false;
DropFrameRange.Reset();
TSharedPtr<FTrackAreaViewModel> ViewModel = WeakViewModel.Pin();
FSequencerEditorViewModel* EditorViewModel = ViewModel->GetEditor()->CastThisChecked<FSequencerEditorViewModel>();
TSharedPtr<FSequencer> Sequencer = EditorViewModel->GetSequencerImpl();
if (Sequencer && DroppedItem)
{
if (TSharedPtr<ITrackExtension> TrackDestination = DroppedItem.ImplicitCast())
{
UMovieSceneTrack* Track = TrackDestination->GetTrack();
const int32 TrackRow = TrackDestination->GetRowIndex();
TSharedPtr<IObjectBindingExtension> BindingExtension = DroppedItem.AsModel()->FindAncestorOfType<IObjectBindingExtension>();
FGuid ObjectBinding = BindingExtension ? BindingExtension->GetObjectGuid() : FGuid();
// give track editors a chance to accept the drag event
const TArray<TSharedPtr<ISequencerTrackEditor>>& TrackEditors = Sequencer->GetTrackEditors();
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition());
FFrameNumber DropFrameNumber = TimeToPixel->PixelToFrame(LocalPos.X).FrameNumber;
if (Sequencer->GetSequencerSettings()->GetForceWholeFrames())
{
DropFrameNumber = FFrameRate::Snap(DropFrameNumber, Sequencer->GetFocusedTickResolution(), Sequencer->GetFocusedDisplayRate()).FrameNumber;
}
// If shift is pressed, drop onto the current time
if (FSlateApplication::Get().GetModifierKeys().IsShiftDown())
{
DropFrameNumber = Sequencer->GetLocalTime().Time.FrameNumber;
}
FSequencerDragDropParams DragDropParams(Track, TrackRow, ObjectBinding, DropFrameNumber, TRange<FFrameNumber>());
for (const TSharedPtr<ISequencerTrackEditor>& TrackEditor : TrackEditors)
{
if (TrackEditor->OnAllowDrop(DragDropEvent, DragDropParams))
{
bAllowDrop = true;
DropFrameRange = DragDropParams.FrameRange;
return FReply::Handled();
}
}
}
}
return SPanel::OnDragOver(MyGeometry, DragDropEvent);
}
FReply SSequencerTrackAreaView::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
WeakDroppedItem = WeakOutliner.Pin()->HitTestNode(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).Y);
TSharedPtr<FViewModel> DroppedItem = WeakDroppedItem.Pin();
TSharedPtr<FTrackAreaViewModel> ViewModel = WeakViewModel.Pin();
FSequencerEditorViewModel* EditorViewModel = ViewModel->GetEditor()->CastThisChecked<FSequencerEditorViewModel>();
TSharedPtr<FSequencer> Sequencer = EditorViewModel->GetSequencerImpl();
if (Sequencer && DroppedItem)
{
ITrackExtension* TrackDestination = DroppedItem->CastThis<ITrackExtension>();
if (TrackDestination)
{
UMovieSceneTrack* Track = TrackDestination->GetTrack();
const int32 TrackRow = TrackDestination->GetRowIndex();
TSharedPtr<IObjectBindingExtension> BindingExtension = DroppedItem->FindAncestorOfType<IObjectBindingExtension>();
FGuid ObjectBinding = BindingExtension ? BindingExtension->GetObjectGuid() : FGuid();
// give track editors a chance to process the drag event
const TArray<TSharedPtr<ISequencerTrackEditor>>& TrackEditors = Sequencer->GetTrackEditors();
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition());
FFrameNumber DropFrameNumber = TimeToPixel->PixelToFrame(LocalPos.X).FrameNumber;
if (Sequencer->GetSequencerSettings()->GetForceWholeFrames())
{
DropFrameNumber = FFrameRate::Snap(DropFrameNumber, Sequencer->GetFocusedTickResolution(), Sequencer->GetFocusedDisplayRate()).FrameNumber;
}
// If shift is pressed, drop onto the current time
if (FSlateApplication::Get().GetModifierKeys().IsShiftDown())
{
DropFrameNumber = Sequencer->GetLocalTime().Time.FrameNumber;
}
FSequencerDragDropParams DragDropParams(Track, TrackRow, ObjectBinding, DropFrameNumber, TRange<FFrameNumber>());
for (const TSharedPtr<ISequencerTrackEditor>& TrackEditor : TrackEditors)
{
if (TrackEditor->OnAllowDrop(DragDropEvent, DragDropParams))
{
WeakDroppedItem = nullptr;
return TrackEditor->OnDrop(DragDropEvent, DragDropParams);
}
}
}
}
WeakDroppedItem = nullptr;
return SPanel::OnDrop(MyGeometry, DragDropEvent);
}
} // namespace Sequencer
} // namespace UE