using UnityEditor; using UnityEngine; using UnityEditor.Sprites; using System.Collections; using System.Collections.Generic; namespace UnityEditor.U2D { public enum AngleRangeAction { SelectRange, ModifyRange, CreateRange, ModifySelector, RemoveRange, } public interface IAngleRangeView { int hoveredRangeIndex { get; } void RequestFocusIndex(int index); float GetAngleFromPosition(Rect rect, float angleOffset); void Repaint(); void SetupLayout(Rect rect, float angleOffset, float radius); bool DoAngleRange(int index, Rect rect, float radius, float angleOffset, ref float start, ref float end, bool snap, bool disabled, Color gradientMin, Color gradientMid, Color gradientMax); bool DoSelectAngleRange(int currentSelected, out int newSelected); bool DoCreateRange(Rect rect, float radius, float angleOffset, float start, float end); void DoCreateRangeTooltip(); bool DoSelector(Rect rect, float angleOffset, float radius, float angle, out float newAngle); bool DoRemoveRange(); bool IsActionActive(AngleRangeAction action); bool IsActionTriggering(AngleRangeAction action); bool IsActionFinishing(AngleRangeAction action); void DrawAngleRangeOutline(Rect rect, float start, float end, float angleOffset, float radius); } public class AngleRangeView : IAngleRangeView { const string kDeleteCommandName = "Delete"; const string kSoftDeleteCommandName = "SoftDelete"; static readonly int kAngleRangeHashCode = "AngleRange".GetHashCode(); static readonly int kCreateRangeHashCode = "CreateRange".GetHashCode(); static readonly int kSelectorHashCode = "Selector".GetHashCode(); private static Color kHightlightColor = new Color(0.25f, 0.5f, 1.0f); private static Color kNoKeboardFocusColor = new Color(0.3f, 0.5f, 0.65f); private static class Contents { public static readonly GUIContent addRangeTooltip = new GUIContent("", "Click to add a new range"); } private int m_FocusedRangeControlID = -1; private int m_HoveredRangeIndex = -1; private int m_HoveredRangeID = -1; private int m_HoveredHandleID = -1; private int m_HotHandleID = -1; private int m_CreateRangeControlID = -1; private int m_SelectorControlID = -1; private int m_RequestFocusIndex = -1; public int hoveredRangeIndex { get { return m_HoveredRangeIndex; } } public void RequestFocusIndex(int index) { GUIUtility.keyboardControl = 0; m_RequestFocusIndex = index; } public float GetAngleFromPosition(Rect rect, float angleOffset) { return Mathf.RoundToInt(SpriteShapeHandleUtility.PosToAngle(Event.current.mousePosition, rect.center, -angleOffset)); } public void Repaint() { HandleUtility.Repaint(); } public void SetupLayout(Rect rect, float angleOffset, float radius) { m_CreateRangeControlID = GUIUtility.GetControlID(kCreateRangeHashCode, FocusType.Passive); m_SelectorControlID = GUIUtility.GetControlID(kSelectorHashCode, FocusType.Passive); LayoutCreateRange(rect, angleOffset, radius); if (Event.current.type == EventType.Layout) { m_HoveredRangeIndex = -1; m_HoveredRangeID = -1; m_HoveredHandleID = -1; if (GUIUtility.hotControl == 0) { m_HotHandleID = -1; } } } private void LayoutCreateRange(Rect rect, float angleOffset, float radius) { if (Event.current.type == EventType.Layout) { var mousePosition = Event.current.mousePosition; var distance = SpriteShapeHandleUtility.DistanceToArcWidth(mousePosition, rect.center, 0f, 360f, radius, AngleRangeGUI.kRangeWidth, angleOffset); HandleUtility.AddControl(m_CreateRangeControlID, distance); } } public bool DoAngleRange(int index, Rect rect, float radius, float angleOffset, ref float start, ref float end, bool snap, bool disabled, Color gradientMin, Color gradientMid, Color gradientMax) { var changed = false; var controlID = GUIUtility.GetControlID(kAngleRangeHashCode, FocusType.Passive); var leftHandleId = GUIUtility.GetControlID(AngleRangeGUI.kLeftHandleHashCode, FocusType.Passive); var rightHandleId = GUIUtility.GetControlID(AngleRangeGUI.kRightHandleHashCode, FocusType.Passive); if (Event.current.type == EventType.Layout) { var distance = SpriteShapeHandleUtility.DistanceToArcWidth(Event.current.mousePosition, rect.center, start, end, radius, AngleRangeGUI.kRangeWidth, angleOffset); HandleUtility.AddControl(controlID, distance); if (HandleUtility.nearestControl == controlID) { m_HoveredRangeIndex = index; m_HoveredRangeID = controlID; } } if (IsActionTriggering(AngleRangeAction.ModifyRange)) { m_HotHandleID = m_HoveredHandleID; GrabKeyboardFocus(controlID); } if (m_RequestFocusIndex == index) { GrabKeyboardFocus(controlID); if (Event.current.type == EventType.Repaint) m_RequestFocusIndex = -1; } using (new EditorGUI.DisabledScope(disabled)) { var midAngle = (end - start) * 0.5f + start; var t = 2f * (midAngle + 180f) / 360f; var color = gradientMin; if (t < 1f) color = Color.Lerp(gradientMin, gradientMid, t); else color = Color.Lerp(gradientMid, gradientMax, t - 1f); if (!disabled) { color = kNoKeboardFocusColor; if (HasKeyboardFocus()) color = kHightlightColor; } EditorGUI.BeginChangeCheck(); AngleRangeGUI.AngleRangeField(rect, leftHandleId, rightHandleId, ref start, ref end, angleOffset, radius, snap, false, false, color); changed = EditorGUI.EndChangeCheck(); } //Extra Layout from handles if (Event.current.type == EventType.Layout && (HandleUtility.nearestControl == leftHandleId || HandleUtility.nearestControl == rightHandleId)) { m_HoveredRangeIndex = index; m_HoveredRangeID = controlID; m_HoveredHandleID = HandleUtility.nearestControl; } return changed; } public bool DoSelectAngleRange(int currentSelected, out int newSelected) { newSelected = currentSelected; if (IsActionTriggering(AngleRangeAction.SelectRange)) { newSelected = m_HoveredRangeIndex; GUI.changed = true; Repaint(); HandleUtility.nearestControl = m_SelectorControlID; return true; } return false; } public bool DoCreateRange(Rect rect, float radius, float angleOffset, float start, float end) { if (IsActionTriggering(AngleRangeAction.CreateRange)) { GUI.changed = true; HandleUtility.nearestControl = m_SelectorControlID; return true; } if (IsActionActive(AngleRangeAction.CreateRange)) { DrawAngleRangeOutline(rect, start, end, angleOffset, radius); if (Event.current.type == EventType.MouseMove) Repaint(); } return false; } public void DoCreateRangeTooltip() { if (IsActionActive(AngleRangeAction.CreateRange)) { var mousePosition = Event.current.mousePosition; EditorGUI.LabelField(new Rect(mousePosition, new Vector2(1f, 20f)), Contents.addRangeTooltip); } } public bool DoSelector(Rect rect, float angleOffset, float radius, float angle, out float newAngle) { EditorGUI.BeginChangeCheck(); newAngle = AngleRangeGUI.AngleField(rect, m_SelectorControlID, angle, angleOffset, Vector2.down * 7.5f, angle, 15f, radius - AngleRangeGUI.kRangeWidth, true, true, false, SpriteShapeHandleUtility.PlayHeadCap); return EditorGUI.EndChangeCheck(); } public bool DoRemoveRange() { EventType eventType = Event.current.type; if (IsActionTriggering(AngleRangeAction.RemoveRange)) { Event.current.Use(); GUI.changed = true; return true; } return false; } public bool IsActionActive(AngleRangeAction action) { if (GUIUtility.hotControl != 0) return false; if (action == AngleRangeAction.SelectRange) return HandleUtility.nearestControl == m_HoveredRangeID; if (action == AngleRangeAction.ModifyRange) return HandleUtility.nearestControl == m_HoveredHandleID; if (action == AngleRangeAction.CreateRange) return HandleUtility.nearestControl == m_CreateRangeControlID; if (action == AngleRangeAction.ModifySelector) return HandleUtility.nearestControl == m_SelectorControlID; if (action == AngleRangeAction.RemoveRange) return HasKeyboardFocus(); return false; } public bool IsActionHot(AngleRangeAction action) { if (GUIUtility.hotControl == 0) return false; if (action == AngleRangeAction.ModifyRange) return GUIUtility.hotControl == m_HotHandleID; return false; } public bool IsActionTriggering(AngleRangeAction action) { if (!IsActionActive(action)) return false; EventType eventType = Event.current.type; if (action == AngleRangeAction.RemoveRange) { if ((eventType == EventType.ValidateCommand || eventType == EventType.ExecuteCommand) && (Event.current.commandName == kSoftDeleteCommandName || Event.current.commandName == kDeleteCommandName)) { if (eventType == EventType.ExecuteCommand) return true; Event.current.Use(); } return false; } return eventType == EventType.MouseDown && Event.current.button == 0; } public bool IsActionFinishing(AngleRangeAction action) { if (!IsActionHot(action)) return false; return (Event.current.type == EventType.MouseUp && Event.current.button == 0) || Event.current.type == EventType.Ignore; } public void DrawAngleRangeOutline(Rect rect, float start, float end, float angleOffset, float radius) { if (Event.current.type == EventType.Repaint) SpriteShapeHandleUtility.DrawRangeOutline(start, end, angleOffset, rect.center, radius, AngleRangeGUI.kRangeWidth - 1f); } private void GrabKeyboardFocus(int controlID) { m_FocusedRangeControlID = controlID; GUIUtility.keyboardControl = controlID; } private bool HasKeyboardFocus() { return GUIUtility.keyboardControl == m_FocusedRangeControlID; } } }