Search code examples
unity-game-enginecustom-controlsunity3d-editorunity-editor

How to make Vector3 fields behave like the ones from Transform in a CustomEditor


In the following gif you can see the difference between how Vector3 fields behave in the Inspector of Transform and of my MonoBehaviours.

enter image description here

The Transform is even a CustomEditor I also wrote using EditorGUILayout.Vector3Field().

[CustomEditor(typeof(Transform), true)]
[CanEditMultipleObjects]
public class AdvancedTransformEditor : Editor
{
    //Unity's built-in editor
    private Editor _defaultEditor;
    private Transform _transform;

    private void OnEnable()
    {
        //When this inspector is created, also create the built-in inspector
        _defaultEditor = CreateEditor(targets, Type.GetType("UnityEditor.TransformInspector, UnityEditor"));
        _transform = target as Transform;
    }

    private void OnDisable()
    {
        //When OnDisable is called, the default editor we created should be destroyed to avoid memory leakage.
        //Also, make sure to call any required methods like OnDisable
        var disableMethod = _defaultEditor.GetType().GetMethod("OnDisable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (disableMethod != null) disableMethod.Invoke(_defaultEditor, null);
        DestroyImmediate(_defaultEditor);
    }

    public override void OnInspectorGUI()
    {
        EditorGUILayout.LabelField("Local Space", EditorStyles.boldLabel);
        _defaultEditor.OnInspectorGUI();

        serializedObject.Update();

        //Show World Space Transform
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("World Space", EditorStyles.boldLabel);

        _transform.position = EditorGUILayout.Vector3Field("Position", _transform.position);

        EditorGUI.BeginDisabledGroup(true);
        EditorGUILayout.Vector3Field("Rotation", _transform.eulerAngles);
        EditorGUILayout.Vector3Field("Scale", _transform.lossyScale);
        EditorGUI.EndDisabledGroup();

        serializedObject.ApplyModifiedProperties();
    }
}

It only works while having _defaultEditor.OnInspectorGUI(); so something in Unity's original editor for the Transform component has to do something different.

When I try to do the same in any other CustomEditor for a MonoBehaviour

// without a CustomEditor
public class Example : MonoBehaviour
{
    public Vector3 example;
}

and

// Width the custom editor
public class ExampleMinWidth : MonoBehaviour
{
    public Vector3 example;
}

[CustomEditor(typeof(ExampleMinWidth))]
public class ExampleMinWidthEditor : Editor
{
    private SerializedProperty example;

    private void OnEnable()
    {
        example = serializedObject.FindProperty("exmaple");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value);

        // I tried both also simply using a PropertyField
        //EditorGUILayout.PropertyField(example);
        serializedObject.ApplyModifiedProperties();
    }
}

or skipping the line _defaultEditor.OnInspectorGUI(); in the AdvancedTransformEditor the Vector3 field gets folded for a certain Inspector width.

How can I get the same behaviour for my fields as for the Transform component - not folding but staying on the same line?


Update

  • I tried it with GUILayout.MinWidth() but this didn't change anything.

  • As suggested I also tried

    example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value, GUILayout.ExpandHeight(false));
    

    (also for the PropertyField()) but that didn't change anything.

  • And Just for trying I also did with ExpandWidth(false) ... the outcome is not very pleasing :D

    enter image description here

  • I even tried GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight) but that makes the field still fold but "bload"/overdraw into the field below.


Solution

  • I found the relevant lines in the TransformInspector

    if (!EditorGUIUtility.wideMode)
    {
        EditorGUIUtility.wideMode = true;
        EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
    }
    
    • EditorGUIUtility.wideMode does two things: Returns whether the editor currently is in widemode and set whether the editor for this component / the next lines shall be behaving like it was in widemode. So they simply force their fields to only "be" in widemode.

    • After that it is necessary to use a "fixed" EditorGUIUtility.labelWidth namely reduced by the width the 3 Vectror3 fields will take in widemode (Unity used 212)