You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This represents UE4/Main @17774255, Release-5.0 @17791557 and Dev-PerfTest @17789485 [CL 17794212 by aurel cordonnier in ue5-release-engine-test branch]
641 lines
20 KiB
C++
641 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SSequencerTrackArea.h"
|
|
#include "Types/PaintArgs.h"
|
|
#include "Layout/ArrangedChildren.h"
|
|
#include "Rendering/DrawElements.h"
|
|
#include "Layout/LayoutUtils.h"
|
|
#include "Widgets/SWeakWidget.h"
|
|
#include "EditorStyleSet.h"
|
|
#include "SSequencerTrackLane.h"
|
|
#include "SSequencerTreeView.h"
|
|
#include "ISequencerHotspot.h"
|
|
#include "SequencerHotspots.h"
|
|
#include "Tools/SequencerEditTool_Movement.h"
|
|
#include "Tools/SequencerEditTool_Selection.h"
|
|
#include "ISequencerTrackEditor.h"
|
|
#include "DisplayNodes/SequencerTrackNode.h"
|
|
#include "DisplayNodes/SequencerObjectBindingNode.h"
|
|
#include "CommonMovieSceneTools.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "Styling/StyleColors.h"
|
|
|
|
FTrackAreaSlot::FTrackAreaSlot(const TSharedPtr<SSequencerTrackLane>& InSlotContent)
|
|
: TAlignmentWidgetSlotMixin<FTrackAreaSlot>(HAlign_Fill, VAlign_Top)
|
|
{
|
|
TrackLane = InSlotContent;
|
|
|
|
this->AttachWidget(
|
|
SNew(SWeakWidget)
|
|
.PossiblyNullContent(InSlotContent)
|
|
);
|
|
}
|
|
|
|
|
|
float FTrackAreaSlot::GetVerticalOffset() const
|
|
{
|
|
auto PinnedTrackLane = TrackLane.Pin();
|
|
return PinnedTrackLane.IsValid() ? PinnedTrackLane->GetPhysicalPosition() : 0.f;
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::Construct(const FArguments& InArgs, TSharedRef<FSequencerTimeSliderController> InTimeSliderController, TSharedRef<FSequencer> InSequencer)
|
|
{
|
|
Sequencer = InSequencer;
|
|
TimeSliderController = InTimeSliderController;
|
|
|
|
bShowPinnedNodes = false;
|
|
|
|
// Input stack in order or priority
|
|
|
|
// Space for the edit tool
|
|
InputStack.AddHandler(nullptr);
|
|
// The time slider controller
|
|
InputStack.AddHandler(TimeSliderController.Get());
|
|
|
|
EditTools.Add(MakeShared<FSequencerEditTool_Selection>(*InSequencer, *this));
|
|
EditTools.Add(MakeShared<FSequencerEditTool_Movement>(*InSequencer));
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::SetTreeView(const TSharedPtr<SSequencerTreeView>& InTreeView)
|
|
{
|
|
TreeView = InTreeView;
|
|
}
|
|
|
|
void SSequencerTrackArea::Empty()
|
|
{
|
|
TrackSlots.Empty();
|
|
Children.Empty();
|
|
}
|
|
|
|
void SSequencerTrackArea::AddTrackSlot(const TSharedRef<FSequencerDisplayNode>& InNode, const TSharedPtr<SSequencerTrackLane>& InSlot)
|
|
{
|
|
TrackSlots.Add(InNode, InSlot);
|
|
Children.AddSlot(FTrackAreaSlot::FSlotArguments(MakeUnique<FTrackAreaSlot>(InSlot)));
|
|
}
|
|
|
|
|
|
TSharedPtr<SSequencerTrackLane> SSequencerTrackArea::FindTrackSlot(const TSharedRef<FSequencerDisplayNode>& InNode)
|
|
{
|
|
return TrackSlots.FindRef(InNode).Pin();
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const
|
|
{
|
|
for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex)
|
|
{
|
|
const FTrackAreaSlot& CurChild = Children[ChildIndex];
|
|
|
|
const EVisibility ChildVisibility = CurChild.GetWidget()->GetVisibility();
|
|
if (!ArrangedChildren.Accepts(ChildVisibility))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TSharedPtr<SSequencerTrackLane> PinnedTrackLane = CurChild.TrackLane.Pin();
|
|
if (!PinnedTrackLane.IsValid() || PinnedTrackLane->IsPinned() != bShowPinnedNodes)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const FMargin Padding(0, CurChild.GetVerticalOffset(), 0, 0);
|
|
|
|
AlignmentArrangeResult XResult = AlignChild<Orient_Horizontal>(AllottedGeometry.GetLocalSize().X, CurChild, Padding, 1.0f, false);
|
|
AlignmentArrangeResult YResult = AlignChild<Orient_Vertical>(AllottedGeometry.GetLocalSize().Y, CurChild, Padding, 1.0f, false);
|
|
|
|
ArrangedChildren.AddWidget(ChildVisibility,
|
|
AllottedGeometry.MakeChild(
|
|
CurChild.GetWidget(),
|
|
FVector2D(XResult.Offset,YResult.Offset),
|
|
FVector2D(XResult.Size, YResult.Size)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
FVector2D SSequencerTrackArea::ComputeDesiredSize( float ) const
|
|
{
|
|
FVector2D MaxSize(0,0);
|
|
for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex)
|
|
{
|
|
const FTrackAreaSlot& CurChild = Children[ChildIndex];
|
|
|
|
const EVisibility ChildVisibilty = CurChild.GetWidget()->GetVisibility();
|
|
if (ChildVisibilty != EVisibility::Collapsed)
|
|
{
|
|
FVector2D ChildDesiredSize = CurChild.GetWidget()->GetDesiredSize();
|
|
MaxSize.X = FMath::Max(MaxSize.X, ChildDesiredSize.X);
|
|
MaxSize.Y = FMath::Max(MaxSize.Y, ChildDesiredSize.Y);
|
|
}
|
|
}
|
|
|
|
return MaxSize;
|
|
}
|
|
|
|
|
|
FChildren* SSequencerTrackArea::GetChildren()
|
|
{
|
|
return &Children;
|
|
}
|
|
|
|
|
|
int32 SSequencerTrackArea::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
// give track editors a chance to paint
|
|
auto TrackEditors = Sequencer.Pin()->GetTrackEditors();
|
|
|
|
for (const auto& TrackEditor : TrackEditors)
|
|
{
|
|
LayerId = TrackEditor->PaintTrackArea(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId + 1, InWidgetStyle);
|
|
}
|
|
|
|
// paint the child widgets
|
|
FArrangedChildren ArrangedChildren(EVisibility::Visible);
|
|
ArrangeChildren(AllottedGeometry, ArrangedChildren);
|
|
|
|
const FPaintArgs NewArgs = Args.WithNewParent(this);
|
|
|
|
for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)
|
|
{
|
|
FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];
|
|
FSlateRect ChildClipRect = MyCullingRect.IntersectionWith( CurWidget.Geometry.GetLayoutBoundingRect() );
|
|
const int32 ThisWidgetLayerId = CurWidget.Widget->Paint( NewArgs, CurWidget.Geometry, ChildClipRect, OutDrawElements, LayerId + 2, InWidgetStyle, ShouldBeEnabled( bParentEnabled ) );
|
|
|
|
LayerId = FMath::Max(LayerId, ThisWidgetLayerId);
|
|
}
|
|
|
|
if (EditTool.IsValid())
|
|
{
|
|
LayerId = EditTool->OnPaint(AllottedGeometry, MyCullingRect, OutDrawElements, LayerId + 1);
|
|
}
|
|
|
|
TOptional<FHighlightRegion> HighlightRegion = TreeView.Pin()->GetHighlightRegion();
|
|
if (HighlightRegion.IsSet())
|
|
{
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
LayerId+1,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(0.f, HighlightRegion->Top - 4.f), FVector2D(AllottedGeometry.GetLocalSize().X, 4.f)),
|
|
FEditorStyle::GetBrush("Sequencer.TrackHoverHighlight_Top"),
|
|
ESlateDrawEffect::None,
|
|
FLinearColor::Black
|
|
);
|
|
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
LayerId+1,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(0.f, HighlightRegion->Bottom), FVector2D(AllottedGeometry.GetLocalSize().X, 4.f)),
|
|
FEditorStyle::GetBrush("Sequencer.TrackHoverHighlight_Bottom"),
|
|
ESlateDrawEffect::None,
|
|
FLinearColor::Black
|
|
);
|
|
}
|
|
|
|
|
|
// Draw drop target
|
|
if (DroppedNode.IsValid() && DroppedNode.Pin()->GetType() != ESequencerNode::Spacer && TrackSlots.Contains(DroppedNode.Pin()))
|
|
{
|
|
TSharedPtr<SSequencerTrackLane> TrackLane = TrackSlots.FindRef(DroppedNode.Pin()).Pin();
|
|
|
|
FGeometry NodeGeometry = TrackLane.Get()->GetCachedGeometry();
|
|
|
|
FSlateColor DashColor = bAllowDrop ? FStyleColors::AccentBlue : FStyleColors::Error;
|
|
|
|
const FSlateBrush* HorizontalBrush = FEditorStyle::GetBrush("WideDash.Horizontal");
|
|
const FSlateBrush* VerticalBrush = FEditorStyle::GetBrush("WideDash.Vertical");
|
|
|
|
int32 DashLayer = LayerId + 1;
|
|
|
|
float DropMinX = 0.f;
|
|
float DropMaxX = NodeGeometry.GetLocalSize().X;
|
|
|
|
if (DropFrameRange.IsSet())
|
|
{
|
|
FTimeToPixel TimeToPixel(NodeGeometry, Sequencer.Pin()->GetViewRange(), Sequencer.Pin()->GetFocusedTickResolution());
|
|
DropMinX = TimeToPixel.FrameToPixel(DropFrameRange.GetValue().GetLowerBoundValue());
|
|
DropMaxX = TimeToPixel.FrameToPixel(DropFrameRange.GetValue().GetUpperBoundValue());
|
|
}
|
|
|
|
// Top
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
DashLayer,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(DropMinX, TrackLane.Get()->GetPhysicalPosition()), FVector2D(DropMaxX-DropMinX, HorizontalBrush->ImageSize.Y)),
|
|
HorizontalBrush,
|
|
ESlateDrawEffect::None,
|
|
DashColor.GetSpecifiedColor());
|
|
|
|
// Bottom
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
DashLayer,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(DropMinX, TrackLane.Get()->GetPhysicalPosition() + (TrackLane.Get()->GetCachedGeometry().GetLocalSize().Y - HorizontalBrush->ImageSize.Y)), FVector2D(DropMaxX-DropMinX, HorizontalBrush->ImageSize.Y)),
|
|
HorizontalBrush,
|
|
ESlateDrawEffect::None,
|
|
DashColor.GetSpecifiedColor());
|
|
|
|
// Left
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
DashLayer,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(DropMinX, TrackLane.Get()->GetPhysicalPosition()), FVector2D(VerticalBrush->ImageSize.X, TrackLane.Get()->GetCachedGeometry().GetLocalSize().Y)),
|
|
VerticalBrush,
|
|
ESlateDrawEffect::None,
|
|
DashColor.GetSpecifiedColor());
|
|
|
|
// Right
|
|
FSlateDrawElement::MakeBox(
|
|
OutDrawElements,
|
|
DashLayer,
|
|
AllottedGeometry.ToPaintGeometry(FVector2D(DropMaxX - VerticalBrush->ImageSize.X, TrackLane.Get()->GetPhysicalPosition()), FVector2D(VerticalBrush->ImageSize.X, TrackLane.Get()->GetCachedGeometry().GetLocalSize().Y)),
|
|
VerticalBrush,
|
|
ESlateDrawEffect::None,
|
|
DashColor.GetSpecifiedColor());
|
|
}
|
|
}
|
|
|
|
return LayerId;
|
|
}
|
|
|
|
|
|
FReply SSequencerTrackArea::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
// Always ensure the edit tool is set up
|
|
InputStack.SetHandlerAt(0, EditTool.Get());
|
|
return InputStack.HandleMouseButtonDown(*this, MyGeometry, MouseEvent);
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
|
|
FReply SSequencerTrackArea::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
FContextMenuSuppressor SuppressContextMenus(TimeSliderController.ToSharedRef());
|
|
|
|
// Always ensure the edit tool is set up
|
|
InputStack.SetHandlerAt(0, EditTool.Get());
|
|
return InputStack.HandleMouseButtonUp(*this, MyGeometry, MouseEvent);
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
bool SSequencerTrackArea::CanActivateEditTool(FName Identifier) const
|
|
{
|
|
auto IdentifierIsFound = [=](TSharedPtr<ISequencerEditTool> InEditTool){ return InEditTool->GetIdentifier() == Identifier; };
|
|
if (InputStack.GetCapturedIndex() != INDEX_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
else if (!EditTool.IsValid())
|
|
{
|
|
return EditTools.ContainsByPredicate(IdentifierIsFound);
|
|
}
|
|
// Can't activate a tool that's already active
|
|
else if (EditTool->GetIdentifier() == Identifier)
|
|
{
|
|
return false;
|
|
}
|
|
// Can only activate a new tool if the current one will let us
|
|
else
|
|
{
|
|
return EditTool->CanDeactivate() && EditTools.ContainsByPredicate(IdentifierIsFound);
|
|
}
|
|
}
|
|
|
|
bool SSequencerTrackArea::AttemptToActivateTool(FName Identifier)
|
|
{
|
|
if ( Sequencer.IsValid() && CanActivateEditTool(Identifier) )
|
|
{
|
|
EditTool = *EditTools.FindByPredicate([=](TSharedPtr<ISequencerEditTool> InEditTool){ return InEditTool->GetIdentifier() == Identifier; });
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SSequencerTrackArea::UpdateHoverStates( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
TSharedPtr<SSequencerTreeView> PinnedTreeView = TreeView.Pin();
|
|
|
|
// Set the node that we are hovering
|
|
TSharedPtr<FSequencerDisplayNode> NewHoveredNode = PinnedTreeView->HitTestNode(MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()).Y);
|
|
PinnedTreeView->GetNodeTree()->SetHoveredNode(NewHoveredNode);
|
|
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
TSharedPtr<ISequencerHotspot> Hotspot = Sequencer.Pin()->GetHotspot();
|
|
if (Hotspot.IsValid())
|
|
{
|
|
Hotspot->UpdateOnHover(*this, *Sequencer.Pin());
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Any other region implies selection mode
|
|
AttemptToActivateTool(FSequencerEditTool_Selection::Identifier);
|
|
}
|
|
|
|
FReply SSequencerTrackArea::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
UpdateHoverStates(MyGeometry, MouseEvent);
|
|
|
|
// Always ensure the edit tool is set up
|
|
InputStack.SetHandlerAt(0, EditTool.Get());
|
|
|
|
FReply Reply = InputStack.HandleMouseMove(*this, MyGeometry, MouseEvent);
|
|
|
|
// Handle right click scrolling on the track area, if the captured index is that of the time slider
|
|
if (Reply.IsEventHandled() && InputStack.GetCapturedIndex() == 1)
|
|
{
|
|
if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton) && HasMouseCapture())
|
|
{
|
|
TreeView.Pin()->ScrollByDelta(-MouseEvent.GetCursorDelta().Y);
|
|
}
|
|
}
|
|
|
|
return Reply;
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
|
|
FReply SSequencerTrackArea::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
// Always ensure the edit tool is set up
|
|
InputStack.SetHandlerAt(0, EditTool.Get());
|
|
FReply EditToolHandle = InputStack.HandleMouseWheel(*this, MyGeometry, MouseEvent);
|
|
if (EditToolHandle.IsEventHandled())
|
|
{
|
|
return EditToolHandle;
|
|
}
|
|
|
|
const float ScrollAmount = -MouseEvent.GetWheelDelta() * GetGlobalScrollAmount();
|
|
Sequencer.Pin()->VerticalScroll(ScrollAmount);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
{
|
|
DroppedNode.Reset();
|
|
bAllowDrop = false;
|
|
DropFrameRange.Reset();
|
|
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
if (EditTool.IsValid())
|
|
{
|
|
EditTool->OnMouseEnter(*this, MyGeometry, MouseEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::OnMouseLeave(const FPointerEvent& MouseEvent)
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
if (EditTool.IsValid())
|
|
{
|
|
EditTool->OnMouseLeave(*this, MouseEvent);
|
|
}
|
|
|
|
TreeView.Pin()->GetNodeTree()->SetHoveredNode(nullptr);
|
|
}
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::OnMouseCaptureLost(const FCaptureLostEvent& CaptureLostEvent)
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
if (EditTool.IsValid())
|
|
{
|
|
EditTool->OnMouseCaptureLost();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
FCursorReply SSequencerTrackArea::OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const
|
|
{
|
|
if ( Sequencer.IsValid() )
|
|
{
|
|
if (CursorEvent.IsMouseButtonDown(EKeys::RightMouseButton) && HasMouseCapture())
|
|
{
|
|
return FCursorReply::Cursor(EMouseCursor::GrabHandClosed);
|
|
}
|
|
|
|
if (EditTool.IsValid())
|
|
{
|
|
return EditTool->OnCursorQuery(MyGeometry, CursorEvent);
|
|
}
|
|
}
|
|
|
|
return FCursorReply::Unhandled();
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
|
|
{
|
|
FVector2D Size = AllottedGeometry.GetLocalSize();
|
|
|
|
if (!IsSlave() && SizeLastFrame.IsSet() && Size.X != SizeLastFrame->X)
|
|
{
|
|
// Zoom by the difference in horizontal size
|
|
const float Difference = Size.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
|
|
);
|
|
}
|
|
|
|
SizeLastFrame = Size;
|
|
|
|
for (int32 Index = 0; Index < Children.Num();)
|
|
{
|
|
if (!StaticCastSharedRef<SWeakWidget>(Children[Index].GetWidget())->ChildWidgetIsValid())
|
|
{
|
|
Children.RemoveAt(Index);
|
|
}
|
|
else
|
|
{
|
|
++Index;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SSequencerTrackArea::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
|
{
|
|
SPanel::OnDragEnter(MyGeometry, DragDropEvent);
|
|
}
|
|
|
|
void SSequencerTrackArea::OnDragLeave(const FDragDropEvent& DragDropEvent)
|
|
{
|
|
DroppedNode.Reset();
|
|
SPanel::OnDragLeave(DragDropEvent);
|
|
}
|
|
|
|
FReply SSequencerTrackArea::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
|
{
|
|
TSharedPtr<SSequencerTreeView> PinnedTreeView = TreeView.Pin();
|
|
|
|
DroppedNode = PinnedTreeView->HitTestNode(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).Y);
|
|
bAllowDrop = false;
|
|
DropFrameRange.Reset();
|
|
|
|
if (DroppedNode.IsValid() && Sequencer.IsValid())
|
|
{
|
|
UMovieSceneTrack* Track = nullptr;
|
|
int32 RowIndex = 0;
|
|
FGuid ObjectBinding;
|
|
|
|
if (DroppedNode.Pin()->GetType() == ESequencerNode::Track)
|
|
{
|
|
TSharedPtr<FSequencerTrackNode> TrackNode = StaticCastSharedPtr<FSequencerTrackNode>(DroppedNode.Pin());
|
|
Track = TrackNode->GetTrack();
|
|
RowIndex = TrackNode->GetSubTrackMode() == FSequencerTrackNode::ESubTrackMode::SubTrack ? TrackNode->GetRowIndex() : 0;
|
|
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = TrackNode->FindParentObjectBindingNode();
|
|
if (ObjectBindingNode.IsValid())
|
|
{
|
|
ObjectBinding = ObjectBindingNode->GetObjectBinding();
|
|
}
|
|
}
|
|
else if (DroppedNode.Pin()->GetType() == ESequencerNode::Object)
|
|
{
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = StaticCastSharedPtr<FSequencerObjectBindingNode>(DroppedNode.Pin());
|
|
ObjectBinding = ObjectBindingNode->GetObjectBinding();
|
|
}
|
|
|
|
// give track editors a chance to accept the drag event
|
|
auto TrackEditors = Sequencer.Pin()->GetTrackEditors();
|
|
|
|
FTimeToPixel TimeToPixel(MyGeometry, Sequencer.Pin()->GetViewRange(), Sequencer.Pin()->GetFocusedTickResolution());
|
|
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition());
|
|
FFrameNumber DropFrameNumber = TimeToPixel.PixelToFrame(LocalPos.X).FrameNumber;
|
|
if (Sequencer.Pin()->GetSequencerSettings()->GetIsSnapEnabled() && Sequencer.Pin()->GetSequencerSettings()->GetSnapPlayTimeToInterval())
|
|
{
|
|
DropFrameNumber = FFrameRate::Snap(DropFrameNumber, Sequencer.Pin()->GetFocusedTickResolution(), Sequencer.Pin()->GetFocusedDisplayRate()).FrameNumber;
|
|
}
|
|
|
|
// If shift is pressed, drop onto the current time
|
|
if (FSlateApplication::Get().GetModifierKeys().IsShiftDown())
|
|
{
|
|
DropFrameNumber = Sequencer.Pin()->GetLocalTime().Time.FrameNumber;
|
|
}
|
|
|
|
FSequencerDragDropParams DragDropParams(Track, RowIndex, ObjectBinding, DropFrameNumber, TRange<FFrameNumber>());
|
|
|
|
for (const auto& TrackEditor : TrackEditors)
|
|
{
|
|
if (TrackEditor->OnAllowDrop(DragDropEvent, DragDropParams))
|
|
{
|
|
bAllowDrop = true;
|
|
DropFrameRange = DragDropParams.FrameRange;
|
|
return FReply::Handled();
|
|
}
|
|
}
|
|
}
|
|
|
|
return SPanel::OnDragOver(MyGeometry, DragDropEvent);
|
|
}
|
|
|
|
|
|
FReply SSequencerTrackArea::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
|
{
|
|
TSharedPtr<SSequencerTreeView> PinnedTreeView = TreeView.Pin();
|
|
|
|
DroppedNode = PinnedTreeView->HitTestNode(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).Y);
|
|
|
|
if (DroppedNode.IsValid() && Sequencer.IsValid())
|
|
{
|
|
UMovieSceneTrack* Track = nullptr;
|
|
int32 RowIndex = 0;
|
|
FGuid ObjectBinding;
|
|
|
|
if (DroppedNode.Pin()->GetType() == ESequencerNode::Track)
|
|
{
|
|
TSharedPtr<FSequencerTrackNode> TrackNode = StaticCastSharedPtr<FSequencerTrackNode>(DroppedNode.Pin());
|
|
Track = TrackNode->GetTrack();
|
|
RowIndex = TrackNode->GetSubTrackMode() == FSequencerTrackNode::ESubTrackMode::SubTrack ? TrackNode->GetRowIndex() : 0;
|
|
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = TrackNode->FindParentObjectBindingNode();
|
|
if (ObjectBindingNode.IsValid())
|
|
{
|
|
ObjectBinding = ObjectBindingNode->GetObjectBinding();
|
|
}
|
|
}
|
|
else if (DroppedNode.Pin()->GetType() == ESequencerNode::Object)
|
|
{
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = StaticCastSharedPtr<FSequencerObjectBindingNode>(DroppedNode.Pin());
|
|
ObjectBinding = ObjectBindingNode->GetObjectBinding();
|
|
}
|
|
|
|
// give track editors a chance to process the drag event
|
|
auto TrackEditors = Sequencer.Pin()->GetTrackEditors();
|
|
|
|
FTimeToPixel TimeToPixel(MyGeometry, Sequencer.Pin()->GetViewRange(), Sequencer.Pin()->GetFocusedTickResolution());
|
|
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition());
|
|
FFrameNumber DropFrameNumber = TimeToPixel.PixelToFrame(LocalPos.X).FrameNumber;
|
|
if (Sequencer.Pin()->GetSequencerSettings()->GetIsSnapEnabled() && Sequencer.Pin()->GetSequencerSettings()->GetSnapPlayTimeToInterval())
|
|
{
|
|
DropFrameNumber = FFrameRate::Snap(DropFrameNumber, Sequencer.Pin()->GetFocusedTickResolution(), Sequencer.Pin()->GetFocusedDisplayRate()).FrameNumber;
|
|
}
|
|
|
|
// If shift is pressed, drop onto the current time
|
|
if (FSlateApplication::Get().GetModifierKeys().IsShiftDown())
|
|
{
|
|
DropFrameNumber = Sequencer.Pin()->GetLocalTime().Time.FrameNumber;
|
|
}
|
|
|
|
FSequencerDragDropParams DragDropParams(Track, RowIndex, ObjectBinding, DropFrameNumber, TRange<FFrameNumber>());
|
|
|
|
for (const auto& TrackEditor : TrackEditors)
|
|
{
|
|
if (TrackEditor->OnAllowDrop(DragDropEvent, DragDropParams))
|
|
{
|
|
DroppedNode.Reset();
|
|
|
|
return TrackEditor->OnDrop(DragDropEvent, DragDropParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
DroppedNode.Reset();
|
|
|
|
return SPanel::OnDrop(MyGeometry, DragDropEvent);
|
|
}
|