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 layoutManager = NSLayoutManager()
21 textContainer = NSTextContainer()
23 super.init(coder: coder)
25 layoutManager.addTextContainer(textContainer)
28 override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
30 let attributedString = attributedStringValue
32 if attributedString.string.hasSuffix("/") {
34 super.drawInterior(withFrame: cellFrame, in: controlView)
39 let attribute = attributedString.attributes(at: 0, effectiveRange: nil)
41 guard let forgroundColor = attribute[NSForegroundColorAttributeName] as? NSColor
44 if forgroundColor == NSColor.controlTextColor {
46 super.drawInterior(withFrame: cellFrame, in: controlView)
51 guard let font = attribute[NSFontAttributeName] as? NSFont
54 let textStorage = NSTextStorage(string: attributedString.string, attributes: attribute)
55 textStorage.addLayoutManager(layoutManager)
56 let range = layoutManager.glyphRange(for: textContainer)
57 let glyph = UnsafeMutablePointer<CGGlyph>.allocate(capacity: range.length)
58 let glyphLength = layoutManager.getGlyphs(in: range,
61 characterIndexes: nil,
63 var point = NSPoint(x: StrokeTextFieldCell.boarderWidth, y: 0)
64 point.y -= font.descender
66 if controlView.isFlipped {
68 point.y -= controlView.frame.height
71 let nsGlyph = UnsafeMutablePointer<NSGlyph>.allocate(capacity: range.length)
73 (0..<range.length).forEach { nsGlyph[$0] = NSGlyph(glyph[$0]) }
75 let path = NSBezierPath()
77 path.appendGlyphs(nsGlyph, count: glyphLength, in: font)
78 path.lineWidth = StrokeTextFieldCell.boarderWidth
79 path.lineJoinStyle = .roundLineJoinStyle
81 if controlView.isFlipped {
83 var affineTransform = AffineTransform()
84 affineTransform.scale(x: 1, y: -1)
85 path.transform(using: affineTransform)
93 textStorage.removeLayoutManager(layoutManager)