For plugin developer it is important to know how the undo system in Demopaja works. The undo systems acts as a kind of garbage collector where all the changed data during is put. And on undo, the data is put back where it came from. The changed data during a single event is put inside a container called undo object. These objects are stored into a ring buffer. The size of this buffer could be for example 100 and when the buffer overflows the oldest undo object is destroyed. At the same time the changes stored in that undo object are deleted and it cannot be undone ever again.
If data should be allocated or deleted during the change operation the pointer to that data is also stored into the undo object. When put, the data is marked either being destroyed or being created. When the object is flushed out of the undo cache if the data is marked to be deleted it is deleted. The deletion flag may be changed is the undo object is undone. Then created data is destroyed and deleted are kept. This all may sound a bit complicated but it has proven to work very well.
After reading this section you should be able to understand the meaning of the few methods which are common in all the EditableI derived classes you will be implementing.
Most of the undo stuff is done internally by the Demopaja system. The only task left for the developer is to complete the methods needed for the undo system. The same methods are also used to make duplicates of the data using the Copy/Paste operation. The methods to be implement are:
create( EditableI* pOriginal )
copy( DataBlockI* pBlock )
restore( EditableI* pEditable )
The second create method is similar as the first, but it is used during the undo process. It should call the constructor which accepts a pointer to the original instance. Each class derived from the EditableI or it's derived classes should have that constructor. The constructor takes care of some of the internal undo logic, and also stores the pointer to the original instance. Using the original instance the data can be later on restored.
The copy() method copies everything from the instance specified as the argument. After the copy() method is called the instace should be able to work as the instance where the data was copied from. This method is used during the duplication process.
The restore() method is used during the undo process to store a snapshot of the state of the effect. It should by no means make a full duplicate of the instance, but only copy the data that is required to restore the state back (using the same method) when the undo action is proceed.
When user requests to change something in the Demopaja (for example change value of a parameter, create new effect) the object that is to be changed is asked to clone itself. The cloned object is put into the undo object. The process of changing a parameter uses the following procedure:
EditableI* pClone; pClone = pObj->clone(); pUndo->add_restore_data( pClone ); pObj->change_param(...);
The clone method can be written as:
pClone = pObj->create( pObj ); // Use clone constructor. pClone->restore( pObj ); // Store current state using restore.
When the change is undone the following procedure is used:
EditableI* pState; EditableI* pOriginal; pState = undoStack[i]; pOriginal = pState->get_original(); pOriginal->restore( pState );
To make a duplicate of an existing object the Demopaja uses the almost similar system as storing data in an undoable action. When the methods in undo actions were clone(), create( EditableI*), and restore() the methods to create a duplicate object are duplicate(), create(), and copy(). When a duplicate is needed the Demopaja system calls the duplicate() method. The duplicate method uses following procedure:
EditableI* pDup; pDup = pObj->create(); // Use default constructor. pDup->copy( pObj ); // Copy the data using copy.