SpriteEditor.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. #if UNITY_EDITOR && UNITY_IMGUI
  3. using Animancer.Editor.Tools;
  4. using Animancer.Units;
  5. using Animancer.Units.Editor;
  6. using System;
  7. using System.Collections.Generic;
  8. using UnityEditor;
  9. using UnityEngine;
  10. using Object = UnityEngine.Object;
  11. namespace Animancer.Editor
  12. {
  13. /// <summary>[Editor-Only]
  14. /// A custom Inspector for <see cref="Sprite"/>s which allows you to directly edit them instead of just showing
  15. /// their details like the default one does.
  16. /// </summary>
  17. /// https://kybernetik.com.au/animancer/api/Animancer.Editor/SpriteEditor
  18. [CustomEditor(typeof(Sprite), true), CanEditMultipleObjects]
  19. public class SpriteEditor : UnityEditor.Editor
  20. {
  21. /************************************************************************************************************************/
  22. private const string
  23. NameTooltip = "The asset name of the sprite",
  24. RectTooltip = "The texture area occupied by the sprite",
  25. PivotTooltip = "The origin point of the sprite relative to its Rect",
  26. BorderTooltip = "The edge sizes used when 9-Slicing the sprite for the UI system (ignored by SpriteRenderers)";
  27. [NonSerialized]
  28. private SerializedProperty
  29. _Name,
  30. _Rect,
  31. _Pivot,
  32. _Border;
  33. [NonSerialized]
  34. private NormalizedPixelField[]
  35. _RectFields,
  36. _PivotFields,
  37. _BorderFields;
  38. [NonSerialized]
  39. private bool _HasBeenModified;
  40. [NonSerialized]
  41. private Target[] _Targets;
  42. private readonly struct Target
  43. {
  44. public readonly Sprite Sprite;
  45. public readonly string AssetPath;
  46. public readonly TextureImporter Importer;
  47. public Target(Object target)
  48. {
  49. Sprite = target as Sprite;
  50. AssetPath = AssetDatabase.GetAssetPath(target);
  51. Importer = AssetImporter.GetAtPath(AssetPath) as TextureImporter;
  52. }
  53. }
  54. /************************************************************************************************************************/
  55. /// <summary>Initializes this editor.</summary>
  56. protected virtual void OnEnable()
  57. {
  58. var targets = this.targets;
  59. _Targets = new Target[targets.Length];
  60. for (int i = 0; i < targets.Length; i++)
  61. _Targets[i] = new(targets[i]);
  62. InitializePreview();
  63. _Name = serializedObject.FindProperty($"m{nameof(_Name)}");
  64. _Rect = serializedObject.FindProperty($"m{nameof(_Rect)}");
  65. if (_Rect != null)
  66. {
  67. _RectFields = new NormalizedPixelField[]
  68. {
  69. new(_Rect.FindPropertyRelative(nameof(Rect.x)), new("X (Left)",
  70. "The distance from the left edge of the texture to the left edge of the sprite"), false),
  71. new(_Rect.FindPropertyRelative(nameof(Rect.y)), new("Y (Bottom)",
  72. "The distance from the bottom edge of the texture to the bottom edge of the sprite"), false),
  73. new(_Rect.FindPropertyRelative(nameof(Rect.width)), new("Width",
  74. "The horizontal size of the sprite"), false),
  75. new(_Rect.FindPropertyRelative(nameof(Rect.height)), new("Height",
  76. "The vertical size of the sprite"), false),
  77. };
  78. }
  79. _Pivot = serializedObject.FindProperty($"m{nameof(_Pivot)}");
  80. if (_Pivot != null)
  81. {
  82. _PivotFields = new NormalizedPixelField[]
  83. {
  84. new(_Pivot.FindPropertyRelative(nameof(Vector2.x)), new("X",
  85. "The horizontal distance from the left edge of the sprite to the pivot point"), true),
  86. new(_Pivot.FindPropertyRelative(nameof(Vector2.y)), new("Y",
  87. "The vertical distance from the bottom edge of the sprite to the pivot point"), true),
  88. };
  89. }
  90. _Border = serializedObject.FindProperty($"m{nameof(_Border)}");
  91. if (_Border != null)
  92. {
  93. _BorderFields = new NormalizedPixelField[]
  94. {
  95. new(_Border.FindPropertyRelative(nameof(Vector4.x)), new("Left",
  96. BorderTooltip), false),
  97. new(_Border.FindPropertyRelative(nameof(Vector4.y)), new("Bottom",
  98. BorderTooltip), false),
  99. new(_Border.FindPropertyRelative(nameof(Vector4.z)), new("Right",
  100. BorderTooltip), false),
  101. new(_Border.FindPropertyRelative(nameof(Vector4.w)), new("Top",
  102. BorderTooltip), false),
  103. };
  104. }
  105. }
  106. /************************************************************************************************************************/
  107. /// <summary>Cleans up this editor.</summary>
  108. protected virtual void OnDisable()
  109. {
  110. CleanUpPreview();
  111. if (_HasBeenModified)
  112. {
  113. var sprite = target as Sprite;
  114. if (sprite == null)
  115. return;
  116. if (EditorUtility.DisplayDialog("Unapplied Import Settings",
  117. $"Unapplied import settings for '{sprite.name}' in '{AssetDatabase.GetAssetPath(sprite)}'",
  118. nameof(Apply), nameof(Revert)))
  119. Apply();
  120. }
  121. }
  122. /************************************************************************************************************************/
  123. #region Inspector
  124. /************************************************************************************************************************/
  125. /// <summary>Are all targets set to <see cref="SpriteImportMode.Multiple"/>?</summary>
  126. private bool AllSpriteModeMultiple
  127. {
  128. get
  129. {
  130. for (int i = 0; i < _Targets.Length; i++)
  131. {
  132. var importer = _Targets[i].Importer;
  133. if (importer == null ||
  134. importer.spriteImportMode != SpriteImportMode.Multiple)
  135. return false;
  136. }
  137. return true;
  138. }
  139. }
  140. /************************************************************************************************************************/
  141. /// <summary>Called by the Unity editor to draw the custom Inspector GUI elements.</summary>
  142. public override void OnInspectorGUI()
  143. {
  144. EditorGUI.BeginChangeCheck();
  145. DoNameGUI();
  146. // If any target isn't set to Multiple, disable the GUI because only renaming will work.
  147. var enabled = GUI.enabled;
  148. if (!AllSpriteModeMultiple)
  149. GUI.enabled = false;
  150. DoRectGUI();
  151. DoPivotGUI();
  152. DoBorderGUI();
  153. GUI.enabled = enabled;
  154. if (EditorGUI.EndChangeCheck())
  155. _HasBeenModified = true;
  156. GUILayout.Space(AnimancerGUI.StandardSpacing);
  157. GUILayout.BeginHorizontal();
  158. {
  159. GUILayout.FlexibleSpace();
  160. GUI.enabled = _HasBeenModified;
  161. if (GUILayout.Button(nameof(Revert)))
  162. Revert();
  163. if (GUILayout.Button(nameof(Apply)))
  164. Apply();
  165. }
  166. GUILayout.EndHorizontal();
  167. }
  168. /************************************************************************************************************************/
  169. private void DoNameGUI()
  170. {
  171. GUILayout.BeginHorizontal();
  172. var enabled = GUI.enabled;
  173. if (_Name.hasMultipleDifferentValues)
  174. GUI.enabled = false;
  175. using (var label = PooledGUIContent.Acquire("Name", NameTooltip))
  176. EditorGUILayout.PropertyField(_Name, label, true);
  177. GUI.enabled = true;
  178. var changed = EditorGUI.EndChangeCheck();// Exclude the Rename button from the main change check.
  179. if (GUILayout.Button("Rename Tool", EditorStyles.miniButton, AnimancerGUI.DontExpandWidth))
  180. AnimancerToolsWindow.Open(typeof(RenameSpritesTool));
  181. EditorGUI.BeginChangeCheck();
  182. AnimancerGUI.SetGuiChanged(changed);
  183. GUI.enabled = enabled;
  184. GUILayout.EndHorizontal();
  185. }
  186. /************************************************************************************************************************/
  187. private void DoRectGUI()
  188. {
  189. var texture = ((Sprite)target).texture;
  190. _RectFields[0].normalizeMultiplier = _RectFields[2].normalizeMultiplier = 1f / texture.width;
  191. _RectFields[1].normalizeMultiplier = _RectFields[3].normalizeMultiplier = 1f / texture.height;
  192. using (var label = PooledGUIContent.Acquire("Rect", RectTooltip))
  193. NormalizedPixelField.DoGroupGUI(_Rect, label, _RectFields);
  194. }
  195. /************************************************************************************************************************/
  196. private void DoPivotGUI()
  197. {
  198. var showMixedValue = EditorGUI.showMixedValue;
  199. var targets = this.targets;
  200. var size = targets[0] is Sprite sprite ? sprite.rect.size : Vector2.one;
  201. for (int i = 1; i < targets.Length; i++)
  202. {
  203. sprite = targets[i] as Sprite;
  204. if (sprite == null || !sprite.rect.size.Equals(size))
  205. EditorGUI.showMixedValue = true;
  206. }
  207. _PivotFields[0].normalizeMultiplier = 1f / size.x;
  208. _PivotFields[1].normalizeMultiplier = 1f / size.y;
  209. using (var label = PooledGUIContent.Acquire("Pivot", PivotTooltip))
  210. NormalizedPixelField.DoGroupGUI(_Pivot, label, _PivotFields);
  211. EditorGUI.showMixedValue = showMixedValue;
  212. }
  213. /************************************************************************************************************************/
  214. private void DoBorderGUI()
  215. {
  216. var size = _Rect.rectValue.size;
  217. _BorderFields[0].normalizeMultiplier = _BorderFields[2].normalizeMultiplier = 1f / size.x;
  218. _BorderFields[1].normalizeMultiplier = _BorderFields[3].normalizeMultiplier = 1f / size.y;
  219. using (var label = PooledGUIContent.Acquire("Border", BorderTooltip))
  220. NormalizedPixelField.DoGroupGUI(_Border, label, _BorderFields);
  221. }
  222. /************************************************************************************************************************/
  223. private void Revert()
  224. {
  225. AnimancerGUI.Deselect();
  226. _HasBeenModified = false;
  227. serializedObject.Update();
  228. }
  229. /************************************************************************************************************************/
  230. private void Apply()
  231. {
  232. AnimancerGUI.Deselect();
  233. _HasBeenModified = false;
  234. var targets = this.targets;
  235. var hasError = false;
  236. for (int i = 0; i < _Targets.Length; i++)
  237. {
  238. var target = _Targets[i];
  239. if (target.Sprite == null ||
  240. target.Importer == null)
  241. continue;
  242. var data = new SpriteDataEditor(target.Importer);
  243. Apply(data, target.Sprite, ref hasError);
  244. if (!hasError)
  245. data.Apply();
  246. }
  247. for (int i = 0; i < targets.Length; i++)
  248. if (targets[i] == null)
  249. return;
  250. serializedObject.Update();
  251. }
  252. /************************************************************************************************************************/
  253. private void Apply(SpriteDataEditor data, Sprite sprite, ref bool hasError)
  254. {
  255. if (data.SpriteCount == 0)
  256. {
  257. if (!_Name.hasMultipleDifferentValues)
  258. {
  259. var path = AssetDatabase.GetAssetPath(sprite);
  260. if (path != null)
  261. {
  262. AssetDatabase.RenameAsset(path, _Name.stringValue);
  263. hasError = true;// Don't apply the importer.
  264. }
  265. }
  266. return;
  267. }
  268. var index = data.IndexOf(sprite);
  269. if (index < 0)
  270. {
  271. hasError = true;
  272. return;
  273. }
  274. if (!_Name.hasMultipleDifferentValues)
  275. data.SetName(index, _Name.stringValue);
  276. if (!_Rect.hasMultipleDifferentValues)
  277. data.SetRect(index, _Rect.rectValue);
  278. if (!_Pivot.hasMultipleDifferentValues)
  279. data.SetPivot(index, _Pivot.vector2Value);
  280. if (!_Border.hasMultipleDifferentValues)
  281. data.SetBorder(index, _Border.vector4Value);
  282. if (!data.ValidateBounds(index, sprite))
  283. hasError = true;
  284. }
  285. /************************************************************************************************************************/
  286. #region Normalized Pixel Field
  287. /************************************************************************************************************************/
  288. /// <summary>
  289. /// A wrapper around a <see cref="SerializedProperty"/> to display it using two float fields where one is
  290. /// normalized and the other is not.
  291. /// </summary>
  292. private class NormalizedPixelField
  293. {
  294. /************************************************************************************************************************/
  295. /// <summary>The target property.</summary>
  296. public readonly SerializedProperty Property;
  297. /// <summary>The label to display next to the property.</summary>
  298. public readonly GUIContent Label;
  299. /// <summary>Is the serialized property value normalized?</summary>
  300. public readonly bool IsNormalized;
  301. /// <summary>The multiplier to turn a non-normalized value into a normalized one.</summary>
  302. public float normalizeMultiplier;
  303. /************************************************************************************************************************/
  304. /// <summary>Creates a new <see cref="NormalizedPixelField"/>.</summary>
  305. public NormalizedPixelField(SerializedProperty property, GUIContent label, bool isNormalized)
  306. {
  307. Property = property;
  308. Label = label;
  309. IsNormalized = isNormalized;
  310. }
  311. /************************************************************************************************************************/
  312. /// <summary>Draws a group of <see cref="NormalizedPixelField"/>s.</summary>
  313. public static void DoGroupGUI(SerializedProperty baseProperty, GUIContent label, NormalizedPixelField[] fields)
  314. {
  315. var height = (AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing) * (fields.Length + 1);
  316. var area = AnimancerGUI.LayoutRect(height);
  317. area.height = AnimancerGUI.LineHeight;
  318. label = EditorGUI.BeginProperty(area, label, baseProperty);
  319. GUI.Label(area, label);
  320. EditorGUI.EndProperty();
  321. EditorGUI.indentLevel++;
  322. for (int i = 0; i < fields.Length; i++)
  323. {
  324. AnimancerGUI.NextVerticalArea(ref area);
  325. fields[i].DoTwinFloatFieldGUI(area);
  326. }
  327. EditorGUI.indentLevel--;
  328. }
  329. /************************************************************************************************************************/
  330. /// <summary>Draws this <see cref="NormalizedPixelField"/>.</summary>
  331. public void DoTwinFloatFieldGUI(Rect area)
  332. {
  333. var attribute = IsNormalized ?
  334. NormalizedPixelFieldAttribute.Normalized :
  335. NormalizedPixelFieldAttribute.Pixel;
  336. var drawer = IsNormalized ?
  337. NormalizedPixelFieldAttributeDrawer.Normalized :
  338. NormalizedPixelFieldAttributeDrawer.Pixel;
  339. attribute.CalculateMultipliers(normalizeMultiplier);
  340. drawer.OnGUI(area, Property, Label);
  341. }
  342. /************************************************************************************************************************/
  343. }
  344. /************************************************************************************************************************/
  345. #endregion
  346. /************************************************************************************************************************/
  347. #region Normalized Pixel Field
  348. /************************************************************************************************************************/
  349. private class NormalizedPixelFieldAttribute : UnitsAttribute
  350. {
  351. /************************************************************************************************************************/
  352. private static new readonly float[] Multipliers = new float[2];
  353. public void CalculateMultipliers(float normalizeMultiplier)
  354. {
  355. if (UnitIndex == 0)// Pixels.
  356. {
  357. Multipliers[0] = 1;
  358. Multipliers[1] = normalizeMultiplier;
  359. }
  360. else// Normalized.
  361. {
  362. Multipliers[0] = 1f / normalizeMultiplier;
  363. Multipliers[1] = 1;
  364. }
  365. }
  366. /************************************************************************************************************************/
  367. private static new readonly string[] Suffixes =
  368. {
  369. "px",
  370. "x",
  371. };
  372. /************************************************************************************************************************/
  373. public static readonly NormalizedPixelFieldAttribute Pixel = new(false);
  374. public static readonly NormalizedPixelFieldAttribute Normalized = new(true);
  375. /************************************************************************************************************************/
  376. public NormalizedPixelFieldAttribute(bool isNormalized)
  377. : base(Multipliers, Suffixes, isNormalized ? 1 : 0)
  378. {
  379. Rule = Validate.Value.IsFinite;
  380. }
  381. /************************************************************************************************************************/
  382. }
  383. /************************************************************************************************************************/
  384. [CustomPropertyDrawer(typeof(NormalizedPixelFieldAttribute), true)]
  385. private class NormalizedPixelFieldAttributeDrawer : UnitsAttributeDrawer
  386. {
  387. /************************************************************************************************************************/
  388. public static readonly NormalizedPixelFieldAttributeDrawer Pixel = new();
  389. public static readonly NormalizedPixelFieldAttributeDrawer Normalized = new();
  390. static NormalizedPixelFieldAttributeDrawer()
  391. {
  392. Pixel.Initialize(NormalizedPixelFieldAttribute.Pixel);
  393. Normalized.Initialize(NormalizedPixelFieldAttribute.Normalized);
  394. }
  395. /************************************************************************************************************************/
  396. /// <inheritdoc/>
  397. protected override int GetLineCount(SerializedProperty property, GUIContent label)
  398. => 1;
  399. /************************************************************************************************************************/
  400. }
  401. /************************************************************************************************************************/
  402. #endregion
  403. /************************************************************************************************************************/
  404. #endregion
  405. /************************************************************************************************************************/
  406. #region Preview
  407. /************************************************************************************************************************/
  408. private static readonly Type
  409. DefaultEditorType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.SpriteInspector");
  410. private readonly Dictionary<Object, UnityEditor.Editor>
  411. TargetToDefaultEditor = new();
  412. /************************************************************************************************************************/
  413. private void InitializePreview()
  414. {
  415. foreach (var target in targets)
  416. {
  417. if (!TargetToDefaultEditor.ContainsKey(target))
  418. {
  419. var editor = CreateEditor(target, DefaultEditorType);
  420. TargetToDefaultEditor.Add(target, editor);
  421. }
  422. }
  423. }
  424. /************************************************************************************************************************/
  425. private void CleanUpPreview()
  426. {
  427. foreach (var editor in TargetToDefaultEditor.Values)
  428. DestroyImmediate(editor);
  429. TargetToDefaultEditor.Clear();
  430. }
  431. /************************************************************************************************************************/
  432. private bool TryGetDefaultEditor(out UnityEditor.Editor editor)
  433. => TargetToDefaultEditor.TryGetValue(target, out editor);
  434. /************************************************************************************************************************/
  435. /// <inheritdoc/>
  436. public override string GetInfoString()
  437. {
  438. if (!TryGetDefaultEditor(out var editor))
  439. return null;
  440. return editor.GetInfoString();
  441. }
  442. /************************************************************************************************************************/
  443. /// <inheritdoc/>
  444. public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
  445. {
  446. if (!TryGetDefaultEditor(out var editor))
  447. return null;
  448. return editor.RenderStaticPreview(assetPath, subAssets, width, height);
  449. }
  450. /************************************************************************************************************************/
  451. /// <inheritdoc/>
  452. public override bool HasPreviewGUI()
  453. {
  454. return TryGetDefaultEditor(out var editor) && editor.HasPreviewGUI();
  455. }
  456. /************************************************************************************************************************/
  457. /// <inheritdoc/>
  458. public override void OnPreviewGUI(Rect area, GUIStyle background)
  459. {
  460. if (TryGetDefaultEditor(out var editor))
  461. editor.OnPreviewGUI(area, background);
  462. var sprite = target as Sprite;
  463. if (sprite == null)
  464. return;
  465. EditorGUI.BeginChangeCheck();
  466. FitAspectRatio(ref area, sprite);
  467. DoPivotDotGUI(area, sprite);
  468. if (EditorGUI.EndChangeCheck())
  469. _HasBeenModified = true;
  470. }
  471. /************************************************************************************************************************/
  472. private static void FitAspectRatio(ref Rect area, Sprite sprite)
  473. {
  474. var areaAspect = area.width / area.height;
  475. var spriteAspect = sprite.rect.width / sprite.rect.height;
  476. if (areaAspect != spriteAspect)
  477. {
  478. if (areaAspect > spriteAspect)
  479. {
  480. var width = area.height * spriteAspect;
  481. area.x += (area.width - width) * 0.5f;
  482. area.width = width;
  483. }
  484. else
  485. {
  486. var height = area.width / spriteAspect;
  487. area.y += (area.height - height) * 0.5f;
  488. area.height = height;
  489. }
  490. }
  491. }
  492. /************************************************************************************************************************/
  493. private static readonly int PivotDotControlIDHint = "PivotDot".GetHashCode();
  494. private static GUIStyle _PivotDot;
  495. private static GUIStyle _PivotDotActive;
  496. [NonSerialized] private Vector2 _MouseDownPivot;
  497. private void DoPivotDotGUI(Rect area, Sprite sprite)
  498. {
  499. _PivotDot ??= "U2D.pivotDot";
  500. _PivotDotActive ??= "U2D.pivotDotActive";
  501. Vector2 pivot;
  502. if (_Pivot.hasMultipleDifferentValues)
  503. {
  504. pivot = sprite.pivot;
  505. pivot.x /= sprite.rect.width;
  506. pivot.y /= sprite.rect.height;
  507. }
  508. else
  509. {
  510. pivot = _Pivot.vector2Value;
  511. }
  512. pivot.x *= area.width;
  513. pivot.y *= area.height;
  514. var pivotArea = new Rect(
  515. area.x + pivot.x - _PivotDot.fixedWidth * 0.5f,
  516. area.yMax - pivot.y - _PivotDot.fixedHeight * 0.5f,
  517. _PivotDot.fixedWidth,
  518. _PivotDot.fixedHeight);
  519. var control = new GUIControl(pivotArea, PivotDotControlIDHint, FocusType.Keyboard);
  520. switch (control.EventType)
  521. {
  522. case EventType.MouseDown:
  523. if (control.Event.button == 0 &&
  524. !control.Event.alt &&
  525. control.TryUseMouseDown())
  526. {
  527. _MouseDownPivot = _Pivot.vector2Value;
  528. GUIUtility.keyboardControl = control.ID;
  529. }
  530. break;
  531. case EventType.MouseUp:
  532. if (control.TryUseMouseUp())
  533. GUIUtility.keyboardControl = 0;
  534. break;
  535. case EventType.MouseDrag:
  536. if (control.TryUseHotControl())
  537. {
  538. pivot = control.Event.mousePosition;
  539. pivot.x = AnimancerUtilities.InverseLerpUnclamped(area.x, area.xMax, pivot.x);
  540. pivot.y = AnimancerUtilities.InverseLerpUnclamped(area.yMax, area.y, pivot.y);
  541. if (control.Event.control)
  542. {
  543. var rect = sprite.rect;
  544. pivot.x = Mathf.Round(pivot.x * rect.width) / rect.width;
  545. pivot.y = Mathf.Round(pivot.y * rect.height) / rect.height;
  546. }
  547. _Pivot.vector2Value = pivot;
  548. }
  549. break;
  550. case EventType.KeyDown:
  551. if (control.TryUseKey(KeyCode.Escape))
  552. {
  553. _Pivot.vector2Value = _MouseDownPivot;
  554. AnimancerGUI.Deselect();
  555. }
  556. break;
  557. case EventType.Repaint:
  558. EditorGUIUtility.AddCursorRect(pivotArea, MouseCursor.Arrow, control.ID);
  559. var style = GUIUtility.hotControl == control.ID ? _PivotDotActive : _PivotDot;
  560. style.Draw(pivotArea, GUIContent.none, control.ID);
  561. break;
  562. }
  563. }
  564. /************************************************************************************************************************/
  565. #endregion
  566. /************************************************************************************************************************/
  567. }
  568. }
  569. #endif