Difference between revisions of "Interfacing with the Undo System"

From The Foundry MODO SDK wiki
Jump to: navigation, search
Line 4: Line 4:
 
  {
 
  {
 
     public:
 
     public:
         void        undo_Forward ()    LXx_OVERRIDE;
+
         void        und_Forward ()    LXx_OVERRIDE;
         void        undo_Reverse ()    LXx_OVERRIDE;
+
         void        und_Reverse ()    LXx_OVERRIDE;
 
  };
 
  };
  
Line 18: Line 18:
 
   
 
   
 
                 void
 
                 void
         undo_Reverse ()    LXx_OVERRIDE
+
         und_Reverse ()    LXx_OVERRIDE
 
         {
 
         {
 
                 std::string  temp;
 
                 std::string  temp;
Line 28: Line 28:
 
   
 
   
 
                 void
 
                 void
         undo_Forward ()    LXx_OVERRIDE
+
         und_Forward ()    LXx_OVERRIDE
 
         {
 
         {
                 undo_Reverse ();
+
                 und_Reverse ();
 
         }
 
         }
 
  };
 
  };
Line 42: Line 42:
 
         std::string        &name)
 
         std::string        &name)
 
  {
 
  {
         CLxUser_UndoService undoSvc;
+
         CLxLoc_UndoService undoSvc;
 
         CSwapName          *undo;
 
         CSwapName          *undo;
 
         ILxUnknownID        obj;
 
         ILxUnknownID        obj;
Line 60: Line 60:
 
         std::string        &name)
 
         std::string        &name)
 
  {
 
  {
         CLxUser_UndoService undoSvc;
+
         CLxLoc_UndoService undoSvc;
 
         CSwapName          *undo;
 
         CSwapName          *undo;
 
         ILxUnknownID        obj;
 
         ILxUnknownID        obj;
Line 74: Line 74:
 
  void changeEvent ()
 
  void changeEvent ()
 
  {
 
  {
         CLxUser_UndoService   undoSvc;
+
         CLxLoc_UndoService   undoSvc;
 
   
 
   
 
         if (undoSvc.State () == LXiUNDO_ACTIVE)
 
         if (undoSvc.State () == LXiUNDO_ACTIVE)

Revision as of 12:04, 20 July 2011

To handle your own undos you need to declare your undo object class.

class CMyUndo : public CLxImpl_Undo
{
    public:
        void         und_Forward ()     LXx_OVERRIDE;
        void         und_Reverse ()     LXx_OVERRIDE;
};

This object represents your undo action and will be managed by the undo system. The forward method will be called when your action is applied or "done" or redone, and reverse will be called when your action is undone.

Let's say, for example, that your undo state is a global string value, like the name of something. When you change the name you want to register the undo action to change it back. If the action is undone the name will go back to the original name, and if the action is redone then the name will change to the new name again. Since this action effectively performs a swap, the forward and reverse actions are essentially the same. Here's an example of such an undo object:

class CSwapName : public CLxImpl_Undo
{
    public:
        std::string  old_name;

                void
        und_Reverse ()     LXx_OVERRIDE
        {
                std::string   temp;

                temp = global_string;
                global_string = old_name;
                old_name = temp;
        }

                void
        und_Forward ()     LXx_OVERRIDE
        {
                und_Reverse ();
        }
};

You register your undo using the Undo service. First you have to allocate your undo object, which you can do with a spawner . This will give you both the ILxUnknownID for the COM object, and the pointer to your undo class. You then initialize the state of the new undo object and add it to the undo system.

This example changes the name and registers an undo action to change it back. In this case UndoService::Record() is used to register an undo action for a change that has already happened.

        void
SetGlobalName_Undoable (
        std::string        &name)
{
        CLxLoc_UndoService undoSvc;
        CSwapName          *undo;
        ILxUnknownID        obj;

        undo = SpawnUndo (obj);

        undo->old_name = global_string;
        global_string = name;

        undoSvc.Record (obj);
}

Because the action is a swap this function can be simplified by creating the action in an "undone" state. Adding it to the undo system by calling UndoService::Apply() performs the forward action and adds it to the system. This means there is only one implementation of the code that performs the swap.

        void
SetGlobalName_Undoable (
        std::string        &name)
{
        CLxLoc_UndoService undoSvc;
        CSwapName          *undo;
        ILxUnknownID        obj;

        undo = SpawnUndo (obj);
        undo->old_name = name;

        undoSvc.Apply (obj);
}

If the undoable change of state is as a result of your own command, then you know that it's always OK to register undo actions. Sometimes your change of state is the result of something more indirect, such as listener events or other state-change methods. In that case you have to make sure that the event is not the result of the user undoing or redoing other changes, in which case it's invalid to add undo events. This is easily tested with the undo service:

void changeEvent ()
{
        CLxLoc_UndoService   undoSvc;

        if (undoSvc.State () == LXiUNDO_ACTIVE)
                performUndoableChange ();
}

If you get an event when undos are active, you respond by changing your state and registering the undo. If, however, you get this same event notification as result of an undo you don't have to change state or register undos. In that case your own undo action will already be fired as part of the same undo.