- Home /
How do you undo operations from an EditorWindow?
I don't understand how to, for example, put sliders back where they were. Here's a test script, that will adjust the alpha value of the _Color property for a Material. Where I have lines commented out, I think I may be onto the right track, but am not sure. Please lead me further down said track, or reroute me.
using UnityEngine; using UnityEditor;
public class UndoTestWindow : EditorWindow {
static UndoTestWindow window; static Material material;
[MenuItem("Assets/Adjust Main Color Alpha", true)] static bool Validate () { if (window) return false;
try {material = (Selection.activeObject as GameObject).renderer.sharedMaterial;}
catch {material = Selection.activeObject as Material;}
return material ? material.HasProperty("_Color") : false;
}
[MenuItem ("Assets/Adjust Main Color Alpha", false, 2000)] static void Open () { window = GetWindow<UndoTestWindow>(true, material.name); }
void OnGUI () {
// Event currentEvent = Event.current; // if (currentEvent.button == 0 && currentEvent.isMouse) { // Undo.SetSnapshotTarget(window, "Adjust " + material.name + " Main Color Alpha"); // Undo.CreateSnapshot(); // Undo.RegisterSnapshot(); // }
Color color = material.color;
color.a = EditorGUILayout.Slider("Main Color Alpha", color.a, 0, 1);
material.color = color;
// if (GUI.changed) EditorUtility.SetDirty(window); }
}
I've learned that I can undo the operation, if I do
Undo.SetSnapshotTarget(material...
...but that only makes the material itself update, not the EditorWindow slider.
P.S. This is the first time I've ever used try/catch, so if you don't think that's a good use of it, for the validation function, please let me know. It seemed very concise.
EDIT: Here's what I've got, in OnGUI, that seems to be working. (Thanks to Daniele.) It seems like there ought to be a better way, to me please let me know if you ever come up with that way:
bool listeningForGuiChanges; void OnGUI () { Event currentEvent = Event.current; if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) { Undo.SetSnapshotTarget(material, "Adjust " + material.name + " Main Color Alpha"); Undo.CreateSnapshot(); Undo.ClearSnapshotTarget(); listeningForGuiChanges = true; }
Color color = material.color;
color.a = EditorGUILayout.Slider("Main Color Alpha", color.a, 0, 1);
material.color = color;
if (listeningForGuiChanges && GUI.changed) {
Undo.SetSnapshotTarget(material, "Adjust " + material.name + " Main Color Alpha");
Undo.RegisterSnapshot();
listeningForGuiChanges = false;
}
}
Id say that is improper usage of try/catch but I can't find a good article to back it up. However, in your case it probably won't do much of a difference to do it otherwise. You can try look for "best practices" on the topic of exception handling.
with try catch you are catching exceptions, so from my POV, catch is for exceptional circumstances only and not for the things that would occur in normal operation. Naturally it works fine, but if you were working on a large project and just catching general exceptions it starts to not scale well.
Answer by Statement · Apr 17, 2011 at 11:23 PM
The thing is that it will use serialization to save any data on the editor window, just like public fields (and SerializeField) do on your everyday scripts! I guess you should be setting a snapshot on the material instead of the window in your case, as the window doesn't hold any member fields suitable for serialization, but the material does.
Like I said, I did that, but although the color change is undone, the slider isn't. Are you saying Undo is impossible, in an Editor Window? That sounds like a lousy oversight...
Oh right, the slider isn't changing. $$anonymous$$aybe you need to repaint the window? By default, editor windows OnGUI isn't continously called. You could try calling Repaint(); or set autoRepaintOnSceneChange true. Undo is not impossible, but you're not having a typical setup to support Undo in that fashion. Since you aren't storing any values on the window itself, it would be meaningless to make a snapshot of the window, since it would have no values to undo.
autoRepaintOnSceneChange does the trick. When would I call Repaint? I don't see an event in the documentation for when Undo is called.
Repaint could be called continouosly, by ending the OnGUI with a call to Repaint(). It wont create a recursive loop, it will notify Unity to render the gui again next frame. But your autoRepaint sounds like a far better option.
Your answer
Follow this Question
Related Questions
Why do I get an empty Undo for my EditorWindow? 0 Answers
Tell difference between Undo & Redo on callback 0 Answers
Editing and Undo for non-unity properties 2 Answers
Undo problems with a Custom EditorWindow 0 Answers
Undo issues in EditorWindow 0 Answers