EM_Task/UnrealEd/Private/MouseDeltaTracker.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

691 lines
26 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MouseDeltaTracker.h"
#include "EngineDefines.h"
#include "SceneView.h"
#include "EditorViewportClient.h"
#include "Settings/LevelEditorViewportSettings.h"
#include "Editor.h"
#include "EditorDragTools.h"
#include "SnappingUtils.h"
#define LOCTEXT_NAMESPACE "MouseDeltaTracker"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// FMouseDeltaTracker
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FMouseDeltaTracker::FMouseDeltaTracker()
: Start(FVector::ZeroVector), StartSnapped(FVector::ZeroVector), StartScreen(FVector::ZeroVector), End(FVector::ZeroVector), EndSnapped(FVector::ZeroVector), EndScreen(FVector::ZeroVector), RawDelta(FVector::ZeroVector), ReductionAmount(FVector::ZeroVector), DragTool(NULL), bHasAttemptedDragTool(false), bUsedDragModifier(false), bIsDeletingDragTool(false)
{
}
FMouseDeltaTracker::~FMouseDeltaTracker()
{
}
/**
* Sets the current axis of the widget for the specified viewport.
*
* @param InViewportClient The viewport whose widget axis is to be set.
*/
void FMouseDeltaTracker::DetermineCurrentAxis(FEditorViewportClient* InViewportClient)
{
const bool AltDown = InViewportClient->IsAltPressed();
const bool ShiftDown = InViewportClient->IsShiftPressed();
const bool ControlDown = InViewportClient->IsCtrlPressed();
const bool LeftMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::LeftMouseButton);
const bool RightMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::RightMouseButton);
const bool MiddleMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::MiddleMouseButton);
const bool bIsRotateObjectMode = InViewportClient->IsOrtho() && ControlDown && RightMouseButtonDown;
// Ctrl + LEFT/RIGHT mouse button acts the same as dragging the most appropriate widget handle.
if ((!InViewportClient->ShouldOrbitCamera() && bIsRotateObjectMode) || ((!bIsRotateObjectMode && ControlDown && !AltDown) &&
(LeftMouseButtonDown || RightMouseButtonDown)))
{
// Only try to pick an axis if we're not dragging by widget handle.
if (InViewportClient->GetCurrentWidgetAxis() == EAxisList::None)
{
switch (InViewportClient->GetWidgetMode())
{
case FWidget::WM_Scale:
// Non-uniform scale when shift is down, uniform when it is up
if (ShiftDown)
{
switch (InViewportClient->ViewportType)
{
case LVT_Perspective:
if (LeftMouseButtonDown && !RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::X);
}
else if (!LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Y);
}
else if (LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Z);
}
break;
case LVT_OrthoXY:
case LVT_OrthoNegativeXY:
InViewportClient->SetCurrentWidgetAxis(EAxisList::XY);
break;
case LVT_OrthoXZ:
case LVT_OrthoNegativeXZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::XZ);
break;
case LVT_OrthoYZ:
case LVT_OrthoNegativeYZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::YZ);
break;
default:
break;
}
}
else
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::XYZ);
}
break;
case FWidget::WM_Translate:
case FWidget::WM_TranslateRotateZ:
case FWidget::WM_2D:
switch (InViewportClient->ViewportType)
{
case LVT_Perspective:
if (LeftMouseButtonDown && !RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::X);
}
else if (!LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Y);
}
else if (LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Z);
}
break;
case LVT_OrthoXY:
case LVT_OrthoNegativeXY:
InViewportClient->SetCurrentWidgetAxis(EAxisList::XY);
break;
case LVT_OrthoXZ:
case LVT_OrthoNegativeXZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::XZ);
break;
case LVT_OrthoYZ:
case LVT_OrthoNegativeYZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::YZ);
break;
default:
break;
}
break;
case FWidget::WM_Rotate:
switch (InViewportClient->ViewportType)
{
case LVT_Perspective:
if (LeftMouseButtonDown && !RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::X);
}
else if (!LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Y);
}
else if (LeftMouseButtonDown && RightMouseButtonDown)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::Z);
}
break;
case LVT_OrthoXY:
case LVT_OrthoNegativeXY:
InViewportClient->SetCurrentWidgetAxis(EAxisList::Z);
break;
case LVT_OrthoXZ:
case LVT_OrthoNegativeXZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::Y);
break;
case LVT_OrthoYZ:
case LVT_OrthoNegativeYZ:
InViewportClient->SetCurrentWidgetAxis(EAxisList::X);
break;
default:
break;
}
break;
default:
break;
}
// if we now have a widget axis we must have used a modifier to get it
if (InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
{
bUsedDragModifier = true;
}
}
}
}
/**
* Begin tracking at the specified location for the specified viewport.
*/
void FMouseDeltaTracker::StartTracking(FEditorViewportClient* InViewportClient, const int32 InX, const int32 InY, const FInputEventState& InInputState, bool bNudge, bool bResetDragToolState)
{
DetermineCurrentAxis(InViewportClient);
// Initialize widget axis (in case it hasn't been set by the hovered hit proxy)
if (InViewportClient->Widget && InViewportClient->GetCurrentWidgetAxis() == EAxisList::None)
{
check(InViewportClient->Viewport);
HHitProxy* HitProxy = InViewportClient->Viewport->GetHitProxy(InX, InY);
if (HitProxy && HitProxy->IsA(HWidgetAxis::StaticGetType()))
{
EAxisList::Type ProxyAxis = ((HWidgetAxis*)HitProxy)->Axis;
InViewportClient->SetCurrentWidgetAxis(ProxyAxis);
}
}
const bool AltDown = InViewportClient->IsAltPressed();
const bool ShiftDown = InViewportClient->IsShiftPressed();
const bool ControlDown = InViewportClient->IsCtrlPressed();
const bool LeftMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::LeftMouseButton);
const bool RightMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::RightMouseButton);
const bool MiddleMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::MiddleMouseButton);
bool bIsDragging = ((ControlDown || ShiftDown) && (LeftMouseButtonDown || RightMouseButtonDown || MiddleMouseButtonDown)) ||
(InViewportClient->GetCurrentWidgetAxis() != EAxisList::None) || bNudge;
// Update bWidgetAxisControlledByDrag since we now know that we have begun dragging an object with the mouse.
if (bIsDragging)
{
InViewportClient->bWidgetAxisControlledByDrag = true;
}
InViewportClient->TrackingStarted(InInputState, bIsDragging, bNudge);
if (InViewportClient->Widget)
{
InViewportClient->Widget->SetDragStartPosition(FVector2D(InX, InY));
InViewportClient->Widget->SetDragging(bIsDragging);
if (InViewportClient->GetWidgetMode() == FWidget::WM_Rotate)
{
InViewportClient->Invalidate();
}
}
// Clear bool that tracks whether AddDelta has been called
bHasReceivedAddDelta = false;
if (bResetDragToolState)
{
bHasAttemptedDragTool = false;
}
ensure(!DragTool.IsValid());
StartSnapped = Start = StartScreen = FVector(InX, InY, 0);
RawDelta = FVector::ZeroVector;
TrackingWidgetMode = InViewportClient->GetWidgetMode();
// No drag tool is active, so handle snapping.
switch (TrackingWidgetMode)
{
case FWidget::WM_Translate:
FSnappingUtils::SnapPointToGrid(StartSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
break;
case FWidget::WM_Scale:
FSnappingUtils::SnapScale(StartSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
break;
case FWidget::WM_Rotate: {
FRotator Rotation(StartSnapped.X, StartSnapped.Y, StartSnapped.Z);
FSnappingUtils::SnapRotatorToGrid(Rotation);
StartSnapped = FVector(Rotation.Pitch, Rotation.Yaw, Rotation.Roll);
}
break;
case FWidget::WM_TranslateRotateZ:
case FWidget::WM_2D:
FSnappingUtils::SnapPointToGrid(StartSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
break;
default:
break;
}
// Clear any snapping helpers on new movement
const bool bClearImmediatley = true;
FSnappingUtils::ClearSnappingHelpers(bClearImmediatley);
End = EndScreen = Start;
EndSnapped = StartSnapped;
bExternalMovement = false; // no external movement has occurred yet.
InViewportClient->Widget->ResetDeltaRotation();
}
/**
* Called when a mouse button has been released. If there are no other
* mouse buttons being held down, the internal information is reset.
*/
bool FMouseDeltaTracker::EndTracking(FEditorViewportClient* InViewportClient)
{
DetermineCurrentAxis(InViewportClient);
if (InViewportClient->Widget)
{
InViewportClient->Widget->SetDragging(false);
}
InViewportClient->TrackingStopped();
InViewportClient->Widget->ResetDeltaRotation();
Start = StartSnapped = StartScreen = End = EndSnapped = EndScreen = RawDelta = ReductionAmount = FVector::ZeroVector;
if (!bIsDeletingDragTool)
{
// Ending the drag tool may pop up a modal dialog which can cause unwanted reentrancy - protect against this.
TGuardValue<bool> RecursionGuard(bIsDeletingDragTool, true);
// Delete the drag tool if one exists.
if (DragTool.IsValid())
{
if (DragTool->IsDragging())
{
DragTool->EndDrag();
}
DragTool.Reset();
return false;
}
}
// Do not fade snapping indicators over time if this viewport is not real time
bool bClearImmediately = !InViewportClient->IsRealtime();
FSnappingUtils::ClearSnappingHelpers(bClearImmediately);
return true;
}
void FMouseDeltaTracker::ConditionalBeginUsingDragTool(FEditorViewportClient* InViewportClient)
{
const bool LeftMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::LeftMouseButton);
const bool RightMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::RightMouseButton);
const bool MiddleMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::MiddleMouseButton);
const bool bAltDown = InViewportClient->IsAltPressed();
const bool bShiftDown = InViewportClient->IsShiftPressed();
const bool bControlDown = InViewportClient->IsCtrlPressed();
// Has there been enough mouse movement to begin using a drag tool. We don't want to start using a tool for clicks(could have very small mouse movements)
bool bEnoughMouseMovement = GetRawDelta().SizeSquared() > MOUSE_CLICK_DRAG_DELTA;
if (bEnoughMouseMovement)
{
const bool bCanDrag = !DragTool.IsValid() && !RightMouseButtonDown && InViewportClient->CanUseDragTool();
if (bCanDrag && !bHasAttemptedDragTool)
{
// Create a drag tool.
if (!(bAltDown + bShiftDown) && bControlDown && MiddleMouseButtonDown && !LeftMouseButtonDown && !RightMouseButtonDown)
{
DragTool = InViewportClient->MakeDragTool(EDragTool::ViewportChange);
}
else
{
if (InViewportClient->IsOrtho())
{
if (LeftMouseButtonDown)
{
DragTool = InViewportClient->MakeDragTool(EDragTool::BoxSelect);
}
else if (!(bControlDown + bAltDown + bShiftDown) && MiddleMouseButtonDown)
{
DragTool = InViewportClient->MakeDragTool(EDragTool::Measure);
}
}
else
{
if (LeftMouseButtonDown && bControlDown && bAltDown)
{
DragTool = InViewportClient->MakeDragTool(EDragTool::FrustumSelect);
}
}
}
if (DragTool.IsValid())
{
DragTool->StartDrag(InViewportClient, GEditor->ClickLocation, FVector2D(StartScreen));
}
}
// Can not attempt to use a drag tool the rest of this tracking session
bHasAttemptedDragTool = true;
}
}
/**
* Adds delta movement into the tracker.
*/
void FMouseDeltaTracker::AddDelta(FEditorViewportClient* InViewportClient, FKey InKey, const int32 InDelta, bool InNudge)
{
const bool LeftMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::LeftMouseButton);
const bool RightMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::RightMouseButton);
const bool MiddleMouseButtonDown = InViewportClient->Viewport->KeyState(EKeys::MiddleMouseButton);
const bool bAltDown = InViewportClient->IsAltPressed();
const bool bShiftDown = InViewportClient->IsShiftPressed();
const bool bControlDown = InViewportClient->IsCtrlPressed();
if (!LeftMouseButtonDown && !MiddleMouseButtonDown && !RightMouseButtonDown && !InNudge)
{
return;
}
// Accumulate raw delta
RawDelta += FVector(InKey == EKeys::MouseX ? InDelta : 0,
InKey == EKeys::MouseY ? InDelta : 0,
0);
// Note that AddDelta has been called since StartTracking
bHasReceivedAddDelta = true;
// If we are using a drag tool, the widget isn't involved so set it to having no active axis. This
// means we will get unmodified mouse movement returned to us by other functions.
const EAxisList::Type SaveAxis = InViewportClient->GetCurrentWidgetAxis();
// If the user isn't dragging with the left mouse button, clear out the axis
// as the widget only responds to the left mouse button.
//
// We allow an exception for dragging with the left and/or right mouse button while holding control
// as that simulates moving objects with the gizmo
//
// We also allow the exception of the middle mouse button when Alt is pressed, or when the current axis is the pivot centre, as it
// allows movement of only the pivot
const bool bIsOrthoObjectRotation = bControlDown && InViewportClient->IsOrtho();
const bool bUsingDragTool = UsingDragTool();
const bool bUsingAxis = !bUsingDragTool && (LeftMouseButtonDown || (bAltDown && MiddleMouseButtonDown) || (SaveAxis == EAxisList::Screen && MiddleMouseButtonDown) || ((bIsOrthoObjectRotation || bControlDown) && RightMouseButtonDown));
ConditionalBeginUsingDragTool(InViewportClient);
if (bUsingDragTool || !InViewportClient->IsTracking() || !bUsingAxis)
{
InViewportClient->SetCurrentWidgetAxis(EAxisList::None);
}
FVector Wk = InViewportClient->TranslateDelta(InKey, InDelta, InNudge);
EndScreen += Wk;
if (InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
{
// Affect input delta by the camera speed
FWidget::EWidgetMode WidgetMode = InViewportClient->GetWidgetMode();
bool bIsRotation = (WidgetMode == FWidget::WM_Rotate) || ((WidgetMode == FWidget::WM_TranslateRotateZ) && (InViewportClient->GetCurrentWidgetAxis() == EAxisList::ZRotation)) || ((WidgetMode == FWidget::WM_2D) && (InViewportClient->GetCurrentWidgetAxis() == EAxisList::Rotate2D));
if (bIsRotation)
{
Wk *= GetDefault<ULevelEditorViewportSettings>()->MouseSensitivty;
}
else if (WidgetMode == FWidget::WM_Scale && !GEditor->UsePercentageBasedScaling())
{
const float ScaleSpeedMultipler = 0.01f;
Wk *= ScaleSpeedMultipler;
}
// Make rotations occur at the same speed, regardless of ortho zoom
if (InViewportClient->IsOrtho())
{
if (bIsRotation)
{
float Scale = 1.0f;
if (InViewportClient->IsOrtho())
{
Scale = DEFAULT_ORTHOZOOM / (float)InViewportClient->GetOrthoZoom();
}
Wk *= Scale;
}
}
// if Absolute Translation, and not just moving the camera around
else if (InViewportClient->IsUsingAbsoluteTranslation(false))
{
// Compute a view.
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
InViewportClient->Viewport,
InViewportClient->GetScene(),
InViewportClient->EngineShowFlags)
.SetRealtimeUpdate(InViewportClient->IsRealtime()));
FSceneView* View = InViewportClient->CalcSceneView(&ViewFamily);
// calculate mouse position
check(InViewportClient->Viewport);
FVector2D MousePosition(InViewportClient->Viewport->GetMouseX(), InViewportClient->Viewport->GetMouseY());
FVector WidgetPosition = InViewportClient->GetWidgetLocation();
FRotator TempRot;
FVector TempScale;
InViewportClient->Widget->AbsoluteTranslationConvertMouseMovementToAxisMovement(View, InViewportClient, WidgetPosition, MousePosition, Wk, TempRot, TempScale);
}
}
End += Wk;
EndSnapped = End;
if (UsingDragTool())
{
FVector Drag = Wk;
if (DragTool->bConvertDelta)
{
FRotator Rot;
InViewportClient->ConvertMovementToDragRot(Wk, Drag, Rot);
}
if (InViewportClient->IsPerspective())
{
DragTool->AddDelta(Wk);
}
else
{
DragTool->AddDelta(Drag);
}
InViewportClient->SetCurrentWidgetAxis(SaveAxis);
}
else
{
switch (InViewportClient->GetWidgetMode())
{
case FWidget::WM_Translate:
FSnappingUtils::SnapPointToGrid(EndSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
break;
case FWidget::WM_Scale:
FSnappingUtils::SnapScale(EndSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
break;
case FWidget::WM_Rotate: {
FRotator Rotation(EndSnapped.X, EndSnapped.Y, EndSnapped.Z);
FSnappingUtils::SnapRotatorToGrid(Rotation);
EndSnapped = FVector(Rotation.Pitch, Rotation.Yaw, Rotation.Roll);
}
break;
case FWidget::WM_TranslateRotateZ:
case FWidget::WM_2D: {
if (InViewportClient->GetCurrentWidgetAxis() == EAxisList::Rotate2D)
{
FRotator Rotation(EndSnapped.X, EndSnapped.Y, EndSnapped.Z);
FSnappingUtils::SnapRotatorToGrid(Rotation);
EndSnapped = FVector(Rotation.Pitch, Rotation.Yaw, Rotation.Roll);
}
else
{
// translation (either xy plane or z)
FSnappingUtils::SnapPointToGrid(EndSnapped, FVector(GEditor->GetGridSize(), GEditor->GetGridSize(), GEditor->GetGridSize()));
}
}
default:
break;
}
}
}
/**
* Returns the raw mouse delta, in pixels.
*/
const FVector FMouseDeltaTracker::GetRawDelta() const
{
return RawDelta;
}
/**
* Returns the current delta.
*/
const FVector FMouseDeltaTracker::GetDelta() const
{
const FVector Delta(End - Start);
return Delta;
}
/**
* Returns the current snapped delta.
*/
const FVector FMouseDeltaTracker::GetDeltaSnapped() const
{
const FVector SnappedDelta(EndSnapped - StartSnapped);
return SnappedDelta;
}
/**
* Returns the absolute delta since dragging started.
*/
const FVector FMouseDeltaTracker::GetAbsoluteDelta() const
{
const FVector Delta(End - Start + ReductionAmount);
return Delta;
}
/**
* Returns the absolute snapped delta since dragging started.
*/
const FVector FMouseDeltaTracker::GetAbsoluteDeltaSnapped() const
{
const FVector SnappedDelta(EndSnapped - StartSnapped + ReductionAmount);
return SnappedDelta;
}
/**
* Returns the screen space delta since dragging started.
*/
const FVector FMouseDeltaTracker::GetScreenDelta() const
{
const FVector Delta(EndScreen - StartScreen);
return Delta;
}
/**
* Converts the delta movement to drag/rotation/scale based on the viewport type or widget axis
*/
void FMouseDeltaTracker::ConvertMovementDeltaToDragRot(FSceneView* InView, FEditorViewportClient* InViewportClient, FVector& InOutDragDelta, FVector& OutDrag, FRotator& OutRotation, FVector& OutScale) const
{
OutDrag = FVector::ZeroVector;
OutRotation = FRotator::ZeroRotator;
OutScale = FVector::ZeroVector;
if (InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
{
InViewportClient->Widget->ConvertMouseMovementToAxisMovement(InView, InViewportClient, bUsedDragModifier, InOutDragDelta, OutDrag, OutRotation, OutScale);
}
else
{
InViewportClient->ConvertMovementToDragRot(InOutDragDelta, OutDrag, OutRotation);
}
}
/**
* Absolute Translation conversion from mouse position on the screen to widget axis movement/rotation.
*/
void FMouseDeltaTracker::AbsoluteTranslationConvertMouseToDragRot(FSceneView* InView, FEditorViewportClient* InViewportClient, FVector& OutDrag, FRotator& OutRotation, FVector& OutScale) const
{
OutDrag = FVector::ZeroVector;
OutRotation = FRotator::ZeroRotator;
OutScale = FVector::ZeroVector;
check(InViewportClient->GetCurrentWidgetAxis() != EAxisList::None);
// calculate mouse position
check(InViewportClient->Viewport);
FVector2D MousePosition(InViewportClient->Viewport->GetMouseX(), InViewportClient->Viewport->GetMouseY());
InViewportClient->Widget->AbsoluteTranslationConvertMouseMovementToAxisMovement(InView, InViewportClient, InViewportClient->GetWidgetLocation(), MousePosition, OutDrag, OutRotation, OutScale);
}
/**
* Subtracts the specified value from End and EndSnapped.
*/
void FMouseDeltaTracker::ReduceBy(const FVector& In)
{
End -= In;
EndSnapped -= In;
ReductionAmount += In;
}
/**
* @return true if a drag tool is being used by the tracker, false otherwise.
*/
bool FMouseDeltaTracker::UsingDragTool() const
{
return DragTool.IsValid() && DragTool->IsDragging();
}
/**
* Renders the drag tool. Does nothing if no drag tool exists.
*/
void FMouseDeltaTracker::Render3DDragTool(const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
if (DragTool.IsValid())
{
DragTool->Render3D(View, PDI);
}
}
/**
* Renders the drag tool. Does nothing if no drag tool exists.
*/
void FMouseDeltaTracker::RenderDragTool(const FSceneView* View, FCanvas* Canvas)
{
if (DragTool.IsValid())
{
DragTool->Render(View, Canvas);
}
}
const FVector FMouseDeltaTracker::GetDragStartPos() const
{
return Start;
}
const bool FMouseDeltaTracker::GetUsedDragModifier() const
{
return bUsedDragModifier;
}
void FMouseDeltaTracker::ResetUsedDragModifier()
{
bUsedDragModifier = false;
}
#undef LOCTEXT_NAMESPACE