Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Making a Proper Drawer similar to Vector3 -- how?

Discussion in 'Scripting' started by Tony-Lovell, Feb 11, 2016.

  1. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    127
    I am trying to follow the docs on Property Drawers, and have gotten close to the right thing.

    I have my own struct, similar to Vector3, but in which the x,y,z components are double rather than float.

    The pertinent part of the struct, I suppose, is this:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4.     [System.Serializable]
    5.     public struct Double3D {
    6.        
    7.         public double x,y,z;
    8. ...
    9.  
    My Property Drawer, which I placed in the Editor folder, looks like so:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4.  
    5. [CustomPropertyDrawer (typeof (Double3D))]
    6. public class Double3DDrawer : PropertyDrawer {
    7.  
    8.     // TODO: this is sort of like, but not exactly like the X positional handling of Vector3
    9.     public override void OnGUI (Rect pos, SerializedProperty prop, GUIContent label) {
    10.  
    11.         float nameWidth = pos.width * .41f;
    12.  
    13.         float labelWidth = 12f;
    14.         float fieldWidth = ((pos.width - nameWidth) / 3f) - labelWidth;
    15.  
    16.         SerializedProperty x = prop.FindPropertyRelative ("x");
    17.         SerializedProperty y = prop.FindPropertyRelative ("y");
    18.         SerializedProperty z = prop.FindPropertyRelative ("z");
    19.  
    20.         float posx = pos.x;
    21.  
    22.         int indent = EditorGUI.indentLevel;
    23.  
    24.         EditorGUI.LabelField (new Rect (pos.x, pos.y, nameWidth, pos.height), prop.displayName);
    25.         posx += nameWidth;
    26.  
    27.         // Draw X
    28.         EditorGUI.LabelField (new Rect (posx, pos.y, labelWidth, pos.height), "X"); posx += labelWidth;
    29.         EditorGUI.DoubleField (
    30.             new Rect (posx, pos.y, fieldWidth, pos.height), x.doubleValue);  posx += fieldWidth;
    31.  
    32.         // Y
    33.         //EditorGUI.indentLevel = 0;
    34.         EditorGUI.LabelField (new Rect (posx, pos.y, labelWidth, pos.height), "Y"); posx += labelWidth;
    35.         EditorGUI.DoubleField (
    36.             new Rect (posx, pos.y, fieldWidth, pos.height), y.doubleValue); posx += fieldWidth;
    37.  
    38.         // Z
    39.         //EditorGUI.indentLevel = 0;
    40.         EditorGUI.LabelField (new Rect (posx, pos.y, labelWidth, pos.height), "Z"); posx += labelWidth;
    41.         EditorGUI.DoubleField (
    42.             new Rect (posx, pos.y, fieldWidth, pos.height), z.doubleValue); posx += fieldWidth;
    43.        
    44.         EditorGUI.indentLevel = indent;
    45.     }
    46. }
    It *almost works*, but any values typed into the three DoubleFields immediately reverts to "0".

    Can someone tell me what am I missing? Thanks in advance.
     
    Oyedoyin1 likes this.
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,222
    Tony-Lovell and lordofduct like this.
  3. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    127
    Perfect! Just the hint I needed.

    tone
     
  4. dazeili

    dazeili

    Joined:
    Oct 8, 2013
    Posts:
    3
    If you want the exact spacing unity uses for Vector 3 use this:
    Code (CSharp):
    1.  
    2. private const float SubLabelSpacing = 4;
    3. private const float BottomSpacing = 2;
    4.  
    5. public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label) {
    6.         pos.height -= BottomSpacing;
    7.         label = EditorGUI.BeginProperty(pos, label, prop);
    8.         var contentRect = EditorGUI.PrefixLabel(pos, GUIUtility.GetControlID(FocusType.Passive), label);
    9.         var labels      = new[] {new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z")};
    10.         var properties  = new[] {prop.FindPropertyRelative("x"), prop.FindPropertyRelative("y"), prop.FindPropertyRelative("z")};
    11.         DrawMultiplePropertyFields(contentRect, labels, properties);
    12.  
    13.         EditorGUI.EndProperty();
    14.     }
    15.  
    16.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
    17.         return base.GetPropertyHeight(property, label) + BottomSpacing;
    18.     }
    19.  
    20.  
    21.     private static void DrawMultiplePropertyFields(Rect pos, GUIContent[] subLabels, SerializedProperty[] props) {
    22.         // backup gui settings
    23.         var indent     = EditorGUI.indentLevel;
    24.         var labelWidth = EditorGUIUtility.labelWidth;
    25.      
    26.         // draw properties
    27.         var propsCount = props.Length;
    28.         var width      = (pos.width - (propsCount - 1) * SubLabelSpacing) / propsCount;
    29.         var contentPos = new Rect(pos.x, pos.y, width, pos.height);
    30.         EditorGUI.indentLevel = 0;
    31.         for (var i = 0; i < propsCount; i++) {
    32.             EditorGUIUtility.labelWidth = EditorStyles.label.CalcSize(subLabels[i]).x;
    33.             EditorGUI.PropertyField(contentPos, props[i], subLabels[i]);
    34.             contentPos.x += width + SubLabelSpacing;
    35.         }
    36.  
    37.         // restore gui settings
    38.         EditorGUIUtility.labelWidth = labelWidth;
    39.         EditorGUI.indentLevel       = indent;
    40.     }