Reputation: 37
I'm trying to write a small drawing app for macOS in Swift using Cocoa. The problem is that the last drawn line disappears when the NSView
is drawn again. Is there a way to keep the drawn lines? I could save the points in an array, but that would drastically decrease the performance. Unfortunately, the CGContextSaveGState
function doesn't save paths.
Here's my class for the NSView
I'm drawing in (with a mouse or a stylus):
import Cocoa
class DrawingView: NSView {
// Variables
var lastPoint = CGPoint.zero
var currentPoint = CGPoint.zero
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
var alpha: CGFloat = 1.0
var brushSize: CGFloat = 2.0
var dragged = false
// Draw function
override func drawRect(rect: NSRect) {
super.drawRect(rect)
let context = NSGraphicsContext.currentContext()?.CGContext
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y)
if !dragged {
CGContextAddLineToPoint(context, lastPoint.x, lastPoint.y)
} else {
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y)
lastPoint = currentPoint
}
CGContextSetLineCap(context, .Round)
CGContextSetLineWidth(context, brushSize)
CGContextSetRGBStrokeColor(context, red, green, blue, alpha)
CGContextSetBlendMode(context, .Normal)
CGContextDrawPath(context, .Stroke)
}
// Mouse event functions
override func mouseDown(event: NSEvent) {
dragged = false
lastPoint = event.locationInWindow
self.setNeedsDisplayInRect(self.frame)
}
override func mouseDragged(event: NSEvent) {
dragged = true
currentPoint = event.locationInWindow
self.setNeedsDisplayInRect(self.frame)
}
override func mouseUp(event: NSEvent) {
self.setNeedsDisplayInRect(self.frame)
}
}
Upvotes: 2
Views: 527
Reputation: 535086
You are looking for CGContextCopyPath. It hands you a CGPath pseudo-object. The easiest way to preserve that it is to stuff into an NSBezierPath as its path
, because an NSBezierPath is a real object and ARC will memory-manage it for you.
Upvotes: 1
Reputation: 437482
For this scenario, I'd step out of CoreGraphics and use NSBezierPath
. You can save that in a property. You can then just call lineToPoint
as more points come in and then call stroke
to draw it. For example:
let strokeColor = NSColor(red: red, green: green, blue: blue, alpha: 1.0)
let path = NSBezierPath()
path.lineWidth = brushSize
path.lineCapStyle = .RoundLineCapStyle
path.lineJoinStyle = .RoundLineJoinStyle
path.moveToPoint(lastPoint)
path.lineToPoint(currentPoint)
...
strokeColor.setStroke()
path.stroke()
Upvotes: 1