Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How to serialize primitive classes in a EditorWindow subclass?

Discussion in 'Scripting' started by AmitChBB, Apr 5, 2022.

  1. AmitChBB

    AmitChBB

    Joined:
    Feb 16, 2021
    Posts:
    36
    Hi there!

    I'm working on a custom editor window. It inherits from EditorWindow.

    I know you can serialize private variables in these types of classes in order to make them customizable via the inspector (the same way you would a Scriptable Object).
    You can do this to "configure" your editor window.

    I noticed that when I try to serialize basic types like string and bool like this, they don't show in the inspector.
    However, stuff like texture do show! It's quite strange.

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. namespace Demo.Scripts
    5. {
    6.     public class WindowTest : EditorWindow
    7.     {
    8.         [SerializeField]
    9.         private bool myBool = true; // Doesn't show in inspector
    10.         [SerializeField]
    11.         private string myText = null; // Doesn't show in inspector
    12.         [SerializeField]
    13.         private Texture myTexture; // Shows in inspector
    14.     }
    15. }

    I am assuming this is the intended behavior and not a bug, since it works for the more complex types.
    Does anyone know how to serialize these basic types?

    Thanks in advance!
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    This is not how you're meant to use Editor windows. When you use Editor Windows, you're meant to take full control of how it should draw fields, such as the example in the documentation: https://docs.unity3d.com/ScriptReference/EditorWindow.html

    Alternatively you can use UI toolkit's CreateGUI rather than OnGui to use the newer UI tools.
     
  3. AmitChBB

    AmitChBB

    Joined:
    Feb 16, 2021
    Posts:
    36
    Hi Spiney199, thanks for getting back to me :)

    Please excuse me if I'm not being clear:

    I'm not trying to create the editor window GUI right now. I know how to do that, and I am aware I need to use things like GUILayout, EditorGUILayout and so on in order to do that.

    What I am trying to do is to serialize fields for the editor window scriptable object itself. That way, when the window is opened, it will have some default values which are set beforehand.
    A good example is loading some texture to use as a 'header' for your editor window:

    Code (CSharp):
    1. public class MyCustomWindow : EditorWindow
    2.     {
    3.         [SerializeField] private Texture logoTexture;
    4.         private string myText = null;
    5.  
    6.         [MenuItem("Windows/MyCustomWindow", false, 0)]
    7.         public static void ShowWindow()
    8.         {
    9.             GetWindow(typeof(MyCustomWindow), true, "My Custom Window");
    10.         }
    11.  
    12.         void OnGUI()
    13.         {
    14.             GUILayout.Label(logoTexture);
    15.             GUILayout.Space(5);
    16.             myText = EditorGUILayout.TextField("My Text Field", myText);
    17.         }
    18.     }
    As you can see, I can supply a sprite to the scriptable object in the inspector view, and then when the window is opened the same sprite is shown as the header of my custom editor window.

    All I am wondering is if such a thing is possible with booleans, strings and the like, and if so - how.
     
    dsfgddsfgdsgd likes this.
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    Apologies I did misread you. Figured you were just trying to make an editor window the same way you'd make the inspector of other classes.

    You would think it should work but there's perhaps some reason why you can't.

    I imagine the workaround here is to make an Editor class for your EditorWindow class and draw/handle the fields yourself.
     
  5. dsfgddsfgdsgd

    dsfgddsfgdsgd

    Joined:
    Jan 24, 2014
    Posts:
    16
    I'm having a similar problem where fields are not appearing in the inspector for an editor window.

    Is there a solution to this problem?
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    You should post your code so far.

    As I mentioned last year simply serialising fields in an EditorWindow class won't make them draw. You have to draw them manually.
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    That is correct, however only an instane would serialize those values. Since EditorWindow instances are not stored on disk but only "live" in memory, this configuration would only persist as long as the window is open. Once you close the window or when you restart Unity, the data would be lost.

    Now you're looking at something completely different. You're not looking at an instance of an editor window but you look at the script asset inspector of the editor window class itself. Components and ScriptableObjects can have what they call Default References set up at the script / type level so when you create an instance of that editorwindow, those references are setup automatically. However those are only reference types to UnityEngine.Object assets you can setup there. You can not define default values for all serializable data here.

    When we talk about "configuring" an EditorWindow, we usually talk about viewing the EditorWindow instance in the inspector. Something like this:

    Code (CSharp):
    1. public class WindowTest : EditorWindow
    2. {
    3.     [SerializeField]
    4.     private bool myBool = true;
    5.     [SerializeField]
    6.     private string myText = null;
    7.     [SerializeField]
    8.     private Texture myTexture;
    9.  
    10.     [MenuItem("Tools/WindowTest")]
    11.     public static void Init()
    12.     {
    13.         GetWindow<WindowTest>();
    14.     }
    15.  
    16.     private void OnGUI()
    17.     {
    18.         if (GUILayout.Button("Config"))
    19.             Selection.activeObject = this;
    20.     }
    21. }
    Now just open a window through the Tools menu item it creates. This will actually create an instance in memory and open the window. I added a "Config" button to the window. When you click it the instance of the editor window itself would be selected so it can be viewed in the inspector. There you will see your 3 serialized variables without any issues. Though as I already said, those are not serialized to disk.

    EditorWindows are actually ScriptableObject (literally, the EditorWindow class is derived from ScriptableObject). However they only live in memory and are not permanentally stored on disk. If you have some configuration data, you usually would use EditorPrefs to store preferences.

    Note: When you setup default references on the script asset of the editor window, say you assign a texture to the default reference that shows up there, when you close the window and open the it again, the texture field should be pre-initialized with the asset reference you setup there. Note that default references ONLY works inside the Unity editor. When you setup default references for components / MonoBehaviours, they are only applied when you create an instance inside the Unity editor. When you create them at runtime they would not be applied. It's a pure editor feature to simplify the creation of those objects. Of course editorwindows are also a pure editor feature, so this doesn't matter here. Though you should understand what's the point behind the default references on script assets. They just serve as default references when you create instances of that type in the editor.
     
    dsfgddsfgdsgd and spiney199 like this.
  8. dsfgddsfgdsgd

    dsfgddsfgdsgd

    Joined:
    Jan 24, 2014
    Posts:
    16
    Thanks for your fast reply spiney

    The code looks like this

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.AddressableAssets;
    3. using UnityEngine.UIElements;
    4.  
    5. namespace Editor
    6. {
    7.     public class PrototypeEditor : EditorWindow
    8.     {
    9.        
    10.         [SerializeField] private VisualTreeAsset template;
    11.         [SerializeField] private VisualTreeAsset template2;
    12.  
    13.         [SerializeField] public int number;
    14.         [SerializeField] public bool truthy;
    15.        
    16.         [SerializeField] public AssetReference someReference;
    17.        
    18.     }
    19. }
    I'm expecting all the serialized fields to show up in the inspector, but I can only see the Visual Tree Asset fields

    MissingFields.png

    , I'm wondering what other people have done to set these types of fields?
     
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    Pretty sure only types inheriting from
    UnityEngine.Object
    can be referenced in those default fields. Nothing else can.

    FYI the script asset is not the editor window, in case there is any misunderstanding there.
     
    dsfgddsfgdsgd likes this.
  10. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    If you want to provide some config data for your editor window, you probably should create a seperate ScriptableObject that just holds the config data you're interested in. You can setup the default references of your window to reference that asset you create in your project. Now you can edit the scriptable object instance that you stored as asset and have the editor window reference it.
     
    dsfgddsfgdsgd likes this.
  11. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,862
    Call me crazy, but can't you also make instances of EditorWindow scriptable objects and write them to disk?

    Then you can retrieve it in whatever static method you define to open the window.
     
  12. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    In theory, yes, practically no because EditorWindows are marked as DontSave objects. So you can slam a CreateAssetMenu onto an EditorWindow class and you can create an instance in the project folder, however you immediately get some asserts from the deep internals of Unity stating exactly what I just mentioned. Also that object somehow gets corrupted as it's not saved but you kinda forced it to. As a result I couldn't delete the broken asset anymore inside the editor. I had to delete it through the explorer. So yes, storing an EditorWindow instance as an asset would theoretically be possible, though the current implementation does not really allow it.
     
    ThermalFusion likes this.