Hello everyone,
I’ve been stuck with this problem for quite a while now, and I can’t find any related thread…
I’m trying to create a custom inspector for a list of scriptable objects.
Following this thread, I’ve been able to display the list (as a ReorderableList) as wanted:
I then tried to add a filter to this list: when the filter toggle is on, all the elements of the list with a type different than the one selected in the filter are removed (in the editor only).
Here is the result:
However, the size of the elements is not updated until I select an element:
Does anyone know how to force the ReorderableList to recalculate all sizes and positions ?
I tried countless things with no luck so far.
Here is all the related code:
Sentence.cs
using UnityEngine;
namespace Audio
{
[System.Serializable]
public class Sentence
{
public SentenceType type;
public AudioClip clip;
[Range(0f, 2f)]
public float volume = 1f;
[Range(.1f, 3f)]
public float pitch = 1f;
}
public enum SentenceType
{
Hello,
OhNo,
Loosers
}
}
VoiceStyle.cs
using Audio;
using UnityEngine;
[CreateAssetMenu(fileName = "New Voice Style", menuName = "Voice Style", order = 52)]
public class VoiceStyle : ScriptableObject
{
[SerializeField] private Sentence[] _sentences;
}
VoiceStyleEditor.cs (in Editor folder)
using UnityEngine;
using UnityEditor;
using Audio;
using UnityEditorInternal;
[CustomEditor(typeof(VoiceStyle))]
public class VoiceStyleEditor : Editor
{
private SerializedProperty sentenceList; //"Copy" of the Object.List
private ReorderableList sentenceReorderableList;
private bool shouldfilter = false;
private SentenceType filter;
private void OnEnable()
{
//Step 1: "link" the SerializedProperties to the properties of the Object
sentenceList = serializedObject.FindProperty("_sentences");
//Step 2: Setup the reorderableList
sentenceReorderableList = new ReorderableList(serializedObject, sentenceList)
{
draggable = true, //Can elements be dragged and their position changed?
displayAdd = true, //Can add elements with "+" button?
displayRemove = true, //Can remove elements with "-" button?
//Header of the list
drawHeaderCallback = rect =>
{
Rect offsetRect = new Rect(rect);
offsetRect.width *= 0.5f;
EditorGUI.LabelField(offsetRect, "Sentences");
//Filter
bool oldShouldFilter = shouldfilter;
SentenceType oldFilter = filter;
offsetRect.x += offsetRect.width;
offsetRect.width = 20;
shouldfilter = EditorGUI.Toggle(offsetRect, shouldfilter);
offsetRect.x += offsetRect.width;
offsetRect.width = rect.width / 2 - offsetRect.width;
GUI.enabled = shouldfilter;
filter = (SentenceType)EditorGUI.EnumPopup(offsetRect, filter);
GUI.enabled = true;
if(oldShouldFilter != shouldfilter || oldFilter != filter)
{
//TODO: Force all elements to recalculate size and position
}
},
//Setup how elements look like
drawElementCallback = (rect, index, active, focused) =>
{
SerializedProperty element = sentenceList.GetArrayElementAtIndex(index); //Get current element to be drawn
//Get elements property that defines name
string propName = ((SentenceType)element.FindPropertyRelative("type").intValue).ToString();
if (!shouldfilter || propName == filter.ToString())
{
//Draw the fields
Rect spaceRect = new Rect(rect.x + 10, rect.y, rect.width - 10, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(spaceRect, element, new GUIContent(propName));
if (element.isExpanded)
{
//Tabulation
spaceRect.x += 20;
spaceRect.width -= 20;
//Retreive all properties
SerializedProperty currProp = element.Copy();
SerializedProperty nextProp = element.Copy();
nextProp.Next(false);
if (currProp.Next(true))
{
do
{
if (SerializedProperty.EqualContents(currProp, nextProp))
break;
spaceRect.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(spaceRect, currProp);
} while (currProp.Next(false));
}
}
}
},
//Configure how tall elements are.
elementHeightCallback = index =>
{
SerializedProperty element = sentenceList.GetArrayElementAtIndex(index);
SentenceType type = (SentenceType)element.FindPropertyRelative("type").intValue;
if (shouldfilter && type != filter)
return 0;
if(element.isExpanded)
{
return EditorGUIUtility.singleLineHeight * element.CountInProperty();
}
return EditorGUIUtility.singleLineHeight;
},
//Set default values when adding new element (otherwise copy last item)
onAddCallback = list =>
{
// The new index will be the current List size before adding
var index = list.serializedProperty.arraySize;
// Since this method overwrites the usual adding, we have to do it manually:
// Simply counting up the array size will automatically add an element
list.serializedProperty.arraySize++;
list.index = index;
SerializedProperty element = list.serializedProperty.GetArrayElementAtIndex(index);
//Link the properties of the element in SerializedProperties that need to have special default value
SerializedProperty volume = element.FindPropertyRelative("volume");
SerializedProperty pitch = element.FindPropertyRelative("pitch");
SerializedProperty type = element.FindPropertyRelative("type");
//And set default values
volume.floatValue = 1f;
pitch.floatValue = 1f;
if (shouldfilter)
{
type.intValue = (int)filter;
}
}
};
}
public override void OnInspectorGUI()
{
//Copy the values of the real Class to the linked SerializedProperties
serializedObject.Update();
//Print the reorderable list
sentenceReorderableList.DoLayoutList();
//Apply the changed SerializedProperties values to the real class
serializedObject.ApplyModifiedProperties();
}
}