Extending (instead of replacing) built-in Inspectors

Hello!

I would like to share a smart solution for extending custom inspectors instead of overriding and replacing the built-ins. How would you, for instance, do something like this?
2654871--187131--Extended Transform Inspector.jpg

When write your own inspector for a built-in class, you have to make sure to replicate its same inspector (kind of what Unify wiki does). That, however, is not always an easy solution.

That inspector uses the built-in editor to show the local space coordinates and then expands that functionality to show world coordinates and some extra stuff.

And here’s a snippet of the example above :slight_smile:

[CustomEditor(typeof(Transform), true)] 
    [CanEditMultipleObjects]
    public class CustomTransformInspector : Editor {

        //Unity's built-in editor
        Editor defaultEditor;
        Transform transform;

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

        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
            MethodInfo 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();

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

            GUI.enabled = false;
            Vector3 localPosition = transform.localPosition;
            transform.localPosition = transform.position;

            Quaternion localRotation = transform.localRotation;
            transform.localRotation = transform.rotation;

            Vector3 localScale = transform.localScale;
            transform.localScale = transform.lossyScale;

            defaultEditor.OnInspectorGUI();
            transform.localPosition = localPosition;
            transform.localRotation = localRotation;
            transform.localScale = localScale;
            GUI.enabled = true;
        }
    }

Note: I am still to figure out a way to show and be able to modify world position (I mean to do it properly. Being able to multi-inspect, Undo and redo and general stuff), that’s why I made it read-only.

I found this to be an easy and clever solution while making my Component Tool Panel editor extension. And it can also be used to expand on GameObject inspector:
2654871--187134--ComponentToolPanel.jpg

I really hope this helps someone =)

31 Likes

I were looking to do something like what you achieve of making a copy of the “default inspector” and calling it’s ongUI for a long time - Thanks!

Neat hack, used your code and it functions flawlessly. So I found the following repo ( Link ) containing all unity editors with the goal to extend the TextEditor but for some reason it won’t register

[CustomEditor(typeof (UnityEngine.UI.Text), true)]
Any ideas why its not registering ?

So far I can only get it to work with Transform… BoxCollider, Rigidbody, MeshRenderer aren’t working.

I’m guessing there is some kind of priority check, but I’d have to dig in the reference source to figure out where it gets determined and if there’s anything we can do about it. So far, I don’t see much of a difference between Transform and the others that would cause them to fail.

If you ever figured it out, I’m curious!

Hm, after much debugging, it seems that just entering play mode made it work. The script recompile somehow doesn’t seem to clear the native type cache for custom editors.

1 Like

This pattern works really great! I use it extensively in Power Inspector, first wrapping the default editors inside custom drawers and then layering all kinds of enhancements on top. Well, actually I only do this when custom editors exist for the targets, otherwise I do even more crazy things, recreating the look of editors without actually using them at all, so that I can customize things to an even greater degree :smile:

One thing to note is that you do not need to call OnDisable or OnDestroy manually for the editor before destroying it, since those get called automatically whenever UnityEngine.Objects are destroyed. So you can just skip that step.

Another thing to be aware of when customizing the editors of assets is AssetImporters. Basically you can call Editor.CreateEditor for either the targets themselves or their asset importers, and get two completely different results. For example the editor you see when inspecting a texture is actually the TextureImporterInspector and not the TextureInspector.

THANK you for your code example and the Editor.CreateEditor trick!
After sifting through tons of posts and answers and official docs and even the reference implementation, nowhere can be found why when trying to override/extending the default Inspector for Transform and calling base.OnInspectorGUI(), like one would expect, the look is COMPLETELY DIFFERENT from Unity’s Transform Inspector (for starters, it suddenly shows the rotation FIRST, and then the position…).

Your method does exactly what I want: show Unity’s actual Inspector,including the relatively new “contrained scale” lock icon, including support for the blue highlighting for prefab overrides, simply extended by my additional elements.

NOTE: Haven’t tested your exact version, but from my understanding to actually support multi-object editing you’d have to use SerializedProperty, instead of accessing target directly. This could explain your troubles with the world position part.

Thanks a lot for this neat hack!

Something I did not realise immediately and that could help others: if the call to GetType() fails and returns null, then Editor.CreateEditor() will simply try to invoke the default editor for this type, which is…ourself.
This results in a infinitely recursive call and a nasty stack overflow that may crash Unity or simply hang it.

So I advise to check the type first and maybe throw or Debug.Log():

string foundEditorType = Type.GetType("UnityEditor.TransformInspector, UnityEditor")
if(!string.IsNullOrEmpty(foundEditorType))
{
  defaultEditor = Editor.CreateEditor(targets, foundEditorType);
}

Alternatively could also fallback to using the default Editor.

Type fallbackEditorType = typeof(Editor).Assembly.GetType("UnityEditor.GenericInspector");

Of course this could fail as well, so checking that the type is not null before calling Editor.CreateEditor is still good practice.

Thanks everyone for this thread, works like a charm ! Well… almost !

I have successfully extended the ModelInspector class, but I lost the Object Preview!

Been playing around with this for a while, anyone knows how I could plug the mesh preview back in ?

With my custom inspector :

Default inspector : (Preview is back)

Script :

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Mesh), true)]
[CanEditMultipleObjects]
public class CustomMeshInspector : Editor
{
    //Unity's built-in editor
    Editor defaultEditor;
    Mesh mesh;

    void OnEnable(){
        //When this inspector is created, also create the built-in inspector
        defaultEditor = Editor.CreateEditor(targets, Type.GetType("UnityEditor.ModelInspector, UnityEditor"));
        mesh = target as Mesh;

    }

    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
MethodInfo 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("Optimization Settings", EditorStyles.boldLabel);
        if (GUILayout.Button("Reduce Mesh"))
        {
            Debug.Log("REDUCING MESH! ");
        }
        defaultEditor.OnInspectorGUI();
    }
}

Thank you for any help, really appreciated.

For reference, this is the ModelInspector class : UnityCsReference/Editor/Mono/Inspector/ModelInspector.cs at master · Unity-Technologies/UnityCsReference · GitHub

1 Like

have you ever tried to add these function overrides in your CustomMeshInspector class?
public override void DrawPreview(Rect previewArea)
{
defaultEditor.DrawPreview(previewArea);
}

public override bool HasPreviewGUI()
{
return defaultEditor.HasPreviewGUI();
}

Is there anything similar for UI_Toolkit

1 Like

Looking for a solution in ui tookit too