Beispiel #1
0
FReply SAnimTrackPanel::OnMouseMove( const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent )
{
	const bool bRightMouseButtonDown = InMouseEvent.IsMouseButtonDown(EKeys::RightMouseButton);

	// When mouse moves, if we are moving a key, update its 'input' position
	if(bRightMouseButtonDown)
	{
		if( !bPanning )
		{
			PanningDistance += FMath::Abs(InMouseEvent.GetCursorDelta().X);
			if ( PanningDistance > FSlateApplication::Get().GetDragTriggerDistance() )
			{
				bPanning = true;
				UE_LOG(LogAnimation, Log, TEXT("MouseMove (Capturing Mouse) %d, %0.5f"), bPanning, PanningDistance);
				return FReply::Handled().CaptureMouse(SharedThis(this));
			}
		}
		else
		{
			FTrackScaleInfo ScaleInfo(ViewInputMin.Get(),  ViewInputMax.Get(), 0.f, 0.f, InMyGeometry.Size);
			FVector2D ScreenDelta = InMouseEvent.GetCursorDelta();
			FVector2D InputDelta;
			InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput;
			InputDelta.Y = -ScreenDelta.Y/ScaleInfo.PixelsPerOutput;

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

			OnSetInputViewRange.Execute(NewViewInputMin, NewViewInputMax);

			UE_LOG(LogAnimation, Log, TEXT("MouseMove (Panning) %0.2f, %0.2f"), ViewInputMin.Get(), ViewInputMax.Get());
			return FReply::Handled();
		}
	}

	return FReply::Unhandled();
}
FReply SColorGradientEditor::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if( HasMouseCapture() && IsEditingEnabled.Get() == true )
	{
		DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
			
		if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) && SelectedStop.IsValid( *CurveOwner ) )
		{
			const float DragThresholdDist = 5.0f;
			if( !bDraggingStop )
			{
				if( DistanceDragged >= DragThresholdDist )
				{
					// Start a transaction, we just started dragging a stop
					bDraggingStop = true;
					GEditor->BeginTransaction( LOCTEXT("MoveGradientStop", "Move Gradient Stop") );
					CurveOwner->ModifyOwner();
				}

				return FReply::Handled();
			}
			else
			{
				// Already dragging a stop, move it
				FTrackScaleInfo ScaleInfo(ViewMinInput.Get(),  ViewMaxInput.Get(), 0.0f, 1.0f, MyGeometry.Size);
				float MouseTime = ScaleInfo.LocalXToInput( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X );
				MoveStop( SelectedStop, MouseTime );

				return FReply::Handled();
			}
		}
	}

	return FReply::Unhandled();
}
FReply STableViewBase::OnTouchMoved( const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent )
{
	if (bStartedTouchInteraction)
	{
		const float ScrollByAmount = InTouchEvent.GetCursorDelta().Y / MyGeometry.Scale;
		AmountScrolledWhileRightMouseDown += FMath::Abs( ScrollByAmount );
		TickScrollDelta -= ScrollByAmount;

		if (AmountScrolledWhileRightMouseDown > FSlateApplication::Get().GetDragTriggerDistance())
		{
			// Make sure the active timer is registered to update the inertial scroll
			if ( !bIsScrollingActiveTimerRegistered )
			{
				bIsScrollingActiveTimerRegistered = true;
				RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &STableViewBase::UpdateInertialScroll));
			}

			const float AmountScrolled = this->ScrollBy( MyGeometry, -ScrollByAmount, EAllowOverscroll::Yes );

			// The user has moved the list some amount; they are probably
			// trying to scroll. From now on, the list assumes the user is scrolling
			// until they lift their finger.
			return FReply::Handled().CaptureMouse( AsShared() );
		}
		return FReply::Handled();
	}
	else
	{
		return FReply::Handled();
	}
}
FReply SButton::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	const float SlateDragStartDistance = FSlateApplication::Get().GetDragTriggerDistance();
	if ( IsPreciseTapOrClick(MouseEvent) && MouseEvent.GetCursorDelta().SizeSquared() > ( SlateDragStartDistance*SlateDragStartDistance ) )
	{
		Release();
	}
	return FReply::Unhandled();
}
FReply FSceneViewport::OnMouseMove( const FGeometry& InGeometry, const FPointerEvent& InMouseEvent )
{
	// Start a new reply state
	CurrentReplyState = FReply::Handled();

	if( !InMouseEvent.GetCursorDelta().IsZero() )
	{
		UpdateCachedMousePos( InGeometry, InMouseEvent );
		UpdateCachedGeometry(InGeometry);

		const bool bViewportHasCapture = ViewportWidget.IsValid() && ViewportWidget.Pin()->HasMouseCapture();
		if( ViewportClient && GetSizeXY() != FIntPoint::ZeroValue )
		{
			// Switch to the viewport clients world before processing input
			FScopedConditionalWorldSwitcher WorldSwitcher( ViewportClient );

			if( bViewportHasCapture )
			{
				ViewportClient->CapturedMouseMove( this, GetMouseX(), GetMouseY() );
			}
			else
			{
				ViewportClient->MouseMove( this, GetMouseX(), GetMouseY() );
			}
		
			if( bViewportHasCapture )
			{
				// Accumulate delta changes to mouse movment.  Depending on the sample frequency of a mouse we may get many per frame.
				//@todo Slate: In directinput, number of samples in x/y could be different...
				const FVector2D CursorDelta = InMouseEvent.GetCursorDelta();
				MouseDelta.X += CursorDelta.X;
				++NumMouseSamplesX;

				MouseDelta.Y -= CursorDelta.Y;
				++NumMouseSamplesY;
			}
		}
	}
	return CurrentReplyState;
}
Beispiel #6
0
FReply FTextEditHelper::OnMouseMove( const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent, const TSharedRef< ITextEditorWidget >& TextEditor )
{
	FReply Reply = FReply::Unhandled();

	if( TextEditor->IsDragSelecting() && TextEditor->GetWidget()->HasMouseCapture() && InMouseEvent.GetCursorDelta() != FVector2D::ZeroVector )
	{
		TextEditor->MoveCursor( FMoveCursor::ViaScreenPointer( InMyGeometry.AbsoluteToLocal( InMouseEvent.GetScreenSpacePosition( ) ), InMyGeometry.Scale, ECursorAction::SelectText ) );
		TextEditor->SetHasDragSelectedSinceFocused( true );
		Reply = FReply::Handled();
	}

	return Reply;
}
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();
}
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;
}
FReply STableViewBase::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{	
	if( MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ) )
	{
		const float ScrollByAmount = MouseEvent.GetCursorDelta().Y / MyGeometry.Scale;
		// 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( ScrollByAmount );

		// Has the mouse moved far enough with the right mouse button held down to start capturing
		// the mouse and dragging the view?
		if( IsRightClickScrolling() )
		{
			// Make sure the active timer is registered to update the inertial scroll
			if (!bIsScrollingActiveTimerRegistered)
			{
				bIsScrollingActiveTimerRegistered = true;
				RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &STableViewBase::UpdateInertialScroll));
			}

			TickScrollDelta -= ScrollByAmount;

			const float AmountScrolled = this->ScrollBy( MyGeometry, -ScrollByAmount, AllowOverscroll );

			FReply Reply = FReply::Handled();

			// The mouse moved enough that we're now dragging the view. Capture the mouse
			// so the user does not have to stay within the bounds of the list while dragging.
			if(this->HasMouseCapture() == false)
			{
				Reply.CaptureMouse( AsShared() ).UseHighPrecisionMouseMovement( AsShared() );
				SoftwareCursorPosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );
				bShowSoftwareCursor = true;
			}

			// Check if the mouse has moved.
			if( AmountScrolled != 0 )
			{
				SoftwareCursorPosition.Y += ScrollByAmount;
			}

			return Reply;
		}
	}

	return FReply::Unhandled();
}
FReply SPaperEditorViewport::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
	const bool bIsRightMouseButtonDown = MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton);
	const bool bIsLeftMouseButtonDown = MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton);
	
	if (HasMouseCapture())
	{
		// Track how much the mouse moved since the mouse down.
		const FVector2D CursorDelta = MouseEvent.GetCursorDelta();
		TotalMouseDelta += CursorDelta.Size();

		if (bIsRightMouseButtonDown)
		{
			FReply ReplyState = FReply::Handled();

			if (!CursorDelta.IsZero())
			{
				bShowSoftwareCursor = true;
			}

			bIsPanning = true;
			ViewOffset -= CursorDelta / GetZoomAmount();

			return ReplyState;
		}
		else if (bIsLeftMouseButtonDown)
		{
//			TSharedPtr<SNode> NodeBeingDragged = NodeUnderMousePtr.Pin();

			// Update the amount to pan panel
			UpdateViewOffset(MyGeometry, MouseEvent.GetScreenSpacePosition());

			const bool bCursorInDeadZone = TotalMouseDelta <= FSlateApplication::Get().GetDragTriggerDistance();

			{
				// We are marquee selecting
				const FVector2D GraphMousePos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) );
				Marquee.Rect.UpdateEndPoint(GraphMousePos);

				return FReply::Handled();
			}
		}
	}

	return FReply::Unhandled();
}
FReply SSequencerTrackArea::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	auto SequencerPin = SequencerWidget.Pin();
	if (SequencerPin.IsValid())
	{
		FReply Reply = SequencerPin->GetEditTool().OnMouseMove(*this, MyGeometry, MouseEvent);
		if (Reply.IsEventHandled())
		{
			return Reply;
		}
	}

	if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton) && HasMouseCapture())
	{
		TreeView.Pin()->ScrollByDelta( -MouseEvent.GetCursorDelta().Y );
	}

	return TimeSliderController->OnMouseMove( SharedThis(this), MyGeometry, MouseEvent );
}
Beispiel #12
0
/**
* The system calls this method to notify the widget that a mouse moved within it. This event is bubbled.
*
* @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 SSplitter::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	const FVector2D LocalMousePosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );

	TArray<FLayoutGeometry> LayoutChildren = ArrangeChildrenForLayout(MyGeometry);

	if ( bIsResizing )
	{
		if ( !MouseEvent.GetCursorDelta().IsZero() )
		{
			if (Orientation == Orient_Horizontal)
			{
				HandleResizing<Orient_Horizontal>( PhysicalSplitterHandleSize, ResizeMode, HoveredHandleIndex, LocalMousePosition, Children, LayoutChildren );
			}
			else
			{
				HandleResizing<Orient_Vertical>( PhysicalSplitterHandleSize, ResizeMode, HoveredHandleIndex, LocalMousePosition, Children, LayoutChildren );
			}
		}

		return FReply::Handled();
	}
	else
	{	
		// Hit test which handle we are hovering over.		
		HoveredHandleIndex = (Orientation == Orient_Horizontal)
			? GetHandleBeingResizedFromMousePosition<Orient_Horizontal>( PhysicalSplitterHandleSize, HitDetectionSplitterHandleSize, LocalMousePosition, LayoutChildren )
			: GetHandleBeingResizedFromMousePosition<Orient_Vertical>( PhysicalSplitterHandleSize, HitDetectionSplitterHandleSize, LocalMousePosition, LayoutChildren );

		if (HoveredHandleIndex != INDEX_NONE)
		{
			if ( FindResizeableSlotBeforeHandle(HoveredHandleIndex, Children) <= INDEX_NONE || FindResizeableSlotAfterHandle(HoveredHandleIndex, Children) >= Children.Num() )
			{
				HoveredHandleIndex = INDEX_NONE;
			}
		}

		return FReply::Unhandled();
	}

}
Beispiel #13
0
FReply STableViewBase::OnTouchMoved( const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent )
{
	if (bStartedTouchInteraction)
	{
		const float ScrollByAmount = InTouchEvent.GetCursorDelta().Y / MyGeometry.Scale;
		AmountScrolledWhileRightMouseDown += FMath::Abs( ScrollByAmount );
		TickScrollDelta -= ScrollByAmount;

		if (AmountScrolledWhileRightMouseDown > FSlateApplication::Get().GetDragTriggerDistance())
		{
			const float AmountScrolled = this->ScrollBy( MyGeometry, -ScrollByAmount, EAllowOverscroll::Yes );

			// The user has moved the list some amount; they are probably
			// trying to scroll. From now on, the list assumes the user is scrolling
			// until they lift their finger.
			return FReply::Handled().CaptureMouse( AsShared() );
		}
		return FReply::Handled();
	}
	else
	{
		return FReply::Handled();
	}
}
Beispiel #14
0
FReply SSection::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if( HasMouseCapture() )
	{
		// Have mouse capture and there are drag operations that need to be performed
		if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) )
		{
			DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
			
			FVector2D LocalMousePos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );

			if( !bDragging )
			{
				// If we are not dragging determine if the mouse has moved far enough to start a drag
				if( DistanceDragged >= SequencerSectionConstants::SectionDragStartDistance )
				{
					bDragging = true;

					if( PressedKey.IsValid() )
					{
						// Clear selected sections when beginning to drag keys
						GetSequencer().GetSelection().EmptySelectedSections();

						bool bSelectDueToDrag = true;
						HandleKeySelection( PressedKey, MouseEvent, bSelectDueToDrag );

						bool bKeysUnderMouse = true;
						CreateDragOperation( MyGeometry, MouseEvent, bKeysUnderMouse );
					}
					else
					{
						// Clear selected keys when beginning to drag a section
						GetSequencer().GetSelection().EmptySelectedKeys();

						HandleSectionSelection( MouseEvent );

						bool bKeysUnderMouse = false;
						CreateDragOperation( MyGeometry, MouseEvent, bKeysUnderMouse );
					}
				
					if( DragOperation.IsValid() )
					{
						DragOperation->OnBeginDrag(LocalMousePos, ParentSectionArea);
					}

				}
			}
			else if( DragOperation.IsValid() )
			{
				// Already in a drag, tell all operations to perform their drag implementations
				FTimeToPixel TimeToPixelConverter = SectionInterface->GetSectionObject()->IsInfinite() ? 			
					FTimeToPixel( ParentGeometry, GetSequencer().GetViewRange()) : 
					FTimeToPixel( MyGeometry, TRange<float>( SectionInterface->GetSectionObject()->GetStartTime(), SectionInterface->GetSectionObject()->GetEndTime() ) );

				DragOperation->OnDrag( MouseEvent, LocalMousePos, TimeToPixelConverter, ParentSectionArea );
			}
		}

		return FReply::Handled();
	}
	else
	{
		// Not dragging


		ResetHoveredState();

		// Checked for hovered key
		// @todo Sequencer - Needs visual cue
		HoveredKey = GetKeyUnderMouse( MouseEvent.GetScreenSpacePosition(), MyGeometry );

		// Only check for edge interaction if not hovering over a key
		if( !HoveredKey.IsValid() )
		{
			CheckForEdgeInteraction( MouseEvent, MyGeometry );
		}
		
	}

	return FReply::Unhandled();
}
FReply FVisualLoggerTimeSliderController::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() )
				{
					FReply::Handled().CaptureMouse(WidgetOwner).UseHighPrecisionMouseMovement(WidgetOwner);
					SoftwareCursorPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
					bPanning = true;
				}
			}
			else
			{
				SoftwareCursorPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());

				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;

				float LocalClampMin = TimeSliderArgs.ClampRange.Get().GetLowerBoundValue();
				float LocalClampMax = TimeSliderArgs.ClampRange.Get().GetUpperBoundValue();

				// Clamp the range
				if ( NewViewOutputMin < LocalClampMin )
				{
					NewViewOutputMin = LocalClampMin;
				}
			
				if ( NewViewOutputMax > LocalClampMax )
				{
					NewViewOutputMax = LocalClampMax;
				}

				TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(NewViewOutputMin, NewViewOutputMax), EViewRangeInterpolation::Immediate, false);
				if (Scrollbar.IsValid())
				{
					float InOffsetFraction = (NewViewOutputMin - LocalClampMin) / (LocalClampMax - LocalClampMin);
					float InThumbSizeFraction = (NewViewOutputMax - NewViewOutputMin) / (LocalClampMax - LocalClampMin);
					Scrollbar->SetState(InOffsetFraction, InThumbSizeFraction);
				}

				if( !TimeSliderArgs.ViewRange.IsBound() )
				{	
					// The  output is not bound to a delegate so we'll manage the value ourselves
					TimeSliderArgs.ViewRange.Set( TRange<float>( NewViewOutputMin, NewViewOutputMax ) );
				}
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			if ( !bDraggingScrubber )
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > 0/*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 );

				float LocalClampMin = TimeSliderArgs.ClampRange.Get().GetLowerBoundValue();
				float LocalClampMax = TimeSliderArgs.ClampRange.Get().GetUpperBoundValue();

				if (NewValue < LocalClampMin)
				{
					NewValue = LocalClampMin;
				}

				if (NewValue > LocalClampMax)
				{
					NewValue = LocalClampMax;
				}

				CommitScrubPosition(NewValue, /*bIsScrubbing=*/true);
			}
		}
		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();
}
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().GetDragTriggerDistnace() )
				{
					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;

				TOptional<float> LocalClampMin = TimeSliderArgs.ClampMin.Get();
				TOptional<float> LocalClampMax = TimeSliderArgs.ClampMax.Get();

				// Clamp the range if clamp values are set
				if ( LocalClampMin.IsSet() && NewViewOutputMin < LocalClampMin.GetValue() )
				{
					NewViewOutputMin = LocalClampMin.GetValue();
				}
			
				if ( LocalClampMax.IsSet() && NewViewOutputMax > LocalClampMax.GetValue() )
				{
					NewViewOutputMax = LocalClampMax.GetValue();
				}

				TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(NewViewOutputMin, NewViewOutputMax));

				if( !TimeSliderArgs.ViewRange.IsBound() )
				{	
					// The  output is not bound to a delegate so we'll manage the value ourselves
					TimeSliderArgs.ViewRange.Set( TRange<float>( NewViewOutputMin, NewViewOutputMax ) );
				}
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			if ( !bDraggingScrubber )
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistnace() )
				{
					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 USequencerSnapSettings* SnapSettings = GetDefault<USequencerSnapSettings>();
				if ( SnapSettings->GetIsSnapEnabled() && SnapSettings->GetSnapPlayTimeToInterval() )
				{
					NewValue = SnapSettings->SnapToInterval(NewValue);
				}

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

	return FReply::Unhandled();
}
FVector2D UKismetInputLibrary::PointerEvent_GetCursorDelta(const FPointerEvent& Input)
{
	return Input.GetCursorDelta();
}
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();
}
Beispiel #20
0
	/** SWidget interface */
	virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
	{
		const bool bIsRightMouseButtonDown = MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton );
		const bool bIsLeftMouseButtonDown = MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton );

		PastePosition = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) );

		if ( this->HasMouseCapture() )
		{
			const FVector2D CursorDelta = MouseEvent.GetCursorDelta();
			// Track how much the mouse moved since the mouse down.
			TotalMouseDelta += CursorDelta.Size();

			if (bIsRightMouseButtonDown)
			{
				FReply ReplyState = FReply::Handled();

				if( !CursorDelta.IsZero() )
				{
					bShowSoftwareCursor = true;
				}

				// Panning and mouse is outside of panel? Pasting should just go to the screen center.
				PastePosition = PanelCoordToGraphCoord( 0.5 * MyGeometry.Size );

				this->bIsPanning = true;
				ViewOffset -= CursorDelta / GetZoomAmount();

				return ReplyState;
			}
			else if (bIsLeftMouseButtonDown)
			{
				TSharedPtr<SNode> NodeBeingDragged = NodeUnderMousePtr.Pin();

				if ( IsEditable.Get() )
				{
					// Update the amount to pan panel
					UpdateViewOffset(MyGeometry, MouseEvent.GetScreenSpacePosition());

					const bool bCursorInDeadZone = TotalMouseDelta <= FSlateApplication::Get().GetDragTriggerDistance();

					if ( NodeBeingDragged.IsValid() )
					{
						if ( !bCursorInDeadZone )
						{
							// Note, NodeGrabOffset() comes from the node itself, so it's already scaled correctly.
							FVector2D AnchorNodeNewPos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) ) - NodeGrabOffset;

							// Dragging an unselected node automatically selects it.
							SelectionManager.StartDraggingNode(NodeBeingDragged->GetObjectBeingDisplayed(), MouseEvent);

							// Move all the selected nodes.
							{
								const FVector2D AnchorNodeOldPos = NodeBeingDragged->GetPosition();
								const FVector2D DeltaPos = AnchorNodeNewPos - AnchorNodeOldPos;
								if (DeltaPos.Size() > KINDA_SMALL_NUMBER)
								{
									MoveSelectedNodes(NodeBeingDragged, AnchorNodeNewPos);
								}
							}
						}

						return FReply::Handled();
					}
				}

				if ( !NodeBeingDragged.IsValid() )
				{
					// We are marquee selecting
					const FVector2D GraphMousePos = PanelCoordToGraphCoord( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ) );
					Marquee.Rect.UpdateEndPoint(GraphMousePos);

					FindNodesAffectedByMarquee( /*out*/ Marquee.AffectedNodes );
					return FReply::Handled();
				}
			}
		}

		return FReply::Unhandled();
	}
Beispiel #21
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();
}
FReply FCanvasSlotExtension::HandleAnchorDragging(const FGeometry& Geometry, const FPointerEvent& Event, EAnchorWidget::Type AnchorType)
{
	if ( bMovingAnchor && !Event.GetCursorDelta().IsZero() )
	{
		float InverseSize = 1.0f / Designer->GetPreviewScale();

		for ( FWidgetReference& Selection : SelectionCache )
		{
			UWidget* PreviewWidget = Selection.GetPreview();
			if ( UCanvasPanel* Canvas = Cast<UCanvasPanel>(PreviewWidget->GetParent()) )
			{
				UCanvasPanelSlot* PreviewCanvasSlot = Cast<UCanvasPanelSlot>(PreviewWidget->Slot);

				FGeometry Geometry;
				if ( Canvas->GetGeometryForSlot(PreviewCanvasSlot, Geometry) )
				{
					FGeometry CanvasGeometry = Canvas->GetCanvasWidget()->GetCachedGeometry();
					FVector2D StartLocalPosition = CanvasGeometry.AbsoluteToLocal(MouseDownPosition);
					FVector2D NewLocalPosition = CanvasGeometry.AbsoluteToLocal(Event.GetScreenSpacePosition());
					FVector2D LocalPositionDelta = NewLocalPosition - StartLocalPosition;

					FVector2D AnchorDelta = LocalPositionDelta / CanvasGeometry.Size;

					const FAnchorData OldLayoutData = PreviewCanvasSlot->LayoutData;
					FAnchorData LayoutData = OldLayoutData;
					
					switch ( AnchorType )
					{
					case EAnchorWidget::Center:
						LayoutData.Anchors.Maximum = BeginAnchors.Maximum + AnchorDelta;
						LayoutData.Anchors.Minimum = BeginAnchors.Minimum + AnchorDelta;
						LayoutData.Anchors.Minimum.X = FMath::Clamp(LayoutData.Anchors.Minimum.X, 0.0f, 1.0f);
						LayoutData.Anchors.Maximum.X = FMath::Clamp(LayoutData.Anchors.Maximum.X, 0.0f, 1.0f);
						LayoutData.Anchors.Minimum.Y = FMath::Clamp(LayoutData.Anchors.Minimum.Y, 0.0f, 1.0f);
						LayoutData.Anchors.Maximum.Y = FMath::Clamp(LayoutData.Anchors.Maximum.Y, 0.0f, 1.0f);
						break;
					}

					switch ( AnchorType )
					{
					case EAnchorWidget::Left:
					case EAnchorWidget::TopLeft:
					case EAnchorWidget::BottomLeft:
						LayoutData.Anchors.Minimum.X = BeginAnchors.Minimum.X + AnchorDelta.X;
						LayoutData.Anchors.Minimum.X = FMath::Clamp(LayoutData.Anchors.Minimum.X, 0.0f, LayoutData.Anchors.Maximum.X);
						break;
					}

					switch ( AnchorType )
					{
					case EAnchorWidget::Right:
					case EAnchorWidget::TopRight:
					case EAnchorWidget::BottomRight:
						LayoutData.Anchors.Maximum.X = BeginAnchors.Maximum.X + AnchorDelta.X;
						LayoutData.Anchors.Maximum.X = FMath::Clamp(LayoutData.Anchors.Maximum.X, LayoutData.Anchors.Minimum.X, 1.0f);
						break;
					}

					switch ( AnchorType )
					{
					case EAnchorWidget::Top:
					case EAnchorWidget::TopLeft:
					case EAnchorWidget::TopRight:
						LayoutData.Anchors.Minimum.Y = BeginAnchors.Minimum.Y + AnchorDelta.Y;
						LayoutData.Anchors.Minimum.Y = FMath::Clamp(LayoutData.Anchors.Minimum.Y, 0.0f, LayoutData.Anchors.Maximum.Y);
						break;
					}

					switch ( AnchorType )
					{
					case EAnchorWidget::Bottom:
					case EAnchorWidget::BottomLeft:
					case EAnchorWidget::BottomRight:
						LayoutData.Anchors.Maximum.Y = BeginAnchors.Maximum.Y + AnchorDelta.Y;
						LayoutData.Anchors.Maximum.Y = FMath::Clamp(LayoutData.Anchors.Maximum.Y, LayoutData.Anchors.Minimum.Y, 1.0f);
						break;
					}

					// Major percentage snapping
					{
						const float MajorAnchorLine = 0.1f;
						const float MajorAnchorLineSnapDistance = 0.1f;

						if ( LayoutData.Anchors.Minimum.X != OldLayoutData.Anchors.Minimum.X )
						{
							ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Minimum.X);
						}

						if ( LayoutData.Anchors.Minimum.Y != OldLayoutData.Anchors.Minimum.Y )
						{
							ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Minimum.Y);
						}

						if ( LayoutData.Anchors.Maximum.X != OldLayoutData.Anchors.Maximum.X )
						{
							ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Maximum.X);
						}

						if ( LayoutData.Anchors.Maximum.Y != OldLayoutData.Anchors.Maximum.Y )
						{
							ProximitySnapValue(MajorAnchorLine, MajorAnchorLineSnapDistance, LayoutData.Anchors.Maximum.Y);
						}
					}

					// Rebase the layout and restore the old value after calculating the new final layout
					// result.
					{
						PreviewCanvasSlot->SaveBaseLayout();
						PreviewCanvasSlot->LayoutData = LayoutData;
						PreviewCanvasSlot->RebaseLayout();

						LayoutData = PreviewCanvasSlot->LayoutData;
						PreviewCanvasSlot->LayoutData = OldLayoutData;
					}

					// If control is pressed reset all positional offset information
					if ( FSlateApplication::Get().GetModifierKeys().IsControlDown() )
					{
						FMargin NewOffsets = FMargin(0, 0, LayoutData.Anchors.IsStretchedHorizontal() ? 0 : LayoutData.Offsets.Right, LayoutData.Anchors.IsStretchedVertical() ? 0 : LayoutData.Offsets.Bottom);
						LayoutData.Offsets = NewOffsets;
					}

					UWidget* TemplateWidget = Selection.GetTemplate();
					UCanvasPanelSlot* TemplateCanvasSlot = CastChecked<UCanvasPanelSlot>(TemplateWidget->Slot);

					static const FName LayoutDataName(TEXT("LayoutData"));

					FObjectEditorUtils::SetPropertyValue<UCanvasPanelSlot, FAnchorData>(PreviewCanvasSlot, LayoutDataName, LayoutData);
					FObjectEditorUtils::SetPropertyValue<UCanvasPanelSlot, FAnchorData>(TemplateCanvasSlot, LayoutDataName, LayoutData);
				}
			};

			return FReply::Handled();
		}
	}

	return FReply::Unhandled();
}