0

I've implemented an undo function in my paint application. The idea is that the undo sets the layer to draw from an array of saved layers. This method is called right before the view is added to for drawing. Note that layerArray is a C array.

-(void)updateLayerUndo
{
CGLayerRef undoLayer = CGLayerCreateWithContext([self.theCanvas viewContext], self.theCanvas.bounds.size, nil);

layerArray[undoCount] = undoLayer;
undoCount += 1;
[[self.undoer prepareWithInvocationTarget:self]performUndoOrRedoWithValueForLayer:layerArray[undoCount - 1]];

}

When the user undoes, it calls the registered method, naturally:

-(void)performUndoOrRedoWithValueForLayer:(CGLayerRef)aLayer
{
undoCount -= 1;
self.theCanvas.myLayer = aLayer;
[[NSNotificationCenter defaultCenter]postNotificationName:@"UndoOrRedoPerformed" object:nil];
[self.theCanvas setNeedsDisplay:YES];
}

The view then does its drawing method, which really just draws the myLayer in the view's context. However, when the user undoes, the view clears out completely instead of incrementally. I feel like I'm missing something, or maybe I don't understand NSUndoManager. Oh, and the methods I showed above are both in an NSDocument subclass, and theCanvas is an instance of an NSView subclass.

PopKernel
  • 4,110
  • 5
  • 29
  • 51
  • Why are you using `self.undoer` instead of the `NSDocument`'s `self.undoManager`? OSX will automatically handle `beginUndoGrouping`/`endUndoGrouping` based on the event loop which will mean that your groups will be correctly created. If you're using a separately-managed `NSUndoManager`, you may not be getting the right group management (unless, you're returning your `self.undoer` from `windowWillReturnUndoManager:`). You're may also have an issue with redo registration, since you don't appear to be registering the opposite operation when you undo. – gaige Mar 02 '14 at 11:35
  • Oh, I didn't realize that the NSDocument class had an undo manager already. I thought you were responsible for creating one. I'll look into that! – PopKernel Mar 02 '14 at 14:31
  • Yeah, that didn't work… What's this about not registering the opposite? I thought it was enough to save previous layers into an array and access them. – PopKernel Mar 02 '14 at 17:10
  • What does your code that calls these actually look like, we're flying pretty blind here. Normally, you'd call `prepareWith...` when you change the model. The method you call specify is should basically reverse the model operation. You can do something similar with the views if you are careful. Additionally, if you want Redo to work, you need to call the `prepareWith...` in response to the undo. You know you're not copying anything into that CGLayer, right? Its going to be blank after initialization and before you put something in it. – gaige Mar 02 '14 at 23:07

1 Answers1

0

I figured it out. The confusion I was having is I was unclear how to set redo, so I misinterpreted what the documentation meant about the undo manager and redoes. I now know that to register a redo, I have to register a undo that is called while the manager is undoing.

PopKernel
  • 4,110
  • 5
  • 29
  • 51