private void CreateListData(SerializedProperty property) { var parent = GetGrandParentPath(property); // Try to find the grand parent in SortableListData var data = listIndex.Find(listData => listData.Parent.Equals(parent)); if (data == null) { data = new SortableListData(parent); listIndex.Add(data); } data.AddProperty(property); var attr = property.GetAttributes <ReorderableAttribute>(); if (attr != null && attr.Length == 1) { var arrayAttr = (ReorderableAttribute)attr[0]; if (arrayAttr != null) { HandleReorderableOptions(arrayAttr, property, data); } } }
private void CreateListData(SerializedProperty property) { string parent = GetGrandParentPath(property); // Try to find the grand parent in SortableListData SortableListData data = listIndex.Find(listData => listData.Parent.Equals(parent)); if (data == null) { data = new SortableListData(parent); listIndex.Add(data); } data.AddProperty(property); object[] attr = property.GetAttributes <SortableArrayAttribute>(); if (attr != null && attr.Length == 1) { SortableArrayAttribute arrayAttr = (SortableArrayAttribute)attr[0]; if (arrayAttr != null && string.IsNullOrEmpty(arrayAttr.ElementHeader) == false) { data.ElementHeaderCallback = delegate(int i) { return(string.Format("{0} {1}", arrayAttr.ElementHeader, (arrayAttr.HeaderZeroIndex ? i : i + 1))); }; } } }
/// <summary> /// Given a SerializedProperty, return the automatic ReorderableList assigned to it if any /// </summary> /// <param name="property"></param> /// <returns></returns> protected ReorderableList GetSortableList(SerializedProperty property) { if (listIndex.Count == 0) { return(null); } string parent = GetGrandParentPath(property); SortableListData data = listIndex.Find(listData => listData.Parent.Equals(parent)); if (data == null) { return(null); } return(data.GetPropertyList(property)); }
/// <summary> /// Set a drag and drop handler function on a SerializedObject's ReorderableList, if any /// </summary> /// <param name="property"></param> /// <param name="handler"></param> /// <returns></returns> protected bool SetDragDropHandler(SerializedProperty property, Action <SerializedProperty, Object[]> handler) { if (listIndex.Count == 0) { return(false); } string parent = GetGrandParentPath(property); SortableListData data = listIndex.Find(listData => listData.Parent.Equals(parent)); if (data == null) { return(false); } data.SetDropHandler(property, handler); return(true); }
/// <summary> /// Draw a SerializedProperty as a ReorderableList if it was found during /// initialization, otherwise use EditorGUILayout.PropertyField /// </summary> /// <param name="property"></param> protected void DrawPropertySortableArray(SerializedProperty property) { // Try to get the sortable list this property belongs to SortableListData listData = null; if (listIndex.Count > 0) { listData = listIndex.Find(data => property.propertyPath.StartsWith(data.Parent)); } if (listData != null) { // Try to show the list if (listData.DoLayoutProperty(property) == false) { EditorGUILayout.PropertyField(property, false); if (property.isExpanded) { EditorGUI.indentLevel++; SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); IterateSerializedProp(targetProp); EditorGUI.indentLevel--; } } } else { SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); bool restoreEnable = GUI.enabled; if (targetProp.propertyPath.StartsWith("m_")) { GUI.enabled = false; } EditorGUILayout.PropertyField(targetProp, targetProp.isExpanded); GUI.enabled = restoreEnable; } }
/// <summary> /// Draw a SerializedProperty as a ReorderableList if it was found during /// initialization, otherwise use EditorGUILayout.PropertyField /// </summary> /// <param name="property"></param> protected void DrawPropertySortableArray(SerializedProperty property) { // Try to get the sortable list this property belongs to SortableListData listData = null; if (listIndex.Count > 0) { listData = listIndex.Find(data => property.propertyPath.StartsWith(data.Parent)); } Editor scriptableEditor; bool isScriptableEditor = editableIndex.TryGetValue(property.propertyPath, out scriptableEditor); // Has ReorderableList if (listData != null) { // Try to show the list if (listData.DoLayoutProperty(property) == false) { EditorGUILayout.PropertyField(property, false); if (property.isExpanded) { EditorGUI.indentLevel++; SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); IterateDrawProperty(targetProp); EditorGUI.indentLevel--; } } } // Else try to draw ScriptableObject editor else if (isScriptableEditor) { bool hasHeader = property.HasAttribute <HeaderAttribute>(); bool hasSpace = property.HasAttribute <SpaceAttribute>(); float foldoutSpace = hasHeader ? 24 : 7; if (hasHeader && hasSpace) { foldoutSpace = 31; } hasSpace |= hasHeader; // No data in property, draw property field with create button if (scriptableEditor == null) { bool doCreate; using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PropertyField(property, uiExpandWidth); using (new EditorGUILayout.VerticalScope(uiWidth50)) { if (hasSpace) { GUILayout.Space(10); } doCreate = GUILayout.Button(labelBtnCreate, EditorStyles.miniButton); } } if (doCreate) { Type propType = property.GetTypeReflection(); var createdAsset = CreateAssetWithSavePrompt(propType, "Assets"); if (createdAsset != null) { property.objectReferenceValue = createdAsset; property.isExpanded = true; } } } // Has data in property, draw foldout and editor else { EditorGUILayout.PropertyField(property); Rect rectFoldout = GUILayoutUtility.GetLastRect(); rectFoldout.width = 20; if (hasSpace) { rectFoldout.yMin += foldoutSpace; } property.isExpanded = EditorGUI.Foldout(rectFoldout, property.isExpanded, GUIContent.none); if (property.isExpanded) { EditorGUI.indentLevel++; using (new EditorGUILayout.VerticalScope(styleEditBox)) { var restoreIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 1; scriptableEditor.serializedObject.Update(); scriptableEditor.OnInspectorGUI(); scriptableEditor.serializedObject.ApplyModifiedProperties(); EditorGUI.indentLevel = restoreIndent; } EditorGUI.indentLevel--; } } } else { SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); bool isStartProp = targetProp.propertyPath.StartsWith("m_"); using (new EditorGUI.DisabledScope(isStartProp)) { EditorGUILayout.PropertyField(targetProp, targetProp.isExpanded); } } }
private void HandleReorderableOptions(ReorderableAttribute arrayAttr, SerializedProperty property, SortableListData data) { // Custom element header if (string.IsNullOrEmpty(arrayAttr.ElementHeader) == false) { data.ElementHeaderCallback = i => string.Format("{0} {1}", arrayAttr.ElementHeader, (arrayAttr.HeaderZeroIndex ? i : i + 1)); } // Draw property as single line if (arrayAttr.ElementSingleLine) { var list = data.GetPropertyList(property); #if UNITY_5_3_OR_NEWER list.elementHeightCallback = index => EditorGUIUtility.singleLineHeight + 6; list.drawElementBackgroundCallback = (rect, index, active, focused) => { if (focused == false) { return; } if (styleHighlight == null) { styleHighlight = GUI.skin.FindStyle("MeTransitionSelectHead"); } GUI.Box(rect, GUIContent.none, styleHighlight); }; #endif list.drawElementCallback = (rect, index, active, focused) => { var element = property.GetArrayElementAtIndex(index); element.isExpanded = false; int childCount = data.GetElementCount(property); if (childCount < 1) { return; } rect.y += 3; rect.height -= 6; if (element.NextVisible(true)) { float restoreWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth /= childCount; float padding = 5f; float width = rect.width - padding * (childCount - 1); width /= childCount; Rect childRect = new Rect(rect) { width = width }; int depth = element.Copy().depth; do { if (element.depth != depth) { break; } if (childCount <= 2) { EditorGUI.PropertyField(childRect, element, false); } else { EditorGUI.PropertyField(childRect, element, GUIContent.none, false); } childRect.x += width + padding; } while (element.NextVisible(false)); EditorGUIUtility.labelWidth = restoreWidth; } }; } }
private void CreateListData(SerializedProperty property) { string parent = GetGrandParentPath(property); // Try to find the grand parent in SortableListData SortableListData data = listIndex.Find(listData => listData.Parent.Equals(parent)); if (data == null) { data = new SortableListData(parent); listIndex.Add(data); } data.AddProperty(property); }
/// <summary> /// Draw a SerializedProperty as a ReorderableList if it was found during /// initialization, otherwise use EditorGUILayout.PropertyField /// </summary> /// <param name="property"></param> protected void DrawPropertySortableArray(SerializedProperty property) { // Try to get the sortable list this property belongs to SortableListData listData = null; if (listIndex.Count > 0) { listData = listIndex.Find(data => property.propertyPath.StartsWith(data.Parent)); } Editor scriptableEditor; bool isScriptableEditor = editableIndex.TryGetValue(property.propertyPath, out scriptableEditor); if (listData != null) { // Try to show the list if (listData.DoLayoutProperty(property) == false) { EditorGUILayout.PropertyField(property, false); if (property.isExpanded) { EditorGUI.indentLevel++; SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); IterateDrawProperty(targetProp); EditorGUI.indentLevel--; } } } else if (isScriptableEditor) { if (scriptableEditor == null) { using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PropertyField(property, uiExpandWidth); if (GUILayout.Button(labelBtnCreate, EditorStyles.miniButton, uiWidth50)) { Type propType = property.GetTypeReflection(); var createdAsset = CreateAssetWithSavePrompt(propType, "Assets"); if (createdAsset != null) { property.objectReferenceValue = createdAsset; } } } } else { EditorGUILayout.PropertyField(property); Rect rectFoldout = GUILayoutUtility.GetLastRect(); rectFoldout.width = 20; property.isExpanded = EditorGUI.Foldout(rectFoldout, property.isExpanded, GUIContent.none); if (property.isExpanded) { EditorGUI.indentLevel++; scriptableEditor.OnInspectorGUI(); GUILayout.Box(GUIContent.none, uiHeight2, uiExpandWidth); EditorGUI.indentLevel--; } } } else { SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); bool isStartProp = targetProp.propertyPath.StartsWith("m_"); using (new EditorGUI.DisabledScope(isStartProp)) { EditorGUILayout.PropertyField(targetProp, targetProp.isExpanded); } } }
private void HandleReorderableOptions(ReorderableAttribute arrayAttr, SerializedProperty property, SortableListData data) { // Custom element header if (string.IsNullOrEmpty(arrayAttr.ElementHeader) == false) { data.ElementHeaderCallback = i => string.Format("{0} {1}", arrayAttr.ElementHeader, (arrayAttr.HeaderZeroIndex ? i : i + 1)); } // Draw property as single line if (arrayAttr.ElementSingleLine) { var list = data.GetPropertyList(property); list.elementHeightCallback = index => EditorGUIUtility.singleLineHeight; list.drawElementCallback = (rect, index, active, focused) => { var element = property.GetArrayElementAtIndex(index); int childCount = element.Copy().CountRemaining(); childCount -= (property.arraySize - 1) - index; if (element.NextVisible(true)) { float restoreWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth /= childCount; float padding = 5f; float width = rect.width - padding * (childCount - 1); width /= childCount; Rect childRect = new Rect(rect) { width = width }; int depth = element.Copy().depth; do { if (element.depth != depth) { break; } if (childCount <= 2) { EditorGUI.PropertyField(childRect, element, false); } else { EditorGUI.PropertyField(childRect, element, GUIContent.none, false); } childRect.x += width + padding; } while (element.NextVisible(false)); EditorGUIUtility.labelWidth = restoreWidth; } }; } }
/// <summary> /// Draw a SerializedProperty as a ReorderableList if it was found during /// initialization, otherwise use EditorGUILayout.PropertyField /// </summary> /// <param name="property"></param> protected void DrawPropertySortableArray(SerializedProperty property) { // Try to get the sortable list this property belongs to SortableListData listData = null; if (listIndex.Count > 0) { listData = listIndex.Find(data => property.propertyPath.StartsWith(data.Parent)); } Editor scriptableEditor; bool isScriptableEditor = editableIndex.TryGetValue(property.propertyPath, out scriptableEditor); // Has ReorderableList if (listData != null) { // Try to show the list if (listData.DoLayoutProperty(property) == false) { EditorGUILayout.PropertyField(property, false); if (property.isExpanded) { EditorGUI.indentLevel++; SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); IterateDrawProperty(targetProp); EditorGUI.indentLevel--; } } } // Else try to draw ScriptableObject editor else if (isScriptableEditor) { bool hasHeader = property.HasAttribute <HeaderAttribute>(); bool hasSpace = property.HasAttribute <SpaceAttribute>(); float foldoutSpace = hasHeader ? 24 : 7; if (hasHeader && hasSpace) { foldoutSpace = 31; } hasSpace |= hasHeader; // No data in property, draw property field with create button if (scriptableEditor == null) { bool doCreate; List <Type> subclasses = new List <Type>(); using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PropertyField(property, uiExpandWidth); using (new EditorGUILayout.VerticalScope(uiWidth50)) { using (new EditorGUILayout.HorizontalScope()) { Type propType = property.GetTypeReflection(); subclasses = Assembly.GetAssembly(propType).GetTypes().Where(x => x.IsSubclassOf(propType)).ToList(); if (subclasses.Count > 0) { string keyname = this.GetType().Name + target.name; if (!nv.editor.EditorData.Instance.HasData <int>(keyname, property.propertyPath)) { nv.editor.EditorData.Instance.SetData <int>(0, keyname, property.propertyPath); } int selection = nv.editor.EditorData.Instance.GetData <int>(keyname, property.propertyPath); selection = EditorGUILayout.Popup(selection, subclasses.Select(x => x.Name).ToArray()); nv.editor.EditorData.Instance.SetData <int>(selection, keyname, property.propertyPath); } if (hasSpace) { GUILayout.Space(10); } doCreate = GUILayout.Button(labelBtnCreate, EditorStyles.miniButton); } } } if (doCreate) { string keyname = this.GetType().Name + target.name; Type propType = property.GetTypeReflection(); if (subclasses.Count > 0) { int selection = nv.editor.EditorData.Instance.GetData <int>(keyname, property.propertyPath); propType = subclasses[selection]; } string pwd = nv.editor.EditorData.Instance.GetData <string>(keyname, property.propertyPath); if (string.IsNullOrEmpty(pwd)) { pwd = Application.dataPath; } var createdAsset = CreateAssetWithSavePrompt(propType, ref pwd); if (createdAsset != null) { nv.editor.EditorData.Instance.SetData <string>(pwd, keyname, property.propertyPath); property.objectReferenceValue = createdAsset; property.isExpanded = true; } } } // Has data in property, draw foldout and editor else { EditorGUILayout.PropertyField(property); Rect rectFoldout = GUILayoutUtility.GetLastRect(); rectFoldout.width = 20; if (hasSpace) { rectFoldout.yMin += foldoutSpace; } property.isExpanded = EditorGUI.Foldout(rectFoldout, property.isExpanded, GUIContent.none); if (property.isExpanded) { EditorGUI.indentLevel++; using (new EditorGUILayout.VerticalScope(styleEditBox)) { var restoreIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 1; scriptableEditor.serializedObject.Update(); scriptableEditor.OnInspectorGUI(); scriptableEditor.serializedObject.ApplyModifiedProperties(); EditorGUI.indentLevel = restoreIndent; } EditorGUI.indentLevel--; } } } else { SerializedProperty targetProp = serializedObject.FindProperty(property.propertyPath); bool isStartProp = targetProp.propertyPath.StartsWith("m_"); #if UNITY_5_5_OR_NEWER using (new EditorGUI.DisabledScope(isStartProp)) { EditorGUILayout.PropertyField(targetProp, targetProp.isExpanded); } #else EditorGUI.BeginDisabledGroup(isStartProp); EditorGUILayout.PropertyField(targetProp, targetProp.isExpanded); EditorGUI.EndDisabledGroup(); #endif } }