static void DrawAngles(FCanvas* Canvas, int32 XPos, int32 YPos, EAxisList::Type ManipAxis, FWidget::EWidgetMode MoveMode, const FRotator& Rotation, const FVector& Translation)
{
	FString OutputString(TEXT(""));
	if (MoveMode == FWidget::WM_Rotate && Rotation.IsZero() == false)
	{
		//Only one value moves at a time
		const FVector EulerAngles = Rotation.Euler();
		if (ManipAxis == EAxisList::X)
		{
			OutputString += FString::Printf(TEXT("Roll: %0.2f"), EulerAngles.X);
		}
		else if (ManipAxis == EAxisList::Y)
		{
			OutputString += FString::Printf(TEXT("Pitch: %0.2f"), EulerAngles.Y);
		}
		else if (ManipAxis == EAxisList::Z)
		{
			OutputString += FString::Printf(TEXT("Yaw: %0.2f"), EulerAngles.Z);
		}
	}
	else if (MoveMode == FWidget::WM_Translate && Translation.IsZero() == false)
	{
		//Only one value moves at a time
		if (ManipAxis == EAxisList::X)
		{
			OutputString += FString::Printf(TEXT(" %0.2f"), Translation.X);
		}
		else if (ManipAxis == EAxisList::Y)
		{
			OutputString += FString::Printf(TEXT(" %0.2f"), Translation.Y);
		}
		else if (ManipAxis == EAxisList::Z)
		{
			OutputString += FString::Printf(TEXT(" %0.2f"), Translation.Z);
		}
	}

	if (OutputString.Len() > 0)
	{
		FCanvasTextItem TextItem( FVector2D(XPos, YPos), FText::FromString( OutputString ), GEngine->GetSmallFont(), FLinearColor::White );
		Canvas->DrawItem( TextItem );
	}
}
bool FSplineComponentVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, FRotator& DeltaRotate, FVector& DeltaScale)
{
	USplineComponent* SplineComp = GetEditedSplineComponent();
	if (SplineComp != nullptr)
	{
		FInterpCurveVector& SplineInfo = SplineComp->SplineInfo;
		FInterpCurveQuat& SplineRotInfo = SplineComp->SplineRotInfo;
		FInterpCurveVector& SplineScaleInfo = SplineComp->SplineScaleInfo;

		const int32 NumPoints = SplineInfo.Points.Num();

		if (SelectedTangentHandle != INDEX_NONE)
		{
			// When tangent handles are manipulated...

			check(SelectedTangentHandle < NumPoints);

			if (!DeltaTranslate.IsZero())
			{
				check(SelectedTangentHandleType != ESelectedTangentHandle::None);

				SplineComp->Modify();

				FInterpCurvePoint<FVector>& EditedPoint = SplineInfo.Points[SelectedTangentHandle];
				const FVector Delta = (SelectedTangentHandleType == ESelectedTangentHandle::Leave) ? DeltaTranslate : -DeltaTranslate;
				const FVector Tangent = EditedPoint.LeaveTangent + SplineComp->ComponentToWorld.InverseTransformVector(Delta);

				EditedPoint.LeaveTangent = Tangent;
				EditedPoint.ArriveTangent = Tangent;
				EditedPoint.InterpMode = CIM_CurveUser;
			}
		}
		else
		{
			// When spline keys are manipulated...

			check(LastKeyIndexSelected != INDEX_NONE);
			check(LastKeyIndexSelected < NumPoints);
			check(SelectedKeys.Num() > 0);

			SplineComp->Modify();

			if (ViewportClient->IsAltPressed() && bAllowDuplication)
			{
				OnDuplicateKey();
				// Don't duplicate again until we release LMB
				bAllowDuplication = false;
			}

			for (int32 SelectedKeyIndex : SelectedKeys)
			{
				FInterpCurvePoint<FVector>& EditedPoint = SplineInfo.Points[SelectedKeyIndex];
				FInterpCurvePoint<FQuat>& EditedRotPoint = SplineRotInfo.Points[SelectedKeyIndex];
				FInterpCurvePoint<FVector>& EditedScalePoint = SplineScaleInfo.Points[SelectedKeyIndex];

				if (!DeltaTranslate.IsZero())
				{
					// Find key position in world space
					const FVector CurrentWorldPos = SplineComp->ComponentToWorld.TransformPosition(EditedPoint.OutVal);
					// Move in world space
					const FVector NewWorldPos = CurrentWorldPos + DeltaTranslate;
					// Convert back to local space
					EditedPoint.OutVal = SplineComp->ComponentToWorld.InverseTransformPosition(NewWorldPos);
				}

				if (!DeltaRotate.IsZero())
				{
					// Set point tangent as user controlled
					EditedPoint.InterpMode = CIM_CurveUser;

					// Rotate tangent according to delta rotation
					FVector NewTangent = SplineComp->ComponentToWorld.GetRotation().RotateVector(EditedPoint.LeaveTangent); // convert local-space tangent vector to world-space
					NewTangent = DeltaRotate.RotateVector(NewTangent); // apply world-space delta rotation to world-space tangent
					NewTangent = SplineComp->ComponentToWorld.GetRotation().Inverse().RotateVector(NewTangent); // convert world-space tangent vector back into local-space
					EditedPoint.LeaveTangent = NewTangent;
					EditedPoint.ArriveTangent = NewTangent;

					// Rotate spline rotation according to delta rotation
					FQuat NewRot = SplineComp->ComponentToWorld.GetRotation() * EditedRotPoint.OutVal; // convert local-space rotation to world-space
					NewRot = DeltaRotate.Quaternion() * NewRot; // apply world-space rotation
					NewRot = SplineComp->ComponentToWorld.GetRotation().Inverse() * NewRot; // convert world-space rotation to local-space
					EditedRotPoint.OutVal = NewRot;
				}

				if (DeltaScale.X != 0.0f)
				{
					// Set point tangent as user controlled
					EditedPoint.InterpMode = CIM_CurveUser;

					const FVector NewTangent = EditedPoint.LeaveTangent * (1.0f + DeltaScale.X);
					EditedPoint.LeaveTangent = NewTangent;
					EditedPoint.ArriveTangent = NewTangent;
				}

				if (DeltaScale.Y != 0.0f)
				{
					// Scale in Y adjusts the scale spline
					EditedScalePoint.OutVal.Y *= (1.0f + DeltaScale.Y);
				}

				if (DeltaScale.Z != 0.0f)
				{
					// Scale in Z adjusts the scale spline
					EditedScalePoint.OutVal.Z *= (1.0f + DeltaScale.Z);
				}
			}
		}

		NotifyComponentModified();
		return true;
	}

	return false;
}
bool FInstancedStaticMeshSCSEditorCustomization::HandleViewportDrag(class USceneComponent* InSceneComponent, class USceneComponent* InComponentTemplate, const FVector& InDeltaTranslation, const FRotator& InDeltaRotation, const FVector& InDeltaScale, const FVector& InPivot)
{
	check(InSceneComponent->IsA(UInstancedStaticMeshComponent::StaticClass()));

	UInstancedStaticMeshComponent* InstancedStaticMeshComponentScene = CastChecked<UInstancedStaticMeshComponent>(InSceneComponent);
	UInstancedStaticMeshComponent* InstancedStaticMeshComponentTemplate = CastChecked<UInstancedStaticMeshComponent>(InComponentTemplate);

	// transform pivot into component's space
	const FVector LocalPivot = InstancedStaticMeshComponentScene->GetComponentToWorld().InverseTransformPosition(InPivot);

	// Ensure that selected instances are up-to-date
	ValidateSelectedInstances(InstancedStaticMeshComponentScene);

	bool bMovedInstance = false;
	check(InstancedStaticMeshComponentScene->SelectedInstances.Num() == InstancedStaticMeshComponentScene->PerInstanceSMData.Num());
	for(int32 InstanceIndex = 0; InstanceIndex < InstancedStaticMeshComponentScene->SelectedInstances.Num(); InstanceIndex++)
	{
		if (InstancedStaticMeshComponentScene->SelectedInstances[InstanceIndex] && InstancedStaticMeshComponentTemplate->PerInstanceSMData.IsValidIndex(InstanceIndex))
		{
			FMatrix& MatrixScene = InstancedStaticMeshComponentScene->PerInstanceSMData[InstanceIndex].Transform;
			FMatrix& MatrixTemplate = InstancedStaticMeshComponentTemplate->PerInstanceSMData[InstanceIndex].Transform;

			FVector Translation = MatrixScene.GetOrigin();
			FRotator Rotation = MatrixScene.Rotator();
			FVector Scale = MatrixScene.GetScaleVector();

			FVector NewTranslation = Translation;
			FRotator NewRotation = Rotation;
			FVector NewScale = Scale;

			if( !InDeltaRotation.IsZero() )
			{
				NewRotation = FRotator( InDeltaRotation.Quaternion() * Rotation.Quaternion() );

				NewTranslation -= LocalPivot;
				NewTranslation = FRotationMatrix( InDeltaRotation ).TransformPosition( NewTranslation );
				NewTranslation += LocalPivot;
			}

			NewTranslation += InDeltaTranslation;

			if( !InDeltaScale.IsNearlyZero() )
			{
				const FScaleMatrix ScaleMatrix( InDeltaScale );

				FVector DeltaScale3D = ScaleMatrix.TransformPosition( Scale );
				NewScale = Scale + DeltaScale3D;

				NewTranslation -= LocalPivot;
				NewTranslation += ScaleMatrix.TransformPosition( NewTranslation );
				NewTranslation += LocalPivot;
			}

			MatrixScene = FScaleRotationTranslationMatrix(NewScale, NewRotation, NewTranslation);
			MatrixTemplate = FScaleRotationTranslationMatrix(NewScale, NewRotation, NewTranslation);

			bMovedInstance = true;
		}
	}

	return bMovedInstance;
}
/**
 * @return		true if the delta was handled by this editor mode tool.
 */
bool FModeTool_Texture::InputDelta(FEditorViewportClient* InViewportClient,FViewport* InViewport,FVector& InDrag,FRotator& InRot,FVector& InScale)
{
	if( InViewportClient->GetCurrentWidgetAxis() == EAxisList::None )
	{
		return false;
	}

	// calculate delta drag for this tick for the call to GEditor->polyTexPan below which is using relative (delta) mode
	FVector deltaDrag = InDrag;
	if (true == InViewportClient->IsPerspective())
	{
		// perspective viewports pass the absolute drag so subtract the last tick's drag value to get the delta
		deltaDrag -= PreviousInputDrag;
	}
	PreviousInputDrag = InDrag;

	if( !deltaDrag.IsZero() )
	{
		// Ensure each polygon has a unique base point index.
		for( FConstLevelIterator Iterator = InViewportClient->GetWorld()->GetLevelIterator(); Iterator; ++Iterator )
		{
			UModel* Model = (*Iterator)->Model;
			for(int32 SurfaceIndex = 0;SurfaceIndex < Model->Surfs.Num();SurfaceIndex++)
			{
				FBspSurf& Surf = Model->Surfs[SurfaceIndex];

				if(Surf.PolyFlags & PF_Selected)
				{
					const FVector Base = Model->Points[Surf.pBase];
					Surf.pBase = Model->Points.Add(Base);
				}
			}
			FMatrix Mat = GLevelEditorModeTools().GetCustomDrawingCoordinateSystem();
			FVector UVW = Mat.InverseTransformVector( deltaDrag );  // InverseTransformNormal because Mat is the transform from the surface/widget's coords to world coords
			GEditor->polyTexPan( Model, UVW.X, UVW.Y, 0 );  // 0 is relative mode because UVW is made from deltaDrag - the user input since the last tick
		}
	}

	if( !InRot.IsZero() )
	{
		const FRotationMatrix RotationMatrix( InRot );

		// Ensure each polygon has unique texture vector indices.
		for ( TSelectedSurfaceIterator<> It(InViewportClient->GetWorld()) ; It ; ++It )
		{
			FBspSurf* Surf = *It;
			UModel* Model = It.GetModel();

			FVector	TextureU = Model->Vectors[Surf->vTextureU];
			FVector TextureV = Model->Vectors[Surf->vTextureV];

			TextureU = RotationMatrix.TransformPosition( TextureU );
			TextureV = RotationMatrix.TransformPosition( TextureV );

			Surf->vTextureU = Model->Vectors.Add(TextureU);
			Surf->vTextureV = Model->Vectors.Add(TextureV);

			const bool bUpdateTexCoords = true;
			const bool bOnlyRefreshSurfaceMaterials = true;
			GEditor->polyUpdateMaster(Model, It.GetSurfaceIndex(), bUpdateTexCoords, bOnlyRefreshSurfaceMaterials);
		}
	}

	if( !InScale.IsZero() )
	{
		float ScaleU = InScale.X / GEditor->GetGridSize();
		float ScaleV = InScale.Y / GEditor->GetGridSize();

		ScaleU = 1.f - (ScaleU / 100.f);
		ScaleV = 1.f - (ScaleV / 100.f);

		// Ensure each polygon has unique texture vector indices.
		for( FConstLevelIterator Iterator = InViewportClient->GetWorld()->GetLevelIterator(); Iterator; ++Iterator )
		{
			UModel* Model = (*Iterator)->Model;
			for(int32 SurfaceIndex = 0;SurfaceIndex < Model->Surfs.Num();SurfaceIndex++)
			{
				FBspSurf& Surf = Model->Surfs[SurfaceIndex];
				if(Surf.PolyFlags & PF_Selected)
				{
					const FVector TextureU = Model->Vectors[Surf.vTextureU];
					const FVector TextureV = Model->Vectors[Surf.vTextureV];

					Surf.vTextureU = Model->Vectors.Add(TextureU);
					Surf.vTextureV = Model->Vectors.Add(TextureV);
				}
			}
			GEditor->polyTexScale( Model, ScaleU, 0.f, 0.f, ScaleV, false );
		}

	}

	return true;
}