[comp.sys.mac.programmer] Heaps + Undo

pcossenb@rodan.acs.syr.edu (Paul C. Ossenbruggen) (06/06/89)

I have a question about heaps. It seems that during the execution of my program
a lot of little handles are created (13 bytes, to be exact) and then deleted.
So what I get on the heap is hundreds of these thirteen byte chunks of free
space. It does not seem to create any problems but I am wondering if it is
symptomatic of a bug. I have used TMON's heap scramble and purge
and have had no crashes (this also gets rid of them). So if it does not matter,
I will forget about it but if you know what might be the cause and if it is a
problem please let me know.

Also does anyone have any experience writing routines to handle undo? If you
have, could you give me an overview of the procedures involved for implementing
it in a graphics environment? I'd mainly like to know how you store the info
that has been deleted and then restore it without creating anomolies. It would
be really helpful if you had some example code I could look at or if you know
of some that is available.

Thanks.
 - Paul








-------------------------------------------------------------------------------
|  Paul C. Ossenbruggen                     pcossenb@rodan.acs.syr.edu        |
|  Syracuse University                      rspco@suvm.bitnet                 |
|                                            pcossenb@sunrise.acs.syr.edu      |

lsr@Apple.COM (Larry Rosenstein) (06/07/89)

In article <1634@cmx.npac.syr.edu> pcossenb@rodan.acs.syr.edu (Paul C. 
Ossenbruggen) writes:

> So what I get on the heap is hundreds of these thirteen byte chunks of 
free
> space. It does not seem to create any problems but I am wondering if it 
is
> symptomatic of a bug. I have used TMON's heap scramble and purge

Not necessarily.  If the stuff is being freed, then everything should be 
cool.  You can try breaking on NewHandle and/or DisposHandle and see who 
is creating/freeing these things, which might point out an inefficiency in 
your program.


> Also does anyone have any experience writing routines to handle undo? If 
you
> have, could you give me an overview of the procedures involved for 
implementing
> it in a graphics environment? I'd mainly like to know how you store the 
info
> that has been deleted and then restore it without creating anomolies. It 
would
> be really helpful if you had some example code I could look at or if you 
know

There are 2 implementation techniques you can use for Undo.  I will use a 
drawing program as the example, since that seems to be what you are asking 
about.

The straightforward technique is to save enough information so that the 
command can be reversed.  For example, if you move a bunch of shapes, you 
can save the distance they were moved  and then to Undo this you simply 
move the same shapes in the opposite direction.

This assumes that you know what shapes were involved in the command, which 
means you also have to remember the selection at the time the command was 
done.  The easiest way to represent selections in a graphics document is 
to add an isSelected bit to each shape.  To remember the current 
selection, therefore, you can add a wasSelected bit.  (This breaks down if 
you wanted to implement multiple levels of undo, however.)

So when you do the command you copy the isSelected bits into the 
wasSelected bits, and do the command.  To undo it, you copy the bits back, 
and then reverse the command.  This means that after the Undo the 
selection will be the same as when the command was originally done, which 
I think is the right thing to do.

This technique breaks down when the amount of information you have to 
remember becomes large or difficult to deal with.  For example, consider 
the Bring to Front command.  In this case you would need to remember the 
exact position of each shape in the list, so that you can put it back in 
the right spot.  This would either require an index field in each object, 
or that you make a copy of the list of shapes, etc.  Any of these 
approaches uses a lot of memory.   Many commands in a graphics editor are 
like this (e.g., changing the fill pattern in the selected shapes).

The solution, therefore, is to pretend the command has been done.  You 
don't change your internal data structures to bring the shapes to the 
front, but you display them on the screen as if the data structures had 
been changed.  You can think of this as a filter that you place between 
the data structure and the display code.  With the filter in place, it 
looks as if the command has been done, but to undo the command you can 
simply remove the filter.  

Assume that the shapes are normally drawn from back to front.  The Bring 
to Front filter changes this order by drawing all the unaffected shapes 
first, and then running through the list a second time drawing the 
affected shapes.  Similarly, implementing change fill pattern involves a 
filter that draws each affected shape with a new pattern, rather than the 
one stored with the shape.

Using filters adds a complication.  When the command can no longer be 
undone, then the filter must be committed against the data structures.  In 
the case of Bring to Front, for example, this means that when the user 
does the next command you first have to adjust the list of shapes to 
(finally) execute the Bring to Front command.  Note that you don't do this 
if the user has undone the Bring to Front command; in that case, the 
filter is not being used.

In MacApp, we use command objects to represent undoable commands.  The 
TCommand class has a Commit method (in addition to DoIt, UndoIt, and 
RedoIt), just so that you can implement filtering.  MacApp will call the 
Commit method just before it calls the DoIt method of the next command 
object (assuming that the old command hasn't been undone).

I don't have any example code that shows the use of filtering, so I can't 
help out there.

Larry Rosenstein, Apple Computer, Inc.
Object Specialist

Internet: lsr@Apple.com   UUCP: {nsc, sun}!apple!lsr
AppleLink: Rosenstein1