Re: [pygtk] Undo and Redo

2005-09-19 Thread Christian Robottom Reis
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

2005-09-04 Thread David M. Cook
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

2005-09-04 Thread Toon Verstraelen

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

2005-09-04 Thread Jens Geiregat
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

2005-09-04 Thread N. Volbers

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

2005-09-03 Thread Brett Viren
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

2005-09-03 Thread Jens Geiregat
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/