A game about forced loneliness, made by TACStudios
1using System;
2using System.Linq;
3using System.Collections.Generic;
4using UnityEngine;
5using UnityEditor;
6
7namespace UnityEditor.U2D.Common.Path
8{
9 [CanEditMultipleObjects]
10 [CustomEditor(typeof(ScriptablePath), true)]
11 internal class ScriptablePathInspector : Editor
12 {
13 private static class Contents
14 {
15 public static readonly GUIContent linearIcon = IconContent("TangentLinear", "TangentLinearPro", "Linear");
16 public static readonly GUIContent continuousIcon = IconContent("TangentContinuous", "TangentContinuousPro", "Continuous");
17 public static readonly GUIContent brokenIcon = IconContent("TangentBroken", "TangentBrokenPro", "Broken");
18 public static readonly GUIContent positionLabel = new GUIContent("Position", "Position of the Control Point");
19 public static readonly GUIContent enableSnapLabel = new GUIContent("Snapping", "Snap points using the snap settings");
20 public static readonly GUIContent tangentModeLabel = new GUIContent("Tangent Mode");
21 public static readonly GUIContent pointLabel = new GUIContent("Point");
22
23
24 private static GUIContent IconContent(string name, string tooltip = null)
25 {
26 return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.common/Path/Editor/Handles/" + name + ".png"), tooltip);
27 }
28
29 private static GUIContent IconContent(string personal, string pro, string tooltip)
30 {
31 if (EditorGUIUtility.isProSkin)
32 return IconContent(pro, tooltip);
33
34 return IconContent(personal, tooltip);
35 }
36 }
37
38 private List<ScriptablePath> m_Paths = null;
39 private bool m_Dragged = false;
40
41 protected List<ScriptablePath> paths
42 {
43 get
44 {
45 if (m_Paths == null)
46 m_Paths = targets.Select( t => t as ScriptablePath).ToList();
47
48 return m_Paths;
49 }
50 }
51
52 public override void OnInspectorGUI()
53 {
54 var lwidth = EditorGUIUtility.labelWidth;
55 EditorGUIUtility.labelWidth = 96;
56 DoTangentModeInspector();
57 DoPositionInspector();
58 EditorGUIUtility.labelWidth = lwidth;
59 }
60
61 protected void DoTangentModeInspector()
62 {
63 if (!IsAnyShapeType(ShapeType.Spline))
64 return;
65
66 EditorGUILayout.BeginHorizontal();
67 EditorGUILayout.PrefixLabel(Contents.tangentModeLabel);
68
69 using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
70 {
71 if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Linear), Contents.linearIcon))
72 SetMixedTangentMode(TangentMode.Linear);
73
74 if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Continuous), Contents.continuousIcon))
75 SetMixedTangentMode(TangentMode.Continuous);
76
77 if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Broken), Contents.brokenIcon))
78 SetMixedTangentMode(TangentMode.Broken);
79 }
80
81 EditorGUILayout.EndHorizontal();
82 }
83
84 protected void DoPositionInspector()
85 {
86 var showMixedValue = EditorGUI.showMixedValue;
87 var wideMode = EditorGUIUtility.wideMode;
88
89 var position = Vector3.zero;
90 var isMixed = GetMixedPosition(out position);
91
92 EditorGUI.showMixedValue = isMixed;
93 EditorGUIUtility.wideMode = true;
94
95 using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
96 {
97 if (GUIUtility.hotControl == 0)
98 m_Dragged = false;
99
100 EditorGUI.BeginChangeCheck();
101 Rect rect = EditorGUILayout.GetControlRect(true, EditorGUI.GetPropertyHeight(SerializedPropertyType.Vector2, Contents.positionLabel), EditorStyles.numberField);
102 rect.width += 80;
103 var delta = EditorGUI.Vector2Field(rect, Contents.positionLabel, position) - (Vector2)position;
104
105 if (EditorGUI.EndChangeCheck())
106 {
107 if (m_Dragged == false)
108 {
109 foreach(var path in paths)
110 path.undoObject.RegisterUndo("Point Position");
111
112 m_Dragged = true;
113 }
114
115 SetMixedDeltaPosition(delta);
116 }
117 }
118
119 EditorGUI.showMixedValue = showMixedValue;
120 EditorGUIUtility.wideMode = wideMode;
121 }
122
123 private bool DoToggle(bool value, GUIContent icon)
124 {
125 const float kButtonWidth = 33f;
126 const float kButtonHeight = 23f;
127 var buttonStyle = new GUIStyle("EditModeSingleButton");
128
129 var changed = false;
130 using (var check = new EditorGUI.ChangeCheckScope())
131 {
132 value = GUILayout.Toggle(value, icon, buttonStyle, GUILayout.Width(kButtonWidth), GUILayout.Height(kButtonHeight));
133 changed = check.changed;
134 }
135
136 return value && changed;
137 }
138
139 private bool GetToggleStateFromTangentMode(TangentMode mode)
140 {
141 foreach(var path in paths)
142 {
143 var selection = path.selection;
144
145 foreach (var index in selection.elements)
146 if (path.GetPoint(index).tangentMode != mode)
147 return false;
148 }
149
150 return true;
151 }
152
153 private void SetMixedTangentMode(TangentMode tangentMode)
154 {
155 foreach(var path in paths)
156 {
157 path.undoObject.RegisterUndo("Tangent Mode");
158
159 foreach (var index in path.selection.elements)
160 path.SetTangentMode(index, tangentMode);
161 }
162
163 SceneView.RepaintAll();
164 }
165
166 private bool GetMixedPosition(out Vector3 position)
167 {
168 var first = true;
169 position = Vector3.zero;
170
171 var activeObject = Selection.activeObject as GameObject;
172 if (Selection.count > 1 || !activeObject)
173 return true;
174
175 foreach(var path in paths)
176 {
177 MonoBehaviour behavior = path.owner as MonoBehaviour;
178 if (!behavior || activeObject != behavior.gameObject)
179 continue;
180 var selection = path.selection;
181
182 foreach (var index in selection.elements)
183 {
184 var controlPoint = path.GetPointLocal(index);
185
186 if (first)
187 {
188 position = controlPoint.position;
189 first = false;
190 }
191 else if (position != controlPoint.position)
192 {
193 return true;
194 }
195 }
196 }
197
198 return false;
199 }
200
201 private void SetMixedDeltaPosition(Vector3 delta)
202 {
203 foreach(var path in paths)
204 {
205 var selection = path.selection;
206 var matrix = path.localToWorldMatrix;
207
208 path.localToWorldMatrix = Matrix4x4.identity;
209
210 foreach (var index in selection.elements)
211 {
212 var controlPoint = path.GetPoint(index);
213 controlPoint.position += delta;
214 path.SetPoint(index, controlPoint);
215 }
216
217 path.localToWorldMatrix = matrix;
218 }
219 }
220
221 private bool IsAnyShapeType(ShapeType shapeType)
222 {
223 foreach(var path in paths)
224 if (path.shapeType == shapeType)
225 return true;
226
227 return false;
228 }
229
230 protected bool IsAnyPointSelected()
231 {
232 foreach(var path in paths)
233 if (path.selection.Count > 0)
234 return true;
235
236 return false;
237 }
238 }
239}