Search Unity

How can I use Undo for an EditorWindow?

Discussion in 'Immediate Mode GUI (IMGUI)' started by JoePatrick, May 11, 2019.

  1. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    So I have made a few custom inspectors before and used the Undo system but how do you use it for an EditorWindow when there are no objects to pass to Undo.RecordObject(), I just want to be able to undo changes to local variables.
    Here is what I have
    Code (CSharp):
    1. namespace RapidIconUIC
    2. {
    3.     public class RapidIconWindow : EditorWindow
    4.     {
    5.         static RapidIconWindow window;
    6.  
    7.         public AssetList assetList;
    8.         public DraggableSeparator leftSeparator, rightSeparator;
    9.         public AssetGrid assetGrid;
    10.         public IconEditor iconEditor;
    11.  
    12.         [MenuItem("Tools/RapidIcon")]
    13.         static void Init()
    14.         {
    15.             window = (RapidIconWindow)GetWindow(typeof(RapidIconWindow), false, "RapidIcon");
    16.             window.minSize = new Vector2(870, 600);
    17.             window.Show();
    18.         }
    19.  
    20.         private void OnEnable()
    21.         {
    22.             //A load of init stuff, including this:
    23.             iconEditor = new IconEditor(assetGrid, window);
    24.             iconEditor.LoadData();
    25.         }
    26.  
    27.         private void OnDisable()
    28.         {
    29.             //Saves some variables to EditorPrefs
    30.             iconEditor.SaveData();
    31.         }
    32.  
    33.         void OnGUI()
    34.         {
    35.             if (!window)
    36.                 Init();
    37.  
    38.             //A load of stuff including:
    39.             iconEditor.Draw(window.position.width - rightSeparator.value, window);
    40.         }
    41.     }
    42. }
    Then in the IconEditor class (doesn't derive from anything), I have a bunch of variables that are changed with GUI controls e.g.
    Code (CSharp):
    1. void DrawTransformControls()
    2.         {
    3.             EditorGUI.BeginChangeCheck();
    4.             Vector3 camPos = EditorGUILayout.Vector3Field("Camera Position", currentIcon.cameraPosition);
    5.             //And some others
    6.             if (EditorGUI.EndChangeCheck())
    7.             {
    8.                 Undo.RecordObject(this, "IconEditor Undo"); //Can't do this as IconEditor is not an Object
    9.                 currentIcon.cameraPosition = camPos; //bad example as I'm changing another object here, but sometimes I do just change a local variable to the IconEditor class
    10.                 //currentIcon also cannot be converted to an Object either anyway
    11.                 UpdateIcon(currentIcon);
    12.             }
    13.         }
    So how can I add undo functionality in this script, and others like it

    Thanks :)
     
    Last edited: May 11, 2019
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    You can mark IconEditor as Serializable, and then pass the RapidIconWindow to the IconEditor to record that.

    When doing Undo/Serialization in an Editor Window, it's the editor window itself you're serializing, as it's a ScriptableObject that Unity does some magic to. Exactly the rules for what serializes and why is undocumented and a bit esoteric, but for the most part it works as usual.
     
  3. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Thanks, I will give that a go :)
     
  4. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    That worked, thanks a lot :D
     
  5. RayAndGames

    RayAndGames

    Joined:
    Sep 5, 2019
    Posts:
    9

    Hello, Sir, it's been a year but I hope you can explain a little bit more about "passing the RapidIconWindow to the IconEditor"
    I have a trouble in trying to implement this Undo system. My code looks like this inside the Editor:


    Code (CSharp):
    1. [System.Serializable]
    2. [CustomEditor(typeof(ChatAsset))]
    3. public class Editor_ChatAsset : Editor
    4. {
    5.     public override void OnInspectorGUI()
    6.     {
    7.         if (GUILayout.Button("Open Window"))
    8.         {
    9.             Window_ChatAsset.Open((ChatAsset)target);
    10.         }
    11.         EditorGUILayout.Space();
    12.         base.OnInspectorGUI();
    13.     }
    14. }

    If you're wondering what Window_ChatAsset.Open() does:
    Code (CSharp):
    1.     public static void Open(ChatAsset chatAsset)
    2.     {
    3.         Window_ChatAsset window = GetWindow<Window_ChatAsset>("Chat Asset Editor");
    4.         window.serializedObject = new SerializedObject(chatAsset);
    5.     }

    I don't really understand how Undo works, and I have read many articles and threads about. Nothing works, or to put it more precise, I don't know how to make it work. Please help..
     
  6. dlghwls

    dlghwls

    Joined:
    May 24, 2020
    Posts:
    2
    Is the problem not resolved yet? Try this.
    Code (CSharp):
    1. [Serializable]
    2.     public class TestWindow : EditorWindow
    3.     {
    4.         [SerializeField] private float test = 0;
    5.         private static TestWindow testWindow;
    6.         private static SerializedObject serializedTestWindow;
    7.  
    8.  
    9.  
    10.         [MenuItem("Test/OpenTestWindow")]
    11.         private static void OpenTestWindow()
    12.         {
    13.             testWindow = GetWindow<TestWindow>(false);
    14.             serializedTestWindow = new SerializedObject(testWindow);
    15.         }
    16.         private void OnGUI()
    17.         {
    18.             Undo.RecordObject(serializedTestWindow.targetObject, "test");
    19.             test = EditorGUILayout.FloatField(nameof(test), test);
    20.         }
    21.     }
    Open window and change test property. And try undo.