private static Vector3 DoDragHandleAxis(DragAxisInfo axisInfo, Vector3 position, ref DragHandleResult result) { // Must request a control ID for each interactible control in the GUI that can respond to events int id = GUIUtility.GetControlID(axisInfo._handleHash, FocusType.Passive); float handleSize = HandleUtility.GetHandleSize(position); Camera camera = Camera.current; Event currentEvent = Event.current; Vector2 mousePos = HEU_EditorUI.GetMousePosition(ref currentEvent, camera); Vector3 handlePosition = Handles.matrix.MultiplyPoint(position); Matrix4x4 cachedHandleMatrix = Handles.matrix; int mouseButtonID = Event.current.button; // Process events (using GetTypeForControl to filter events relevant to this control) switch (currentEvent.GetTypeForControl(id)) { case EventType.MouseDown: { if (HandleUtility.nearestControl == id && (mouseButtonID == 0 || mouseButtonID == 1)) { GUIUtility.hotControl = id; axisInfo._dragMouseCurrent = axisInfo._dragMouseStart = mousePos; axisInfo._dragWorldStart = position; axisInfo._handleHasMoved = false; currentEvent.Use(); EditorGUIUtility.SetWantsMouseJumping(1); if (mouseButtonID == 0) { result = DragHandleResult.LMB_PRESS; } else if (mouseButtonID == 1) { result = DragHandleResult.RMB_PRESS; } } break; } case EventType.MouseUp: { if (GUIUtility.hotControl == id && (mouseButtonID == 0 || mouseButtonID == 1)) { GUIUtility.hotControl = 0; currentEvent.Use(); EditorGUIUtility.SetWantsMouseJumping(0); if (mouseButtonID == 0) { result = DragHandleResult.LMB_RELEASE; } else if (mouseButtonID == 1) { result = DragHandleResult.RMB_RELEASE; } // Double-click if (mousePos == axisInfo._dragMouseStart) { bool doubleClick = (axisInfo._handleClickID == id) && (Time.realtimeSinceStartup - axisInfo._handleClickTime < _handleDoubleClikcInterval); axisInfo._handleClickID = id; axisInfo._handleClickTime = Time.realtimeSinceStartup; if (mouseButtonID == 0) { result = doubleClick ? DragHandleResult.LMB_DOUBLECLICK : DragHandleResult.LMB_CLICK; } else if (mouseButtonID == 1) { result = doubleClick ? DragHandleResult.RMB_DOUBLECLICK : DragHandleResult.RMB_CLICK; } } } break; } case EventType.MouseDrag: { if (GUIUtility.hotControl == id) { if (axisInfo._dragAxis == DragAxis.ALL_AXIS) { // Free movement - (all axis) // Flip y because Unity is inverted axisInfo._dragMouseCurrent += new Vector2(currentEvent.delta.x, -currentEvent.delta.y); Vector3 position2 = camera.WorldToScreenPoint(Handles.matrix.MultiplyPoint(axisInfo._dragWorldStart)) + (Vector3)(axisInfo._dragMouseCurrent - axisInfo._dragMouseStart); position = Handles.matrix.inverse.MultiplyPoint(camera.ScreenToWorldPoint(position2)); } else { // Linear movement (constraint to current axis) // Get the delta between the original handle position and the original mouse down position // This is used to substract from relative mouse movement to counter the handle jump when dragging Vector3 originalDragStartSS = HEU_EditorUI.GetHandleWorldToScreenPosition(axisInfo._dragWorldStart, camera); Vector3 deltaOriginalDragOffset = axisInfo._dragMouseStart - new Vector2(originalDragStartSS.x, originalDragStartSS.y); Vector3 startPosSS = HEU_EditorUI.GetHandleWorldToScreenPosition(position, camera); Vector3 constraintSS = HEU_EditorUI.GetHandleWorldToScreenPosition(position + axisInfo._direction, camera) - startPosSS; Vector3 mousePosV3 = mousePos; Vector3 relativeMousePos = mousePosV3 - startPosSS - deltaOriginalDragOffset; float projection = Vector3.Dot(relativeMousePos, constraintSS.normalized); float normalization = 1 / constraintSS.magnitude; float scale = projection * normalization; position += axisInfo._direction * scale; } if (mouseButtonID == 0) { result = DragHandleResult.LMB_DRAG; } else if (mouseButtonID == 1) { result = DragHandleResult.RMB_DRAG; } axisInfo._handleHasMoved = true; GUI.changed = true; currentEvent.Use(); } break; } case EventType.MouseMove: case EventType.Repaint: { Color handleColor = Handles.color; if ((GUIUtility.hotControl == id && axisInfo._handleHasMoved) || (HandleUtility.nearestControl == id)) { Handles.color = Color.yellow; } else { Handles.color = axisInfo._axisColor; } Handles.matrix = Matrix4x4.identity; if (axisInfo._dragAxis == DragAxis.ALL_AXIS) { HEU_EditorUI.DrawCubeCap(id, handlePosition, Quaternion.identity, handleSize * 0.25f); } else { HEU_EditorUI.DrawArrowCap(id, handlePosition, Quaternion.LookRotation(axisInfo._direction), handleSize); } Handles.matrix = cachedHandleMatrix; Handles.color = handleColor; // This forces a Repaint. We want this when we change the axis color due to being cursor being nearest. if (currentEvent.type == EventType.MouseMove && HandleUtility.nearestControl == id) { SceneView.RepaintAll(); } break; } case EventType.Layout: { // AddControl tells Unity where each Handle is relative to the current mouse position Handles.matrix = Matrix4x4.identity; if (axisInfo._dragAxis == DragAxis.ALL_AXIS) { float distance = handleSize * 0.3f; HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(handlePosition, distance)); } else { HandleUtility.AddControl(id, HandleUtility.DistanceToLine(handlePosition, handlePosition + axisInfo._direction * handleSize) * 0.4f); } Handles.matrix = cachedHandleMatrix; break; } } return(position); }