Search Unity

RecordUndo changes using Handles.MoveHandle

Discussion in 'Immediate Mode GUI (IMGUI)' started by Dark-Protocol, Jan 24, 2016.

  1. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Hello,
    TL;DR Version: How to properly record undo states when moving an object using Handles.MoveHandle ?

    I'm working on a custom editor which allows me to move some non-gameobject and non-transform objects in the scene view using Handles. (the objects are stored in a component). I have a custom editor for the component that holds the moveable objects and I'm trying to add Undo functionality via Undo.RecordObject. My problem is that it's hard to know when to record the undo since there is no way for the custom editor to know whether or not the user is going to move the handle. For example, I can just click on the handle and not move the object. I can check for changes using GUI.changed or just manually check if the position of the object has changed and record the undo then but recording at that time will be too late because the object has already moved. My solution was to save the object's position every OnSceneGUI and if a movement is detected, then save the moved position, revert the object's position to the previously recorded position, record the undo and then restore the object's position from the saved object's position and then set a flag which will prevent the editor for saving more states until the user has released the left mouse button.

    So for example:
    Code (CSharp):
    1. Vector3 originalPos = point.position;
    2. point.position = Handles.MoveHandle(point.position.....);
    3. if(point.position != originalPos && canRecordUndo){
    4. Vector3 movedPos = point.position;
    5. point.position = originalPos;
    6. Undo.RecordObject(target, "Point move");
    7. canRecordUndo = false;
    8. }
    And later check if the left mouse button has been released and set canRecordUndo to false.

    Now, as you can see, this is all really clunky and complicated so I was wondering if there was a better way to do it. I tried saving undo states after each movement. Kind of like Photoshop does with the History. So it would be like:
    Code (CSharp):
    1. Vector3 originalPos = point.position;
    2. point.position = Handles.MoveHandle(point.position.....);
    3. if(point.position != originalPos){
    4. undoIsRecording = true;
    5. }
    6. if(LeftMouseButtonUp && undoIsRecording){
    7. undoIsRecording = false;
    8. Undo.RecordObject(target...);
    9. }
    But that doesn't work at all because I guess RecordObject has to be used before making any changes, not after making the change

    Also, I don't like the whole thing where I need to check if the mouse button is up because if I'm not hovering over the scene view or over the inspector with the mouse, I can't capture that event so an Undo state won't be created.
     
  2. skalev

    skalev

    Joined:
    Feb 16, 2012
    Posts:
    264
    You do need to record the object before moving it. If you just call Undo.RecordObject() or Undo.RegisterCompleteObjectUndo(), unity will do the rest. you don't need to record anything, and if no changes happened, there will be no undo.
     
  3. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Thanks Skalev, I actually figured that out myself several days ago but I forgot to post back. Didn't expect it to be so easy.