Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Custom Property Drawer Height and Width (SOLVED)

Discussion in 'Editor & General Support' started by GamezAtWork, May 6, 2017.

  1. GamezAtWork

    GamezAtWork

    Joined:
    Jan 12, 2013
    Posts:
    2
    Hey guys!

    So... I've been trying to create a Custom Property Drawer for one of my custom classes, and... well... I have no idea how to fix this height and width issue...

    Long story short, it looks like this:
    upload_2017-5-6_18-27-37.png
    Like, Script is supposed to be a Monobehaviour (which is actually filled up by the way), UI Image is supposed to be a Texture2D (which is ALSO filled up), and when you click on Script it makes the dropdown list appear instead, and ARGH.

    I would really like to find out why the width of this property drawer, the height of the property drawer, and all the elements' positions are all messed up, along with the interactable areas, and how to fix it.

    (By the way, the elements actually DO work as intended, just that their click areas are almost all wrong)

    Here is my code:

    Code (CSharp):
    1.     public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
    2.  
    3.         SerializedObject childObj = new UnityEditor.SerializedObject(property.objectReferenceValue as Command);
    4.         SerializedProperty ite = childObj.GetIterator();
    5.  
    6.         float totalHeight = EditorGUI.GetPropertyHeight (property, label);
    7.  
    8.         while (ite.NextVisible(true))
    9.         {
    10.             totalHeight += EditorGUI.GetPropertyHeight(ite, label);
    11.         }
    12.  
    13.  
    14.         return totalHeight;
    15.     }
    Code (CSharp):
    1. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
    2.  
    3.         allTypeStrings = new List<string>();
    4.         allTypes = Methods.GetSubclasses<Command>(true);
    5.         foreach(System.Type type in allTypes)
    6.         {
    7.             allTypeStrings.Add(type.Name);
    8.         }
    9.  
    10.         label = EditorGUI.BeginProperty(position, label, property);
    11.  
    12.         // Draw label
    13.         position = EditorGUI.PrefixLabel(position,  GUIUtility.GetControlID (FocusType.Passive), label);
    14.  
    15.         // Don't make child fields be indented
    16.         int indent = EditorGUI.indentLevel;
    17.         EditorGUI.indentLevel = 0;
    18.  
    19.         Rect classRect = new Rect(position.x, position.y, position.width, position.height);
    20.  
    21.         Command actualVal = property.objectReferenceValue as Command;
    22.         int currIndex = -1;
    23.         if (actualVal != null)
    24.         {
    25.             for (int j = 0; j < allTypeStrings.Count; ++j)
    26.             {
    27.                 if (allTypeStrings[j] == actualVal.GetType().Name)
    28.                     currIndex = j;
    29.             }
    30.         }
    31.  
    32.         EditorGUI.BeginChangeCheck ();
    33.  
    34.         int newIndex = EditorGUI.Popup(classRect, currIndex, allTypeStrings.ToArray());
    35.  
    36.         if (EditorGUI.EndChangeCheck())
    37.         {
    38.             property.objectReferenceValue = ScriptableObject.CreateInstance(allTypes[newIndex]);
    39.             //actualVal = ScriptableObject.CreateInstance(allTypes[newIndex]) as Command;
    40.             Debug.Log(property.objectReferenceValue);
    41.             Debug.Log("Changed to " + (property.objectReferenceValue as System.Object as Command).commandName);
    42.         }
    43.  
    44.         Command finalValue = property.objectReferenceValue as Command;
    45.  
    46.         if (finalValue != null)
    47.         {
    48.             EditorGUI.indentLevel = 1;
    49.  
    50.             SerializedObject childObj = new UnityEditor.SerializedObject(finalValue);
    51.  
    52.             Debug.Log("Child number is " + childObj.GetIterator().displayName);
    53.             SerializedProperty ite = childObj.GetIterator();
    54.             int i = 1;
    55.             while (ite.NextVisible(true))
    56.             {
    57.                 Debug.Log("Child is " + ite.displayName);
    58.                 Rect newRect = new Rect(position.x, position.y + i * 20, position.width, position.height);
    59.                 EditorGUI.PropertyField(newRect, ite);
    60.                 ++i;
    61.             }
    62.             childObj.ApplyModifiedProperties();
    63.         }
    64.  
    65.         // Set indent back to what it was
    66.         EditorGUI.indentLevel = indent;
    67.  
    68.         EditorGUI.EndProperty();
    69.  
    70.     }
     
    TwoHeadedDog likes this.
  2. GamezAtWork

    GamezAtWork

    Joined:
    Jan 12, 2013
    Posts:
    2
    Okay never mind I solved it!

    So apparently it was indeed a combination of multiple problems at once.

    Height Issue
    Firstly, I used position.height for the rects, which, i assume uses the value from GetPropertyHeight (the one I made). This kinda caused all of the properties to have the HUGE height of all the properties combined, which caused it to mess up.
    So I changed them from position.height to EditorGUI.GetPropertyHeight(property) and EditorGUI.GetPropertyHeight(ite), and that solved like almost all the problems.

    upload_2017-5-10_16-24-54.png

    Indentation Issue
    So the next problem was that everything was like SUPER INDENTED to the right (even when I remove the indent level thing), which was caused by this line:

    Code (CSharp):
    1. position = EditorGUI.PrefixLabel(position,  GUIUtility.GetControlID (FocusType.Passive), label);
    The rect which is outputted by the PrefixLabel actually was the area on the right of the Label, which means everything was squeezed into the right space. I mean, it could work in other cases, but I don't want that, so I fixed it by just removing the PrefixLabel and adding in the label into Popup instead, like so:

    Code (CSharp):
    1. int newIndex = EditorGUI.Popup(classRect, property.displayName, currIndex, allTypeStrings.ToArray());
    upload_2017-5-10_16-30-32.png

    Overlap with bottom
    For the last part, that was more a careless mistake than anything else.
    In my GetPropertyHeight function, I used while (ite.NextVisible(true)), but that meant that it will NOT execute on the first element, which means it will always be short of one element. Fixing it was trivial:

    Code (CSharp):
    1.         float totalHeight = EditorGUI.GetPropertyHeight (property, label, true);
    2.  
    3.         ite.Next(true);
    4.         totalHeight += EditorGUI.GetPropertyHeight(ite, label, true);
    5.  
    6.         while (ite.NextVisible(true))
    7.         {
    8.             totalHeight += EditorGUI.GetPropertyHeight(ite, label, true);
    9.         }
    10.  
    Final Result
    upload_2017-5-10_16-39-28.png

    Q.E.D (I hope)

    EDIT:

    That last part is wrong! It turns out that in the old case, it DOES add all the elements' heights, the REAL problem was that I forgot to take into account the vertical spacing between the elements when I placed them and when I calculated the height. These are the corrected bits:

    Code (CSharp):
    1.     public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
    2.  
    3.         SerializedObject childObj = new UnityEditor.SerializedObject(property.objectReferenceValue as Command);
    4.         SerializedProperty ite = childObj.GetIterator();
    5.  
    6.         float totalHeight = EditorGUI.GetPropertyHeight (property, label, true) + EditorGUIUtility.standardVerticalSpacing;
    7.  
    8.         while (ite.NextVisible(true))
    9.         {
    10.             totalHeight += EditorGUI.GetPropertyHeight(ite, label, true) + EditorGUIUtility.standardVerticalSpacing;
    11.         }
    12.  
    13.         return totalHeight;
    14.     }
    Code (CSharp):
    1.             SerializedObject childObj = new UnityEditor.SerializedObject(finalValue);
    2.  
    3.             SerializedProperty ite = childObj.GetIterator();
    4.             float prevHeight = EditorGUI.GetPropertyHeight(property, label, true);
    5.  
    6.             while (ite.NextVisible(true))
    7.             {
    8.                 Debug.Log("Child is " + ite.displayName);
    9.                 Rect newRect = new Rect(position.x, position.y + prevHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUI.GetPropertyHeight(ite, label, true));
    10.                 prevHeight += newRect.height + EditorGUIUtility.standardVerticalSpacing;
    11.                 EditorGUI.PropertyField(newRect, ite);
    12.             }
    13.             childObj.ApplyModifiedProperties();
     
    Last edited: May 10, 2017
  3. dsalisbury

    dsalisbury

    Joined:
    Mar 5, 2018
    Posts:
    4
    I just want to say thank you. The fact that you asked a question, didn't get an answer, figured it out on your own, and then came back to tell the rest of us makes you a gd hero. :)
     
  4. Bropoc

    Bropoc

    Joined:
    Sep 30, 2014
    Posts:
    8
    For real. It's a bad habit for this landscape where someone has a problem and we never get resolution. Woe be to us who suffer the same.
     
  5. WorkshopInProgress

    WorkshopInProgress

    Joined:
    Feb 21, 2019
    Posts:
    1
    This is honestly a more helpful answer than the Unity documentation on PropertyDrawers. I hadn't realized we could use EditorGUI functions in it.
     
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,909
    If you have feedback about the docs then do please use the rating function at the bottom of the page. It does take us time but we do respond to this feedback. We actually resolved over 1500 of them last week ;)
     
  7. VengadoraVG

    VengadoraVG

    Joined:
    Nov 21, 2015
    Posts:
    7
    property drawers implementation is unecessarily complex :S
     
  8. telgo

    telgo

    Joined:
    Dec 10, 2015
    Posts:
    6
    What rating function? I am not sure what you are referring to.

    My issue is with the TextSwitcher PropertyDrawer. I just want the text field to be big enough for several lines of text, but can't see how to do this.
     
  9. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,909
    I'm referring to this on each page of the docs
    upload_2020-3-26_15-56-8.png

    You can file a bug report regarding the TextSwitcher https://unity3d.com/unity/qa/bug-reporting
     
  10. telgo

    telgo

    Joined:
    Dec 10, 2015
    Posts:
    6
    Thanks for the prompt response. This isn't really a bug though, just missing info about the PropertyDrawer. I'll try anyway.
     
  11. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,909
unityunity