using UnityEngine; using UnityEditor; using UnityEditorInternal; using System.Collections.Generic; using YKMoon; namespace YKMoonEditor { //T: element type public class SubclassReorderableList { private ReorderableList m_ReorderableList; public SerializedObject serializedObject { get; private set; } public SerializedProperty elements { get; private set; } private List subClassTypes; public SubclassReorderableList(SerializedObject serializedObject, SerializedProperty elements) { this.serializedObject = serializedObject; this.elements = elements; subClassTypes = GetSubclassTypes(); m_ReorderableList = new ReorderableList(serializedObject, elements, true, true, true, true); m_ReorderableList.drawElementCallback = DrawElement; m_ReorderableList.elementHeightCallback = GetElementHeight; m_ReorderableList.drawHeaderCallback = DrawEventHeader; m_ReorderableList.onAddDropdownCallback = OnAddDropdown; //m_ReorderableList.headerHeight = 32; } private void DrawElement(Rect rect, int index, bool isActive, bool isFocused) { var element = m_ReorderableList.serializedProperty.GetArrayElementAtIndex(index); EditorGUI.PropertyField(rect, element); } private float GetElementHeight(int index) { var element = m_ReorderableList.serializedProperty.GetArrayElementAtIndex(index); return EditorGUI.GetPropertyHeight(element); } public void DoLayoutList() { m_ReorderableList.DoLayoutList(); } protected virtual void DrawEventHeader(Rect headerRect) { GUIContent content = new GUIContent(string.Format("{0} ({1})", elements.name, m_ReorderableList.count), elements.tooltip); var style = GUI.skin.GetStyle("BoldLabel"); style.fontSize = 16; EditorGUI.LabelField(headerRect, content, style); } public int arraySize { get { return m_ReorderableList.count; } } public int index { get => m_ReorderableList.index; set => m_ReorderableList.index = Mathf.Min(Mathf.Max(0, value), arraySize); } private void OnAddDropdown(Rect buttonRect, ReorderableList list) { var menu = new GenericMenu(); foreach(var type in subClassTypes) { menu.AddItem(new GUIContent(type.GetDisplayName()), false, OnClickAddElement, type); } menu.ShowAsContext(); } private void OnClickAddElement(object args) { System.Type subClassType = (System.Type)args; Undo.RecordObject(serializedObject.targetObject, "Add New Item"); var newItem = (T)System.Activator.CreateInstance(subClassType); var scriptType = serializedObject.targetObject.GetType(); var listField = scriptType.GetField(elements.name); List list = (List)listField.GetValue(serializedObject.targetObject); list.Add(newItem); this.index = list.Count - 1; serializedObject.ApplyModifiedProperties(); } private List GetSubclassTypes() { List result = new List(); var targetSuperType = typeof(T); foreach(var type in targetSuperType.Assembly.GetTypes()) { if(!type.IsAbstract && IsBaseTypeContains(type, targetSuperType)) { result.Add(type); } } return result; } private bool IsBaseTypeContains(System.Type type, System.Type targetSuperType) { if (type.BaseType == null) { return false; } if (type.BaseType == targetSuperType) { return true; } return IsBaseTypeContains(type.BaseType, targetSuperType); } } }