ImageEditor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System.Linq;
  2. using UnityEngine;
  3. using UnityEditor.AnimatedValues;
  4. using UnityEngine.UI;
  5. namespace UnityEditor.UI
  6. {
  7. /// <summary>
  8. /// Editor class used to edit UI Sprites.
  9. /// </summary>
  10. [CustomEditor(typeof(Image), true)]
  11. [CanEditMultipleObjects]
  12. /// <summary>
  13. /// Custom Editor for the Image Component.
  14. /// Extend this class to write a custom editor for a component derived from Image.
  15. /// </summary>
  16. public class ImageEditor : GraphicEditor
  17. {
  18. SerializedProperty m_FillMethod;
  19. SerializedProperty m_FillOrigin;
  20. SerializedProperty m_FillAmount;
  21. SerializedProperty m_FillClockwise;
  22. SerializedProperty m_Type;
  23. SerializedProperty m_FillCenter;
  24. SerializedProperty m_Sprite;
  25. SerializedProperty m_PreserveAspect;
  26. SerializedProperty m_UseSpriteMesh;
  27. SerializedProperty m_PixelsPerUnitMultiplier;
  28. GUIContent m_SpriteContent;
  29. GUIContent m_SpriteTypeContent;
  30. GUIContent m_ClockwiseContent;
  31. AnimBool m_ShowSlicedOrTiled;
  32. AnimBool m_ShowSliced;
  33. AnimBool m_ShowTiled;
  34. AnimBool m_ShowFilled;
  35. AnimBool m_ShowType;
  36. private class Styles
  37. {
  38. public static GUIContent text = EditorGUIUtility.TrTextContent("Fill Origin");
  39. public static GUIContent[] OriginHorizontalStyle =
  40. {
  41. EditorGUIUtility.TrTextContent("Left"),
  42. EditorGUIUtility.TrTextContent("Right")
  43. };
  44. public static GUIContent[] OriginVerticalStyle =
  45. {
  46. EditorGUIUtility.TrTextContent("Bottom"),
  47. EditorGUIUtility.TrTextContent("Top")
  48. };
  49. public static GUIContent[] Origin90Style =
  50. {
  51. EditorGUIUtility.TrTextContent("BottomLeft"),
  52. EditorGUIUtility.TrTextContent("TopLeft"),
  53. EditorGUIUtility.TrTextContent("TopRight"),
  54. EditorGUIUtility.TrTextContent("BottomRight")
  55. };
  56. public static GUIContent[] Origin180Style =
  57. {
  58. EditorGUIUtility.TrTextContent("Bottom"),
  59. EditorGUIUtility.TrTextContent("Left"),
  60. EditorGUIUtility.TrTextContent("Top"),
  61. EditorGUIUtility.TrTextContent("Right")
  62. };
  63. public static GUIContent[] Origin360Style =
  64. {
  65. EditorGUIUtility.TrTextContent("Bottom"),
  66. EditorGUIUtility.TrTextContent("Right"),
  67. EditorGUIUtility.TrTextContent("Top"),
  68. EditorGUIUtility.TrTextContent("Left")
  69. };
  70. }
  71. protected override void OnEnable()
  72. {
  73. base.OnEnable();
  74. m_SpriteContent = EditorGUIUtility.TrTextContent("Source Image");
  75. m_SpriteTypeContent = EditorGUIUtility.TrTextContent("Image Type");
  76. m_ClockwiseContent = EditorGUIUtility.TrTextContent("Clockwise");
  77. m_Sprite = serializedObject.FindProperty("m_Sprite");
  78. m_Type = serializedObject.FindProperty("m_Type");
  79. m_FillCenter = serializedObject.FindProperty("m_FillCenter");
  80. m_FillMethod = serializedObject.FindProperty("m_FillMethod");
  81. m_FillOrigin = serializedObject.FindProperty("m_FillOrigin");
  82. m_FillClockwise = serializedObject.FindProperty("m_FillClockwise");
  83. m_FillAmount = serializedObject.FindProperty("m_FillAmount");
  84. m_PreserveAspect = serializedObject.FindProperty("m_PreserveAspect");
  85. m_UseSpriteMesh = serializedObject.FindProperty("m_UseSpriteMesh");
  86. m_PixelsPerUnitMultiplier = serializedObject.FindProperty("m_PixelsPerUnitMultiplier");
  87. m_ShowType = new AnimBool(m_Sprite.objectReferenceValue != null);
  88. m_ShowType.valueChanged.AddListener(Repaint);
  89. var typeEnum = (Image.Type)m_Type.enumValueIndex;
  90. m_ShowSlicedOrTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced);
  91. m_ShowSliced = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced);
  92. m_ShowTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Tiled);
  93. m_ShowFilled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Filled);
  94. m_ShowSlicedOrTiled.valueChanged.AddListener(Repaint);
  95. m_ShowSliced.valueChanged.AddListener(Repaint);
  96. m_ShowTiled.valueChanged.AddListener(Repaint);
  97. m_ShowFilled.valueChanged.AddListener(Repaint);
  98. SetShowNativeSize(true);
  99. }
  100. protected override void OnDisable()
  101. {
  102. m_ShowType.valueChanged.RemoveListener(Repaint);
  103. m_ShowSlicedOrTiled.valueChanged.RemoveListener(Repaint);
  104. m_ShowSliced.valueChanged.RemoveListener(Repaint);
  105. m_ShowTiled.valueChanged.RemoveListener(Repaint);
  106. m_ShowFilled.valueChanged.RemoveListener(Repaint);
  107. }
  108. public override void OnInspectorGUI()
  109. {
  110. serializedObject.Update();
  111. SpriteGUI();
  112. AppearanceControlsGUI();
  113. RaycastControlsGUI();
  114. MaskableControlsGUI();
  115. m_ShowType.target = m_Sprite.objectReferenceValue != null;
  116. if (EditorGUILayout.BeginFadeGroup(m_ShowType.faded))
  117. TypeGUI();
  118. EditorGUILayout.EndFadeGroup();
  119. SetShowNativeSize(false);
  120. if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded))
  121. {
  122. EditorGUI.indentLevel++;
  123. if ((Image.Type)m_Type.enumValueIndex == Image.Type.Simple)
  124. EditorGUILayout.PropertyField(m_UseSpriteMesh);
  125. EditorGUILayout.PropertyField(m_PreserveAspect);
  126. EditorGUI.indentLevel--;
  127. }
  128. EditorGUILayout.EndFadeGroup();
  129. NativeSizeButtonGUI();
  130. serializedObject.ApplyModifiedProperties();
  131. }
  132. void SetShowNativeSize(bool instant)
  133. {
  134. Image.Type type = (Image.Type)m_Type.enumValueIndex;
  135. bool showNativeSize = (type == Image.Type.Simple || type == Image.Type.Filled) && m_Sprite.objectReferenceValue != null;
  136. base.SetShowNativeSize(showNativeSize, instant);
  137. }
  138. /// <summary>
  139. /// Draw the atlas and Image selection fields.
  140. /// </summary>
  141. protected void SpriteGUI()
  142. {
  143. EditorGUI.BeginChangeCheck();
  144. EditorGUILayout.PropertyField(m_Sprite, m_SpriteContent);
  145. if (EditorGUI.EndChangeCheck())
  146. {
  147. var newSprite = m_Sprite.objectReferenceValue as Sprite;
  148. if (newSprite)
  149. {
  150. Image.Type oldType = (Image.Type)m_Type.enumValueIndex;
  151. if (newSprite.border.SqrMagnitude() > 0)
  152. {
  153. m_Type.enumValueIndex = (int)Image.Type.Sliced;
  154. }
  155. else if (oldType == Image.Type.Sliced)
  156. {
  157. m_Type.enumValueIndex = (int)Image.Type.Simple;
  158. }
  159. }
  160. (serializedObject.targetObject as Image).DisableSpriteOptimizations();
  161. }
  162. }
  163. /// <summary>
  164. /// Sprites's custom properties based on the type.
  165. /// </summary>
  166. protected void TypeGUI()
  167. {
  168. EditorGUILayout.PropertyField(m_Type, m_SpriteTypeContent);
  169. ++EditorGUI.indentLevel;
  170. {
  171. Image.Type typeEnum = (Image.Type)m_Type.enumValueIndex;
  172. bool showSlicedOrTiled = (!m_Type.hasMultipleDifferentValues && (typeEnum == Image.Type.Sliced || typeEnum == Image.Type.Tiled));
  173. if (showSlicedOrTiled && targets.Length > 1)
  174. showSlicedOrTiled = targets.Select(obj => obj as Image).All(img => img.hasBorder);
  175. m_ShowSlicedOrTiled.target = showSlicedOrTiled;
  176. m_ShowSliced.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced);
  177. m_ShowTiled.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Tiled);
  178. m_ShowFilled.target = (!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Filled);
  179. Image image = target as Image;
  180. if (EditorGUILayout.BeginFadeGroup(m_ShowSlicedOrTiled.faded))
  181. {
  182. if (image.hasBorder)
  183. EditorGUILayout.PropertyField(m_FillCenter);
  184. EditorGUILayout.PropertyField(m_PixelsPerUnitMultiplier);
  185. }
  186. EditorGUILayout.EndFadeGroup();
  187. if (EditorGUILayout.BeginFadeGroup(m_ShowSliced.faded))
  188. {
  189. if (image.sprite != null && !image.hasBorder)
  190. EditorGUILayout.HelpBox("This Image doesn't have a border.", MessageType.Warning);
  191. }
  192. EditorGUILayout.EndFadeGroup();
  193. if (EditorGUILayout.BeginFadeGroup(m_ShowTiled.faded))
  194. {
  195. if (image.sprite != null && !image.hasBorder && (image.sprite.texture.wrapMode != TextureWrapMode.Repeat || image.sprite.packed))
  196. EditorGUILayout.HelpBox("It looks like you want to tile a sprite with no border. It would be more efficient to modify the Sprite properties, clear the Packing tag and set the Wrap mode to Repeat.", MessageType.Warning);
  197. }
  198. EditorGUILayout.EndFadeGroup();
  199. if (EditorGUILayout.BeginFadeGroup(m_ShowFilled.faded))
  200. {
  201. EditorGUI.BeginChangeCheck();
  202. EditorGUILayout.PropertyField(m_FillMethod);
  203. if (EditorGUI.EndChangeCheck())
  204. {
  205. m_FillOrigin.intValue = 0;
  206. }
  207. var shapeRect = EditorGUILayout.GetControlRect(true);
  208. switch ((Image.FillMethod)m_FillMethod.enumValueIndex)
  209. {
  210. case Image.FillMethod.Horizontal:
  211. EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.OriginHorizontalStyle, Styles.text);
  212. break;
  213. case Image.FillMethod.Vertical:
  214. EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.OriginVerticalStyle, Styles.text);
  215. break;
  216. case Image.FillMethod.Radial90:
  217. EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin90Style, Styles.text);
  218. break;
  219. case Image.FillMethod.Radial180:
  220. EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin180Style, Styles.text);
  221. break;
  222. case Image.FillMethod.Radial360:
  223. EditorGUI.Popup(shapeRect, m_FillOrigin, Styles.Origin360Style, Styles.text);
  224. break;
  225. }
  226. EditorGUILayout.PropertyField(m_FillAmount);
  227. if ((Image.FillMethod)m_FillMethod.enumValueIndex > Image.FillMethod.Vertical)
  228. {
  229. EditorGUILayout.PropertyField(m_FillClockwise, m_ClockwiseContent);
  230. }
  231. }
  232. EditorGUILayout.EndFadeGroup();
  233. }
  234. --EditorGUI.indentLevel;
  235. }
  236. /// <summary>
  237. /// All graphics have a preview.
  238. /// </summary>
  239. public override bool HasPreviewGUI() { return true; }
  240. /// <summary>
  241. /// Draw the Image preview.
  242. /// </summary>
  243. public override void OnPreviewGUI(Rect rect, GUIStyle background)
  244. {
  245. Image image = target as Image;
  246. if (image == null) return;
  247. Sprite sf = image.sprite;
  248. if (sf == null) return;
  249. SpriteDrawUtility.DrawSprite(sf, rect, image.canvasRenderer.GetColor());
  250. }
  251. /// <summary>
  252. /// A string containing the Image details to be used as a overlay on the component Preview.
  253. /// </summary>
  254. /// <returns>
  255. /// The Image details.
  256. /// </returns>
  257. public override string GetInfoString()
  258. {
  259. Image image = target as Image;
  260. Sprite sprite = image.sprite;
  261. int x = (sprite != null) ? Mathf.RoundToInt(sprite.rect.width) : 0;
  262. int y = (sprite != null) ? Mathf.RoundToInt(sprite.rect.height) : 0;
  263. return string.Format("Image Size: {0}x{1}", x, y);
  264. }
  265. }
  266. }