/// <summary> /// Draw the on-screen selection, knobs, and handle all interaction logic. /// </summary> public void OnSceneGUI() { if (!EditorPrefs.GetBool("New GUI", true)) { return; } if (Tools.current != Tool.View) { return; } mWidget = target as NGUIWidget; Handles.color = mOutlineColor; Transform t = mWidget.cachedTransform; Event e = Event.current; int id = GUIUtility.GetControlID(s_Hash, FocusType.Passive); EventType type = e.GetTypeForControl(id); Vector3[] corners = NGUIMath.CalculateWidgetCorners(mWidget); Handles.DrawLine(corners[0], corners[1]); Handles.DrawLine(corners[1], corners[2]); Handles.DrawLine(corners[2], corners[3]); Handles.DrawLine(corners[0], corners[3]); Vector3[] worldPos = new Vector3[8]; worldPos[0] = corners[0]; worldPos[1] = corners[1]; worldPos[2] = corners[2]; worldPos[3] = corners[3]; worldPos[4] = (corners[0] + corners[1]) * 0.5f; worldPos[5] = (corners[1] + corners[2]) * 0.5f; worldPos[6] = (corners[2] + corners[3]) * 0.5f; worldPos[7] = (corners[0] + corners[3]) * 0.5f; Vector2[] screenPos = new Vector2[8]; for (int i = 0; i < 8; ++i) { screenPos[i] = HandleUtility.WorldToGUIPoint(worldPos[i]); } Bounds b = new Bounds(screenPos[0], Vector3.zero); for (int i = 1; i < 8; ++i) { b.Encapsulate(screenPos[i]); } // Time to figure out what kind of action is underneath the mouse Action actionUnderMouse = mAction; NGUIWidget.Pivot pivotUnderMouse = NGUIWidget.Pivot.Center; if (actionUnderMouse == Action.None) { int index = 0; float dist = GetScreenDistance(worldPos, e.mousePosition, out index); if (dist < 10f) { pivotUnderMouse = mPivots[index]; actionUnderMouse = Action.Scale; } else if (e.modifiers == 0 && NGUIEditorTools.DistanceToRectangle(corners, e.mousePosition) == 0f) { actionUnderMouse = Action.Move; } else if (dist < 30f) { actionUnderMouse = Action.Rotate; } } // Change the mouse cursor to a more appropriate one #if !UNITY_3_5 { Vector2 min = b.min; Vector2 max = b.max; min.x -= 30f; max.x += 30f; min.y -= 30f; max.y += 30f; Rect rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y); if (actionUnderMouse == Action.Rotate) { SetCursorRect(rect, MouseCursor.RotateArrow); } else if (actionUnderMouse == Action.Move) { SetCursorRect(rect, MouseCursor.MoveArrow); } else if (actionUnderMouse == Action.Scale) { SetCursorRect(rect, MouseCursor.ScaleArrow); } else { SetCursorRect(rect, MouseCursor.Arrow); } } #endif switch (type) { case EventType.Repaint: { Handles.BeginGUI(); { for (int i = 0; i < 8; ++i) { DrawKnob(worldPos[i], mWidget.pivot == mPivots[i], id); } } Handles.EndGUI(); } break; case EventType.MouseDown: { mStartMouse = e.mousePosition; mAllowSelection = true; if (e.button == 1) { if (e.modifiers == 0) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } else if (e.button == 0 && actionUnderMouse != Action.None && Raycast(corners, out mStartDrag)) { mStartPos = t.position; mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; mActionUnderMouse = actionUnderMouse; GUIUtility.hotControl = GUIUtility.keyboardControl = id; e.Use(); } } break; case EventType.MouseDrag: { // Prevent selection once the drag operation begins bool dragStarted = (e.mousePosition - mStartMouse).magnitude > 3f; if (dragStarted) { mAllowSelection = false; } if (GUIUtility.hotControl == id) { e.Use(); if (mAction != Action.None || mActionUnderMouse != Action.None) { Vector3 pos; if (Raycast(corners, out pos)) { if (mAction == Action.None && mActionUnderMouse != Action.None) { // Wait until the mouse moves by more than a few pixels if (dragStarted) { if (mActionUnderMouse == Action.Move) { mStartPos = t.position; NGUIEditorTools.RegisterUndo("Move widget", t); } else if (mActionUnderMouse == Action.Rotate) { mStartRot = t.localRotation.eulerAngles; mStartDir = mStartDrag - t.position; NGUIEditorTools.RegisterUndo("Rotate widget", t); } else if (mActionUnderMouse == Action.Scale) { mStartPos = t.localPosition; mStartScale = t.localScale; mDragPivot = pivotUnderMouse; NGUIEditorTools.RegisterUndo("Scale widget", t); } mAction = actionUnderMouse; } } if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos + (pos - mStartDrag); pos = t.localPosition; pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); t.localPosition = pos; } else if (mAction == Action.Rotate) { Vector3 dir = pos - t.position; float angle = Vector3.Angle(mStartDir, dir); if (angle > 0f) { float dot = Vector3.Dot(Vector3.Cross(mStartDir, dir), t.forward); if (dot < 0f) { angle = -angle; } angle = mStartRot.z + angle; if (e.modifiers != EventModifiers.Shift) { angle = Mathf.Round(angle / 15f) * 15f; } else { angle = Mathf.Round(angle); } t.localRotation = Quaternion.Euler(mStartRot.x, mStartRot.y, angle); } } else if (mAction == Action.Scale) { // World-space delta since the drag started Vector3 delta = pos - mStartDrag; // Adjust the widget's position and scale based on the delta, restricted by the pivot AdjustPosAndScale(mWidget, mStartPos, mStartScale, delta, mDragPivot); } } } } } } break; case EventType.MouseUp: { if (GUIUtility.hotControl == id) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; if (e.button < 2) { bool handled = false; if (e.button == 1) { // Right-click: Select the widget below NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); for (int i = widgets.Length; i > 0;) { NGUIWidget w = widgets[--i]; if (w == mWidget) { break; } last = w; } if (last != null) { Selection.activeGameObject = last.gameObject; handled = true; } } else if (mAction == Action.None) { if (mAllowSelection) { // Left-click: Select the widget above NGUIWidget last = null; NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) { for (int i = 0; i < widgets.Length; ++i) { NGUIWidget w = widgets[i]; if (w == mWidget) { if (last != null) { Selection.activeGameObject = last.gameObject; } handled = true; break; } last = w; } if (!handled) { Selection.activeGameObject = widgets[0].gameObject; handled = true; } } } } else { // Finished dragging something mAction = Action.None; mActionUnderMouse = Action.None; Vector3 pos = t.localPosition; Vector3 scale = t.localScale; if (mWidget.pixelPerfectAfterResize) { t.localPosition = pos; t.localScale = scale; mWidget.MakePixelPerfect(); } else { pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); scale.x = Mathf.Round(scale.x); scale.y = Mathf.Round(scale.y); t.localPosition = pos; t.localScale = scale; } handled = true; } if (handled) { mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } } } else if (mAllowSelection) { NGUIWidget[] widgets = Raycast(mWidget, e.mousePosition); if (widgets.Length > 0) { Selection.activeGameObject = widgets[0].gameObject; } } mAllowSelection = true; } break; case EventType.KeyDown: { if (e.keyCode == KeyCode.UpArrow) { Vector3 pos = t.localPosition; pos.y += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.DownArrow) { Vector3 pos = t.localPosition; pos.y -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.LeftArrow) { Vector3 pos = t.localPosition; pos.x -= 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.RightArrow) { Vector3 pos = t.localPosition; pos.x += 1f; t.localPosition = pos; e.Use(); } else if (e.keyCode == KeyCode.Escape) { if (GUIUtility.hotControl == id) { if (mAction != Action.None) { if (mAction == Action.Move) { t.position = mStartPos; } else if (mAction == Action.Rotate) { t.localRotation = Quaternion.Euler(mStartRot); } else if (mAction == Action.Scale) { t.position = mStartPos; t.localScale = mStartScale; } } GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; mActionUnderMouse = Action.None; mAction = Action.None; e.Use(); } else { Selection.activeGameObject = null; Tools.current = Tool.Move; } } } break; } }