Custom Property Drawer in List layout messed up

Hi all,
I’m having a weird trouble with custom Property Drawer. My current setup is like this (fairly complicated)
A Custom Editor Window that has:

  • A list that contains:
  • Class WheelInfo. That contains:
  • Struct SuspensionData.
    For SuspensionData drawer, I just followed the Unity Live Training, because I just want to replace the float’s with sliders, and foldouts to clean things up.
    For wheelInfo, same, Just to contain SuspensionData and some sliders.
    But things turns out like this:

    As you can see, the foldout of each element in the list is gone. The foldout for each suspensionData struct inside each WheelInfo is also gone, and the layout is messed up. I have no idea why this is happening, eventhough I’m following 100% the Live Training and the Documentation example.
    Here are the codes:
[CustomPropertyDrawer(typeof(WheelInfo))]
public class WheelInfoInspector : PropertyDrawer {

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        //base.OnGUI(position, property, label);
        EditorGUI.BeginProperty(position, label, property);
        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
EditorGUILayout.PropertyField(property.FindPropertyRelative("suspension"), true);
        EditorGUI.EndProperty();

}
[CustomPropertyDrawer(typeof(SuspensionData))]
public class SuspensionInspector : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        //base.OnGUI(position, property, label);
        EditorGUI.BeginProperty(position, label, property);
        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

    
            springFold = EditorGUILayout.Foldout(springFold, new GUIContent("Spring", "Spring Settings"), true);

            if (springFold)
            {
                EditorGUILayout.Slider(property.FindPropertyRelative("suspensionTravel"), 0f, 10f);
               }

        EditorGUI.EndProperty();
    }
}

By the way, is there a way to render the default property drawer, and then draw extra things along with the default layout?
Thank you very much.

Hey,

Don’t use EditorGUILayout in property drawers but instead EditorGUI or GUI. Because Property Drawer has a Rect in params of OnGUI which are reserved for drawer, if you put EditorGUILayout/GUILayout, it will be drawed after the reserved rect.

You can’t use PropertyDrawer if you want tot do that. You can do it with code in your Custom Editor Window.

2 Likes

Thank you very much for the reply.
So I cannot get lazy and has to calculate rect on my own now, no more auto layout :slight_smile:

Update. Now I’m having trouble with the layout of list:


Here is the code for a little head-up:

EditorGUI.PropertyField(new Rect(position.x, position.y, position.size.x / 3, EditorGUI.GetPropertyHeight(property.FindPropertyRelative("wheelController"))),
            property.FindPropertyRelative("wheelController"),
            new GUIContent("Wheel Controller", "The wheel Controller script of this wheel"));
        EditorGUI.PropertyField(new Rect(position.x + position.size.x / 3, position.y, position.size.x / 3, EditorGUI.GetPropertyHeight(property.FindPropertyRelative("wheelMesh"))),
            property.FindPropertyRelative("wheelMesh"),
            new GUIContent("Wheel Model", "The Mesh of this Wheel"));
        EditorGUI.PropertyField(new Rect(position.x + ((position.size.x / 3) * 2), position.y, position.size.x / 3, EditorGUI.GetPropertyHeight(property.FindPropertyRelative("wheelPos"))),
            property.FindPropertyRelative("wheelPos"),
            new GUIContent("Wheel Position", "The position of the current wheel on the rigidbody"));
        EditorGUI.Slider(new Rect(position.x, position.y + EditorGUI.GetPropertyHeight(property.FindPropertyRelative("wheelPos")), position.size.x / 2, EditorGUI.GetPropertyHeight(property.FindPropertyRelative("sprungMass"))),
            property.FindPropertyRelative("sprungMass"), 0, 2000,
            new GUIContent("Sprung Mass", "The mass this wheel is supporting"));

And inside the editor window class, the list containing the wheel info class is like this:

EditorGUILayout.PropertyField(wheelInfoListProperty, true);

So basically, the wheel info property drawer, I’m putting 3 property fields on one line, and then the next line is a slider. I got the position of the slider within the local property rect of current wheel info class right, but there is something wrong with the layout of the list.

I have no idea why the property fields are clogged up like this. Should the next element in the list automatically gets spaced out, and should be inside a foldout?
I would really appriciate any help, any reply, because I cannot find any documentation related to what I’m trying to do.

You have to specify the height of the drawer like this:

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
    int lineCount = 2;
    return EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount-1);
}
3 Likes

Oh man thank you so much for your help. The wheel info drawer is mostly done now, but I’m having trouble with the foldouts of suspension drawer


As you can see, the “spring” foldout opens but the height of the suspension drawer doesn’t change, and all the foldouts of the other elements also opens. The foldout thingy, I honestly have no idea why.
Here are the codes for suspension drawer:

 static bool springFold;
    static bool damperFold;
    static bool geoFold;
    static bool totalFold;
    static bool infoFold;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        //base.OnGUI(position, property, label);
        EditorGUI.BeginProperty(position, label, property);
        Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive) , label);
        EditorGUIUtility.labelWidth = 128;
       
        springFold = EditorGUI.Foldout(new Rect(pos.x, pos.y, 50, EditorGUIUtility.singleLineHeight), springFold,
            new GUIContent("Spring", "Spring Settings"), true);
        if (springFold)
        {
            springExtraLine = 2; //add lines if this foldout expands
            EditorGUI.Slider(new Rect(pos.x, pos.y + EditorGUIUtility.singleLineHeight, pos.size.x / 2, EditorGUIUtility.singleLineHeight),
                property.FindPropertyRelative("suspensionTravel"), 0, 20, new GUIContent("Travel", "The Maximum Length the spring can travel in m"));
            EditorGUI.Slider(new Rect(pos.x + pos.size.x / 2, pos.y + EditorGUIUtility.singleLineHeight, pos.size.x / 2, EditorGUIUtility.singleLineHeight),
                property.FindPropertyRelative("springRate"), 0, 100000, new GUIContent("Rate", "The Rate/Stiffness of the Spring in N/m"));
        }
        else { springExtraLine = 1; }
}
 public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        int totalLine = 3 + springExtraLine + damperExtraLine + geoExtraLine;

        return EditorGUIUtility.singleLineHeight * totalLine ;

    }

And here is wheel info drawer that contains suspension drawer:

 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
EditorGUI.PropertyField(new Rect(pos.x, pos.y + EditorGUIUtility.singleLineHeight * 2, pos.size.x, EditorGUI.GetPropertyHeight(property.FindPropertyRelative("suspension"))),
EditorGUI.BeginProperty(position, label, property);
Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
            property.FindPropertyRelative("suspension"), true);
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        //return base.GetPropertyHeight(property, label);
        int lineCount = 4;
        return EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount - 1);
    }

Would you mind helping me again? Thank you. I would post the full code if you need. I’m only posting snippets now because the full code is very long.
P.s: Unity really need to step up the documentation for editor scripting. There are so many "black magic’ stuffs.

You are welcome. :slight_smile:

SerializedProperty has a property isExpanded, you must use it for fold your property (so others elements foldout will not be expanded).
Don’t compute lineCount in OnGUI() because GetPropertyHeight() is called before it.
Do something like that:

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    //base.OnGUI(position, property, label);
    EditorGUI.BeginProperty(position, label, property);
    Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive) , label);
    EditorGUIUtility.labelWidth = 128;
  
    SerializedProperty travelProperty = property.FindPropertyRelative("suspensionTravel");
    travelProperty.isExpanded = EditorGUI.Foldout(new Rect(pos.x, pos.y, 50, EditorGUIUtility.singleLineHeight), travelProperty.isExpanded, new GUIContent("Spring", "Spring Settings"), true);
    if (travelProperty.isExpanded)
    {
        EditorGUI.Slider(new Rect(pos.x, pos.y + EditorGUIUtility.singleLineHeight, pos.size.x / 2, EditorGUIUtility.singleLineHeight), travelProperty, 0, 20, new GUIContent("Travel", "The Maximum Length the spring can travel in m"));
        EditorGUI.Slider(new Rect(pos.x + pos.size.x / 2, pos.y + EditorGUIUtility.singleLineHeight, pos.size.x / 2, EditorGUIUtility.singleLineHeight), property.FindPropertyRelative("springRate"), 0, 100000, new GUIContent("Rate", "The Rate/Stiffness of the Spring in N/m"));
    }
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
    int totalLine = 3;
  
    SerializedProperty travelProperty = property.FindPropertyRelative("suspensionTravel");
    if(travelProperty.isExpanded)
        totalLine ++;

    return EditorGUIUtility.singleLineHeight * totalLine + EditorGUIUtility.standardVerticalSpacing * (totalLine - 1);
}

It took me a couple of years to understand very well editor scripting :eyes:

10 Likes

You sir saved me from countless hours of headaches and sky-rocketed my progress :slight_smile:
Now just one more step and everything will be perfect. Is there a way to collapse/fold list elements just like how the original editor gui did? Right now what I’m having is this:


The property drawer of each element is perfect. However an ability to fold element would be better when the list gets long.

Again, thank you so much :slight_smile:

https://github.com/SubjectNerd-Unity/ReorderableInspector

PsyKaw you saved my butt with this post! I finally understand what GetPropertyHeight is doing thanks to you.

1 Like

WOW!!! I have to say, even on version 2022.2 this works a treat, words cannot explain how happy I was seeing what I wanted to happen actually happen :smile: . Thank you for your wisdom and consider me taught!