- Home /
Why does Undo.RecordObject not work after EditorGUILayout.CurveField?
Undo.RecordObject doesn't add a new undo record and doesn't mark the scene as dirty after I modify a curve in the editor which is drawn by EditorGUILayout.CurveField in OnInspectorGUI event.
The other fields I tried work fine but CurveField doesn't cause the undo system work even thou GUI.changed is True.
How can I record the modified curve to undo system (and mark the scene dirty) ?
public override void OnInspectorGUI()
{
if (Driver.WidgetType == null)
{
SelectedTypeIndex = EditorGUILayout.Popup(SelectedTypeIndex, TypeNames);
if (GUILayout.Button("Set Widget Type")) SetWidgetTypeButtonClick();
}
else
{
EditorGUILayout.LabelField(Driver.WidgetType.FullName);
foreach (var Property in WidgetDriver.Properties[Driver.WidgetType])
{
var Value = Property.GetValue(Driver.Widget, null);
object NewValue = null;
//todo: Bu kısım EditorUtilities'e geçirilsin.
if (Property.PropertyType == typeof(Bounds)) NewValue = EditorGUILayout.BoundsField(Property.Name, (Bounds)Value);
else if (Property.PropertyType == typeof(Color)) NewValue = EditorGUILayout.ColorField(Property.Name, (Color)Value);
else if (Property.PropertyType == typeof (AnimationCurve)) NewValue = EditorGUILayout.CurveField(Property.Name, (AnimationCurve)Value ?? new AnimationCurve());
else if (Property.PropertyType == typeof (string)) NewValue = EditorGUILayout.TextField(Property.Name, (string)Value);
else if (Property.PropertyType == typeof (int)) NewValue = EditorGUILayout.IntField(Property.Name, (int)Value);
else if (Property.PropertyType == typeof (float)) NewValue = EditorGUILayout.FloatField(Property.Name, (float)Value);
else if (Property.PropertyType == typeof (bool)) NewValue = EditorGUILayout.Toggle(Property.Name, (bool)Value);
else if (Property.PropertyType == typeof (Vector3)) NewValue = EditorGUILayout.Vector3Field(Property.Name, (Vector3)Value);
else EditorGUILayout.LabelField($"{Property.Name} (unsupported type)");
if (GUI.changed)
{
Undo.RecordObject(Driver, $"Set Widget Property: {Property.Name}");
try
{
Property.SetValue(Driver.Widget, NewValue, null);
}
catch (Exception E)
{
Debug.LogException(E);
}
}
}
}
}
Answer by IgorAherne · Jul 19, 2017 at 10:14 PM
I found this post by complete accident:
quoting it in case it's deleted:
.
Undo.RegisterCompleteObjectUndo(Object objectToUndo, string name)
will record a copy of the full state of the object that it will keep, unlikeUndo.RecordObject(Object objectToUndo, string name)
that will only keep a copy of the state until the end of the frame to compute a diff.
By the way, I just got the following error that drove me to find more on this method:
Generating diff of this object for undo because the type tree changed. This happens if you have used Undo.RecordObject when changing the script property. Please use Undo.RegisterCompleteObjectUndo So RegisterCompleteObjectUndo seems important in complex situations were a diff is not possible.
Couple of words from myself:
Undo.RegisterCompleteObjectUndo seems to work with Event and editor-GUI as well every time. And RecordObject seemed only to work sometimes (only worked occasionally)
Additionally, if you are working with Event in editor script, and actually have code that Use()s the GUI event, chances are the event might not get through to unity's undo system. You might need to call Undo.FlushUndoRecordObjects(); after RegisterCompleteObjectUndo()
.
Don't forget to use EditorUtility.SetDirty() on the object, AFTER you've recoreded into Undo
Here is an example, allowing me to offset 2D viewport up/down left/right:
void DragViewingArea() {
int id = GUIUtility.GetControlID(6, FocusType.Passive);
//prepare for drag:
if (_currentEvent.type == EventType.MouseDown && _currentEvent.button == 2) {
Undo.RegisterCompleteObjectUndo(_fsm, "begin drag FSM viewport on " + _fsm.gameObject.name);
Undo.FlushUndoRecordObjects();
GUIUtility.hotControl = id;
_currentEvent.Use();
return;
}
//drag:
if(_currentEvent.type == EventType.MouseDrag && GUIUtility.hotControl == id) {
_fsm._fsmEditorWindow_TableOffset += _currentEvent.delta;
_currentEvent.Use();
EditorUtility.SetDirty(_fsm); //set dirty as soon as we actually drag
return;
}
//finished dragging
if (_currentEvent.type == EventType.mouseUp && _currentEvent.button == 2 && GUIUtility.hotControl == id) {
GUIUtility.hotControl = 0;
_currentEvent.Use();
return;
}
}
Your answer
Follow this Question
Related Questions
How to remove undo from history (RevertAllInCurrentGroup?) 1 Answer
AnimationCurve, how can i know when the end of the curve has been reached? 3 Answers
Simple question about a graph controlling 0 Answers
How can I set the tangents of Keyframes in an AnimationCurve through scripting? 1 Answer
Evaluating Animation Curves in Full 0 Answers