You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Deprecate TAlignmentWidgetSlotMixin old declartive function. They were not invalidating the widget. Deprecate TPanelChildren.Add and Insert function. We now use TUniquePtr, the ownership of the Slot wouldn't exist outside of the life of the slot. #jira UE-109145 #preflight 60c262b49e139d000114edda [CL 16639956 by Patrick Boutot in ue5-main branch]
604 lines
19 KiB
C++
604 lines
19 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 "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() && 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() && DroppedNode.Pin()->GetType() == ESequencerNode::Track && Sequencer.IsValid())
|
|
{
|
|
TSharedPtr<FSequencerTrackNode> TrackNode = StaticCastSharedPtr<FSequencerTrackNode>(DroppedNode.Pin());
|
|
UMovieSceneTrack* Track = TrackNode->GetTrack();
|
|
int32 RowIndex = TrackNode->GetSubTrackMode() == FSequencerTrackNode::ESubTrackMode::SubTrack ? TrackNode->GetRowIndex() : 0;
|
|
|
|
FGuid ObjectBinding;
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = TrackNode->FindParentObjectBindingNode();
|
|
if (ObjectBindingNode.IsValid())
|
|
{
|
|
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;
|
|
}
|
|
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() && DroppedNode.Pin()->GetType() == ESequencerNode::Track && Sequencer.IsValid())
|
|
{
|
|
TSharedPtr<FSequencerTrackNode> TrackNode = StaticCastSharedPtr<FSequencerTrackNode>(DroppedNode.Pin());
|
|
UMovieSceneTrack* Track = TrackNode->GetTrack();
|
|
int32 RowIndex = TrackNode->GetSubTrackMode() == FSequencerTrackNode::ESubTrackMode::SubTrack ? TrackNode->GetRowIndex() : 0;
|
|
|
|
FGuid ObjectBinding;
|
|
TSharedPtr<FSequencerObjectBindingNode> ObjectBindingNode = TrackNode->FindParentObjectBindingNode();
|
|
if (ObjectBindingNode.IsValid())
|
|
{
|
|
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;
|
|
}
|
|
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);
|
|
}
|