[Solved] Cannot scroll down CustomInspector inside EditorWindow

Hello, I’m working on an EditorWindow whose sole purpose is to display the content of a ScriptableObject. I didn’t want to recreate every field by hand, as it seems pointless, since all I’m doing is replicating its fields without changing them. So I’m using a CustomEditor for my ScriptableObject, that only returns its base default Inspector:

The problem is, the default inspector for the SO is cropped at the bottom if the window is of a smaller size. Here is the end result:

As you can see, the bottom of the custom editor is cropped by the Project tab, and it doesn’t seem to implement a scrollable area by default. I’ve tried using both the ScrollView and ListView VisualElements, but none of them work. I would like for a way to be able to display the scrollbar on the side when the window becomes smaller than its content.

Here is the SO:

using UnityEngine;

namespace Herve.Runtime.Models
{
    /// <summary>
    /// Contains the data for the settings used by the plugin during runtime.
    /// </summary>
    //[CreateAssetMenu(fileName = "New Runtime Settings", menuName = "Herve/RuntimeSettings", order = 0)]
    public sealed class RuntimeSettingsSO : ScriptableObject
    {
        #region Properties

        /// <summary>
        /// <see langword="true"/> to allow the player to go back to previous lines and choices
        /// </summary>
        [field: SerializeField]
        [field: Tooltip("Should Hervé allow the player to go back to previous lines and choices?")]
        public bool AllowRollback { get; private set; } = true;

        /// <summary>
        /// <see langword="true"/> to allow the player to save at any point during a dialogue
        /// </summary>
        [field: SerializeField]
        [field: Tooltip("Should Hervé allow the player to save at any point during a dialogue?")]
        public bool AllowSavingAnywhere { get; private set; } = true;

        /// <summary>
        /// <see langword="true"/> to enable automatic saving
        /// </summary>
        [field: SerializeField]
        [field: Tooltip("Should Hervé enable automatic saving?")]
        public bool AllowAutoSave { get; private set; } = true;

        // TODO : Add a field for changing which languages are to be added to the game

        /// <summary>
        /// The container of all global variables shared across all dialogues
        /// </summary>
        [field: SerializeField]
        [field: Tooltip("Contains the global variables shared across all dialogues. " +
                        "You can add, edit and remove them from the Runtime Settings window, " +
                        "or directly from the Dialogue Editor window in the window's inspector.")]
        public VariableRegistry GlobalVariables { get; private set; } = new();

        #endregion
    }
}

Here is the CustomEditor:

using Herve.Runtime.Models;
using UnityEditor;
using UnityEngine.UIElements;

/// <summary>
/// Custom Inspector to display the RuntimeSettingsSO
/// in other editors
/// </summary>
[CustomEditor(typeof(RuntimeSettingsSO))]
public class RuntimeSettingsSOCustomEditor : Editor
{
    #region Public methods

    /// <summary>
    /// Displays the default inspector for the RuntimeSettingsSO object
    /// </summary>
    /// <returns>The default inspector for the RuntimeSettingsSO object</returns>
    public override VisualElement CreateInspectorGUI()
    {
        return base.CreateInspectorGUI();
    }

    #endregion
}

And here is the EditorWindow. The window only grabs the SO from the Assets folder if the reference is lost (hot reloading, reboot, etc…) and creates a cached editor to display it:

using Herve.Editor.Models;
using Herve.Runtime.Models;
using UnityEditor;
using UnityEngine;

namespace Herve.Editor.Views
{
    /// <summary>
    /// Displays the editor window for the settings to be applied
    /// during the execution of the game
    /// </summary>
    internal sealed class HerveRuntimeSettingsEditorWindow : EditorWindow
    {
        #region Private fields

        /// <summary>
        /// The cached editor for the scriptableObject
        /// </summary>
        private UnityEditor.Editor _cachedEditor;

        #endregion

        #region Internal static methods

        /// <summary>
        /// Creates and opens an instance of this editor window
        /// </summary>
        internal static HerveRuntimeSettingsEditorWindow Open()
        {
            HerveRuntimeSettingsEditorWindow window = GetWindow<HerveRuntimeSettingsEditorWindow>("Herve Runtime Settings", true);
            return window;
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Called once per frame to draw UIElements
        /// </summary>
        private void OnGUI()
        {
            this._cachedEditor.OnInspectorGUI();
        }

        /// <summary>
        /// Called when the window is active or created
        /// </summary>
        private void OnEnable()
        {
            if (HerveRuntimeSettings.Value == null)
            {
                if (!AssetDatabase.AssetPathExists(EditorConstants.DEFAULT_RUNTIME_SETTINGS_PATH))
                {
                    HerveRuntimeSettings.Value = ScriptableObject.CreateInstance<RuntimeSettingsSO>();
                    HerveRuntimeSettings.Value.name = EditorConstants.DEFAULT_RUNTIME_SETTINGS_NAME;
                    AssetDatabase.CreateAsset(HerveRuntimeSettings.Value, EditorConstants.DEFAULT_RUNTIME_SETTINGS_PATH);
                }
                else
                {
                    HerveRuntimeSettings.Value = AssetDatabase.LoadAssetAtPath<RuntimeSettingsSO>(EditorConstants.DEFAULT_RUNTIME_SETTINGS_PATH);
                }
            }

            if (this._cachedEditor == null)
            {
                this._cachedEditor = UnityEditor.Editor.CreateEditor(HerveRuntimeSettings.Value, typeof(RuntimeSettingsSOCustomEditor));
            }
            else
            {
                this._cachedEditor.target = HerveRuntimeSettings.Value;
            }
        }

        private void OnDisable()
        {
            Object.DestroyImmediate(this._cachedEditor);
        }

        #endregion

    }
}

Okay, so the answer was stupidly easy:

using Herve.Runtime.Models;
using UnityEditor;
using UnityEngine;

/// <summary>
/// Custom Inspector to display the RuntimeSettingsSO
/// in other editors
/// </summary>
[CustomEditor(typeof(RuntimeSettingsSO))]
public class RuntimeSettingsSOCustomEditor : Editor
{
    private Vector2 scrollPos;

    #region Public methods

    public override void OnInspectorGUI()
    {
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
        base.OnInspectorGUI();
        EditorGUILayout.EndScrollView();
    }

    #endregion
}

I had overriden the wrong method. CreateInspectorGUI() wasn’t the place to do so, since it needs to return the root visualelement of the editor. OnInspectorGI allows me to place the scrollView accordingly.