Enhence the built-in components of unity


This article will present you how you can add any kind of behavior in the build-in Unity components. With a friendly user interface which can be fold and unfold.

This method is generic and work for all custom inspectors. I use here the Transform component as an exemple, to show how to implement a basic Reset button, which work for multiple selections, and handle the Undo/Redo.

Result in action:

How to create a basic custom Editor

The general approach of extending the inspector is to create an editorScript that will call the default inspectorGUI, and append the functionality you want after it. Think about putting all you editor script inside an Editor folder in your project. In the exemple bellow a simple button is added to the Transform components:

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Transform), true)]
public class CustomTransformEditor : Editor
{
    public override void OnInspectorGUI()
    {
        // Draw default GUI of the Transform Component
        base.OnInspectorGUI();

        // Here add your customs GUI stuffs
        GUILayout.Button('Reset');
    }
}
And that it ! right ? Not at all... Notice the aspect of the current component at this state. Why the hell our rotation apear as a Quaternion ?

In fact, at this state we just discoverd that Unity usually create a CustomEditor for his components. For making it pretty, and for adding functionality.
But... What if we want to add features too, how can we keep the old inspector ?

Well, you can, but it's hard. You can look at the source code of unity, and copy it, it will work fine. But we don't want that, we are lazy.

Unity have created more than one hundred Custom Inspector, and unfortunatly, we can't derive from them because they are all private. As it is, we can't use inheritence for deriving our custom inspector from them. We need to use instead some composition, and some reflection.

If you are curious, you can download the C# source code of Unity at there official github. From here you can open it in visual studio, and start to dig in. You can find their TransformInspector script here.




Use a Decorator which does the job for us


First, I have created a script with an

enum
which contain the list of all custom inspector. Expecially useful next time you will search in the source code of Unity.

BuiltInEditorComponentsEnum.cs
Download
Copy
/// <summary>
/// this script containt the list of all 
/// Unity's Built In Inspector Types
/// 
/// Thanks to https://pastebin.com/Kq3T8aMw
/// for the datas
/// </summary>

namespace ExtUnityComponents
{
    public enum BUILT_IN_EDITOR_COMPONENTS
    {
        AnchoredJoint2DEditor,
        AnimationClipEditor,
        AnimationEditor,
        AnimatorInspector,
        AnimatorOverrideControllerInspector,
        AssetStoreAssetInspector,
        AudioChorusFilterEditor,
        AudioClipInspector,
        AudioDistortionFilterEditor,
        AudioEchoFilterEditor,
        AudioHighPassFilterEditor,
        AudioImporterInspector,
        AudioLowPassFilterInspector,
        AudioMixerControllerInspector,
        AudioMixerGroupEditor,
        AudioMixerSnapshotControllerInspector,
        AudioReverbFilterEditor,
        AudioReverbZoneEditor,
        AudioSourceInspector,
        AvatarEditor,
        AvatarMaskInspector,
        BillboardAssetInspector,
        BillboardRendererInspector,
        BlendTreeInspector,
        BoxCollider2DEditor,
        BoxColliderEditor,
        CameraEditor,
        CanvasEditor,
        CapsuleColliderEditor,
        CharacterControllerEditor,
        CircleCollider2DEditor,
        ClothInspector,
        Collider2DEditorBase,
        Collider3DEditorBase,
        ColliderEditorBase,
        ColorPresetLibraryEditor,
        CubemapInspector,
        CurvePresetLibraryEditor,
        DefaultAssetInspector,
        DistanceJoint2DEditor,
        DoubleCurvePresetLibraryEditor,
        EdgeCollider2DEditor,
        EditorSettingsInspector,
        Effector2DEditor,
        FogEditor,
        FontInspector,
        GameObjectInspector,
        GenericInspector,
        GradientPresetLibraryEditor,
        GraphicsSettingsInspector,
        HingeJoint2DEditor,
        HingeJointEditor,
        Joint2DEditorBase,
        LightEditor,
        LightingEditor,
        LightmapParametersEditor,
        LightProbeGroupInspector,
        LightProbesInspector,
        LineRendererInspector,
        LODGroupEditor,
        MaterialEditor,
        MeshColliderEditor,
        MeshRendererEditor,
        ModelImporterClipEditor,
        ModelImporterEditor,
        ModelImporterModelEditor,
        ModelImporterRigEditor,
        ModelInspector,
        MonoScriptImporterInspector,
        MonoScriptInspector,
        MovieImporterInspector,
        MovieTextureInspector,
        NavMeshAgentInspector,
        NavMeshObstacleInspector,
        OcclusionAreaEditor,
        OcclusionPortalInspector,
        OffMeshLinkInspector,
        OtherRenderingEditor,
        ParticleRendererEditor,
        ParticleSystemInspector,
        Physics2DSettingsInspector,
        PhysicsManagerInspector,
        PlayerSettingsEditor,
        PluginImporterInspector,
        PolygonCollider2DEditor,
        ProceduralMaterialInspector,
        ProceduralTextureInspector,
        QualitySettingsEditor,
        RectTransformEditor,
        ReflectionProbeEditor,
        RendererEditorBase,
        RenderSettingsInspector,
        RenderTextureInspector,
        RigidbodyEditor,
        ScriptExecutionOrderInspector,
        ShaderImporterInspector,
        ShaderInspector,
        ShaderVariantCollectionInspector,
        SkinnedMeshRendererEditor,
        SliderJoint2DEditor,
        SpeedTreeImporterInspector,
        SpeedTreeMaterialInspector,
        SphereColliderEditor,
        SpringJoint2DEditor,
        SpriteInspector,
        SpriteRendererEditor,
        SubstanceImporterInspector,
        TagManagerInspector,
        TerrainInspector,
        TextAssetInspector,
        TextMeshInspector,
        Texture3DInspector,
        TextureImporterInspector,
        TextureInspector,
        TrailRendererInspector,
        TransformInspector,
        TreeEditor,
        TrueTypeFontImporterInspector,
        WebCamTextureInspector,
        WheelColliderEditor,
        WheelJoint2DEditor,
        WindInspector
    }

    public enum CUSTOM_EDITOR_COMPONENTS
    {
        MeshFilterEditor
    }
}

Then we will inherite our CustomTransformEditor script from a complexe Decorator, and call his constructor. this Decorator will do everything we don't want to know about, and simply call our

CustomOnInspectorGUI()
function every
InspectorGUI()
.

using UnityEditor;
using UnityEngine;

/// <summary>
/// Custom Transform editor
/// </summary>
[CustomEditor(typeof(Transform))]
public class CustomTransformEditor : DecoratorComponentsEditor
{
  /// <summary>
  /// here call the constructor of the CustomWrapperEditor class,
  /// by telling it who we are (a Transform Inspector)
  /// NOTE: if you want to decorate your own inspector, or decorate an inspector
  ///   witch doesn't have a Unity Editor, use
  ///   : base(CUSTOM_EDITOR_COMPONENTS.[YourOwnInspector]) instead.
  ///   the decorator will handle it.
  /// </summary>
  public CustomTransformEditor()
      : base(BUILT_IN_EDITOR_COMPONENTS.TransformInspector)
  {

  }

  /// <summary>
  /// you should use that function instead of OnEnable()
  /// </summary>
  protected override void OnCustomEnable()
  {
      //initialiee basic stuff
  }

  /// <summary>
  /// This function is called at each OnInspectorGUI()
  /// </summary>
  protected override void CustomOnInspectorGUI()
  {
    // Here add your customs GUI stuffs
    GUILayout.Button('Reset');
  }

  /// <summary>
  /// this function is called on the first OnSceneGUI()
  /// usefull to initialize GUI stuffs
  /// </summary>
  /// <param name='sceneview'>current drawing scene view</param>
  protected override void InitOnFirstOnSceneGUI(SceneView sceneview)
  {
    //initialise GUI stuffs
  }
  

And that pretty much it for the basics ! The script will remember your choice when you fold/unfold the extension button. I put bellow the full CustomTransformEditor script, with some additionnal code for the behavior of the reset button, as well as the Decorator script.

As you see in the exemple, I have provided you a somes virtual functions usefull when we are dealing with editor scripts. Don't hesitate to look into the decorator to see all the virtual function you can use.




Final Scripts:

CustomTransformEditor
Download
Copy
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using static UnityEditor.EditorGUILayout;


/// <summary>
/// Custom Transform editor.
/// </summary>
namespace ExtUnityComponents
{
    [CustomEditor(typeof(Transform))]
    [CanEditMultipleObjects]
    public class CustomTransformEditor : DecoratorComponentsEditor
    {
        /// <summary>
        /// here call the constructor of the DecoratorComponentsEditor class,
        /// by telling it who we are (a Transform Inspector)
        /// </summary>
        public CustomTransformEditor()
            : base(BUILT_IN_EDITOR_COMPONENTS.TransformInspector)
        {

        }

        /// <summary>
        /// This function is called at each OnInspectorGUI
        /// </summary>
        protected override void OnCustomInspectorGUI()
        {
            DisplayResetTransform();
        }

        /// <summary>
        /// display reset transform buttons
        /// </summary>
        private void DisplayResetTransform()
        {
            using (HorizontalScope horizontalScope = new HorizontalScope(EditorStyles.helpBox))
            {
                GUILayout.Label("Reset datas:");
                if (GUILayout.Button("Reset"))
                {
                    ApplyResetTransform();
                }
            }
        }

        // <summary>
        /// when we click on reset, reset every target to there
        /// default state
        /// </summary>
        private void ApplyResetTransform()
        {
            for (int i = 0; i < base.ConcretTargets.Length; i++)
            {
                Undo.RecordObject(base.ConcretTargets[i], "position transform");
                Transform current = (Transform)base.ConcretTargets[i];
                current.localPosition = Vector3.zero;
                current.localRotation = Quaternion.identity;
                current.localScale = Vector3.one;
            }
        }
    }
}
DecoratorComponentsEditor
Download
Copy
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace ExtUnityComponents
{
    public abstract class DecoratorComponentsEditor : Editor
    {
        /// <summary>
        /// all the virtual function at your disposal
        /// </summary>
        #region virtual functions

        /// <summary>
        /// called when the inspector is enabled
        /// </summary>
        protected virtual void OnCustomEnable() { }

        /// <summary>
        /// called when the inspector is disabled
        /// </summary>
        protected virtual void OnCustomDisable() { }


        /// <summary>
        /// called every OnInspectorGUI inside the herited class
        /// </summary>
        protected virtual void OnCustomInspectorGUI() { }

        /// <summary>
        /// called at the first OnInspectorGUI inside the herited class
        /// </summary>
        protected virtual void InitOnFirstInspectorGUI() { }

        /// <summary>
        /// called at the first OnSceneGUI inside the herited class
        /// </summary>
        /// <param name="sceneview">current drawing scene view</param>
        protected virtual void CustomOnSceneGUI(SceneView sceneview) { }

        /// <summary>
        /// called at the first OnSceneGUI inside the herited class
        /// </summary>
        /// <param name="sceneview">current drawing scene view</param>
        protected virtual void InitOnFirstOnSceneGUI(SceneView sceneview) { }

        /// <summary>
        /// called every editor Update inside the herited class
        /// </summary>
        protected virtual void OnEditorUpdate() { }

        /// <summary>
        /// called at the first Editor Update inside the herited class
        /// </summary>
        protected virtual void InitOnFirstEditorUpdate() { }


        #endregion

        /// <summary>
        /// some private variable
        /// </summary>
        #region private variables

        /// EditorPref key for save the open/close extension
        private const string KEY_EXPAND_EDITOR_EXTENSION = "KEY_EXPAND_EDITOR_EXTENSION";
        private bool _openExtensions = false;    //is this extension currently open or close ? save this for every gameObjects's components
        protected bool IsExtensionOpened() => _openExtensions;
        private readonly object[] EMPTY_ARRAY = new object[0];   //empty array for invoking methods using reflection
        private System.Type _decoratedEditorType = null;       //Type object for the internally used (decorated) editor.
        private System.Type _editedObjectType;          //Type object for the object that is edited by this editor.
        private Editor _editorInstance;                 //urrent editorInstance
        private bool _isCustomEditor = false;
        private string _nameCustomEditor;
        private bool _hasInitSceneGUI = false;
        private bool _hasInitEditorUpdate = false;

        protected Component ConcretTarget;
        protected Component[] ConcretTargets;

        /// reflexion cache
        private Dictionary<string, MethodInfo> _decoratedMethods = new Dictionary<string, MethodInfo>();
        private Assembly _editorAssembly = Assembly.GetAssembly(typeof(Editor));

        /// <summary>
        /// get editor instance
        /// </summary>
        /// <returns>editor instance</returns>
        protected Editor GetEditorInstance()
        {
            return _editorInstance;
        }

        #endregion

        /// <summary>
        /// all the required setup and initialisation
        /// </summary>
        #region initialisation editor

        /// <summary>
        /// need to be called here to initialize the default editor
        /// </summary>
        private void OnEnable()
        {
            SetupEditor();
            OnCustomEnable();
        }

        /// <summary>
        /// need to destroy the customEditor when quitting !
        /// </summary>
        void OnDisable()
        {
            if (_editorInstance != null)
            {
                DestroyImmediate(_editorInstance);
            }
            _hasInitSceneGUI = false;
            _hasInitEditorUpdate = false;
            SceneView.duringSceneGui -= OwnOnSceneGUI;
            EditorApplication.update -= CustomEditorApplicationUpdate;
            OnCustomDisable();
        }

        protected T[] GetTargets<T>() where T : Component
        {
            T[] array = new T[ConcretTargets.Length];
            for (int i = 0; i < ConcretTargets.Length; i++)
            {
                array[i] = (T)ConcretTargets[i];
            }
            return (array);
        }

        protected T GetTargetIndex<T>(int index) where T : Component
        {
            if (ConcretTargets == null
                || ConcretTargets.Length == 0
                || index < 0
                || index >= ConcretTargets.Length)
            {
                return (default(T));
            }
            return ((T)ConcretTargets[index]);
        }

        /// <summary>
        /// Need to destroy the instance even on Destroy !
        /// I don't know why. Unity generate leaks after each compilation
        /// because of the CreateEditor
        /// </summary>
        private void OnDestroy()
        {
            if (_editorInstance != null)
            {
                DestroyImmediate(_editorInstance);
            }
            //SceneView.duringSceneGui -= OwnOnSceneGUI;
            //EditorApplication.update -= OnEditorApplicationUpdate;
        }

        /// <summary>
        /// here create the editor instance, and open / close the extension panel if needed
        /// </summary>
        private void SetupEditor()
        {
            if (_editorInstance != null)
            {
                return;
            }
            _hasInitSceneGUI = false;
            _hasInitEditorUpdate = false;
            CreateDefaultInstance();
            OpenOrCloseExtension();
        }


        /// <summary>
        /// here create the editor instance
        /// </summary>
        private void CreateDefaultInstance()
        {
            if (_decoratedEditorType == null || targets == null)
            {
                return;
            }
            _editorInstance = Editor.CreateEditor(targets, _decoratedEditorType);
        }

        /// <summary>
        /// manage if the extensions are opened or closed, and save this setting in EditorPrefs
        /// </summary>
        private void OpenOrCloseExtension()
        {
            if (EditorPrefs.HasKey(KEY_EXPAND_EDITOR_EXTENSION + _nameCustomEditor))
            {
                _openExtensions = EditorPrefs.GetBool(KEY_EXPAND_EDITOR_EXTENSION + _nameCustomEditor);
            }
            else
            {
                _openExtensions = false;
                EditorPrefs.SetBool(KEY_EXPAND_EDITOR_EXTENSION + _nameCustomEditor, _openExtensions);
            }
        }

        public DecoratorComponentsEditor(CUSTOM_EDITOR_COMPONENTS editorTypeCustom)
        {
            _isCustomEditor = true;
            _nameCustomEditor = editorTypeCustom.ToString();
        }

        /// <summary>
        /// constructor of the class: here we initialize reflexion variables
        /// </summary>
        /// <param name="editorTypeName">name of the component we inspect</param>
        public DecoratorComponentsEditor(BUILT_IN_EDITOR_COMPONENTS editorTypeName)
        {
            _nameCustomEditor = editorTypeName.ToString();
            _isCustomEditor = false;
            _decoratedEditorType = _editorAssembly.GetTypes().Where(t => t.Name == editorTypeName.ToString()).FirstOrDefault();
            Init();

            // Check CustomEditor types.
            System.Type originalEditedType = GetCustomEditorType(_decoratedEditorType);

            if (originalEditedType != _editedObjectType)
            {
                throw new System.ArgumentException(
                    string.Format("Type {0} does not match the editor {1} type {2}",
                              _editedObjectType, editorTypeName, originalEditedType));
            }
        }

        /// <summary>
        /// iniitalisation of reflexion variables
        /// </summary>
        private void Init()
        {
            var flags = BindingFlags.NonPublic | BindingFlags.Instance;

            var attributes = this.GetType().GetCustomAttributes(typeof(CustomEditor), true) as CustomEditor[];
            var field = attributes.Select(editor => editor.GetType().GetField("m_InspectedType", flags)).First();

            _editedObjectType = field.GetValue(attributes[0]) as System.Type;
        }

        /// <summary>
        /// from a given type of editor, get his CustomEditor as type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private System.Type GetCustomEditorType(System.Type type)
        {
            var flags = BindingFlags.NonPublic | BindingFlags.Instance;

            var attributes = type.GetCustomAttributes(typeof(CustomEditor), true) as CustomEditor[];
            var field = attributes.Select(editor => editor.GetType().GetField("m_InspectedType", flags)).First();

            return field.GetValue(attributes[0]) as System.Type;
        }

        /// <summary>
        /// From a given name of class, invoke it using reflexion
        /// </summary>
        protected void CallMethodUsingReflexion(string methodName)
        {
            MethodInfo method = null;

            // Add MethodInfo to cache
            if (!_decoratedMethods.ContainsKey(methodName))
            {
                var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;

                method = _decoratedEditorType.GetMethod(methodName, flags);

                if (method != null)
                {
                    _decoratedMethods[methodName] = method;
                }
                else
                {
                    //Debug.LogError(string.Format("Could not find method {0}", method));
                }
            }
            else
            {
                method = _decoratedMethods[methodName];
            }

            if (method != null)
            {
                method.Invoke(GetEditorInstance(), EMPTY_ARRAY);
            }
        }

        #endregion

        /// <summary>
        /// The core loop function for display
        /// everything
        /// </summary>
        #region Display Extension

        /// <summary>
        /// here the main InspectorGUI.
        /// It's here that we call the base OnInspecctorGUI.
        /// Then we show the GUI --------- Extension [+]
        /// then if it's open, we call the abstract class CustomOnInspectorGUI()
        /// </summary>
        public override void OnInspectorGUI()
        {
            if (!_isCustomEditor)
            {
                ManageUnityInspector();
            }
            else
            {
                ManageCustomNewInspector();
            }
        }
        private void ManageUnityInspector()
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().OnInspectorGUI();
            CommonExtenstionInspectorGUI();
        }
        private void ManageCustomNewInspector()
        {
            base.OnInspectorGUI();
            CommonExtenstionInspectorGUI();
        }

        /// <summary>
        /// called whatever this editor is inherited from a custom unity component,
        /// or just a standar sutom editor
        /// </summary>
        private void CommonExtenstionInspectorGUI()
        {
            TryToInitOnFirstInspectorGUI();
            if (ExpendBehavior())
            {
                OnCustomInspectorGUI();
            }
        }

        /// <summary>
        /// init the targets inspected and store them.
        /// This is called at the first OnInspectorGUI()
        /// Not in the constructor ! we don't have targets information in the constructor
        /// </summary>
        private void TryToInitOnFirstInspectorGUI()
        {
            if (ConcretTargets == null)
            {
                ConcretTarget = (Component)target;
                ConcretTargets = new Component[targets.Length];
                for (int i = 0; i < targets.Length; i++)
                {
                    ConcretTargets[i] = (Component)targets[i];
                }
                //_meshFilterHiddedTools = _concretTarget.GetOrAddComponent<MeshFilterHiddedTools>();

                SceneView.duringSceneGui -= OwnOnSceneGUI;
                SceneView.duringSceneGui += OwnOnSceneGUI;
                EditorApplication.update -= CustomEditorApplicationUpdate;
                EditorApplication.update += CustomEditorApplicationUpdate;

                InitOnFirstInspectorGUI();
            }
        }

        private void TryToInitOnFirstOnEditorUpdate()
        {
            if (!_hasInitEditorUpdate)
            {
                InitOnFirstEditorUpdate();
                _hasInitEditorUpdate = true;
            }
        }

        /// <summary>
        /// editor update loop
        /// </summary>
        private void CustomEditorApplicationUpdate()
        {
            if (!_isCustomEditor)
            {
                if (GetEditorInstance() == null)
                {
                    return;
                }
            }
            if (!IsExtensionOpened())
            {
                return;
            }
            TryToInitOnFirstOnEditorUpdate();
            OnEditorUpdate();
        }

        /// <summary>
        /// This function is called at each OnSceneGUI to try to initialize it
        /// </summary>
        private void TryToInitOnFirstOnSceneGUI(SceneView sceneview)
        {
            if (!_hasInitSceneGUI)
            {
                InitOnFirstOnSceneGUI(sceneview);
                _hasInitSceneGUI = true;
            }
        }

        private void OwnOnSceneGUI(SceneView sceneview)
        {
            if (!_isCustomEditor)
            {
                if (GetEditorInstance() == null)
                {
                    return;
                }
            }

            if (!IsExtensionOpened())
            {
                return;
            }

            TryToInitOnFirstOnSceneGUI(sceneview);
            CustomOnSceneGUI(sceneview);
        }

        /// <summary>
        /// display the Expand behavior of the component editor
        /// </summary>
        private bool ExpendBehavior()
        {
            GUIStyle lineStyle = new GUIStyle();
            lineStyle.normal.background = EditorGUIUtility.whiteTexture;
            lineStyle.stretchWidth = true;
            lineStyle.margin = new RectOffset(0, 0, 12, 18);

            var c = GUI.color;
            var p = GUILayoutUtility.GetRect(GUIContent.none, lineStyle, GUILayout.Height(1));
            p.width -= 120;
            if (Event.current.type == EventType.Repaint)
            {
                GUI.color = EditorGUIUtility.isProSkin ?
                    new Color(0.157f, 0.157f, 0.157f) : new Color(0.5f, 0.5f, 0.5f);
                lineStyle.Draw(p, false, false, false, false);
            }

            EditorGUI.LabelField(new Rect(p.xMax + 30, p.y - 7, 70, 25), "Extensions");

            GUI.color = Color.white;
            GUI.backgroundColor = Color.white;
            if (GUI.Button(new Rect(p.xMax + 100, p.y - 7, 18, 16), (_openExtensions ? " -" : " +")))
            {
                _openExtensions = !_openExtensions;
                EditorPrefs.SetBool(KEY_EXPAND_EDITOR_EXTENSION + _nameCustomEditor, _openExtensions);
            }
            GUI.backgroundColor = Color.white;


            GUI.color = c;

            return (_openExtensions);
        }

        
        #endregion

        /// <summary>
        /// other basic unity fonction we have to manage
        /// </summary>
        #region Unity Fonctions
        public void OnSceneGUI()
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            CallMethodUsingReflexion("OnSceneGUI");
        }

        protected override void OnHeaderGUI()
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            CallMethodUsingReflexion("OnHeaderGUI");
        }

        public override void DrawPreview(Rect previewArea)
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().DrawPreview(previewArea);
        }

        public override string GetInfoString()
        {
            if (GetEditorInstance() == null)
            {
                return ("");
            }
            return GetEditorInstance().GetInfoString();
        }

        public override GUIContent GetPreviewTitle()
        {
            if (GetEditorInstance() == null)
            {
                return (null);
            }
            return GetEditorInstance().GetPreviewTitle();
        }

        public override bool HasPreviewGUI()
        {
            if (GetEditorInstance() == null)
            {
                return (false);
            }
            return GetEditorInstance().HasPreviewGUI();
        }

        public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().OnInteractivePreviewGUI(r, background);
        }

        public override void OnPreviewGUI(Rect r, GUIStyle background)
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().OnPreviewGUI(r, background);
        }

        public override void OnPreviewSettings()
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().OnPreviewSettings();
        }

        public override void ReloadPreviewInstances()
        {
            if (GetEditorInstance() == null)
            {
                return;
            }
            GetEditorInstance().ReloadPreviewInstances();
        }

        public override Texture2D RenderStaticPreview(string assetPath, Object[] subAssets, int width, int height)
        {
            if (GetEditorInstance() == null)
            {
                return (null);
            }
            return GetEditorInstance().RenderStaticPreview(assetPath, subAssets, width, height);
        }

        public override bool RequiresConstantRepaint()
        {
            if (GetEditorInstance() == null)
            {
                return (false);
            }
            return GetEditorInstance().RequiresConstantRepaint();
        }

        public override bool UseDefaultMargins()
        {
            if (GetEditorInstance() == null)
            {
                return (true);
            }
            return GetEditorInstance().UseDefaultMargins();
        }

        #endregion
    }
}










See also:

Move parent and keep children in place

This article show how to move, rotate and scale a gameObject without affecting its children



Time, TimeScale and DeltaTime in Editor

I have created a TimeEditor Class which reflects the behaviour of the Time class in editor mode. Useful for tools who need timer & slow motion