void FSequencerTimeSliderController::PanByDelta( float InDelta )
{
	TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get().GetAnimationTarget();

	float CurrentMin = LocalViewRange.GetLowerBoundValue();
	float CurrentMax = LocalViewRange.GetUpperBoundValue();

	// Adjust the delta to be a percentage of the current range
	InDelta *= ScrubConstants::ScrollPanFraction * (CurrentMax - CurrentMin);

	SetViewRange(CurrentMin + InDelta, CurrentMax + InDelta, EViewRangeInterpolation::Animated);
}
bool FSequencerTimeSliderController::ZoomByDelta( float InDelta, float MousePositionFraction )
{
	TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get().GetAnimationTarget();
	float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();
	float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
	const float OutputViewSize = LocalViewRangeMax - LocalViewRangeMin;
	const float OutputChange = OutputViewSize * InDelta;

	float NewViewOutputMin = LocalViewRangeMin - (OutputChange * MousePositionFraction);
	float NewViewOutputMax = LocalViewRangeMax + (OutputChange * (1.f - MousePositionFraction));

	if( FMath::Abs( OutputChange ) > 0.01f && NewViewOutputMin < NewViewOutputMax )
	{
		SetViewRange(NewViewOutputMin, NewViewOutputMax, EViewRangeInterpolation::Animated);
		return true;
	}

	return false;
}
FReply FSequencerTimeSliderController::OnMouseMove( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if ( WidgetOwner.HasMouseCapture() )
	{
		if (MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ))
		{
			if (!bPanning)
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					bPanning = true;
				}
			}
			else
			{
				TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
				float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
				float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();

				FScrubRangeToScreen ScaleInfo( LocalViewRange, MyGeometry.Size );
				FVector2D ScreenDelta = MouseEvent.GetCursorDelta();
				FVector2D InputDelta;
				InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput;

				float NewViewOutputMin = LocalViewRangeMin - InputDelta.X;
				float NewViewOutputMax = LocalViewRangeMax - InputDelta.X;

				ClampViewRange(NewViewOutputMin, NewViewOutputMax);
				SetViewRange(NewViewOutputMin, NewViewOutputMax, EViewRangeInterpolation::Immediate);
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
			DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );

			if ( MouseDragType == DRAG_NONE )
			{
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					FScrubRangeToScreen RangeToScreen(LocalViewRange, MyGeometry.Size);
					const float ScrubPosition = TimeSliderArgs.ScrubPosition.Get();

					TRange<float> PlaybackRange = TimeSliderArgs.PlaybackRange.Get();
					float LocalMouseDownPos = RangeToScreen.InputToLocalX(MouseDownRange[0]);

					// Favor dragging the end position
					if (HitTestPlaybackEnd(RangeToScreen, PlaybackRange, LocalMouseDownPos, ScrubPosition))
					{
						MouseDragType = DRAG_END_RANGE;
						TimeSliderArgs.OnBeginPlaybackRangeDrag.ExecuteIfBound();
					}
					else if (HitTestPlaybackStart(RangeToScreen, PlaybackRange, LocalMouseDownPos, ScrubPosition))
					{
						MouseDragType = DRAG_START_RANGE;
						TimeSliderArgs.OnBeginPlaybackRangeDrag.ExecuteIfBound();
					}
					else if (FSlateApplication::Get().GetModifierKeys().AreModifersDown(EModifierKey::Control))
					{
						MouseDragType = DRAG_SETTING_RANGE;
					}
					else
					{
						MouseDragType = DRAG_SCRUBBING_TIME;
						TimeSliderArgs.OnBeginScrubberMovement.ExecuteIfBound();
					}
				}
			}
			else
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetLastScreenSpacePosition() );
				float NewValue = RangeToScreen.LocalXToInput( CursorPos.X );


				// Set the start range time?
				if (MouseDragType == DRAG_START_RANGE)
				{
					if (TimeSliderArgs.Settings->GetIsSnapEnabled())
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}

					SetPlaybackRangeStart(NewValue);
				}
				// Set the end range time?
				else if(MouseDragType == DRAG_END_RANGE)
				{
					if (TimeSliderArgs.Settings->GetIsSnapEnabled())
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}
					
					SetPlaybackRangeEnd(NewValue);
				}
				else if (MouseDragType == DRAG_SCRUBBING_TIME)
				{
					if ( TimeSliderArgs.Settings->GetIsSnapEnabled() && TimeSliderArgs.Settings->GetSnapPlayTimeToInterval() )
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}
					
					// Delegate responsibility for clamping to the current viewrange to the client
					CommitScrubPosition( NewValue, /*bIsScrubbing=*/true );
				}
				else if (MouseDragType == DRAG_SETTING_RANGE)
				{
					MouseDownRange[1] = NewValue;
				}
			}
		}
		return FReply::Handled();
	}

	return FReply::Unhandled();
}
FReply FSequencerTimeSliderController::OnMouseMove( TSharedRef<SWidget> WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if ( WidgetOwner->HasMouseCapture() )
	{
		if (MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ))
		{
			if (!bPanning)
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					bPanning = true;
				}
			}
			else
			{
				TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
				float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
				float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();

				FScrubRangeToScreen ScaleInfo( LocalViewRange, MyGeometry.Size );
				FVector2D ScreenDelta = MouseEvent.GetCursorDelta();
				FVector2D InputDelta;
				InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput;

				float NewViewOutputMin = LocalViewRangeMin - InputDelta.X;
				float NewViewOutputMax = LocalViewRangeMax - InputDelta.X;

				SetViewRange(NewViewOutputMin, NewViewOutputMax, EViewRangeInterpolation::Immediate);
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			if ( !bDraggingScrubber )
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					bDraggingScrubber = true;
					TimeSliderArgs.OnBeginScrubberMovement.ExecuteIfBound();
				}
			}
			else
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetLastScreenSpacePosition() );
				float NewValue = RangeToScreen.LocalXToInput( CursorPos.X );

				const USequencerSettings* Settings = GetDefault<USequencerSettings>();
				if ( Settings->GetIsSnapEnabled() && Settings->GetSnapPlayTimeToInterval() )
				{
					NewValue = Settings->SnapTimeToInterval(NewValue);
				}

				CommitScrubPosition( NewValue, /*bIsScrubbing=*/true );
			}
		}
		return FReply::Handled();
	}

	return FReply::Unhandled();
}