using UnityEngine; using UnityEvent = UnityEngine.Event; namespace UnityEditor.U2D.Sprites { internal static class SpriteEditorHandles { private static Vector2 s_CurrentMousePosition; private static Vector2 s_DragStartScreenPosition; private static Vector2 s_DragScreenOffset; static internal Vector2 PointSlider(Vector2 pos, MouseCursor cursor, GUIStyle dragDot, GUIStyle dragDotActive) { int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard); Vector2 screenVal = Handles.matrix.MultiplyPoint(pos); Rect handleScreenPos = new Rect( screenVal.x - dragDot.fixedWidth * .5f, screenVal.y - dragDot.fixedHeight * .5f, dragDot.fixedWidth, dragDot.fixedHeight ); var evt = UnityEvent.current; switch (evt.GetTypeForControl(id)) { case EventType.Repaint: if (GUIUtility.hotControl == id) dragDotActive.Draw(handleScreenPos, GUIContent.none, id); else dragDot.Draw(handleScreenPos, GUIContent.none, id); break; } return ScaleSlider(pos, cursor, handleScreenPos); } static internal Vector2 ScaleSlider(Vector2 pos, MouseCursor cursor, Rect cursorRect) { int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard); return ScaleSlider(id, pos, cursor, cursorRect); } static private Vector2 ScaleSlider(int id, Vector2 pos, MouseCursor cursor, Rect cursorRect) { Vector2 screenVal = Handles.matrix.MultiplyPoint(pos); var evt = UnityEvent.current; switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: // am I closest to the thingy? if (evt.button == 0 && cursorRect.Contains(UnityEvent.current.mousePosition) && !evt.alt) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus s_CurrentMousePosition = evt.mousePosition; s_DragStartScreenPosition = evt.mousePosition; s_DragScreenOffset = s_CurrentMousePosition - screenVal; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(1); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == id) { s_CurrentMousePosition += evt.delta; Vector2 oldPos = pos; pos = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition); if (!Mathf.Approximately((oldPos - pos).magnitude, 0f)) GUI.changed = true; evt.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { GUIUtility.hotControl = 0; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(0); } break; case EventType.KeyDown: if (GUIUtility.hotControl == id) { if (evt.keyCode == KeyCode.Escape) { pos = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset); GUIUtility.hotControl = 0; GUI.changed = true; evt.Use(); } } break; case EventType.Repaint: if (GUIUtility.hotControl == 0 || GUIUtility.hotControl == id) EditorGUIUtility.AddCursorRect(cursorRect, cursor, id); break; } return pos; } static internal Vector2 PivotSlider(Rect sprite, Vector2 pos, GUIStyle pivotDot, GUIStyle pivotDotActive) { int id = GUIUtility.GetControlID("Slider1D".GetHashCode(), FocusType.Keyboard); // Convert from normalized space to texture space pos = new Vector2(sprite.xMin + sprite.width * pos.x, sprite.yMin + sprite.height * pos.y); Vector2 screenVal = Handles.matrix.MultiplyPoint(pos); Rect handleScreenPos = new Rect( screenVal.x - pivotDot.fixedWidth * .5f, screenVal.y - pivotDot.fixedHeight * .5f, pivotDotActive.fixedWidth, pivotDotActive.fixedHeight ); var evt = UnityEvent.current; switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: // am I closest to the thingy? if (evt.button == 0 && handleScreenPos.Contains(UnityEvent.current.mousePosition) && !evt.alt) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus s_CurrentMousePosition = evt.mousePosition; s_DragStartScreenPosition = evt.mousePosition; Vector2 rectScreenCenter = Handles.matrix.MultiplyPoint(pos); s_DragScreenOffset = s_CurrentMousePosition - rectScreenCenter; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(1); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == id) { s_CurrentMousePosition += evt.delta; Vector2 oldPos = pos; Vector3 scrPos = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition - s_DragScreenOffset); pos = new Vector2(scrPos.x, scrPos.y); if (!Mathf.Approximately((oldPos - pos).magnitude, 0f)) GUI.changed = true; evt.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { GUIUtility.hotControl = 0; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(0); } break; case EventType.KeyDown: if (GUIUtility.hotControl == id) { if (evt.keyCode == KeyCode.Escape) { pos = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset); GUIUtility.hotControl = 0; GUI.changed = true; evt.Use(); } } break; case EventType.Repaint: EditorGUIUtility.AddCursorRect(handleScreenPos, MouseCursor.Arrow, id); if (GUIUtility.hotControl == id) pivotDotActive.Draw(handleScreenPos, GUIContent.none, id); else pivotDot.Draw(handleScreenPos, GUIContent.none, id); break; } // Convert from texture space back to normalized space pos = new Vector2((pos.x - sprite.xMin) / sprite.width, (pos.y - sprite.yMin) / sprite.height); return pos; } static internal Rect SliderRect(Rect pos) { int id = GUIUtility.GetControlID("SliderRect".GetHashCode(), FocusType.Keyboard); var evt = UnityEvent.current; // SpriteEditorWindow is telling us we got selected and so we fake a mousedown on our Repaint event to get "one-click dragging" going on if (SpriteEditorWindow.s_OneClickDragStarted && evt.type == EventType.Repaint) { HandleSliderRectMouseDown(id, evt, pos); SpriteEditorWindow.s_OneClickDragStarted = false; } switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: // am I closest to the thingy? if (evt.button == 0 && pos.Contains(Handles.inverseMatrix.MultiplyPoint(UnityEvent.current.mousePosition)) && !evt.alt) { HandleSliderRectMouseDown(id, evt, pos); evt.Use(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == id) { s_CurrentMousePosition += evt.delta; Vector2 oldCenter = pos.center; pos.center = Handles.inverseMatrix.MultiplyPoint(s_CurrentMousePosition - s_DragScreenOffset); if (!Mathf.Approximately((oldCenter - pos.center).magnitude, 0f)) GUI.changed = true; evt.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2)) { GUIUtility.hotControl = 0; evt.Use(); EditorGUIUtility.SetWantsMouseJumping(0); } break; case EventType.KeyDown: if (GUIUtility.hotControl == id) { if (evt.keyCode == KeyCode.Escape) { pos.center = Handles.inverseMatrix.MultiplyPoint(s_DragStartScreenPosition - s_DragScreenOffset); GUIUtility.hotControl = 0; GUI.changed = true; evt.Use(); } } break; case EventType.Repaint: Vector2 topleft = Handles.inverseMatrix.MultiplyPoint(new Vector2(pos.xMin, pos.yMin)); Vector2 bottomright = Handles.inverseMatrix.MultiplyPoint(new Vector2(pos.xMax, pos.yMax)); EditorGUIUtility.AddCursorRect(new Rect(topleft.x, topleft.y, bottomright.x - topleft.x, bottomright.y - topleft.y), MouseCursor.Arrow, id); break; } return pos; } static internal void HandleSliderRectMouseDown(int id, UnityEvent evt, Rect pos) { GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus s_CurrentMousePosition = evt.mousePosition; s_DragStartScreenPosition = evt.mousePosition; Vector2 rectScreenCenter = Handles.matrix.MultiplyPoint(pos.center); s_DragScreenOffset = s_CurrentMousePosition - rectScreenCenter; EditorGUIUtility.SetWantsMouseJumping(1); } static int s_RectSelectionID = GUIUtility.GetPermanentControlID(); static internal Rect RectCreator(Rect textureArea, GUIStyle rectStyle) { var evt = UnityEvent.current; Vector2 mousePos = evt.mousePosition; int id = s_RectSelectionID; Rect result = new Rect(); switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: if (evt.button == 0) { GUIUtility.hotControl = id; // Make sure that the starting position is clamped to inside texture area s_DragStartScreenPosition = Handles.inverseMatrix.MultiplyPoint(mousePos); s_DragStartScreenPosition.x = Mathf.Min(Mathf.Max(s_DragStartScreenPosition.x, textureArea.xMin), textureArea.xMax); s_DragStartScreenPosition.y = Mathf.Min(Mathf.Max(s_DragStartScreenPosition.y, textureArea.yMin), textureArea.yMax); evt.Use(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == id) { evt.Use(); } break; case EventType.Repaint: { var startDragPoint = Handles.matrix.MultiplyPoint(s_DragStartScreenPosition); if (GUIUtility.hotControl == id && ValidRect(startDragPoint, mousePos)) { // TODO: use rectstyle //rectStyle.Draw (GetCurrentRect (true, textureWidth, textureHeight, s_DragStartScreenPosition, s_CurrentMousePosition), GUIContent.none, false, false, false, false); SpriteEditorUtility.BeginLines(Color.green * 1.5f); SpriteEditorUtility.DrawBox(GetCurrentRect(false, textureArea, startDragPoint, mousePos)); SpriteEditorUtility.EndLines(); } } break; case EventType.MouseUp: if (GUIUtility.hotControl == id && evt.button == 0) { var startDragPoint = Handles.matrix.MultiplyPoint(s_DragStartScreenPosition); if (ValidRect(startDragPoint, mousePos)) { result = GetCurrentRect(false, textureArea, startDragPoint, mousePos); GUI.changed = true; evt.Use(); } GUIUtility.hotControl = 0; } break; case EventType.KeyDown: if (GUIUtility.hotControl == id) { if (evt.keyCode == KeyCode.Escape) { GUIUtility.hotControl = 0; GUI.changed = true; evt.Use(); } } break; } return result; } static internal Rect RectCreator(float textureWidth, float textureHeight, GUIStyle rectStyle) { return RectCreator(new Rect(0, 0, textureWidth, textureHeight), rectStyle); } static private bool ValidRect(Vector2 startPoint, Vector2 endPoint) { return Mathf.Abs((endPoint - startPoint).x) > 5f && Mathf.Abs((endPoint - startPoint).y) > 5f; } static private Rect GetCurrentRect(bool screenSpace, Rect clampArea, Vector2 startPoint, Vector2 endPoint) { Rect r = EditorGUIExt.FromToRect(Handles.inverseMatrix.MultiplyPoint(startPoint), Handles.inverseMatrix.MultiplyPoint(endPoint)); r = SpriteEditorUtility.ClampedRect(SpriteEditorUtility.RoundToInt(r), clampArea, false); if (screenSpace) { Vector2 topleft = Handles.matrix.MultiplyPoint(new Vector2(r.xMin, r.yMin)); Vector2 bottomright = Handles.matrix.MultiplyPoint(new Vector2(r.xMax, r.yMax)); r = new Rect(topleft.x, topleft.y, bottomright.x - topleft.x, bottomright.y - topleft.y); } return r; } } }