Search code examples
swiftundonsundomanager

How to add Undo for NSBezierPath with NSUndoManager on Mac OS X with Swift 4?


I'm trying to add Undo function for NSBezierPath.

This function draws circle with NSBezierPath with radius 45. with mouseLocation as center of the circle

Then it draws the NSBezierPath on CAShapeLayer and add to the NSViewController's view.

How should I add Undo function for this method. Thank you in advance.

func bezierPathMouseUndoTest(mouseLocation: CGPoint, color: NSColor) {

    let frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(100), height: CGFloat(100))

    // The path should be the entire circle.
    let circlePath = NSBezierPath.init()
    circlePath.appendArc(withCenter: CGPoint(x: mouseLocation.x, y: mouseLocation.y), radius: (frame.size.width - 10)/2, startAngle: CGFloat(90.0), endAngle: CGFloat(-270.0), clockwise: true) // start from up

    // Setup the CAShapeLayer with the path, colors, and line width
    circleLayer = CAShapeLayer()

    circleLayer.path = circlePath.CGPath

    circleLayer.fillColor = NSColor.clear.cgColor
    circleLayer.strokeColor = color.cgColor
    circleLayer.lineWidth = 5.0;

    circleLayer.strokeEnd = 1.0
    circleLayer.frame = frame

    // Add the circleLayer to the view's layer's sublayers
    self.view.layer?.addSublayer(circleLayer)
    self.undoManager?.setActionName("Draw Bezier Path")

}

Solution

  • Thank you Willeke.

    I added undo for Adding bezierPath to new layer using additional two functions. And changed the above code a little bit.

    replace "self.view.layer?.addSublayer(circleLayer)" with "self.addSublayer(layer: circleLayer)"

    remove "self.undoManager?.setActionName("Draw Bezier Path")"

    add two functions below

    func addSublayer(layer: CALayer) {
        undoManager?.registerUndo(withTarget: self, selector: #selector(removeSublayer), object: layer)
        self.undoManager?.setActionName("Draw Bezier Path")
        self.view.layer?.addSublayer(layer)
    
    }
    
    func removeSublayer(layer: CALayer) {
        undoManager?.registerUndo(withTarget: self, selector: #selector(addSublayer), object: layer)
        layer.removeFromSuperlayer()
    }