A game about forced loneliness, made by TACStudios
1using System;
2using UnityEditor.U2D.Layout;
3using UnityEditor.U2D.Common;
4using UnityEngine;
5using UnityEngine.UIElements;
6
7namespace UnityEditor.U2D.Animation
8{
9#if ENABLE_UXML_SERIALIZED_DATA
10 [UxmlElement]
11#endif
12 internal partial class PivotInspectorPanel : VisualElement
13 {
14 EnumField m_PivotAlignment;
15 Vector2Field m_PivotPosition;
16
17#if ENABLE_UXML_TRAITS
18 public class CustomUxmlFactory : UxmlFactory<PivotInspectorPanel, UxmlTraits> { }
19#endif
20
21 internal static PivotInspectorPanel CreateFromUxml()
22 {
23 var visualTree = ResourceLoader.Load<VisualTreeAsset>("SkinningModule/PivotInspectorPanel.uxml");
24 var ve = (PivotInspectorPanel)visualTree.CloneTree().Q("PivotInspectorPanel");
25 ve.styleSheets.Add(ResourceLoader.Load<StyleSheet>("SkinningModule/PivotInspectorPanelStyle.uss"));
26 if (EditorGUIUtility.isProSkin)
27 ve.AddToClassList("Dark");
28 ve.LocalizeTextInChildren();
29 ve.BindElements();
30 return ve;
31 }
32
33 private void BindElements()
34 {
35 m_PivotPosition = this.Q<Vector2Field>("PivotPositionField");
36 m_PivotAlignment = this.Q<EnumField>("pivotField");
37 m_PivotAlignment.Init(SpriteAlignment.Center);
38 m_PivotAlignment.label = TextContent.pivot;
39 }
40
41 public EnumField pivotAlignment
42 {
43 get => m_PivotAlignment;
44 set => m_PivotAlignment = value;
45 }
46
47 public Vector2Field pivotPosition
48 {
49 get => m_PivotPosition;
50 set => m_PivotPosition = value;
51 }
52 }
53
54 internal class PivotTool : SkeletonToolWrapper
55 {
56 static class Styles
57 {
58 public static GUIStyle pivotdotactive = "U2D.pivotDotActive";
59 public static GUIStyle pivotdot = "U2D.pivotDot";
60 }
61
62 Vector2 m_Pivot = Vector2.zero;
63 Vector2 m_CurrentMousePosition;
64 Vector2 m_DragScreenOffset;
65 Vector2 m_DragStartScreenPosition;
66 SpriteCache m_LastSelectedSprite;
67 PivotInspectorPanel m_InspectorPanel;
68 int m_SlideHashCode = "PivotTool_Slider1D".GetHashCode();
69 readonly Rect k_PivotNormalizedRect = Rect.MinMaxRect(0, 0, 1, 1);
70 Rect m_PivotRect = Rect.zero;
71
72 static bool CanSelectWhileInPivotTool() => false;
73
74 public override void Initialize(LayoutOverlay layout)
75 {
76 base.Initialize(layout);
77 m_InspectorPanel = PivotInspectorPanel.CreateFromUxml();
78 layout.rightOverlay.Add(m_InspectorPanel);
79 m_InspectorPanel.SetHiddenFromLayout(true);
80 m_InspectorPanel.pivotAlignment.RegisterValueChangedCallback(PivotAlignmentValueChange);
81 m_InspectorPanel.pivotPosition.RegisterValueChangedCallback(PivotPositionValueChange);
82 }
83
84 void PivotAlignmentValueChange(ChangeEvent<Enum> evt)
85 {
86 m_Pivot = GetPivotPoint((SpriteAlignment)m_InspectorPanel.pivotAlignment.value, m_Pivot);
87 m_InspectorPanel.pivotPosition.SetValueWithoutNotify(m_Pivot);
88 UpdateCharacterPivot();
89 }
90
91 void PivotPositionValueChange(ChangeEvent<Vector2> evt)
92 {
93 m_Pivot = m_InspectorPanel.pivotPosition.value;
94 m_InspectorPanel.pivotAlignment.SetValueWithoutNotify(SpriteAlignment.Custom);
95 UpdateCharacterPivot();
96 }
97
98
99 protected override void OnGUI()
100 {
101 base.OnGUI();
102 var pivot = PivotSlider(m_PivotRect, m_Pivot, Styles.pivotdot, Styles.pivotdotactive);
103 if (m_Pivot != pivot)
104 {
105 UpdateViewFields();
106 m_Pivot = pivot;
107 UpdateCharacterPivot();
108 }
109 }
110
111 void UpdateCharacterPivot()
112 {
113 using (skinningCache.UndoScope(TextContent.pivotChanged))
114 {
115 skinningCache.character.pivot = m_Pivot;
116 skinningCache.events.pivotChange.Invoke();
117 }
118 }
119
120 protected override void OnActivate()
121 {
122 if (skinningCache.hasCharacter)
123 {
124 base.OnActivate();
125 m_PivotRect = new Rect(0, 0, skinningCache.character.dimension.x, skinningCache.character.dimension.y);
126 m_LastSelectedSprite = skinningCache.selectedSprite;
127 m_InspectorPanel.SetHiddenFromLayout(false);
128 m_Pivot = skinningCache.character.pivot;
129 UpdateViewFields();
130
131 skinningCache.selectionTool.CanSelect += CanSelectWhileInPivotTool;
132 skinningCache.selectedSprite = null;
133 }
134 else
135 {
136 m_InspectorPanel.SetHiddenFromLayout(true);
137 }
138 }
139
140 void UpdateViewFields()
141 {
142 SpriteAlignment alignment;
143 TranslatePivotPoint(m_Pivot, out alignment);
144 m_InspectorPanel.pivotAlignment.SetValueWithoutNotify(alignment);
145 m_InspectorPanel.pivotPosition.SetValueWithoutNotify(m_Pivot);
146 }
147
148 protected override void OnDeactivate()
149 {
150 if (skinningCache.hasCharacter)
151 {
152 base.OnDeactivate();
153 m_InspectorPanel.SetHiddenFromLayout(true);
154
155 skinningCache.selectionTool.CanSelect -= CanSelectWhileInPivotTool;
156 if (isActive)
157 skinningCache.selectedSprite = m_LastSelectedSprite;
158 }
159 }
160
161 void TranslatePivotPoint(Vector2 pivot, out SpriteAlignment alignment)
162 {
163 if (new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.yMax) == pivot)
164 alignment = SpriteAlignment.TopLeft;
165 else if (new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.yMax) == pivot)
166 alignment = SpriteAlignment.TopCenter;
167 else if (new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.yMax) == pivot)
168 alignment = SpriteAlignment.TopRight;
169 else if (new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.center.y) == pivot)
170 alignment = SpriteAlignment.LeftCenter;
171 else if (new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.center.y) == pivot)
172 alignment = SpriteAlignment.Center;
173 else if (new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.center.y) == pivot)
174 alignment = SpriteAlignment.RightCenter;
175 else if (new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.yMin) == pivot)
176 alignment = SpriteAlignment.BottomLeft;
177 else if (new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.yMin) == pivot)
178 alignment = SpriteAlignment.BottomCenter;
179 else if (new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.yMin) == pivot)
180 alignment = SpriteAlignment.BottomRight;
181 else
182 alignment = SpriteAlignment.Custom;
183 }
184
185 Vector2 GetPivotPoint(SpriteAlignment alignment, Vector2 customPivot)
186 {
187 switch (alignment)
188 {
189 case SpriteAlignment.TopLeft:
190 return new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.yMax);
191
192 case SpriteAlignment.TopCenter:
193 return new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.yMax);
194
195 case SpriteAlignment.TopRight:
196 return new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.yMax);
197
198 case SpriteAlignment.LeftCenter:
199 return new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.center.y);
200
201 case SpriteAlignment.Center:
202 return new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.center.y);
203
204 case SpriteAlignment.RightCenter:
205 return new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.center.y);
206
207 case SpriteAlignment.BottomLeft:
208 return new Vector2(k_PivotNormalizedRect.xMin, k_PivotNormalizedRect.yMin);
209
210 case SpriteAlignment.BottomCenter:
211 return new Vector2(k_PivotNormalizedRect.center.x, k_PivotNormalizedRect.yMin);
212
213 case SpriteAlignment.BottomRight:
214 return new Vector2(k_PivotNormalizedRect.xMax, k_PivotNormalizedRect.yMin);
215
216 case SpriteAlignment.Custom:
217 return new Vector2(customPivot.x * k_PivotNormalizedRect.width, customPivot.y * k_PivotNormalizedRect.height);
218 }
219
220 return Vector2.zero;
221 }
222
223 Vector2 PivotSlider(Rect sprite, Vector2 pos, GUIStyle pivotDot, GUIStyle pivotDotActive)
224 {
225 int id = GUIUtility.GetControlID(m_SlideHashCode, FocusType.Keyboard);
226
227 // Convert from normalized space to texture space
228 pos = new Vector2(sprite.xMin + sprite.width * pos.x, sprite.yMin + sprite.height * pos.y);
229
230 Vector2 screenVal = Handles.matrix.MultiplyPoint(pos);
231
232 Rect handleScreenPos = new Rect(
233 screenVal.x - pivotDot.fixedWidth * .5f,
234 screenVal.y - pivotDot.fixedHeight * .5f,
235 pivotDotActive.fixedWidth,
236 pivotDotActive.fixedHeight
237 );
238
239 var evt = Event.current;
240 switch (evt.GetTypeForControl(id))
241 {
242 case EventType.MouseDown:
243 // am I closest to the thingy?
244 if (evt.button == 0 && handleScreenPos.Contains(Event.current.mousePosition) && !evt.alt)
245 {
246 GUIUtility.hotControl = GUIUtility.keyboardControl = id; // Grab mouse focus
247 m_CurrentMousePosition = evt.mousePosition;
248 m_DragStartScreenPosition = evt.mousePosition;
249 Vector2 rectScreenCenter = Handles.matrix.MultiplyPoint(pos);
250 m_DragScreenOffset = m_CurrentMousePosition - rectScreenCenter;
251 evt.Use();
252 EditorGUIUtility.SetWantsMouseJumping(1);
253 }
254
255 break;
256 case EventType.MouseDrag:
257 if (GUIUtility.hotControl == id)
258 {
259 m_CurrentMousePosition += evt.delta;
260 Vector2 oldPos = pos;
261 Vector3 scrPos = Handles.inverseMatrix.MultiplyPoint(m_CurrentMousePosition - m_DragScreenOffset);
262 pos = new Vector2(scrPos.x, scrPos.y);
263 if (!Mathf.Approximately((oldPos - pos).magnitude, 0f))
264 GUI.changed = true;
265 evt.Use();
266 }
267
268 break;
269 case EventType.MouseUp:
270 if (GUIUtility.hotControl == id && (evt.button == 0 || evt.button == 2))
271 {
272 GUIUtility.hotControl = 0;
273 evt.Use();
274 EditorGUIUtility.SetWantsMouseJumping(0);
275 }
276
277 break;
278 case EventType.KeyDown:
279 if (GUIUtility.hotControl == id)
280 {
281 if (evt.keyCode == KeyCode.Escape)
282 {
283 pos = Handles.inverseMatrix.MultiplyPoint(m_DragStartScreenPosition - m_DragScreenOffset);
284 GUIUtility.hotControl = 0;
285 GUI.changed = true;
286 evt.Use();
287 }
288 }
289
290 break;
291 case EventType.Repaint:
292 EditorGUIUtility.AddCursorRect(handleScreenPos, MouseCursor.Arrow, id);
293
294 if (GUIUtility.hotControl == id)
295 pivotDotActive.Draw(handleScreenPos, GUIContent.none, id);
296 else
297 pivotDot.Draw(handleScreenPos, GUIContent.none, id);
298
299 break;
300 }
301
302 // Convert from texture space back to normalized space
303 pos = new Vector2((pos.x - sprite.xMin) / sprite.width, (pos.y - sprite.yMin) / sprite.height);
304
305 return pos;
306 }
307 }
308}