FoldoutHeader with Toggle

I’m trying to create this kind of control, just a standard FoldoutHeader with a Toggle.

image

I got this to work with GUILayout methods, but when I draw it through EditorGUI, the Toggle ignores all the clicks and just the FoldoutHeader captures them.

This is the working GUILayout version:

public static bool FoldoutTogglePropertyHeader(bool foldout, GUIContent label, ref bool boolValue, params GUILayoutOption[] options)
{
    var e = Event.current;
    var bgColor = GUI.backgroundColor;

    using (new GUILayout.HorizontalScope())
    {
        GUILayout.Space(CurrentIndentWidth);
        
        using (new GUILayout.HorizontalScope(EditorStyles.foldoutHeader, options))
        {
            GUILayout.Space(-16);
            GUILayout.Label(foldout ? "▼" : "►", LBEditorGUILayout.foldoutLabelStyle, GUILayout.Width(20));
            
            boolValue = GUILayout.Toggle(boolValue, "", GUILayout.Width(20));

            GUILayout.Label(label);
        }

        if (e.type == EventType.MouseDown)
        {
            var rect = GUILayoutUtility.GetLastRect();
            if (rect.Contains(e.mousePosition))
                foldout = !foldout;
        }
    }

    GUI.backgroundColor = bgColor;

    return foldout;
}

Any ideas on why this happen?

And this is the non-working EditorGUI version:

 public static bool FoldoutTogglePropertyHeader(Rect rect, bool foldout, GUIContent label, ref bool boolValue)
 {
     var indentWidth = LBGUILayout.CurrentIndentWidth + LBGUILayout.SingleIndentWidth;

     var foldoutRect = new Rect(rect) { x = rect.x + indentWidth - 3, width = rect.width - indentWidth + 3 };
     foldout = EditorGUI.BeginFoldoutHeaderGroup(foldoutRect, foldout, GUIContent.none);
     EditorGUI.EndFoldoutHeaderGroup();

     var toggleRect = new Rect(rect) { x = rect.x + 20, width = 140 };
     boolValue = EditorGUI.ToggleLeft(toggleRect, GUIContent.none, boolValue);
     
     var labelRect = new Rect(rect) { x = rect.x + 40, width = rect.width - 40 };
     EditorGUI.LabelField(labelRect, label);

     return foldout;
 }

Well, this was quite unexpected. After trying every logical workaround I could think about, nothing seemed to work. So I started trying random things. One of them worked.

If you first draw the Toggle and, after that, you draw the FoldoutHeader on top, the Toggle detects the clicks again ??¿?¿?

And just to make the drawing of the Toggle consistent, you need to draw it again on top of the FoldoutHeader.

This is the working code I’m using right now.

// --------------------------------------------------
public static bool FoldoutTogglePropertyHeader(Rect rect, bool foldout, GUIContent label, ref bool boolValue)
{
    var indentWidth = LBGUILayout.CurrentIndentWidth + LBGUILayout.SingleIndentWidth;

    // First draw the Toggle
    var toggleRect = new Rect(rect) { x = rect.x + 20, width = 50 };
    boolValue = EditorGUI.ToggleLeft(toggleRect, GUIContent.none, boolValue);
    
    // Then draw the FoldoutHeader on top
    var foldoutRect = new Rect(rect) { x = rect.x + indentWidth - 3, width = rect.width - indentWidth + 3 };
    foldout = EditorGUI.BeginFoldoutHeaderGroup(foldoutRect, foldout, GUIContent.none);
    EditorGUI.EndFoldoutHeaderGroup();

    // Draw the Toggle again on top
    EditorGUI.ToggleLeft(toggleRect, GUIContent.none, boolValue);

    var labelRect = new Rect(rect) { x = rect.x + 40, width = rect.width - 40 };
    EditorGUI.LabelField(labelRect, label);


    return foldout;
}