No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PivotTool.cs 12KB

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