Thu 11 Mar 2010 05:17:35 PM UTC, original submission:
For the sake of completeness:
There is no working Undo function or a history of changes.
The function needs to revert changes of any kind from a users point of view: Everything should reflect the way the user handles Denemo and Undo those actions, not Denemo's own procedures.
Important is not to pass the buck to script authors and users for the sake of a quick, clean and performant implementation. The most important point is that it works for all possible cases of scripts and actions a user can invoke. Script Authors and Users should not think about how to undo their scripts, Denemo should handle it alone.
Example: After Delete a note/chord it should place the exact same chord, with all its properties (staccato, attached directives, stem direction, thinkable future properties) on the same place.
Another Example for "Users view": If a scripts adds 4 notes Undo should not just delete the last one just because this was the very last primitive function. A script should be handled as one action.
Optional Features
- Unlimited Undo until the very beginning of a file.
- Make Undo possible even if Denemo is restarted in between, in other words create a Change History and save it in the .denemo file itself.
- Show the change history and return to a specific state at a current time
Additional thoughts from Ardour (http://www.ardour.org) main developer about Undo:
well, first of all, the basic goal was to avoid having to "register" specific actions/functions/methods ahead of time, which was how i understood the GIMP to have done things
because we had C++ available, and libsigc++ provided the abstraction of "closures" (a function/method along with its arguments) at a high level, myself and someone i bumped into on a mailing list unrelated to linux audio started hashing out some ideas
the basic idea was the keep a list of pairs of closures. one member of the pair represented how to undo an action, the other represented how to redo it
a specific command might consist of just one pair
or it might consist of N pairs. when undoing, you execute all the undo halves sequentially, ditto for redo
libs/pbd/undo.cc is a non-ardour-specific class that handles all this
the key object is Command, which is an abstract class
in ardour itself, the most common Command instance is something called MementoCommand
this is an object which stores the state of an object and a reference to the object. most things in ardour inherit from PBD::Stateful, and thus have a ::set_state(const XMLNode&) method
this makes it (relatively) easy to make a MementoCommand out of two XMLNodes (the before and after state) and a ref to the object
to undo, simply call set_state() with the "before" XMLNode ; to redo, call set_state() with the after state
HOWEVER
this has some pretty deep issues
one is that its inefficient in some cases. you end up storing the entire state of the object before & after, even if you only changed one tiny detail.
so we are trying to move toward a new instance of Command that just stores "deltas" and provides a way to change just one (or two) aspects of an object's state back and forth
|