Capture the heights of GUILayout.Window to dynamically calculate tops of subsequent windows in edit

I thought it would be easy to dynamically lay out some windows in scene view, but the inner workings of Unity have me stymied.

I think the root of my problem stems from OnSceneGUI running twice before rendering the windows.

To see what’s happening:

  1. put a breakpoint at “CurWindow = GUILayout.Window (2, n…”
  2. select a gameobject that does NOT have OnSceneGUITester attached
  3. start debugging
  4. select the gameobject with OnSceneGUITester attached.
  5. notice how the windows are not yet rendered
  6. also note the value of WindowTop (150)
  7. continue execution
  8. on second break, note the value of WindowTop (231)
  9. continue execution
  10. the windows are rendered, but with tops at the first run of OnSceneGUI

I think it makes sense that the first Rects are rendered, since the second time GUILayout.Window is called, it will be ignored (or something) because the IDs are the same as first run.

What appears to be happening, to me, is Unity is initializing the window Rects and then calling OnSceneGUI again to change the Rect based on its contents.

I could hard code the Rect, but then I’d have to keep track of the heights of everything I put into each window.

Can anyone shed some light on why OnSceneGUI gets called twice?
Any workarounds that might let me dynamically layout the windows without having to manually track everthing in them?

****** Empty script OnSceneGUITester.cs:

using UnityEngine;
using System.Collections;

public class OnSceneGUITester : MonoBehaviour {

}

****** OnSceneGUITesterEditor.cs in Editor folder:

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor (typeof(OnSceneGUITester))]
public class OnSceneGUITesterEditor : Editor
{

    float WindowTop;

    public void OnSceneGUI ()
    {

        WindowTop = 100f;

        Rect CurWindow = GUILayout.Window (1, new Rect (10, WindowTop, 50, 50), (id) => {
            GUILayout.Label ("Some Label Text");
            GUILayout.Label ("Some Label Text");
            GUILayout.Label ("Some Label Text");
            GUILayout.Label ("Some Label Text");
            GUILayout.Label ("Some Label Text");
            GUILayout.Label ("Some Label Text");
        }, "title");


        WindowTop += CurWindow.height;

        CurWindow = GUILayout.Window (2, new Rect (10, WindowTop, 50, 50), (id) => {
            GUILayout.Label ("Some Other Label Text");
        }, "title");


        WindowTop += CurWindow.height;

        GUILayout.Window (3, new Rect (10, WindowTop, 50, 50), (id) => {
            GUILayout.Label ("Some Other Label Text");
        }, "title");

    }
}

OnGUI and its buddies can be called two or more times every frame, depending on what exactly happens during that frame. The most common: once for layout, once for drawing. There’s also one call for every input event received, so if your user has moved the mouse, clicked the mouse, and pressed a key in the same frame (or between redraws), that’s three more calls.

Event.current holds a reference to the current event for which OnGUI is being called this time, and it should have all the information you need.

1 Like

Thanks for your suggestion StarManta, however, I’m not sure how I can use it.

How would I use Event.current to limit the rendering of the windows to use the correct Rect height?

Sorry if I’m being obtuse, I’m just not seeing it.
Maybe I’m approaching this all wrong.

The OnGUI() system is great for doing simple stuff in code, but I have to warn you that a lot of people dislike it, even though Unity3D itself is actually written using it.

I use OnGUI a lot, but the only thing I do is to display data with it, and capture events by setting boolean flags, or adjusting a temporary variable (like a volume slider).

Do all of your logical “heavy lifting” inside an Update() routine such that you can reliably know how long it has been since the last update, do validation, etc. Do not do any kind of logic program flow control inside of OnGUI()-type methods.

Also, please be sure to view the second sticky post on the top of the forum for code formatting guidelines.

This explanation helped me.

Thanks Kurt and Bored,

I’m working in edit mode, so update doesn’t get called.
The video gave me a little more insight, but probably applies more to manually keeping track of content rather than using the auto-layout that happens.

Looks like trying to capture the heights of the windows and use them may be too much ask or too complicated to reasonably implement.
I think I’m going to have to bite the bullet and keep track of everything if I want to get my windows to lay out like I want.