using UnityEditor.Callbacks; using UnityEditorInternal; using UnityEngine; using UnityEngine.Scripting.APIUpdating; using UnityEngine.U2D.Animation; namespace UnityEditor.U2D.Animation { [CustomEditor(typeof(SpriteLibraryAsset))] [MovedFrom("UnityEditor.Experimental.U2D.Animation")] internal class SpriteLibraryAssetInspector : Editor { static class Style { public static GUIContent duplicateWarningText = EditorGUIUtility.TrTextContent("Duplicate name found or name hash clashes. Please use a different name"); public static GUIContent duplicateWarning = EditorGUIUtility.TrIconContent("console.warnicon.sml", duplicateWarningText.text); public static GUIContent nameLabel = new GUIContent(TextContent.label); public static string categoryListLabel = TextContent.categoryList; public static int lineSpacing = 3; } SerializedProperty m_Labels; ReorderableList m_LabelReorderableList; bool m_UpdateHash = false; static readonly float k_ElementHeight = EditorGUIUtility.singleLineHeight * 3; protected override bool ShouldHideOpenButton() => true; [OnOpenAsset(OnOpenAssetAttributeMode.Execute)] public static bool ExecuteOpenSpriteLibraryAsset(int instanceID) { if (EditorUtility.InstanceIDToObject(instanceID) is SpriteLibraryAsset) return true; return false; } public void OnEnable() { m_Labels = serializedObject.FindProperty("m_Labels"); m_LabelReorderableList = new ReorderableList(serializedObject, m_Labels, true, false, true, true); SetupOrderList(); } public void OnDisable() { var sla = target as SpriteLibraryAsset; if (sla != null) sla.UpdateHashes(); } float GetElementHeight(int index) { var property = m_Labels.GetArrayElementAtIndex(index); var spriteListProp = property.FindPropertyRelative("m_CategoryList"); if (spriteListProp.isExpanded) return (spriteListProp.arraySize + 1) * (EditorGUIUtility.singleLineHeight + Style.lineSpacing) + k_ElementHeight; return k_ElementHeight; } void DrawElement(Rect rect, int index, bool selected, bool focused) { var property = m_Labels.GetArrayElementAtIndex(index); var catRect = new Rect(rect.x, rect.y, rect.width - k_ElementHeight, EditorGUIUtility.singleLineHeight); var vaRect = new Rect(rect.x, rect.y + EditorGUIUtility.singleLineHeight, rect.width - k_ElementHeight, EditorGUIUtility.singleLineHeight); var categoryProp = property.FindPropertyRelative("m_Name"); var spriteListProp = property.FindPropertyRelative("m_CategoryList"); EditorGUI.BeginChangeCheck(); var newCatName = EditorGUI.DelayedTextField(catRect, categoryProp.stringValue); if (EditorGUI.EndChangeCheck()) { newCatName = newCatName.Trim(); m_UpdateHash = true; if (categoryProp.stringValue != newCatName) { // Check if this nameLabel is already taken if (!IsNameInUsed(newCatName, m_Labels, "m_Name", 0)) categoryProp.stringValue = newCatName; else Debug.LogWarning(Style.duplicateWarningText.text); } } spriteListProp.isExpanded = EditorGUI.Foldout(vaRect, spriteListProp.isExpanded, Style.categoryListLabel); if (spriteListProp.isExpanded) { EditorGUI.indentLevel++; var indentedRect = EditorGUI.IndentedRect(vaRect); var labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 40 + indentedRect.x - vaRect.x; indentedRect.y += EditorGUIUtility.singleLineHeight + Style.lineSpacing; var sizeRect = indentedRect; int size = EditorGUI.IntField(sizeRect, TextContent.size, spriteListProp.arraySize); if (size != spriteListProp.arraySize && size >= 0) spriteListProp.arraySize = size; indentedRect.y += EditorGUIUtility.singleLineHeight + Style.lineSpacing; DrawSpriteListProperty(indentedRect, spriteListProp); EditorGUIUtility.labelWidth = labelWidth; EditorGUI.indentLevel--; } } void DrawSpriteListProperty(Rect rect, SerializedProperty spriteListProp) { for (int i = 0; i < spriteListProp.arraySize; ++i) { var element = spriteListProp.GetArrayElementAtIndex(i); EditorGUI.BeginChangeCheck(); var oldName = element.FindPropertyRelative("m_Name").stringValue; var nameRect = new Rect(rect.x, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight); bool nameDuplicate = IsNameInUsed(oldName, spriteListProp, "m_Name", 1); if (nameDuplicate) { nameRect.width -= 20; } var newName = EditorGUI.DelayedTextField( nameRect, Style.nameLabel, oldName); if (nameDuplicate) { nameRect.x += nameRect.width; nameRect.width = 20; GUI.Label(nameRect, Style.duplicateWarning); } if (EditorGUI.EndChangeCheck()) { newName = newName.Trim(); element.FindPropertyRelative("m_Name").stringValue = newName; } EditorGUI.PropertyField(new Rect(rect.x + rect.width / 2 + 5, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("m_Sprite")); rect.y += EditorGUIUtility.singleLineHeight + Style.lineSpacing; } } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUI.BeginChangeCheck(); if (EditorGUI.EndChangeCheck()) SetupOrderList(); m_UpdateHash = false; m_LabelReorderableList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); if (m_UpdateHash) (target as SpriteLibraryAsset).UpdateHashes(); } bool IsNameInUsed(string name, SerializedProperty property, string propertyField, int threshold) { int count = 0; var nameHash = SpriteLibraryUtility.GetStringHash(name); for (int i = 0; i < property.arraySize; ++i) { var sp = property.GetArrayElementAtIndex(i); var otherName = sp.FindPropertyRelative(propertyField).stringValue; var otherNameHash = SpriteLibraryUtility.GetStringHash(otherName); if (otherName == name || nameHash == otherNameHash) { count++; if (count > threshold) return true; } } return false; } void OnAddCallback(ReorderableList list) { var oldSize = m_Labels.arraySize; m_Labels.arraySize += 1; const string kNewCatName = "New Category"; string newCatName = kNewCatName; int catNameIncrement = 1; while (true) { if (IsNameInUsed(newCatName, m_Labels, "m_Name", 0)) newCatName = string.Format("{0} {1}", kNewCatName, catNameIncrement++); else break; } var sp = m_Labels.GetArrayElementAtIndex(oldSize); sp.FindPropertyRelative("m_Name").stringValue = newCatName; sp.FindPropertyRelative("m_Hash").intValue = SpriteLibraryUtility.GetStringHash(newCatName); } private void SetupOrderList() { m_LabelReorderableList.drawElementCallback = DrawElement; m_LabelReorderableList.elementHeight = k_ElementHeight; m_LabelReorderableList.elementHeightCallback = GetElementHeight; m_LabelReorderableList.onAddCallback = OnAddCallback; } } }