Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Combining foldout and fields

Discussion in 'Immediate Mode GUI (IMGUI)' started by Estecka, Jul 25, 2018.

  1. Estecka

    Estecka

    Joined:
    Oct 11, 2013
    Posts:
    62
    It's not unusual when I I create a custom PropertyDrawer with folded properties, that I still want to draw a field (the most significant one) right in front of the foldout, so it can be accessed even when the property is folded :
    foldout.gif
    I find this looks nice, but I'm starting to get several issues with this layout.

    Here's a simple code that does just that, put a foldout arrow in front of a property :
    Code (CSharp):
    1. [CustomPropertyDrawer(typeof(KeyCode))]
    2. public class KeycodeDrawer : PropertyDrawer {
    3.     public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
    4.  
    5.         Rect foldoutPos = position;
    6.         //foldoutPos.width = 0;
    7.         property.isExpanded = EditorGUI.Foldout (foldoutPos, property.isExpanded, GUIContent.none);
    8.  
    9.         EditorGUI.PropertyField (position, property);
    10.  
    11.     }//
    12.  
    13. } // END Drawer
    If you run the code as is, the foldout arrow will work just fine, but you won't be able to select a keycode from the popup menu, like the foldout is blocking the way.
    The solution I had found to this is the commented line in the code above: setting the foldout's width to Zero.

    Now everything works nicely... or so it seems. From this solution arises issue n°2 :
    If you try making an array of keycode, instead of a single field, then the foldout arrow can no longer be clicked anymore.
     
  2. Estecka

    Estecka

    Joined:
    Oct 11, 2013
    Posts:
    62
    So, where does the inconsistency between array/single property come from ?
    And why does the foldout prevent from using its assigned rect, when it's not actually using this rect for anything ?
     
  3. PsyKaw

    PsyKaw

    Joined:
    Aug 16, 2012
    Posts:
    102
    Your foldout is too big. Try something like this:
    Code (CSharp):
    1. foldoutPos.width = EditorGUIUtility.labelWidth;
    instead of foldoutPos.width = 0;
    So the foldout interaction is only on the label of the property and you should interact with your property and foldout too.
     
    Estecka likes this.
  4. Estecka

    Estecka

    Joined:
    Oct 11, 2013
    Posts:
    62
    I eventually figured out what it is that makes array work differently from single property :
    EditorGUI.indentLevel
    is set to 1 in array and 0 otherwise.

    Apparently, every single control you draw will automatically be indented, so if you draw multiple controls on the same line, they will all have their own little indentation.
    (Their left bound will be moved to the right, but their right bound stays where it is, hence my zero-sized foldout arrow ends up with a negative width.)

    So the solution to draw everything at the exact place and with the exact size that you asked is to start the property drawer with either :
    Code (CSharp):
    1. position = EditorGUI.IndentedRect(position);
    2. EditorGUI.indentLevel = 0;
    or
    Code (CSharp):
    1. position = EditorGUI.PrefixLabel (position, label, EditorStyles.helpBox);
    2. EditorGUI.indentLevel = 0;
    Depending on what you're drawing

    I knew this was a thing with EditorGUILayout, but I did not expect EditorGUI to interact this way with the indentation. (Until now I believed that the position parameter provided to OnGUI was already pre-indented.)