Skip to content

Instantly share code, notes, and snippets.

@cemolcay
Created February 1, 2017 10:48
Show Gist options
  • Select an option

  • Save cemolcay/28cb15001cd4786e78830369e074aa5c to your computer and use it in GitHub Desktop.

Select an option

Save cemolcay/28cb15001cd4786e78830369e074aa5c to your computer and use it in GitHub Desktop.
UIBezierPath methods missing on NSBezierPath for swift 3
public struct NSRectCorner: OptionSet {
public let rawValue: UInt
public static let none = NSRectCorner(rawValue: 0)
public static let topLeft = NSRectCorner(rawValue: 1 << 0)
public static let topRight = NSRectCorner(rawValue: 1 << 1)
public static let bottomLeft = NSRectCorner(rawValue: 1 << 2)
public static let bottomRight = NSRectCorner(rawValue: 1 << 3)
public static var all: NSRectCorner {
return [.topLeft, .topRight, .bottomLeft, .bottomRight]
}
public init(rawValue: UInt) {
self.rawValue = rawValue
}
}
public extension NSBezierPath {
public var cgPath: CGPath {
let path = CGMutablePath()
var points = [CGPoint](repeating: .zero, count: 3)
for i in 0 ..< self.elementCount {
let type = self.element(at: i, associatedPoints: &points)
switch type {
case .moveToBezierPathElement:
path.move(to: CGPoint(x: points[0].x, y: points[0].y))
case .lineToBezierPathElement:
path.addLine(to: CGPoint(x: points[0].x, y: points[0].y))
case .curveToBezierPathElement:
path.addCurve(
to: CGPoint(x: points[2].x, y: points[2].y),
control1: CGPoint(x: points[0].x, y: points[0].y),
control2: CGPoint(x: points[1].x, y: points[1].y))
case .closePathBezierPathElement:
path.closeSubpath()
}
}
return path
}
public convenience init(roundedRect rect: NSRect, byRoundingCorners corners: NSRectCorner, cornerRadii: NSSize) {
self.init()
let topLeft = rect.origin
let topRight = NSPoint(x: rect.maxX, y: rect.minY);
let bottomRight = NSPoint(x: rect.maxX, y: rect.maxY);
let bottomLeft = NSPoint(x: rect.minX, y: rect.maxY);
if corners.contains(.topLeft) {
move(to: CGPoint(
x: topLeft.x + cornerRadii.width,
y: topLeft.y))
} else {
move(to: topLeft)
}
if corners.contains(.topRight) {
line(to: CGPoint(
x: topRight.x - cornerRadii.width,
y: topRight.y))
curve(
to: topRight,
controlPoint1: CGPoint(
x: topRight.x,
y: topRight.y + cornerRadii.height),
controlPoint2: CGPoint(
x: topRight.x,
y: topRight.y + cornerRadii.height))
} else {
line(to: topRight)
}
if corners.contains(.bottomRight) {
line(to: CGPoint(
x: bottomRight.x,
y: bottomRight.y - cornerRadii.height))
curve(
to: bottomRight,
controlPoint1: CGPoint(
x: bottomRight.x - cornerRadii.width,
y: bottomRight.y),
controlPoint2: CGPoint(
x: bottomRight.x - cornerRadii.width,
y: bottomRight.y))
} else {
line(to: bottomRight)
}
if corners.contains(.bottomLeft) {
line(to: CGPoint(
x: bottomLeft.x + cornerRadii.width,
y: bottomLeft.y))
curve(
to: bottomLeft,
controlPoint1: CGPoint(
x: bottomLeft.x,
y: bottomLeft.y - cornerRadii.height),
controlPoint2: CGPoint(
x: bottomLeft.x,
y: bottomLeft.y - cornerRadii.height))
} else {
line(to: bottomLeft)
}
if corners.contains(.topLeft) {
line(to: CGPoint(
x: topLeft.x,
y: topLeft.y + cornerRadii.height))
curve(
to: topLeft,
controlPoint1: CGPoint(
x: topLeft.x + cornerRadii.width,
y: topLeft.y),
controlPoint2: CGPoint(
x: topLeft.x + cornerRadii.width,
y: topLeft.y))
} else {
line(to: topLeft)
}
close()
}
}
@dmsl1805

dmsl1805 commented Nov 29, 2018

Copy link
Copy Markdown

If it is still needed for someone, I've updated it to Swift 4

struct NSRectCorner: OptionSet {
   let rawValue: UInt
   
   static let none = NSRectCorner(rawValue: 0)
   static let topLeft = NSRectCorner(rawValue: 1 << 0)
   static let topRight = NSRectCorner(rawValue: 1 << 1)
   static let bottomLeft = NSRectCorner(rawValue: 1 << 2)
   static let bottomRight = NSRectCorner(rawValue: 1 << 3)
   static var all: NSRectCorner {
       return [.topLeft, .topRight, .bottomLeft, .bottomRight]
   }
   
  init(rawValue: UInt) {
       self.rawValue = rawValue
   }
}

extension NSBezierPath {
   var cgPath: CGPath {
       let path = CGMutablePath()
       var points = [CGPoint](repeating: .zero, count: 3)
       for i in 0 ..< self.elementCount {
           let type = self.element(at: i, associatedPoints: &points)
           switch type {
           case .moveTo:
               path.move(to: CGPoint(x: points[0].x, y: points[0].y))
           case .lineTo:
               path.addLine(to: CGPoint(x: points[0].x, y: points[0].y))
           case .curveTo:
               path.addCurve(
                   to: CGPoint(x: points[2].x, y: points[2].y),
                   control1: CGPoint(x: points[0].x, y: points[0].y),
                   control2: CGPoint(x: points[1].x, y: points[1].y))
           case .closePath:
               path.closeSubpath()
           }
       }
       return path
   }
   
   convenience init(roundedRect rect: NSRect, byRoundingCorners corners: NSRectCorner, cornerRadius: NSSize) {
       self.init()
       defer { close() }
       
       let topLeft = rect.origin
       let topRight = NSPoint(x: rect.maxX, y: rect.minY)
       let bottomRight = NSPoint(x: rect.maxX, y: rect.maxY)
       let bottomLeft = NSPoint(x: rect.minX, y: rect.maxY)
       
       if corners.contains(.topLeft) {
           move(to: CGPoint(x: topLeft.x + cornerRadius.width,
                            y: topLeft.y))
       } else {
           move(to: topLeft)
       }
       
       if corners.contains(.topRight) {
           line(to: CGPoint(x: topRight.x - cornerRadius.width,
                            y: topRight.y))
           curve(to: topRight,
                 controlPoint1: CGPoint(x: topRight.x,
                                        y: topRight.y + cornerRadius.height),
                 controlPoint2: CGPoint(x: topRight.x,
                                        y: topRight.y + cornerRadius.height))
       } else {
           line(to: topRight)
       }
       
       if corners.contains(.bottomRight) {
           line(to: CGPoint(x: bottomRight.x, 
                            y: bottomRight.y - cornerRadius.height))
           curve(to: bottomRight, 
                 controlPoint1: CGPoint(x: bottomRight.x - cornerRadius.width,
                                        y: bottomRight.y),
                 controlPoint2: CGPoint(x: bottomRight.x - cornerRadius.width,
                                        y: bottomRight.y))
       } else {
           line(to: bottomRight)
       }
       
       if corners.contains(.bottomLeft) {
           line(to: CGPoint(x: bottomLeft.x + cornerRadius.width,
                            y: bottomLeft.y))
           curve(to: bottomLeft,
                 controlPoint1: CGPoint(x: bottomLeft.x,
                                        y: bottomLeft.y - cornerRadius.height),
                 controlPoint2: CGPoint(x: bottomLeft.x,
                                        y: bottomLeft.y - cornerRadius.height))
       } else {
           line(to: bottomLeft)
       }
       
       if corners.contains(.topLeft) {
           line(to: CGPoint(x: topLeft.x,
                            y: topLeft.y + cornerRadius.height))
           curve(to: topLeft,
                 controlPoint1: CGPoint(x: topLeft.x + cornerRadius.width,
                                        y: topLeft.y),
                 controlPoint2: CGPoint(x: topLeft.x + cornerRadius.width,
                                        y: topLeft.y))
       } else {
           line(to: topLeft)
       }
   }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment