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
}
}
