Re: [pygtk] Undo and Redo
On Sun, Sep 04, 2005 at 09:51:11AM +0200, N. Volbers wrote: > def my_function(arg1, arg2, undolist=[]): Have you checked to be sure that the default list argument is indeed safe? This is usually very error-prone, because the list is created and associated with the class, not the instance. Or is this just an example? Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3376 0125 ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Undo and Redo
On Sun, Sep 04, 2005 at 09:51:11AM +0200, N. Volbers wrote: > Look at "Documentation" and then at the "Developer's Guide". This is a > very nice introduction to an undo mechanism that basically works like > this: If you call an undoable function, then it must return an > undo-tuple which contains the name of a function f and the appropriate > arguments x,y,..., so that f(x,y,...) will undo the last action. This > will also enable you to offer a "redo" mechanism for free! This seems more Pythonic to me than the Java-ish Action base class method. If you wanted to get fancy, you could use a decorator, so you just decorate the methods you want un/redoable. Dave Cook ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Undo and Redo
3. Yet another approach is used by gazpacho (google for link), where for every action there is a wrapper with a do and an undo function. I have tried this approach for a molecular editing tool and it worked very well. Later on I've switched to a similar (but more complex) mechanism that was even easier to maintain: - create an Action base class that has a pre_do, do and post_do method, no undo. - When such action object is created, the tree methods are called in order - in pre_do, the action assigns itself as current_action to the application model - In the do method the application model is only modified through primitive action objects with very limited functionality. Both do and undo method's of the primitives are very simple. (I have only five of such different Primitive types for a molecular editing tool). In the initialization of the Primitive class, there are two lines like this: context.application.current_model.current_action.primitives.append(self) self.do() - the post_do method, the current action is pushed on the undo stack and the redo stack is cleared When undo is called: - The last action is popped from the undo stack - the undo methods of all primitives are called in reverse order - the action is pushed on the redo stack Similar things happen when redo is called This approach has some strong advantages: - The fact the the do&undo method pairs are limited, saves you a lot of time, because for all (non-primitive) actions you don't have to care about the fact that do and undo are each others inverses. This is also the main reason why I took this approach. - If some primitive actions have 'consequenses', they are also tracked. In my case: when an atom is removed from a molecule, also the bonds connecting the atom to other atoms had to be removed from the model. - Not all actions have to be undoable: saving files, changing the configuration of the program, opening a online help, ... Such actions have an empty primitives list when post_do is executed. Just leave these actions out of the undo stack. It's also rather easy to extend the idea in several ways: - for each class derived from Action you can also write a static method that tells when the action is applicable or not. - Repeat functionality is also easily implemented. Just make sure that parameterized actions store their parameters in dedicated object. - Interactive actions, like rotating a molecule with the mouse, also fit in this framework. Yo see, there is a lot to tell about undo&redo. If you plan to write a program that will grow a very large set of features (actions), then you really have to consider to make your undo mechanism rock solid. It will certainly pay off in terms of implementation time. good luck, Toon ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Undo and Redo
On 9/4/05, Brett Viren <[EMAIL PROTECTED]> wrote: > Hi Jens, > > Jens Geiregat <[EMAIL PROTECTED]> writes: > > > I would like to add undo and redo buttons to my program. The problem > > is I do not have any idea how to implement the undo and redo-actions. > > Are there some (easy) examples on this subject? Or other (small) > > pygtk-programs that support undo and redo? > > What you want to do is google "memento design pattern". It's well > discussed in the GOF's Software Design Patterns book. > > Basically, just before your application data is modified, it must > bundle up any information it needs in order to undo this mod. This > bundle is the memento. It then pushes this memento object onto an > undo stack and makes whatever change. When you click the "undo" > button the top memento is popped from the undo stack and applied to > your application data (and its UI reflects this change). By requiring > the the application to produce a memento at the time of applying the > undo memento, you can keep a redo stack as well. > > All this is very application specific so must be written to fit. It > works best when you abstract your application data away from the UI > (ie, as a model in MVC) and have the model present and accept > mementos. In principle, it would be possible to allow automatic > undo/redo in an MVC system, but I've not seen it in the few I've > looked at. > > Luck, > -Brett. > > Thanks a lot guys! Jens Geiregat ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Undo and Redo
Jens Geiregat schrieb: Hi, I would like to add undo and redo buttons to my program. The problem is I do not have any idea how to implement the undo and redo-actions. Are there some (easy) examples on this subject? Or other (small) pygtk-programs that support undo and redo? Hello Jens, your question is a very interesting one! I had the same problem about a year ago when I started writing my application in python. As a starting point, I would advise you to look at the following three sources: 1. Skencil, a vector drawing program: http://www.nongnu.org/skencil/ by Bernhard Herzog. Look at "Documentation" and then at the "Developer's Guide". This is a very nice introduction to an undo mechanism that basically works like this: If you call an undoable function, then it must return an undo-tuple which contains the name of a function f and the appropriate arguments x,y,..., so that f(x,y,...) will undo the last action. This will also enable you to offer a "redo" mechanism for free! The only problem I had with this approach was that you waste the possibility to use the return value! 2. SloppyPlot, a plotting program, written by myself :-), http://sloppyplot.berlios.de It includes an Undo library (Sloppy.Lib.Undo) which works similar to the one found in Skencil, with the difference, that the undo information is appended to an undo list, which is passed to the function as keyword argument: def my_function(arg1, arg2, undolist=[]): undolist.append( ...undo information... ) The benefit of this approach is, that you can still return any value you like. Also, you can decide not to use the undo mechanism by simply not passing any undolist to the function. In this case, the undo information is appended to the [] list and is basically discarded! If you need more information, feel free to contact me. 3. Yet another approach is used by gazpacho (google for link), where for every action there is a wrapper with a do and an undo function. Hope this helps, Niklas. ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Undo and Redo
Hi Jens, Jens Geiregat <[EMAIL PROTECTED]> writes: > I would like to add undo and redo buttons to my program. The problem > is I do not have any idea how to implement the undo and redo-actions. > Are there some (easy) examples on this subject? Or other (small) > pygtk-programs that support undo and redo? What you want to do is google "memento design pattern". It's well discussed in the GOF's Software Design Patterns book. Basically, just before your application data is modified, it must bundle up any information it needs in order to undo this mod. This bundle is the memento. It then pushes this memento object onto an undo stack and makes whatever change. When you click the "undo" button the top memento is popped from the undo stack and applied to your application data (and its UI reflects this change). By requiring the the application to produce a memento at the time of applying the undo memento, you can keep a redo stack as well. All this is very application specific so must be written to fit. It works best when you abstract your application data away from the UI (ie, as a model in MVC) and have the model present and accept mementos. In principle, it would be possible to allow automatic undo/redo in an MVC system, but I've not seen it in the few I've looked at. Luck, -Brett. ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
[pygtk] Undo and Redo
Hi, I would like to add undo and redo buttons to my program. The problem is I do not have any idea how to implement the undo and redo-actions. Are there some (easy) examples on this subject? Or other (small) pygtk-programs that support undo and redo? thx, Jens Geiregat ___ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/