Search Unity

GUILayoutUtility.GetRect with inconsistent results

Discussion in 'Immediate Mode GUI (IMGUI)' started by nafonso, Jan 14, 2008.

  1. nafonso

    nafonso

    Joined:
    Aug 10, 2006
    Posts:
    377
    I'm trying to get the Rect of a button and I try the following code:
    Code (csharp):
    1. // options is an array of GUILayoutOption
    2. Rect areaRect = GUILayoutUtility.GetRect( new GUIContent("text"), "button", options );
    3. GUILayout.BeginArea( areaRect );
    4. Debug.Log( areaRect );
    5. GUILayout.Label( textBefore, "label centered" );
    6. GUILayout.EndArea();
    However, in the console I get the following output:
    Is there a bug with that GUILayout.GetRect function? I have the same behaviour with each GetRect that I pass the GUILayoutOptions.

    One thing worth noting is that the label is never visible. If I hardcore the rect to the value (left:0.00, top57.00, width150.00, height19.00), which is the one it was supposed to always return, the label is drawn correctly.
     
  2. KlaRo115

    KlaRo115

    Joined:
    Feb 24, 2006
    Posts:
    675
    Try this...
    Code (csharp):
    1. function OnGUI () {
    2.     if (GUI.Button (Rect (1,1,200,25), "I'm a buttom...")) {
    3.         print ("Nothing happens...");
    4.     }
    5. }
     
  3. KlaRo115

    KlaRo115

    Joined:
    Feb 24, 2006
    Posts:
    675
    Attach this script to a GUItexture...
    8)
     
  4. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    You use GUILayoutUtility.GetRect to generate a rect for normal GUI

    So you would do something like this:
    Code (csharp):
    1.  
    2. Rect areaRect= GUILayoutUtility.GetRect ("Text label", GetRect( new GUIContent("text"), "button", );
    3. if (GUI.Button (areaRect, "text"))
    4.    Debug.Log ("ASDF");
    5.  
    Unless you are doing truly weird stuff, You would not pass in a rect to GUILayout that is generated this way.

    If you zoom out a bit, what is it that you're trying to accomplish?
     
  5. nafonso

    nafonso

    Joined:
    Aug 10, 2006
    Posts:
    377
    Well, what I'm trying to do is this:


    It is a button that will not only react to clicks but also to key shortcuts.

    The button is working (however the keyboard events are not being caught yet, don't realize why either).

    The screenshot is with the rect for the BeginArea hardcoded. If I use the following code, I get those inconsistencies posted in the first post:

    Code (csharp):
    1. public class GUILayoutExtras {
    2.     public static Color m_shortcutTextColor = new Color( 0.75f, 0.35f, 0.05f );
    3.    
    4.     public static bool ShortcutButton( string text, params GUILayoutOption[] options ){
    5.         string[] textParts = text.Split('');
    6.        
    7.         string textBefore = textParts[0];
    8.         string textShortcut = textParts[1].Substring(0,1);
    9.         string textAfter = textParts[1].Substring(1);
    10.        
    11.         bool buttonClicked = GUILayout.Button("", options);
    12.        
    13.         Rect areaRect = GUILayoutUtility.GetRect( new GUIContent("text"), "button", options );//new Rect(0,37,150,19);
    14.        
    15.         GUILayout.BeginArea( areaRect );
    16. //      Debug.Log( areaRect );
    17.  
    18.         GUILayout.BeginHorizontal();
    19.             GUILayout.FlexibleSpace();
    20.             GUILayout.Label( textBefore, "label centered" );
    21.  
    22.             Color previousColor = GUI.contentColor;
    23.             GUI.contentColor = m_shortcutTextColor;
    24.             GUILayout.Label( textShortcut, "label centered" );
    25.             GUI.contentColor = previousColor;
    26.  
    27.             GUILayout.Label( textAfter, "label centered" );
    28.             GUILayout.FlexibleSpace();
    29.         GUILayout.EndHorizontal();
    30.         GUILayout.EndArea();
    31.        
    32.         return buttonClicked || Event.current.Equals( Event.KeyboardEvent(textShortcut.ToLower()) ) || Event.current.Equals( Event.KeyboardEvent("#"+textShortcut.ToLower()));
    33.     }
    34. }
    35.  
    I have to create the BeginArea to make the text be on top of the button, and I need to know the size of the button to make the label of the button right in the middle of it.

    Btw, is one of my wishes is that the GUI buttons supported something like GUILayout.Button("&New Game") and would return true if we pressed on 'n' or clicked on the button. Is such a feature planned?
     
  6. Brian-Kehrer

    Brian-Kehrer

    Joined:
    Nov 7, 2006
    Posts:
    411
    I'm also getting flickering values on GUILayoutUtility.GetRect
    between the actual rect, and Rect(0,0,0,0)

    I have solved it with an if check to discard anything below a threshold, but this seems like unintended behavior.
     
  7. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    That is the intended behaviour.

    UnityGUI first sends a layout event in order to record all calls to GetRect - then it calculates all layouting so it can return something sensible on the "real" event call.

    so when Event.current.type == EventType.Layout, we do not have a rect yet, so we just return (0,0,0,0) - however, all other GUI code does not do anything when it's layouting, so that is ok.
     
  8. Brian-Kehrer

    Brian-Kehrer

    Joined:
    Nov 7, 2006
    Posts:
    411
    I meant the need to check if values are zero.

    I'm building my own scroll box, and pulling the rect.height into the vertical scrollbar.
    I guess I'm hacking the GUILayoutUtility to calculate a rect for me, I haven't come up with a better way yet.

    However, my scrollbar goes nuts when I build this, or often doesn't work at all.

    I moved the height calculations into update and check to make sure it's non-zero. Then it works pretty well, smoothed scrolling (with my scrollbar on the left)
    Code (csharp):
    1.  
    2.  
    3. function Update (){
    4. var scrollDif = (Mathf.Round(scrollPosition)- actualScroll);
    5.     if(Mathf.Abs(scrollDif) > .01){
    6.         actualScroll = (actualScroll + 4*Time.deltaTime*scrollDif);
    7.     }
    8.     else{
    9.        
    10.         scrollPosition = Mathf.FloorToInt(scrollPosition);
    11.         actualScroll = Mathf.Clamp(scrollPosition,0,scrollHeight);//return to int pixel space
    12.        
    13.     }
    14. }
    15. function SomeGUIFunction(id : int){
    16. var test : GUIContent = new GUIContent(tmpJournal);
    17.     scrollRect = GUILayoutUtility.GetRect(test, "Copy",GUILayout.Width(390));
    18.     scrollHeight = scrollRect.height;
    19.     scrollPosition = GUI.VerticalScrollbar(Rect(20,80,10,390),scrollPosition,390.0,0.0,scrollHeight);  
    20.        
    21.  
    22.  
    23.     var pos = new Vector3(35,80-actualScroll,0);
    24.     var q =  Quaternion(0,0,0,1);
    25.     var s = new Vector3(1,1,1);
    26.     var tMatrix : Matrix4x4 = Matrix4x4.TRS(pos, q, s);
    27.     GUI.matrix = tMatrix;//scrollbar offset
    28.         GUI.BeginGroup(Rect(0,actualScroll,390,392));//clipping
    29.             GUI.Label(Rect(0,-actualScroll,390,scrollHeight),tmpJournal, "Copy");
    30.         GUI.EndGroup();                
    31.     pos = Vector3(0,0,0);
    32.     tMatrix= Matrix4x4.TRS(pos, q, s);
    33.     GUI.matrix = tMatrix;  
    34. }
    35.  
    EDIT: After reading your message again, I've done this.. Thanks for the help.
    Code (csharp):
    1.  
    2. if (Event.current.type == EventType.Repaint){
    3.             scrollHeight = scrollRect.height;
    4.         }
    5.