Created
May 21, 2023 13:27
-
-
Save eonist/f00abf190c1bbaf12842b2a6d9d54548 to your computer and use it in GitHub Desktop.
NSBezierPath+Ext
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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