Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Indenting Foldouts in the Editor

Discussion in 'Immediate Mode GUI (IMGUI)' started by smarcus, Sep 9, 2009.

  1. smarcus

    smarcus

    Joined:
    Sep 18, 2007
    Posts:
    113
    Hey all...

    I'm working on a custom inspector and in an effort to tidy up the interface, I was wondering how to do staggered sublevels with the foldouts. Here's an example clip from the scene hierarchy:



    And here's what I have in my inspector:



    I'm using the EditorGUILayout classes and there doesn't seem to be a way to indent things a fixed amount (you can fake it with labels by adding spaces, but the controls are still aligned with the left edge, and the foldout arrows don't have integrated labels to pad).

    I've been experimenting with the BeginHorizontal() calls but these seem to evenly space the controls across the inspector, with no ability to control the spacing. Any ideas?

    thanks!
     
  2. Molix

    Molix

    Joined:
    Apr 24, 2009
    Posts:
    92
    Untested, but you can probably use something like:

    Code (csharp):
    1. EditorGUILayout.BeginVertical();
    2.   EditorGUILayout.Foldout(...); // parent foldout
    3.   EditorGUILayout.BeginHorizontal();
    4.     EditorGUILayout.Space();
    5.     EditorGUILayout.Foldout(...); // child foldout
    6.   EditorGUILayout.EndHorizontal();
    7. EditorGUILayout.EndVertical();
     
  3. smarcus

    smarcus

    Joined:
    Sep 18, 2007
    Posts:
    113
    I tried that-- it ends up spacing like this:

    ...the elements are spaced evenly across the horizontal. It's possible to chain a bunch together like so:

    Code (csharp):
    1.  
    2. EditorGUILayout.BeginVertical();
    3.   EditorGUILayout.Foldout(...); // parent foldout
    4.   EditorGUILayout.BeginHorizontal();
    5.     EditorGUILayout.Space();
    6.     EditorGUILayout.Foldout(...); // child foldout
    7.     EditorGUILayout.Space();
    8.     EditorGUILayout.Space();
    9.     EditorGUILayout.Space();
    10.     EditorGUILayout.Space();
    11.     EditorGUILayout.Space();
    12.     EditorGUILayout.Space();
    13.     EditorGUILayout.Space();
    14.     EditorGUILayout.Space();
    15.     EditorGUILayout.Space();
    16.     EditorGUILayout.Space();
    17.   EditorGUILayout.EndHorizontal();
    18. EditorGUILayout.EndVertical();
    19.  
    so that the foldout occurs at the 1/12 mark... But I feel like there must be a better way than that.
     
  4. Molix

    Molix

    Joined:
    Apr 24, 2009
    Posts:
    92
    This is kind of old now, but it looks like the foldouts are right aligned (rather than left). It would explain the behavior in both code samples.
     
  5. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Isn't the problem that it is a horizontal group instead of a vertical one?
     
  6. HQC

    HQC

    Joined:
    Oct 23, 2010
    Posts:
    1
    Up~,I also have this problem
     
  7. nicodrive

    nicodrive

    Joined:
    Jul 5, 2012
    Posts:
    14
    Sorry for necroposting.
    Answer for question is using GUILayout.Space(10) instead EditorGUILayout.Space(); in Molix code... may be this help some one
     
  8. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
    So, one Space() is then enough per tree row. Then:

    A
    |---B
    ....|---C

    Try having some descriptor struct, that contains both depth and content, like:

    Code (csharp):
    1. public struct Descriptor {
    2.     public int Depth;
    3.     public string Text;
    4. }
    5.  
    Then your nodes are:

    A {Depth = 0}
    B {Depth = 1}
    C {Depth = 2}

    And you have to loop through the array of descriptors, and for each:

    Code (csharp):
    1. EditorGUILayout.BeginHorizontal();
    2.     EditorGUILayout.Space(descriptor.Depth * 10); // or even GUILayout.Label("", GUILayout.Width(10));
    3.     EditorGUILayout.Foldout(...);
    4. EditorGUILayout.EndHorizontal();
     
  9. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
  10. athibodeau

    athibodeau

    Joined:
    Feb 10, 2014
    Posts:
    3
    FYI, unfortunately indentLevel doesn't apply to buttons. If you want them indented (ex: advanced operations), this works:

    EditorGUILayout.BeginHorizontal();
    EditorGUILayout.Space();
    EditorGUILayout.BeginVertical();

    if(GUILayout.Button("MyButton"))
    {
    // Do stuff.
    }

    EditorGUILayout.EndVertical();
    EditorGUILayout.EndHorizontal();

    The space is forced to be to the left of whatever is in the vertical group on the right.
     
  11. deram_scholzara

    deram_scholzara

    Joined:
    Aug 26, 2005
    Posts:
    1,043
    Old thread, but...

    So far as I can tell, the indent width seems to be about (exactly?) 15 pixels, and there's a 4 pixel margin at the edge of windows. So, you should be able to use:
    Code (CSharp):
    1. GUILayout.Space(indentLevel * 15 + 4);
    to get the indent spacing you need for GUILayout controls (such as Button()).

    Edit: Corrected the pixel count to 15 (had previously stated it was 16, but I've checked the source code and know better now).

    Edit2: Corrected the formula to always add an additional 4 pixels to compensate for the EditorWindow margin (which is also ignored by GUILayout).
     
    Last edited: Oct 16, 2016
    oferei likes this.
  12. G3al

    G3al

    Joined:
    Nov 28, 2014
    Posts:
    4
    "Old thread, but..."
    This thing here says - "To maximize future compatibility, do not make assumptions about what a specific indent level means..."
    https://docs.unity3d.com/ScriptReference/EditorGUI-indentLevel.html

    Now lets do just that:
    Code (CSharp):
    1. EditorGUI.indentLevel++;
    2.  
    3.         var texPreviewRect = EditorGUILayout.GetControlRect(false, 40);
    4.         texPreviewRect = EditorGUI.IndentedRect(texPreviewRect);
    5.         if(_prop_colorDistiortion.objectReferenceValue != null)
    6.         {
    7.             EditorGUI.DrawPreviewTexture(new Rect(texPreviewRect.x, texPreviewRect.y, 40, texPreviewRect.height), _prop_tex.objectReferenceValue as Texture);
    8.         }
    9.         else
    10.         {
    11.             EditorGUI.DrawPreviewTexture(new Rect(texPreviewRect.x, texPreviewRect.y, 40, texPreviewRect.height), Texture2D.whiteTexture);
    12.         }
    13.  
    14.         EditorGUI.indentLevel--;
    The key function in the above snippet is: recalculating the texPreviewRect using EditorGUI.IndentedRect(Rect source), for which i dont seem to find reference around the API, maybe its a new undocumented thing :), but basically it seems to applies the indentation to the passed rect value
     
  13. deram_scholzara

    deram_scholzara

    Joined:
    Aug 26, 2005
    Posts:
    1,043

    I'm back! So, here's what I ultimately decided is the most convenient way to do buttons in the Editor layout (short of Unity actually adding EditorGUILayout.Button):

    Code (CSharp):
    1.     private bool EditorButton(string label, params GUILayoutOption[] options)
    2.     {
    3.         bool clickedState = false;
    4.  
    5.         EditorGUILayout.BeginHorizontal();
    6.         {
    7.             var reservedSpace = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(options));
    8.  
    9.             if (GUI.Button(reservedSpace, label))
    10.             {
    11.                 clickedState = true;
    12.             }
    13.         }
    14.  
    15.         EditorGUILayout.EndHorizontal();
    16.  
    17.         return clickedState;
    18.     }
     
    richard_harrington and zwcloud like this.