Skip to content

Instantly share code, notes, and snippets.

@eonist
Created May 21, 2023 13:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eonist/f00abf190c1bbaf12842b2a6d9d54548 to your computer and use it in GitHub Desktop.
Save eonist/f00abf190c1bbaf12842b2a6d9d54548 to your computer and use it in GitHub Desktop.
NSBezierPath+Ext
import Cocoa
/**
* - Fixme: ⚠️️ Still in use? Good question, deperecate? we can deprecate this
* - Fixme: ⚠️️⚠️️ move to gist
*/
extension NSBezierPath {
/**
* Init
* - Fixme: ⚠️️ Add support for CGSize for radii
* - Parameters:
* - rect: Rect to draw
* - corners: which corners should be round
* - radius: amount of roundness
*/
public convenience init(roundedRect rect: CGRect, byRoundingCorners corners: NSRectCorner, cornerRadii radius: CGFloat) {
self.init()
let min: CGPoint = .init(x: rect.origin.x, y: rect.origin.y)
let max: CGPoint = .init(x: rect.origin.x + rect.size.width, y: rect.origin.y + rect.size.height)
bottomRight(corners: corners, radius: radius, min: min, max: max)
topRight(corners: corners, radius: radius, min: min, max: max)
topLeft(corners: corners, radius: radius, min: min, max: max)
bottomLeft(corners: corners, radius: radius, min: min, max: max)
}
}
/**
* Helpers
*/
extension NSBezierPath {
/**
* TopLeft
* - Parameters:
* - corners: - Fixme: ⚠️️ doc
* - radius: - Fixme: ⚠️️ doc
* - min: - Fixme: ⚠️️ doc
* - max: - Fixme: ⚠️️ doc
*/
private func topLeft(corners: NSRectCorner, radius: CGFloat, min: CGPoint, max: CGPoint) {
let topLeftCorner = CGPoint(x: min.x, y: max.y)
if corners.contains(.topLeft) {
line(to: CGPoint(x: min.x + radius, y: max.y))
curve(to: CGPoint(x: min.x, y: max.y - radius), controlPoint1: topLeftCorner, controlPoint2: topLeftCorner)
} else {
line(to: topLeftCorner)
}
}
/**
* TR
* - Parameters:
* - corners: - Fixme: ⚠️️
* - radius: - Fixme: ⚠️️
* - min: - Fixme: ⚠️️
* - max: - Fixme: ⚠️️
*/
private func topRight(corners: NSRectCorner, radius: CGFloat, min: CGPoint, max: CGPoint) {
let topRightCorner = CGPoint(x: max.x, y: max.y)
if corners.contains(.topRight) {
line(to: CGPoint(x: max.x, y: max.y - radius))
curve(to: CGPoint(x: max.x - radius, y: max.y), controlPoint1: topRightCorner, controlPoint2: topRightCorner)
} else {
line(to: topRightCorner)
}
}
/**
* BR
* - Parameters:
* - corners: - Fixme: ⚠️️
* - radius: - Fixme: ⚠️️
* - min: - Fixme: ⚠️️
* - max: - Fixme: ⚠️️
*/
private func bottomRight(corners: NSRectCorner, radius: CGFloat, min: CGPoint, max: CGPoint) {
let bottomRightCorner = CGPoint(x: max.x, y: min.y)
move(to: bottomRightCorner)
if corners.contains(.bottomRight) {
line(to: CGPoint(x: max.x - radius, y: min.y))
curve(to: CGPoint(x: max.x, y: min.y + radius), controlPoint1: bottomRightCorner, controlPoint2: bottomRightCorner)
} else {
line(to: bottomRightCorner)
}
}
/**
* BL
* - Parameters:
* - corners: - Fixme: ⚠️️
* - radius: - Fixme: ⚠️️
* - min: - Fixme: ⚠️️
* - max: - Fixme: ⚠️️
*/
func bottomLeft(corners: NSRectCorner, radius: CGFloat, min: CGPoint, max: CGPoint) {
let bottomLeftCorner = CGPoint(x: min.x, y: min.y)
if corners.contains(.bottomLeft) {
line(to: CGPoint(x: min.x, y: min.y + radius))
curve(to: CGPoint(x: min.x + radius, y: min.y), controlPoint1: bottomLeftCorner, controlPoint2: bottomLeftCorner)
} else {
line(to: bottomLeftCorner)
}
}
}
/**
* NSBezierPath -> cgPath
*/
extension NSBezierPath {
/**
* untested
* - Remark: Needed to convert NSBezierPath to cgPath
*/
public var cgPath: CGPath? {
if self.elementCount == 0 { return nil }
let path = CGMutablePath()
var didClosePath = false
for i in 0...self.elementCount - 1 { // - Fixme: ⚠️ why isn't this: 0..<.elementCount?
var points = [NSPoint](repeating: .zero, count: 3)
switch self.element(at: i, associatedPoints: &points) {
case .moveTo: path.move(to: points[0]) // Swift 3 updated
case .lineTo: path.addLine(to: points[0])
case .curveTo: path.addCurve(to: points[2], control1: points[0], control2: points[1])
case .closePath: path.closeSubpath(); didClosePath = true
@unknown default: fatalError("unknown case")
}
}
if !didClosePath { path.closeSubpath() }
return path.copy()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment