GUILayout ArgumentException when combining with GUI.Tooltip

Sample code:

GUILayout.BeginArea(new Rect(1620f, 150f, 290f, 560f));
GUILayout.BeginHorizontal("box");
GUILayout.Label("[TITLE]", new GUILayoutOption[]
{
	GUILayout.Height(40f)
});
GUILayout.EndHorizontal();
GUILayout.BeginVertical("box");
this.myToggle = GUILayout.Toggle(this.myToggle, new GUIContent("Toggle Title", "togglehint"));
GUILayout.EndVertical();
GUILayout.BeginVertical("box");
if (GUI.tooltip == "togglehint")
{
	GUILayout.Label("Hint Title");
	GUILayout.Label("Hint Body");
}
GUILayout.EndVertical();
GUILayout.FlexibleSpace();
GUILayout.EndArea();

Getting this error continuously:

ArgumentException: Getting control 0’s position in a group with only 0 controls when doing Repaint
Aborting at UnityEngine.GUILayoutGroup.GetNext ()

All I want is to make sure I display relevant tooltip because ugly primitive implementation like from the docs resource:

GUI.Label(new Rect(10, 40, 100, 40), GUI.tooltip);

Will display ANY tooltip regardless of group or area.

Well, the problem is that “GUI.tooltip” is set from inside GUIStyle.Draw. That means it’s content changes during the Repaint event. However since you check the tooltip in between elements you will mess up the layout system since during the layout event you would “draw” / call a different number of elements.

There are basically two solutions:

  • Either make sure you always draw the same number of elements, no matter what’s the content of “GUI.tooltip”.
  • Cache the tooltip at the end of your GUI code during the repaint event and use the cached version in your actual code. That way it won’t change in between.

First case:

GUILayout.BeginVertical("box");
if (GUI.tooltip == "togglehint")
{
    GUILayout.Label("Hint Title");
    GUILayout.Label("Hint Body");
}
else
{
    GUILayout.Label("");
    GUILayout.Label("");
}
GUILayout.EndVertical();

Second case:

    // [ ... ]
    GUILayout.BeginVertical("box");
    if (cachedTooltip == "togglehint")
    {
        GUILayout.Label("Hint Title");
        GUILayout.Label("Hint Body");
    }
    GUILayout.EndVertical();
    GUILayout.FlexibleSpace();
    GUILayout.EndArea();
    if (Event.current.type == EventType.Repaint)
        cachedTooltip = GUI.tooltip;
}

If you have many different tooltips you may want to just create a method that gets the tooltip text based on the “GUI.tooltip” string. That way you can always draw the tool tip gui elements. Just let the method return an empty string if you don’t want to display anything.

I would avoid showing the tooltip integrated in the actual layout. Keep in mind that showing the tooltip can change the layout which is actually quite nasty. Tooltips usually should be displayed either in a fix position or outside / on top of the layout.