예제 #1
0
/**
 * See SWidget::OnMouseButtonUp.
 *
 * @param MyGeometry The Geometry of the widget receiving the event
 * @param MouseEvent Information about the input event
 *
 * @return Whether the event was handled along with possible requests for the system to take action.
 */
FReply SCheckBox::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
	{
		bIsPressed = false;

		if( ClickMethod == EButtonClickMethod::MouseDown )
		{
			// NOTE: If we're configured to click on mouse-down, then we never capture the mouse thus
			//       may never receive an OnMouseButtonUp() call.  We make sure that our bIsPressed
			//       state is reset by overriding OnMouseLeave().
		}
		else
		{
			const bool IsUnderMouse = MyGeometry.IsUnderLocation( MouseEvent.GetScreenSpacePosition() );
			if ( IsUnderMouse )
			{
				// If we were asked to allow the button to be clicked on mouse up, regardless of whether the user
				// pressed the button down first, then we'll allow the click to proceed without an active capture
				if( ClickMethod == EButtonClickMethod::MouseUp || HasMouseCapture() )
				{
					ToggleCheckedState();
					const TAttribute<ESlateCheckBoxState::Type>& State = IsCheckboxChecked.Get();
					if(State == ESlateCheckBoxState::Checked)
					{
						PlayCheckedSound();
					}
					else if(State == ESlateCheckBoxState::Unchecked)
					{
						PlayUncheckedSound();
					}
				}
			}
		}

		return FReply::Handled().ReleaseMouseCapture();
	}

	return FReply::Unhandled();
}
예제 #2
0
FReply FVisualLoggerTimeSliderController::OnMouseButtonUp( TSharedRef<SWidget> WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && WidgetOwner->HasMouseCapture();
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && WidgetOwner->HasMouseCapture() && TimeSliderArgs.AllowZoom ;
	
	if ( bHandleRightMouseButton )
	{
		if (!bPanning)
		{
			// return unhandled in case our parent wants to use our right mouse button to open a context menu
			return FReply::Unhandled().ReleaseMouseCapture();
		}
		
		bPanning = false;
		FReply::Handled().CaptureMouse(WidgetOwner).UseHighPrecisionMouseMovement(WidgetOwner);

		return FReply::Handled().ReleaseMouseCapture();
	}
	else if ( bHandleLeftMouseButton )
	{
		if( bDraggingScrubber )
		{
			TimeSliderArgs.OnEndScrubberMovement.ExecuteIfBound();
		}
		else
		{
			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			CommitScrubPosition( NewValue, /*bIsScrubbing=*/false );
		}

		bDraggingScrubber = false;
		return FReply::Handled().ReleaseMouseCapture();

	}

	return FReply::Unhandled();
}
예제 #3
0
/**
* The system asks each widget under the mouse to provide a cursor. This event is bubbled.
* 
* @return FCursorReply::Unhandled() if the event is not handled; return FCursorReply::Cursor() otherwise.
*/
FCursorReply SSplitter::OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const
{
	const FVector2D LocalMousePosition = MyGeometry.AbsoluteToLocal( CursorEvent.GetScreenSpacePosition() );

	TArray<FLayoutGeometry> LayoutChildren = ArrangeChildrenForLayout(MyGeometry);

	// Hit test which handle we are hovering over.		
	const int32 CurrentHoveredHandleIndex = (Orientation == Orient_Horizontal)
		? GetHandleBeingResizedFromMousePosition<Orient_Horizontal>( PhysicalSplitterHandleSize, HitDetectionSplitterHandleSize, LocalMousePosition, LayoutChildren )
		: GetHandleBeingResizedFromMousePosition<Orient_Vertical>( PhysicalSplitterHandleSize, HitDetectionSplitterHandleSize, LocalMousePosition, LayoutChildren );

	if (CurrentHoveredHandleIndex != INDEX_NONE)
	{
		return ( Orientation == Orient_Horizontal )
			? FCursorReply::Cursor( EMouseCursor::ResizeLeftRight )
			: FCursorReply::Cursor( EMouseCursor::ResizeUpDown );
	}
	else
	{
		return FCursorReply::Unhandled();
	}
}
예제 #4
0
float STrack::GetNodeDragDropDataPos( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent )
{
	float DataPos = 0.f;
	TSharedPtr<FTrackNodeDragDropOp> DragDropOp = StaticCastSharedPtr<FTrackNodeDragDropOp>(DragDropEvent.GetOperation());
	if(DragDropOp.IsValid())
	{
		TSharedPtr<STrackNode> TrackNode = DragDropOp->OriginalTrackNode.Pin();
		if(TrackNode.IsValid())
		{
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(TrackNode->GetDragDropScreenSpacePosition(MyGeometry, DragDropEvent));
			DataPos = LocalToDataX(CursorPos.X, MyGeometry);
			if(TrackNode->SnapToDragBars())
			{
				float OriginalX = DataPos;
				DataPos = GetSnappedPosForLocalPos(MyGeometry, CursorPos.X);
				TrackNode->OnSnapNodeDataPosition(OriginalX, DataPos);
			}
		}
	}

	return DataPos;
}
예제 #5
0
void SGraphPanel::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const
{
	SNodePanel::OnArrangeChildren(AllottedGeometry, ArrangedChildren);

	FArrangedChildren MyArrangedChildren(ArrangedChildren.GetFilter());
	for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)
	{
		FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];
		TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(CurWidget.Widget);

		TArray<FOverlayWidgetInfo> OverlayWidgets = ChildNode->GetOverlayWidgets(false, CurWidget.Geometry.Size);

		for (int32 WidgetIndex = 0; WidgetIndex < OverlayWidgets.Num(); ++WidgetIndex)
		{
			FOverlayWidgetInfo& OverlayInfo = OverlayWidgets[WidgetIndex];

			MyArrangedChildren.AddWidget(AllottedGeometry.MakeChild( OverlayInfo.Widget.ToSharedRef(), CurWidget.Geometry.Position + OverlayInfo.OverlayOffset, OverlayInfo.Widget->GetDesiredSize(), GetZoomAmount() ));
		}
	}

	ArrangedChildren.Append(MyArrangedChildren);
}
예제 #6
0
int32 FSlateImageRun::OnPaint( const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const 
{
	// The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry
	const float InverseScale = Inverse(AllottedGeometry.Scale);

	if ( Image->DrawAs != ESlateBrushDrawType::NoDrawType )
	{
		const FColor FinalColorAndOpacity( InWidgetStyle.GetColorAndOpacityTint() * Image->GetTint( InWidgetStyle ) );
		const uint32 DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
		FSlateDrawElement::MakeBox(
			OutDrawElements, 
			++LayerId, 
			AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))), 
			Image, 
			MyClippingRect, 
			DrawEffects, 
			FinalColorAndOpacity
			);
	}

	return LayerId;
}
예제 #7
0
void SSection::CheckForEdgeInteraction( const FPointerEvent& MouseEvent, const FGeometry& SectionGeometry )
{
	bLeftEdgeHovered = false;
	bRightEdgeHovered = false;
	bLeftEdgePressed = false;
	bRightEdgePressed = false;

	if (!SectionInterface->SectionIsResizable())
	{
		return;
	}

	// Make areas to the left and right of the geometry.  We will use these areas to determine if someone dragged the left or right edge of a section
	FGeometry SectionRectLeft = SectionGeometry.MakeChild(
		FVector2D::ZeroVector,
		FVector2D( SequencerSectionConstants::SectionGripSize, SectionGeometry.Size.Y )
		);

	FGeometry SectionRectRight = SectionGeometry.MakeChild(
		FVector2D( SectionGeometry.Size.X - SequencerSectionConstants::SectionGripSize, 0 ), 
		SectionGeometry.Size 
		);

	if( SectionRectLeft.IsUnderLocation( MouseEvent.GetScreenSpacePosition() ) )
	{
		if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
		{
			bLeftEdgePressed = true;
		}
		else
		{
			bLeftEdgeHovered = true;
		}
	}
	else if( SectionRectRight.IsUnderLocation( MouseEvent.GetScreenSpacePosition() ) )
	{
		if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
		{
			bRightEdgePressed = true;
		}
		else
		{
			bRightEdgeHovered = true;
		}
	}
}
	virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override
	{
		if (!SlideCurve.IsPlaying())
		{
			StartSlideOffset = 0;
		}

		// Delete any widgets that are now offscreen
		if (Children.Num() != 0)
		{
			const float Alpha = 1.f - SlideCurve.GetLerp();
			float PositionSoFar = AllottedGeometry.GetLocalSize().Y + Alpha * StartSlideOffset;

			for (int32 Index = 0; PositionSoFar > 0 && Index < NumSlots(); ++Index)
			{
				const SBoxPanel::FSlot& CurChild = Children[Index];
				const EVisibility ChildVisibility = CurChild.GetWidget()->GetVisibility();

				if (ChildVisibility != EVisibility::Collapsed)
				{
					const FVector2D ChildDesiredSize = CurChild.GetWidget()->GetDesiredSize();
					PositionSoFar -= ChildDesiredSize.Y + CurChild.SlotPadding.Get().GetTotalSpaceAlong<Orient_Vertical>();
				}
			}

			for (int32 Index = MaxNumVisible; Index < Children.Num(); )
			{
				if (StaticCastSharedRef<SWidgetStackItem>(Children[Index].GetWidget())->bIsFinished)
				{
					Children.RemoveAt(Index);
				}
				else
				{
					++Index;
				}
			}
		}
	}
예제 #9
0
FReply FScrollyZoomy::OnMouseMove( const TSharedRef<SWidget> MyWidget, IScrollableZoomable& ScrollableZoomable, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
	{
		// If scrolling with the right mouse button, we need to remember how much we scrolled.
		// If we did not scroll at all, we will bring up the context menu when the mouse is released.
		AmountScrolledWhileRightMouseDown += FMath::Abs( MouseEvent.GetCursorDelta().X ) + FMath::Abs( MouseEvent.GetCursorDelta().Y );

		// Has the mouse moved far enough with the right mouse button held down to start capturing
		// the mouse and dragging the view?
		if (IsRightClickScrolling())
		{
			this->HorizontalIntertia.AddScrollSample( MouseEvent.GetCursorDelta().X, FPlatformTime::Seconds() );
			this->VerticalIntertia.AddScrollSample( MouseEvent.GetCursorDelta().Y, FPlatformTime::Seconds() );
			const bool DidScroll = ScrollableZoomable.ScrollBy( MouseEvent.GetCursorDelta() );

			FReply Reply = FReply::Handled();

			// Capture the mouse if we need to
			if (MyWidget->HasMouseCapture() == false)
			{
				Reply.CaptureMouse( MyWidget ).UseHighPrecisionMouseMovement( MyWidget );
				SoftwareCursorPosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
				bShowSoftwareCursor = true;
			}

			// Check if the mouse has moved.
			if (DidScroll)
			{
				SoftwareCursorPosition += MouseEvent.GetCursorDelta();
			}

			return Reply;
		}
	}

	return FReply::Unhandled();
}
예제 #10
0
int32 SGridPanel::LayoutDebugPaint(const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId ) const
{
	float XOffset = 0;
	for (int32 Column=0; Column<Columns.Num(); ++Column)
	{
		float YOffset = 0;
		for (int32 Row=0; Row<Rows.Num(); ++Row)
		{
			FSlateDrawElement::MakeDebugQuad
			(
				OutDrawElements, 
				LayerId,
				AllottedGeometry.ToPaintGeometry( FVector2D(XOffset, YOffset), FVector2D( Columns[Column], Rows[Row] ) ),
				MyClippingRect
			);

			YOffset += Rows[Row];
		}
		XOffset += Columns[Column];
	}

	return LayerId;
}
예제 #11
0
int32 SBox::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
	// An SBox just draws its only child
	FArrangedChildren ArrangedChildren(EVisibility::Visible);
	{
#if SLATE_HD_STATS
		SCOPE_CYCLE_COUNTER( STAT_SlateOnPaint_SBox );
#endif
		this->ArrangeChildren(AllottedGeometry, ArrangedChildren);
	}

	// Maybe none of our children are visible
	if( ArrangedChildren.Num() > 0 )
	{
		check( ArrangedChildren.Num() == 1 );
		FArrangedWidget& TheChild = ArrangedChildren[0];

		const FSlateRect ChildClippingRect = AllottedGeometry.GetClippingRect().InsetBy( ChildSlot.SlotPadding.Get() * AllottedGeometry.Scale ).IntersectionWith(MyClippingRect);

		return TheChild.Widget->Paint( Args.WithNewParent(this), TheChild.Geometry, ChildClippingRect, OutDrawElements, LayerId, InWidgetStyle, ShouldBeEnabled( bParentEnabled ) );
	}
	return LayerId;
}
예제 #12
0
FReply FSceneViewport::OnTouchEnded( const FGeometry& MyGeometry, const FPointerEvent& TouchEvent )
{
	// Start a new reply state
	CurrentReplyState = FReply::Handled(); 

	UpdateCachedMousePos(MyGeometry, TouchEvent);
	UpdateCachedGeometry(MyGeometry);

	if( ViewportClient )
	{
		// Switch to the viewport clients world before processing input
		FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient );

		const FVector2D TouchPosition = MyGeometry.AbsoluteToLocal(TouchEvent.GetLastScreenSpacePosition());

		if( !ViewportClient->InputTouch( this, TouchEvent.GetUserIndex(), TouchEvent.GetPointerIndex(), ETouchType::Ended, TouchPosition, FDateTime::Now(), TouchEvent.GetTouchpadIndex()) )
		{
			CurrentReplyState = FReply::Unhandled(); 
		}
	}

	return CurrentReplyState;
}
FReply FSequencerTimeSliderController::OnMouseButtonDown( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton;
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && TimeSliderArgs.AllowZoom;
	
	DistanceDragged = 0;

	FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
	MouseDownRange[0] = RangeToScreen.LocalXToInput(MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition()).X);
	MouseDownRange[1] = MouseDownRange[0];

	if ( bHandleLeftMouseButton )
	{
		return FReply::Handled().CaptureMouse( WidgetOwner.AsShared() ).PreventThrottling();
	}
	else if ( bHandleRightMouseButton )
	{
		// Always capture mouse if we left or right click on the widget
		return FReply::Handled().CaptureMouse( WidgetOwner.AsShared() );
	}

	return FReply::Unhandled();
}
예제 #14
0
FReply SFlareKeyBind::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
	if (bWaitingForKey)
	{
		SetKey(MouseEvent.GetEffectingButton());
		return FReply::Handled();
	}

	else if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton)
	{
		// Get the center of the widget so we can lock our mouse there
		FSlateRect Rect = MyGeometry.GetClippingRect();
		WaitingMousePos.X = (Rect.Left + Rect.Right) * 0.5f;
		WaitingMousePos.Y = (Rect.Top + Rect.Bottom) * 0.5f;
		FSlateApplication::Get().GetPlatformApplication().Get()->Cursor->SetPosition(WaitingMousePos.X, WaitingMousePos.Y);

		KeyText->SetText(LOCTEXT("SFlareKeyBindPressAnyKey", "Press a key..."));
		bWaitingForKey = true;
		FSlateApplication::Get().GetPlatformApplication().Get()->Cursor->Show(false);
		return FReply::Handled();
	}
	return FReply::Unhandled();
}
예제 #15
0
FVector2D SPaperEditorViewport::ComputeEdgePanAmount(const FGeometry& MyGeometry, const FVector2D& TargetPosition)
{
	// How quickly to ramp up the pan speed as the user moves the mouse further past the edge of the graph panel.
	static const float EdgePanSpeedCoefficient = 0.1f;

	// Never pan slower than this, it's just unpleasant.
	static const float MinPanSpeed = 5.0f;

	// Start panning before we reach the edge of the graph panel.
	static const float EdgePanForgivenessZone = 30.0f;

	const FVector2D LocalCursorPos = MyGeometry.AbsoluteToLocal( TargetPosition );

	// If the mouse is outside of the graph area, then we want to pan in that direction.
	// The farther out the mouse is, the more we want to pan.

	FVector2D EdgePanThisTick(0,0);
	if ( LocalCursorPos.X <= EdgePanForgivenessZone )
	{
		EdgePanThisTick.X += FMath::Min( -MinPanSpeed, EdgePanSpeedCoefficient * (EdgePanForgivenessZone - LocalCursorPos.X) );
	}
	else if( LocalCursorPos.X >= MyGeometry.Size.X - EdgePanForgivenessZone )
	{
		EdgePanThisTick.X = FMath::Max( MinPanSpeed, EdgePanSpeedCoefficient * (MyGeometry.Size.X - EdgePanForgivenessZone - LocalCursorPos.X) );
	}

	if ( LocalCursorPos.Y <= EdgePanForgivenessZone )
	{
		EdgePanThisTick.Y += FMath::Min( -MinPanSpeed, EdgePanSpeedCoefficient * (EdgePanForgivenessZone - LocalCursorPos.Y) );
	}
	else if( LocalCursorPos.Y >= MyGeometry.Size.Y - EdgePanForgivenessZone )
	{
		EdgePanThisTick.Y = FMath::Max( MinPanSpeed, EdgePanSpeedCoefficient * (MyGeometry.Size.Y - EdgePanForgivenessZone - LocalCursorPos.Y) );
	}

	return EdgePanThisTick;
}
예제 #16
0
FReply FVisualLoggerTimeSliderController::OnMouseButtonDown( TSharedRef<SWidget> WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton;
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && TimeSliderArgs.AllowZoom;
	
	DistanceDragged = 0;

	if ( bHandleLeftMouseButton )
	{
		// Always capture mouse if we left or right click on the widget
		FScrubRangeToScreen RangeToScreen(TimeSliderArgs.ViewRange.Get(), MyGeometry.Size);
		FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
		float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

		CommitScrubPosition(NewValue, /*bIsScrubbing=*/false);
		return FReply::Handled().CaptureMouse( WidgetOwner ).PreventThrottling();
	}
	else if ( bHandleRightMouseButton )
	{
		return FReply::Handled().CaptureMouse(WidgetOwner);
	}

	return FReply::Unhandled();
}
	void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override
	{
		if ( AllottedGeometry.IsUnderLocation(FSlateApplication::Get().GetCursorPos()) )
		{
			if ( !ResizeCurve.IsPlaying() )
			{
				if ( ResizeCurve.IsAtStart() )
				{
					ResizeCurve.Play();
				}
				else if ( ResizeCurve.IsAtEnd() )
				{
					ResizeCurve.PlayReverse();
				}
			}
		}
		else
		{
			if ( !ResizeCurve.IsAtStart() && ((!ResizeCurve.IsInReverse() && ResizeCurve.IsPlaying()) || !ResizeCurve.IsPlaying()) )
			{
				ResizeCurve.PlayReverse();
			}
		}
	}
예제 #18
0
FReply SProfilerThreadView::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	FReply Reply = FReply::Unhandled();

	if( IsReady() )
	{
		MousePositionOnButtonDown = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );

		if( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton )
		{
			bIsLeftMousePressed = true;
			DistanceDragged = PositionXMS;

			// Capture mouse, so we can move outside this widget.
			Reply = FReply::Handled().CaptureMouse( SharedThis( this ) );
		}
		else if( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton )
		{
			bIsRightMousePressed = true;
		}
	}

	return Reply;
}
예제 #19
0
FReply SVirtualJoystick::OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& Event)
{
	FVector2D LocalCoord = MyGeometry.AbsoluteToLocal( Event.GetScreenSpacePosition() );

	for (int32 ControlIndex = 0; ControlIndex < Controls.Num(); ControlIndex++)
	{
		FControlInfo& Control = Controls[ControlIndex];

		// is this control the one captured to this pointer?
		if (Control.CapturedPointerIndex == Event.GetPointerIndex())
		{
			if (Control.bNeedUpdatedCenter)
			{
				return FReply::Unhandled();
			}
			else if (HandleTouch(ControlIndex, LocalCoord, MyGeometry.Size))
			{
				return FReply::Handled();
			}
		}
	}

	return FReply::Unhandled();
}
예제 #20
0
FReply SProfilerThreadView::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	//	SCOPE_LOG_TIME_FUNC();

	FReply Reply = FReply::Unhandled();

	if( IsReady() )
	{
		const FVector2D LocalMousePosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
		
		HoveredPositionX = 0.0;//PositionToFrameIndex( LocalMousePosition.X );
		HoveredPositionY = 0.0;

		const float CursorPosXDelta = -MouseEvent.GetCursorDelta().X;
		const float ScrollSpeed = 1.0f / ZoomFactorX;

		if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) )
		{
			if( HasMouseCapture() && !MouseEvent.GetCursorDelta().IsZero() )
			{
				DistanceDragged += CursorPosXDelta*ScrollSpeed*0.1;

				// Inform other widgets that we have scrolled the thread-view.
				SetPositionX( FMath::Clamp( DistanceDragged, 0.0, TotalRangeXMS - RangeXMS ) );
				CursorType = EThreadViewCursor::Hand;
				Reply = FReply::Handled();
			}
		}
		else
		{
			CursorType = EThreadViewCursor::Default;
		}
	}

	return Reply;
}
예제 #21
0
bool SColorWheel::ProcessMouseAction(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bProcessWhenOutsideColorWheel)
{
	const FVector2D LocalMouseCoordinate = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
	const FVector2D Location = LocalMouseCoordinate / (MyGeometry.Size * 0.5f) - FVector2D(1.0f, 1.0f);
	const float Radius = Location.Size();

	if (Radius <= 1.0f || bProcessWhenOutsideColorWheel)
	{
		float Angle = FMath::Atan2(Location.Y, Location.X);

		if (Angle < 0.0f)
		{
			Angle += 2.0f * PI;
		}

		FLinearColor NewColor = SelectedColor.Get();
		NewColor.R = Angle * 180.0f * INV_PI;
		NewColor.G = FMath::Min(Radius, 1.0f);

		OnValueChanged.ExecuteIfBound(NewColor);
	}

	return (Radius <= 1.0f);
}
예제 #22
0
int32 SScrubWidget::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
	const bool bActiveFeedback = IsHovered() || bDragging;
	const FSlateBrush* BackgroundImage = bActiveFeedback ?
		FEditorStyle::GetBrush("SpinBox.Background.Hovered") :
		FEditorStyle::GetBrush("SpinBox.Background");

	const FSlateBrush* FillImage = bActiveFeedback ?
		FEditorStyle::GetBrush("SpinBox.Fill.Hovered") :
		FEditorStyle::GetBrush("SpinBox.Fill");

	const int32 BackgroundLayer = LayerId;

	const FSlateFontInfo SmallLayoutFont( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 10 );

	const bool bEnabled = ShouldBeEnabled( bParentEnabled );
	const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

	const int32 TextLayer = BackgroundLayer + 1;

	const FSlateBrush* StyleInfo = FEditorStyle::GetBrush( TEXT( "ProgressBar.Background" ) );
	const float GeomHeight = AllottedGeometry.Size.Y;

	if ( NumOfKeys.Get() > 0 && SequenceLength.Get() > 0)
	{
		const FTrackScaleInfo TimeScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, AllottedGeometry.Size);
		const int32 Divider = SScrubWidget::GetDivider( ViewInputMin.Get(), ViewInputMax.Get(), AllottedGeometry.Size, SequenceLength.Get(), NumOfKeys.Get() );
		const float HalfDivider = Divider/2.f;
		
		const int32 TotalNumKeys = NumOfKeys.Get();

		const float TimePerKey = (TotalNumKeys > 0) ? SequenceLength.Get() / (float)(TotalNumKeys) : 0.0f;

		for (float KeyVal = 0; KeyVal < TotalNumKeys; KeyVal += HalfDivider)
		{
			const float CurValue = KeyVal*TimePerKey;
			const float XPos = TimeScaleInfo.InputToLocalX(CurValue);

			if ( FGenericPlatformMath::Fmod(KeyVal, Divider) == 0.f )
			{
				const FVector2D Offset(XPos, 0.f);
				const FVector2D Size(1, GeomHeight);
				// draw each box with key frame
				FSlateDrawElement::MakeBox(
					OutDrawElements,
					BackgroundLayer,
					AllottedGeometry.ToPaintGeometry(Offset, Size),
					StyleInfo,
					MyClippingRect,
					DrawEffects,
					InWidgetStyle.GetColorAndOpacityTint()
					);

				const int32 FrameNumber = KeyVal;
				const FString FrameString = FString::Printf(TEXT("%d"), (FrameNumber));
				const FVector2D TextOffset(XPos+2.f, 0.f);

				const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
				const FVector2D TextSize = FontMeasureService->Measure(FrameString, SmallLayoutFont);

				FSlateDrawElement::MakeText(
					OutDrawElements,
					TextLayer, 
					AllottedGeometry.ToPaintGeometry(TextOffset, TextSize), 
					FrameString, 
					SmallLayoutFont, 
					MyClippingRect, 
					DrawEffects);
			}
 			else if (HalfDivider > 1.f)
 			{
 				const float Height = GeomHeight;
 				const FVector2D Offset(XPos, Height*0.25f);
 				const FVector2D Size(1, Height*0.5f);
 				// draw each box with key frame
 				FSlateDrawElement::MakeBox(
 					OutDrawElements,
 					BackgroundLayer,
					AllottedGeometry.ToPaintGeometry(Offset, Size),
 					StyleInfo,
 					MyClippingRect,
 					DrawEffects,
 					InWidgetStyle.GetColorAndOpacityTint()
 					);
 
 			}
		}

		const int32 ArrowLayer = TextLayer + 1;
		{
			const float XPos = TimeScaleInfo.InputToLocalX(ValueAttribute.Get());
			const float Height = AllottedGeometry.Size.Y;
			const FVector2D Offset( XPos - Height*0.25f, 0.f );

			FPaintGeometry MyGeometry =	AllottedGeometry.ToPaintGeometry( Offset, FVector2D(Height*0.5f, Height) );
			FLinearColor ScrubColor = InWidgetStyle.GetColorAndOpacityTint();
			ScrubColor.A = ScrubColor.A*0.5f;
			ScrubColor.B *= 0.1f;
			ScrubColor.G *= 0.1f;
			FSlateDrawElement::MakeBox( 
				OutDrawElements,
				ArrowLayer, 
				MyGeometry, 
				StyleInfo, 
				MyClippingRect, 
				DrawEffects, 
				ScrubColor
				);
		}

		// Draggable Bars
		if ( DraggableBars.IsBound() )
		{
			for ( const float BarValue : DraggableBars.Get() )
			{
				const float BarXPos = TimeScaleInfo.InputToLocalX(BarValue);
				const FVector2D BarOffset(BarXPos-2.f, 0.f);
				const FVector2D Size(4.f, GeomHeight);

				FLinearColor BarColor = InWidgetStyle.GetColorAndOpacityTint();	
				BarColor.R *= 0.1f;
				BarColor.G *= 0.1f;

				FSlateDrawElement::MakeBox(
					OutDrawElements,
					ArrowLayer+1,
					AllottedGeometry.ToPaintGeometry(BarOffset, Size),
					StyleInfo,
					MyClippingRect,
					DrawEffects,
					BarColor
					);
			}
		}

		return FMath::Max( ArrowLayer, SCompoundWidget::OnPaint( Args, AllottedGeometry, MyClippingRect, OutDrawElements, ArrowLayer, InWidgetStyle, bEnabled ) );
	}

	return SCompoundWidget::OnPaint( Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bEnabled );
}
예제 #23
0
FReply SScrubWidget::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	// Bar Dragging
	if(DraggingBar)
	{
		// Update bar if we are dragging
		FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
		FTrackScaleInfo ScaleInfo(ViewInputMin.Get(),  ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size);
		float NewDataPos = FMath::Clamp( ScaleInfo.LocalXToInput(CursorPos.X), ViewInputMin.Get(), ViewInputMax.Get() );
		OnBarDrag.ExecuteIfBound(DraggableBarIndex, NewDataPos);
	}
	else
	{
		// Update what bar we are hovering over
		FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
		FTrackScaleInfo ScaleInfo(ViewInputMin.Get(),  ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size);
		DraggableBarIndex = INDEX_NONE;
		if ( DraggableBars.IsBound() )
		{
			const TArray<float>& DraggableBarsVal = DraggableBars.Get();
			for ( int32 I=0; I < DraggableBarsVal.Num(); I++ )
			{
				if( FMath::Abs( ScaleInfo.InputToLocalX(DraggableBarsVal[I]) - CursorPos.X ) < 10 )
				{
					DraggableBarIndex = I;
					break;
				}
			}
		}
	}

	if ( this->HasMouseCapture() )
	{
		if (MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ) && bPanning)
		{
			FTrackScaleInfo ScaleInfo(ViewInputMin.Get(),  ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size);
			FVector2D ScreenDelta = MouseEvent.GetCursorDelta();
			float InputDeltaX = ScreenDelta.X/ScaleInfo.PixelsPerInput;

			bMouseMovedDuringPanning |= !ScreenDelta.IsNearlyZero(0.001f);

			float NewViewInputMin = ViewInputMin.Get() - InputDeltaX;
			float NewViewInputMax = ViewInputMax.Get() - InputDeltaX;
			// we'd like to keep  the range if outside when panning
			if ( NewViewInputMin < 0.f )
			{
				NewViewInputMin = 0.f;
				NewViewInputMax = ScaleInfo.ViewInputRange;
			}
			else if ( NewViewInputMax > SequenceLength.Get() )
			{
				NewViewInputMax = SequenceLength.Get();
				NewViewInputMin = NewViewInputMax - ScaleInfo.ViewInputRange;
			}

			OnSetInputViewRange.ExecuteIfBound(NewViewInputMin, NewViewInputMax);
		}
		else if (!bDragging)
		{
			DistanceDragged += FMath::Abs(MouseEvent.GetCursorDelta().X);
			if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
			{
				bDragging = true;
			}
			if( bDragging )
			{
				OnBeginSliderMovement.ExecuteIfBound();
			}
		}
		else if (bDragging)
		{
			FTrackScaleInfo TimeScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size);
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = TimeScaleInfo.LocalXToInput(CursorPos.X);

			CommitValue( NewValue, true, false );
		}
		return FReply::Handled();
	}

	

	return FReply::Unhandled();
}
예제 #24
0
int32 SSpineWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements,
							   int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const {

	SSpineWidget* self = (SSpineWidget*)this;

	if (widget && widget->skeleton && widget->Atlas) {
		widget->skeleton->getColor().set(widget->Color.R, widget->Color.G, widget->Color.B, widget->Color.A);

		if (widget->atlasNormalBlendMaterials.Num() != widget->Atlas->atlasPages.Num()) {
			widget->atlasNormalBlendMaterials.SetNum(0);
			widget->pageToNormalBlendMaterial.Empty();
			widget->atlasAdditiveBlendMaterials.SetNum(0);
			widget->pageToAdditiveBlendMaterial.Empty();
			widget->atlasMultiplyBlendMaterials.SetNum(0);
			widget->pageToMultiplyBlendMaterial.Empty();
			widget->atlasScreenBlendMaterials.SetNum(0);
			widget->pageToScreenBlendMaterial.Empty();

			for (int i = 0; i < widget->Atlas->atlasPages.Num(); i++) {
				AtlasPage* currPage = widget->Atlas->GetAtlas()->getPages()[i];

				UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(widget->NormalBlendMaterial, widget);
				material->SetTextureParameterValue(widget->TextureParameterName, widget->Atlas->atlasPages[i]);
				widget->atlasNormalBlendMaterials.Add(material);
				widget->pageToNormalBlendMaterial.Add(currPage, material);

				material = UMaterialInstanceDynamic::Create(widget->AdditiveBlendMaterial, widget);
				material->SetTextureParameterValue(widget->TextureParameterName, widget->Atlas->atlasPages[i]);
				widget->atlasAdditiveBlendMaterials.Add(material);
				widget->pageToAdditiveBlendMaterial.Add(currPage, material);

				material = UMaterialInstanceDynamic::Create(widget->MultiplyBlendMaterial, widget);
				material->SetTextureParameterValue(widget->TextureParameterName, widget->Atlas->atlasPages[i]);
				widget->atlasMultiplyBlendMaterials.Add(material);
				widget->pageToMultiplyBlendMaterial.Add(currPage, material);

				material = UMaterialInstanceDynamic::Create(widget->ScreenBlendMaterial, widget);
				material->SetTextureParameterValue(widget->TextureParameterName, widget->Atlas->atlasPages[i]);
				widget->atlasScreenBlendMaterials.Add(material);
				widget->pageToScreenBlendMaterial.Add(currPage, material);
			}
		} else {
			widget->pageToNormalBlendMaterial.Empty();
			widget->pageToAdditiveBlendMaterial.Empty();
			widget->pageToMultiplyBlendMaterial.Empty();
			widget->pageToScreenBlendMaterial.Empty();

			for (int i = 0; i < widget->Atlas->atlasPages.Num(); i++) {
				AtlasPage* currPage = widget->Atlas->GetAtlas()->getPages()[i];

				UTexture2D* texture = widget->Atlas->atlasPages[i];
				UTexture* oldTexture = nullptr;

				UMaterialInstanceDynamic* current = widget->atlasNormalBlendMaterials[i];
				if (!current || !current->GetTextureParameterValue(widget->TextureParameterName, oldTexture) || oldTexture != texture) {
					UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(widget->NormalBlendMaterial, widget);
					material->SetTextureParameterValue(widget->TextureParameterName, texture);
					widget->atlasNormalBlendMaterials[i] = material;
				}
				widget->pageToNormalBlendMaterial.Add(currPage, widget->atlasNormalBlendMaterials[i]);

				current = widget->atlasAdditiveBlendMaterials[i];
				if (!current || !current->GetTextureParameterValue(widget->TextureParameterName, oldTexture) || oldTexture != texture) {
					UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(widget->AdditiveBlendMaterial, widget);
					material->SetTextureParameterValue(widget->TextureParameterName, texture);
					widget->atlasAdditiveBlendMaterials[i] = material;
				}
				widget->pageToAdditiveBlendMaterial.Add(currPage, widget->atlasAdditiveBlendMaterials[i]);

				current = widget->atlasMultiplyBlendMaterials[i];
				if (!current || !current->GetTextureParameterValue(widget->TextureParameterName, oldTexture) || oldTexture != texture) {
					UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(widget->MultiplyBlendMaterial, widget);
					material->SetTextureParameterValue(widget->TextureParameterName, texture);
					widget->atlasMultiplyBlendMaterials[i] = material;
				}
				widget->pageToMultiplyBlendMaterial.Add(currPage, widget->atlasMultiplyBlendMaterials[i]);

				current = widget->atlasScreenBlendMaterials[i];
				if (!current || !current->GetTextureParameterValue(widget->TextureParameterName, oldTexture) || oldTexture != texture) {
					UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(widget->ScreenBlendMaterial, widget);
					material->SetTextureParameterValue(widget->TextureParameterName, texture);
					widget->atlasScreenBlendMaterials[i] = material;
				}
				widget->pageToScreenBlendMaterial.Add(currPage, widget->atlasScreenBlendMaterials[i]);
			}
		}
		// self->UpdateMesh(LayerId, OutDrawElements, AllottedGeometry, widget->skeleton);
	}
	//return LayerId;

	self->renderData.IndexData.SetNumUninitialized(6);
	uint32* indexData = (uint32*)renderData.IndexData.GetData();
	indexData[0] = 0;
	indexData[1] = 1;
	indexData[2] = 2;
	indexData[3] = 2;
	indexData[4] = 3;
	indexData[5] = 0;

	self->renderData.VertexData.SetNumUninitialized(4);
	FSlateVertex* vertexData = (FSlateVertex*)renderData.VertexData.GetData();
	FVector2D offset = AllottedGeometry.AbsolutePosition;
	FColor white = FColor(0xffffffff);

	float width = AllottedGeometry.GetAbsoluteSize().X;
	float height = AllottedGeometry.GetAbsoluteSize().Y;

	setVertex(&vertexData[0], 0, 0, 0, 0, white, offset);
	setVertex(&vertexData[1], width, 0, 1, 0, white, offset);
	setVertex(&vertexData[2], width, height, 1, 1, white, offset);
	setVertex(&vertexData[3], 0, height, 0, 1, white, offset);

	if (brush && renderData.VertexData.Num() > 0 && renderData.IndexData.Num() > 0) {
		FSlateShaderResourceProxy* shaderResource = FSlateDataPayload::ResourceManager->GetShaderResource(widget->Brush);
		FSlateResourceHandle resourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(widget->Brush);
		if (shaderResource)
			FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, resourceHandle, renderData.VertexData,
											   renderData.IndexData, nullptr, 0, 0);
	}

	return LayerId;
}
예제 #25
0
int32 FAnimationSection::OnPaintSection( const FGeometry& AllottedGeometry, const FSlateRect& SectionClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, bool bParentEnabled ) const
{
	UMovieSceneAnimationSection* AnimSection = Cast<UMovieSceneAnimationSection>(&Section);
	
	FTimeToPixel TimeToPixelConverter( AllottedGeometry, TRange<float>( Section.GetStartTime(), Section.GetEndTime() ) );

	// Add a box for the section
	FSlateDrawElement::MakeBox(
		OutDrawElements,
		LayerId,
		AllottedGeometry.ToPaintGeometry(),
		FEditorStyle::GetBrush("Sequencer.GenericSection.Background"),
		SectionClippingRect,
		ESlateDrawEffect::None,
		FLinearColor(0.7f, 0.4f, 0.7f, 1.f)
	);

	// Darken the part that doesn't have animation
	if (AnimSection->GetAnimationStartTime() > AnimSection->GetStartTime())
	{
		float StartDarkening = AnimSection->GetStartTime();
		float EndDarkening = FMath::Min(AnimSection->GetAnimationStartTime(), AnimSection->GetEndTime());
		
		float StartPixels = TimeToPixelConverter.TimeToPixel(StartDarkening);
		float EndPixels = TimeToPixelConverter.TimeToPixel(EndDarkening);

		FSlateDrawElement::MakeBox(
			OutDrawElements,
			LayerId + 1,
			AllottedGeometry.ToPaintGeometry(FVector2D(StartPixels, 0), FVector2D(EndPixels - StartPixels, AllottedGeometry.Size.Y)),
			FEditorStyle::GetBrush("WhiteTexture"),
			SectionClippingRect,
			ESlateDrawEffect::None,
			FLinearColor(0.f, 0.f, 0.f, 0.3f)
		);
	}

	// Add lines where the animation starts and ends/loops
	float CurrentTime = AnimSection->GetAnimationStartTime();
	while (CurrentTime < AnimSection->GetEndTime())
	{
		if (CurrentTime > AnimSection->GetStartTime())
		{
			float CurrentPixels = TimeToPixelConverter.TimeToPixel(CurrentTime);

			TArray<FVector2D> Points;
			Points.Add(FVector2D(CurrentPixels, 0));
			Points.Add(FVector2D(CurrentPixels, AllottedGeometry.Size.Y));

			FSlateDrawElement::MakeLines(
				OutDrawElements,
				LayerId + 2,
				AllottedGeometry.ToPaintGeometry(),
				Points,
				SectionClippingRect
			);
		}
		CurrentTime += AnimSection->GetAnimationDuration();
	}

	return LayerId+3;
}
int32 FSequencerTimeSliderController::OnPaintTimeSlider( bool bMirrorLabels, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
	const bool bEnabled = bParentEnabled;
	const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

	TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
	const float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
	const float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();
	const float LocalSequenceLength = LocalViewRangeMax-LocalViewRangeMin;
	
	FVector2D Scale = FVector2D(1.0f,1.0f);
	if ( LocalSequenceLength > 0)
	{
		FScrubRangeToScreen RangeToScreen( LocalViewRange, AllottedGeometry.Size );
	
		const float MajorTickHeight = 9.0f;
	
		FDrawTickArgs Args;
		Args.AllottedGeometry = AllottedGeometry;
		Args.bMirrorLabels = bMirrorLabels;
		Args.bOnlyDrawMajorTicks = false;
		Args.TickColor = FLinearColor::White;
		Args.ClippingRect = MyClippingRect;
		Args.DrawEffects = DrawEffects;
		Args.StartLayer = LayerId;
		Args.TickOffset = bMirrorLabels ? 0.0f : FMath::Abs( AllottedGeometry.Size.Y - MajorTickHeight );
		Args.MajorTickHeight = MajorTickHeight;

		DrawTicks( OutDrawElements, RangeToScreen, Args );

		FPaintPlaybackRangeArgs PlaybackRangeArgs(
			bMirrorLabels ? FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Bottom_L") : FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Top_L"),
			bMirrorLabels ? FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Bottom_R") : FEditorStyle::GetBrush("Sequencer.Timeline.PlayRange_Top_R"),
			6.f
		);
		LayerId = DrawPlaybackRange(AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, RangeToScreen, PlaybackRangeArgs);

		float HalfSize = FMath::CeilToFloat(ScrubHandleSize/2.0f);

		// Draw the scrub handle
		float XPos = RangeToScreen.InputToLocalX( TimeSliderArgs.ScrubPosition.Get() );

		// Should draw above the text
		const int32 ArrowLayer = LayerId + 2;
		FPaintGeometry MyGeometry =	AllottedGeometry.ToPaintGeometry( FVector2D( XPos-HalfSize, 0 ), FVector2D( ScrubHandleSize, AllottedGeometry.Size.Y ) );
		FLinearColor ScrubColor = InWidgetStyle.GetColorAndOpacityTint();

		// @todo Sequencer this color should be specified in the style
		ScrubColor.A = ScrubColor.A*0.75f;
		ScrubColor.B *= 0.1f;
		ScrubColor.G *= 0.2f;
		FSlateDrawElement::MakeBox( 
			OutDrawElements,
			ArrowLayer, 
			MyGeometry,
			bMirrorLabels ? ScrubHandleUp : ScrubHandleDown,
			MyClippingRect, 
			DrawEffects, 
			ScrubColor
			);

		// Draw the current time next to the scrub handle
		float Time = TimeSliderArgs.ScrubPosition.Get();

		FString FrameString;
		if (SequencerSnapValues::IsTimeSnapIntervalFrameRate(TimeSliderArgs.Settings->GetTimeSnapInterval()) && TimeSliderArgs.Settings->GetShowFrameNumbers())
		{
			float FrameRate = 1.0f/TimeSliderArgs.Settings->GetTimeSnapInterval();
			float FrameTime = Time * FrameRate;
			int32 Frame = SequencerHelpers::TimeToFrame(Time, FrameRate);
					
			const float FrameTolerance = 0.001f;
			if (FMath::IsNearlyEqual(FrameTime, (float)Frame, FrameTolerance))
			{
				FrameString = FString::Printf( TEXT("%d"), TimeToFrame(Time));
			}
			else
			{
				FrameString = FString::Printf( TEXT("%.3f"), FrameTime);
			}
		}
		else
		{
			FrameString = FString::Printf( TEXT("%.2f"), Time );
		}

		FSlateFontInfo SmallLayoutFont( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 10 );

		const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
		FVector2D TextSize = FontMeasureService->Measure(FrameString, SmallLayoutFont);

		// Flip the text position if getting near the end of the view range
		if ((AllottedGeometry.Size.X - XPos) < (TextSize.X + 14.f))
		{
			XPos = XPos - TextSize.X - 12.f;
		}
		else
		{
			XPos = XPos + 10.f;
		}

		FVector2D TextOffset( XPos,  Args.bMirrorLabels ? TextSize.Y-6.f : Args.AllottedGeometry.Size.Y - (Args.MajorTickHeight+TextSize.Y) );

		FSlateDrawElement::MakeText(
			OutDrawElements,
			Args.StartLayer+1, 
			Args.AllottedGeometry.ToPaintGeometry( TextOffset, TextSize ), 
			FrameString, 
			SmallLayoutFont, 
			Args.ClippingRect, 
			Args.DrawEffects,
			Args.TickColor 
		);
		
		if (MouseDragType == DRAG_SETTING_RANGE)
		{
			float MouseStartPosX = RangeToScreen.InputToLocalX(MouseDownRange[0]);
			float MouseEndPosX = RangeToScreen.InputToLocalX(MouseDownRange[1]);

			float RangePosX = MouseStartPosX < MouseEndPosX ? MouseStartPosX : MouseEndPosX;
			float RangeSizeX = FMath::Abs(MouseStartPosX - MouseEndPosX);

			FSlateDrawElement::MakeBox(
				OutDrawElements,
				LayerId+1,
				AllottedGeometry.ToPaintGeometry( FVector2D(RangePosX, 0.f), FVector2D(RangeSizeX, AllottedGeometry.Size.Y) ),
				bMirrorLabels ? ScrubHandleDown : ScrubHandleUp,
				MyClippingRect,
				DrawEffects,
				MouseStartPosX < MouseEndPosX ? FLinearColor(0.5f, 0.5f, 0.5f) : FLinearColor(0.25f, 0.3f, 0.3f)
			);
		}

		return ArrowLayer;
	}

	return LayerId;
}
예제 #27
0
int32 SGraphPanel::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
#if SLATE_HD_STATS
	SCOPE_CYCLE_COUNTER( STAT_SlateOnPaint_SGraphPanel );
#endif

	CachedAllottedGeometryScaledSize = AllottedGeometry.Size * AllottedGeometry.Scale;

	//Style used for objects that are the same between revisions
	FWidgetStyle FadedStyle = InWidgetStyle;
	FadedStyle.BlendColorAndOpacityTint(FLinearColor(0.45f,0.45f,0.45f,0.45f));

	// First paint the background
	const UEditorExperimentalSettings& Options = *GetDefault<UEditorExperimentalSettings>();

	const FSlateBrush* BackgroundImage = FEditorStyle::GetBrush(TEXT("Graph.Panel.SolidBackground"));
	PaintBackgroundAsLines(BackgroundImage, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId);

	const float ZoomFactor = AllottedGeometry.Scale * GetZoomAmount();

	FArrangedChildren ArrangedChildren(EVisibility::Visible);
	ArrangeChildNodes(AllottedGeometry, ArrangedChildren);

	// Determine some 'global' settings based on current LOD
	const bool bDrawShadowsThisFrame = GetCurrentLOD() > EGraphRenderingLOD::LowestDetail;

	// Because we paint multiple children, we must track the maximum layer id that they produced in case one of our parents
	// wants to an overlay for all of its contents.

	// Save LayerId for comment boxes to ensure they always appear below nodes & wires
	const int32 CommentNodeShadowLayerId = LayerId++;
	const int32 CommentNodeLayerId = LayerId++;

	// Save a LayerId for wires, which appear below nodes but above comments
	// We will draw them later, along with the arrows which appear above nodes.
	const int32 WireLayerId = LayerId++;

	const int32 NodeShadowsLayerId = LayerId;
	const int32 NodeLayerId = NodeShadowsLayerId + 1;
	int32 MaxLayerId = NodeLayerId;

	const FVector2D NodeShadowSize = GetDefault<UGraphEditorSettings>()->GetShadowDeltaSize();
	const UEdGraphSchema* Schema = GraphObj->GetSchema();

	// Draw the child nodes
	{
		// When drawing a marquee, need a preview of what the selection will be.
		const FGraphPanelSelectionSet* SelectionToVisualize = &(SelectionManager.SelectedNodes);
		FGraphPanelSelectionSet SelectionPreview;
		if ( Marquee.IsValid() )
		{			
			ApplyMarqueeSelection(Marquee, SelectionManager.SelectedNodes, SelectionPreview);
			SelectionToVisualize = &SelectionPreview;
		}

		// Context for rendering node infos
		FKismetNodeInfoContext Context(GraphObj);

		TArray<FGraphDiffControl::FNodeMatch> NodeMatches;
		for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)
		{
			FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];
			TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(CurWidget.Widget);
			
			// Examine node to see what layers we should be drawing in
			int32 ShadowLayerId = NodeShadowsLayerId;
			int32 ChildLayerId = NodeLayerId;

			// If a comment node, draw in the dedicated comment slots
			{
				UObject* NodeObj = ChildNode->GetObjectBeingDisplayed();
				if (NodeObj && NodeObj->IsA(UEdGraphNode_Comment::StaticClass()))
				{
					ShadowLayerId = CommentNodeShadowLayerId;
					ChildLayerId = CommentNodeLayerId;
				}
			}


			const bool bNodeIsVisible = FSlateRect::DoRectanglesIntersect( CurWidget.Geometry.GetClippingRect(), MyClippingRect );

			if (bNodeIsVisible)
			{
				const bool bSelected = SelectionToVisualize->Contains( StaticCastSharedRef<SNodePanel::SNode>(CurWidget.Widget)->GetObjectBeingDisplayed() );

				// Handle Node renaming once the node is visible
				if( bSelected && ChildNode->IsRenamePending() )
				{
					ChildNode->ApplyRename();
				}

				// Draw the node's shadow.
				if (bDrawShadowsThisFrame || bSelected)
				{
					const FSlateBrush* ShadowBrush = ChildNode->GetShadowBrush(bSelected);
					FSlateDrawElement::MakeBox(
						OutDrawElements,
						ShadowLayerId,
						CurWidget.Geometry.ToInflatedPaintGeometry(NodeShadowSize),
						ShadowBrush,
						MyClippingRect
						);
				}

				// Draw the comments and information popups for this node, if it has any.
				{
					const SNodePanel::SNode::FNodeSlot& CommentSlot = ChildNode->GetOrAddSlot( ENodeZone::TopCenter );
					float CommentBubbleY = -CommentSlot.Offset.Get().Y;
					Context.bSelected = bSelected;
					TArray<FGraphInformationPopupInfo> Popups;

					{
						ChildNode->GetNodeInfoPopups(&Context, /*out*/ Popups);
					}

					for (int32 PopupIndex = 0; PopupIndex < Popups.Num(); ++PopupIndex)
					{
						FGraphInformationPopupInfo& Popup = Popups[PopupIndex];
						PaintComment(Popup.Message, CurWidget.Geometry, MyClippingRect, OutDrawElements, ChildLayerId, Popup.BackgroundColor, /*inout*/ CommentBubbleY, InWidgetStyle);
					}
				}

				int32 CurWidgetsMaxLayerId;
				{
					UEdGraphNode* NodeObj = Cast<UEdGraphNode>(ChildNode->GetObjectBeingDisplayed());

					/** When diffing nodes, nodes that are different between revisions are opaque, nodes that have not changed are faded */
					FGraphDiffControl::FNodeMatch NodeMatch = FGraphDiffControl::FindNodeMatch(GraphObjToDiff, NodeObj, NodeMatches);
					if (NodeMatch.IsValid())
					{
						NodeMatches.Add(NodeMatch);
					}
					const bool bNodeIsDifferent = (!GraphObjToDiff || NodeMatch.Diff());

					/* When dragging off a pin, we want to duck the alpha of some nodes */
					TSharedPtr< SGraphPin > OnlyStartPin = (1 == PreviewConnectorFromPins.Num()) ? PreviewConnectorFromPins[0].FindInGraphPanel(*this) : TSharedPtr< SGraphPin >();
					const bool bNodeIsNotUsableInCurrentContext = Schema->FadeNodeWhenDraggingOffPin(NodeObj, OnlyStartPin.IsValid() ? OnlyStartPin.Get()->GetPinObj() : NULL);
					const FWidgetStyle& NodeStyleToUse = (bNodeIsDifferent && !bNodeIsNotUsableInCurrentContext)? InWidgetStyle : FadedStyle;

					// Draw the node.O
					CurWidgetsMaxLayerId = CurWidget.Widget->Paint( Args.WithNewParent(this), CurWidget.Geometry, MyClippingRect, OutDrawElements, ChildLayerId, NodeStyleToUse, ShouldBeEnabled( bParentEnabled ) );
				}

				// Draw the node's overlay, if it has one.
				{
					// Get its size
					const FVector2D WidgetSize = CurWidget.Geometry.Size;

					{
						TArray<FOverlayBrushInfo> OverlayBrushes;
						ChildNode->GetOverlayBrushes(bSelected, WidgetSize, /*out*/ OverlayBrushes);

						for (int32 BrushIndex = 0; BrushIndex < OverlayBrushes.Num(); ++BrushIndex)
						{
							FOverlayBrushInfo& OverlayInfo = OverlayBrushes[BrushIndex];
							const FSlateBrush* OverlayBrush = OverlayInfo.Brush;
							if(OverlayBrush != NULL)
							{
								FPaintGeometry BouncedGeometry = CurWidget.Geometry.ToPaintGeometry(OverlayInfo.OverlayOffset, OverlayBrush->ImageSize, 1.f);

								// Handle bouncing
								const float BounceValue = FMath::Sin(2.0f * PI * BounceCurve.GetLerpLooping());
								BouncedGeometry.DrawPosition += (OverlayInfo.AnimationEnvelope * BounceValue * ZoomFactor);

								CurWidgetsMaxLayerId++;
								FSlateDrawElement::MakeBox(
									OutDrawElements,
									CurWidgetsMaxLayerId,
									BouncedGeometry,
									OverlayBrush,
									MyClippingRect
									);
							}

						}
					}

					{
						TArray<FOverlayWidgetInfo> OverlayWidgets = ChildNode->GetOverlayWidgets(bSelected, WidgetSize);

						for (int32 WidgetIndex = 0; WidgetIndex < OverlayWidgets.Num(); ++WidgetIndex)
						{
							FOverlayWidgetInfo& OverlayInfo = OverlayWidgets[WidgetIndex];
							if(OverlayInfo.Widget->GetVisibility() == EVisibility::Visible)
							{
								// call SlatePrepass as these widgets are not in the 'normal' child hierarchy
								OverlayInfo.Widget->SlatePrepass();

								const FGeometry WidgetGeometry = CurWidget.Geometry.MakeChild(OverlayInfo.OverlayOffset, OverlayInfo.Widget->GetDesiredSize(), 1.f);

								OverlayInfo.Widget->Paint(Args.WithNewParent(this), WidgetGeometry, MyClippingRect, OutDrawElements, CurWidgetsMaxLayerId, InWidgetStyle, bParentEnabled);
							}
						}
					}
				}

				MaxLayerId = FMath::Max( MaxLayerId, CurWidgetsMaxLayerId + 1 );
			}
		}
	}

	MaxLayerId += 1;


	// Draw connections between pins 
	if (Children.Num() > 0 )
	{

		//@TODO: Pull this into a factory like the pin and node ones
		FConnectionDrawingPolicy* ConnectionDrawingPolicy;
		{
			ConnectionDrawingPolicy = Schema->CreateConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
			if (!ConnectionDrawingPolicy)
			{
				if (Schema->IsA(UAnimationGraphSchema::StaticClass()))
				{
					ConnectionDrawingPolicy = new FAnimGraphConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
				}
				else if (Schema->IsA(UAnimationStateMachineSchema::StaticClass()))
				{
					ConnectionDrawingPolicy = new FStateMachineConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
				}
				else if (Schema->IsA(UEdGraphSchema_K2::StaticClass()))
				{
					ConnectionDrawingPolicy = new FKismetConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
				}
				else if (Schema->IsA(USoundCueGraphSchema::StaticClass()))
				{
					ConnectionDrawingPolicy = new FSoundCueGraphConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
				}
				else if (Schema->IsA(UMaterialGraphSchema::StaticClass()))
				{
					ConnectionDrawingPolicy = new FMaterialGraphConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements, GraphObj);
				}
				else
				{
					ConnectionDrawingPolicy = new FConnectionDrawingPolicy(WireLayerId, MaxLayerId, ZoomFactor, MyClippingRect, OutDrawElements);
				}
			}
		}

		TArray<TSharedPtr<SGraphPin>> OverridePins;
		for (const FGraphPinHandle& Handle : PreviewConnectorFromPins)
		{
			TSharedPtr<SGraphPin> Pin = Handle.FindInGraphPanel(*this);
			if (Pin.IsValid())
			{
				OverridePins.Add(Pin);
			}
		}
		ConnectionDrawingPolicy->SetHoveredPins(CurrentHoveredPins, OverridePins, TimeSinceMouseEnteredPin);
		ConnectionDrawingPolicy->SetMarkedPin(MarkedPin);

		// Get the set of pins for all children and synthesize geometry for culled out pins so lines can be drawn to them.
		TMap<TSharedRef<SWidget>, FArrangedWidget> PinGeometries;
		TSet< TSharedRef<SWidget> > VisiblePins;
		for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex)
		{
			TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(Children[ChildIndex]);

			// If this is a culled node, approximate the pin geometry to the corner of the node it is within
			if (IsNodeCulled(ChildNode, AllottedGeometry))
			{
				TArray< TSharedRef<SWidget> > NodePins;
				ChildNode->GetPins(NodePins);

				const FVector2D NodeLoc = ChildNode->GetPosition();
				const FGeometry SynthesizedNodeGeometry(GraphCoordToPanelCoord(NodeLoc), AllottedGeometry.AbsolutePosition, FVector2D::ZeroVector, 1.f);

				for (TArray< TSharedRef<SWidget> >::TConstIterator NodePinIterator(NodePins); NodePinIterator; ++NodePinIterator)
				{
					const SGraphPin& PinWidget = static_cast<const SGraphPin&>((*NodePinIterator).Get());
					FVector2D PinLoc = NodeLoc + PinWidget.GetNodeOffset();

					const FGeometry SynthesizedPinGeometry(GraphCoordToPanelCoord(PinLoc), AllottedGeometry.AbsolutePosition, FVector2D::ZeroVector, 1.f);
					PinGeometries.Add(*NodePinIterator, FArrangedWidget(*NodePinIterator, SynthesizedPinGeometry));
				}

				// Also add synthesized geometries for culled nodes
				ArrangedChildren.AddWidget( FArrangedWidget(ChildNode, SynthesizedNodeGeometry) );
			}
			else
			{
				ChildNode->GetPins(VisiblePins);
			}
		}

		// Now get the pin geometry for all visible children and append it to the PinGeometries map
		TMap<TSharedRef<SWidget>, FArrangedWidget> VisiblePinGeometries;
		{
			this->FindChildGeometries(AllottedGeometry, VisiblePins, VisiblePinGeometries);
			PinGeometries.Append(VisiblePinGeometries);
		}

		// Draw preview connections (only connected on one end)
		if (PreviewConnectorFromPins.Num() > 0)
		{
			for (const FGraphPinHandle& Handle : PreviewConnectorFromPins)
			{
				TSharedPtr< SGraphPin > CurrentStartPin = Handle.FindInGraphPanel(*this);
				if (!CurrentStartPin.IsValid())
				{
					continue;
				}
				const FArrangedWidget* PinGeometry = PinGeometries.Find( CurrentStartPin.ToSharedRef() );

				if (PinGeometry != NULL)
				{
					FVector2D StartPoint;
					FVector2D EndPoint;

					if (CurrentStartPin->GetDirection() == EGPD_Input)
					{
						StartPoint = AllottedGeometry.AbsolutePosition + PreviewConnectorEndpoint;
						EndPoint = FGeometryHelper::VerticalMiddleLeftOf( PinGeometry->Geometry ) - FVector2D(ConnectionDrawingPolicy->ArrowRadius.X, 0);
					}
					else
					{
						StartPoint = FGeometryHelper::VerticalMiddleRightOf( PinGeometry->Geometry );
						EndPoint = AllottedGeometry.AbsolutePosition + PreviewConnectorEndpoint;
					}

					ConnectionDrawingPolicy->DrawPreviewConnector(PinGeometry->Geometry, StartPoint, EndPoint, CurrentStartPin.Get()->GetPinObj());
				}

				//@TODO: Re-evaluate this incompatible mojo; it's mutating every pin state every frame to accomplish a visual effect
				ConnectionDrawingPolicy->SetIncompatiblePinDrawState(CurrentStartPin, VisiblePins);
			}
		}
		else
		{
			//@TODO: Re-evaluate this incompatible mojo; it's mutating every pin state every frame to accomplish a visual effect
			ConnectionDrawingPolicy->ResetIncompatiblePinDrawState(VisiblePins);
		}

		// Draw all regular connections
		ConnectionDrawingPolicy->Draw(PinGeometries, ArrangedChildren);

		delete ConnectionDrawingPolicy;
	}

	// Draw a shadow overlay around the edges of the graph
	++MaxLayerId;
	PaintSurroundSunkenShadow(FEditorStyle::GetBrush(TEXT("Graph.Shadow")), AllottedGeometry, MyClippingRect, OutDrawElements, MaxLayerId);

	if(ShowGraphStateOverlay.Get())
	{
		const FSlateBrush* BorderBrush = nullptr;
		if((GEditor->bIsSimulatingInEditor || GEditor->PlayWorld != NULL))
		{
			// Draw a surrounding indicator when PIE is active, to make it clear that the graph is read-only, etc...
			BorderBrush = FEditorStyle::GetBrush(TEXT("Graph.PlayInEditor"));
		}
		else if(!IsEditable.Get())
		{
			// Draw a different border when we're not simulating but the graph is read-only
			BorderBrush = FEditorStyle::GetBrush(TEXT("Graph.ReadOnlyBorder"));
		}

		if(BorderBrush)
		{
			// Actually draw the border
			FSlateDrawElement::MakeBox(
				OutDrawElements,
				MaxLayerId,
				AllottedGeometry.ToPaintGeometry(),
				BorderBrush,
				MyClippingRect
				);
		}
	}

	// Draw the marquee selection rectangle
	PaintMarquee(AllottedGeometry, MyClippingRect, OutDrawElements, MaxLayerId);

	// Draw the software cursor
	++MaxLayerId;
	PaintSoftwareCursor(AllottedGeometry, MyClippingRect, OutDrawElements, MaxLayerId);

	return MaxLayerId;
}
FReply FSequencerTimeSliderController::OnMouseButtonUp( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && WidgetOwner.HasMouseCapture();
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && WidgetOwner.HasMouseCapture() && TimeSliderArgs.AllowZoom ;

	if ( bHandleRightMouseButton )
	{
		if (!bPanning)
		{
			// Open a context menu if allowed
			if (ContextMenuSupression == 0 && TimeSliderArgs.PlaybackRange.IsSet())
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );

				float MouseValue = RangeToScreen.LocalXToInput( CursorPos.X );
				if (TimeSliderArgs.Settings->GetIsSnapEnabled())
				{
					MouseValue = TimeSliderArgs.Settings->SnapTimeToInterval(MouseValue);
				}

				TSharedRef<SWidget> MenuContent = OpenSetPlaybackRangeMenu(MouseValue);
				FSlateApplication::Get().PushMenu(
					WidgetOwner.AsShared(),
					MouseEvent.GetEventPath() != nullptr ? *MouseEvent.GetEventPath() : FWidgetPath(),
					MenuContent,
					MouseEvent.GetScreenSpacePosition(),
					FPopupTransitionEffect( FPopupTransitionEffect::ContextMenu )
					);

				return FReply::Handled().SetUserFocus(MenuContent, EFocusCause::SetDirectly).ReleaseMouseCapture();
			}

			// return unhandled in case our parent wants to use our right mouse button to open a context menu
			return FReply::Unhandled().ReleaseMouseCapture();
		}
		
		bPanning = false;
		
		return FReply::Handled().ReleaseMouseCapture();
	}
	else if ( bHandleLeftMouseButton )
	{
		if (MouseDragType == DRAG_START_RANGE)
		{
			TimeSliderArgs.OnEndPlaybackRangeDrag.ExecuteIfBound();
		}
		// Set the end range time?
		else if (MouseDragType == DRAG_END_RANGE)
		{
			TimeSliderArgs.OnEndPlaybackRangeDrag.ExecuteIfBound();
		}
		else if (MouseDragType == DRAG_SETTING_RANGE)
		{
			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() )
			{
				NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
			}

			float DownValue = MouseDownRange[0];
				
			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() )
			{
				DownValue = TimeSliderArgs.Settings->SnapTimeToInterval(DownValue);
			}

			// Zoom in
			if (NewValue > DownValue)
			{
				// push the current value onto the stack
				RangeStack.Add(FVector2D(TimeSliderArgs.ViewRange.Get().GetLowerBoundValue(), TimeSliderArgs.ViewRange.Get().GetUpperBoundValue()));
			}
			// Zoom out
			else if (RangeStack.Num())
			{
				// pop the stack
				FVector2D LastRange = RangeStack.Pop();
				DownValue = LastRange[0];
				NewValue = LastRange[1];
			}

			TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(DownValue, NewValue), EViewRangeInterpolation::Immediate);
					
			if( !TimeSliderArgs.ViewRange.IsBound() )
			{	
				// The output is not bound to a delegate so we'll manage the value ourselves
				TimeSliderArgs.ViewRange.Set( TRange<float>( DownValue, NewValue ) );
			}
		}
		else
		{
			TimeSliderArgs.OnEndScrubberMovement.ExecuteIfBound();

			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() && TimeSliderArgs.Settings->GetSnapPlayTimeToInterval() )
			{
				NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
			}
			
			CommitScrubPosition( NewValue, /*bIsScrubbing=*/false );
		}

		MouseDragType = DRAG_NONE;
		return FReply::Handled().ReleaseMouseCapture();

	}

	return FReply::Unhandled();
}
int32 FSequencerTimeSliderController::OnPaintSectionView( const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, bool bEnabled, const FPaintSectionAreaViewArgs& Args ) const
{
	const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

	TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
	float LocalScrubPosition = TimeSliderArgs.ScrubPosition.Get();

	float ViewRange = LocalViewRange.Size<float>();
	float PixelsPerInput = ViewRange > 0 ? AllottedGeometry.Size.X / ViewRange : 0;
	float LinePos =  (LocalScrubPosition - LocalViewRange.GetLowerBoundValue()) * PixelsPerInput;

	FScrubRangeToScreen RangeToScreen( LocalViewRange, AllottedGeometry.Size );

	if (Args.PlaybackRangeArgs.IsSet())
	{
		LayerId = DrawPlaybackRange(AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, RangeToScreen, Args.PlaybackRangeArgs.GetValue());
	}

	if( Args.bDisplayTickLines )
	{
		static FLinearColor TickColor(0.f, 0.f, 0.f, 0.3f);
		
		// Draw major tick lines in the section area
		FDrawTickArgs DrawTickArgs;
		DrawTickArgs.AllottedGeometry = AllottedGeometry;
		DrawTickArgs.bMirrorLabels = false;
		DrawTickArgs.bOnlyDrawMajorTicks = true;
		DrawTickArgs.TickColor = TickColor;
		DrawTickArgs.ClippingRect = MyClippingRect;
		DrawTickArgs.DrawEffects = DrawEffects;
		// Draw major ticks under sections
		DrawTickArgs.StartLayer = LayerId-1;
		// Draw the tick the entire height of the section area
		DrawTickArgs.TickOffset = 0.0f;
		DrawTickArgs.MajorTickHeight = AllottedGeometry.Size.Y;

		DrawTicks( OutDrawElements, RangeToScreen, DrawTickArgs );
	}

	if( Args.bDisplayScrubPosition )
	{
		// Draw a line for the scrub position
		TArray<FVector2D> LinePoints;
		LinePoints.AddUninitialized(2);
		LinePoints[0] = FVector2D( 0.0f, 0.0f );
		LinePoints[1] = FVector2D( 0.0f, FMath::RoundToFloat( AllottedGeometry.Size.Y ) );

		FSlateDrawElement::MakeLines(
			OutDrawElements,
			LayerId+1,
			AllottedGeometry.ToPaintGeometry( FVector2D(LinePos, 0.0f ), FVector2D(1.0f,1.0f) ),
			LinePoints,
			MyClippingRect,
			DrawEffects,
			FLinearColor::White,
			false
			);
	}

	return LayerId;
}
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();
}