2 // StrokeTextFieldCell.swift
5 // Created by Hori,Masaki on 2017/01/01.
6 // Copyright © 2017年 Hori,Masaki. All rights reserved.
11 final class StrokeTextFieldCell: NSTextFieldCell {
13 private static let boarderWidth: CGFloat = 2.0
15 private let layoutManager = NSLayoutManager()
16 private let textContainer = NSTextContainer()
18 required init(coder: NSCoder) {
20 super.init(coder: coder)
22 layoutManager.addTextContainer(textContainer)
25 override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
27 let attributedString = attributedStringValue
29 if attributedString.string.hasSuffix("/") {
31 super.drawInterior(withFrame: cellFrame, in: controlView)
36 let attribute = attributedString.attributes(at: 0, effectiveRange: nil)
38 guard let forgroundColor = attribute[.foregroundColor] as? NSColor else { return }
40 if forgroundColor == .controlTextColor {
42 super.drawInterior(withFrame: cellFrame, in: controlView)
47 guard let font = attribute[.font] as? NSFont else { return }
49 let textStorage = NSTextStorage(string: attributedString.string, attributes: attribute)
50 textStorage.addLayoutManager(layoutManager)
51 let range = layoutManager.glyphRange(for: textContainer)
52 let glyph = UnsafeMutablePointer<CGGlyph>.allocate(capacity: range.length)
53 let glyphLength = layoutManager.getGlyphs(in: range,
56 characterIndexes: nil,
58 var point = NSPoint(x: StrokeTextFieldCell.boarderWidth, y: 0)
59 point.y -= font.descender
61 if controlView.isFlipped {
63 point.y -= controlView.frame.height
66 let nsGlyph = UnsafeMutablePointer<NSGlyph>.allocate(capacity: range.length)
68 (0..<range.length).forEach { nsGlyph[$0] = NSGlyph(glyph[$0]) }
70 let path = NSBezierPath()
72 path.appendGlyphs(nsGlyph, count: glyphLength, in: font)
73 path.lineWidth = StrokeTextFieldCell.boarderWidth
74 path.lineJoinStyle = .roundLineJoinStyle
76 if controlView.isFlipped {
78 var affineTransform = AffineTransform()
79 affineTransform.scale(x: 1, y: -1)
80 path.transform(using: affineTransform)
88 textStorage.removeLayoutManager(layoutManager)