OSDN Git Service

7ea4da5059ad6484aa4c171d7d790f2aaefb33f0
[kcd/KCD.git] / KCD / StrokeTextFieldCell.swift
1 //
2 //  StrokeTextFieldCell.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/01/01.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 final class StrokeTextFieldCell: NSTextFieldCell {
12     
13     private static let boarderWidth: CGFloat = 2.0
14     
15     private let layoutManager = NSLayoutManager()
16     private let textContainer = NSTextContainer()
17     
18     required init(coder: NSCoder) {
19                 
20         super.init(coder: coder)
21         
22         layoutManager.addTextContainer(textContainer)
23     }
24     
25     override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
26         
27         let attributedString = attributedStringValue
28         
29         if attributedString.string.hasSuffix("/") {
30             
31             super.drawInterior(withFrame: cellFrame, in: controlView)
32             
33             return
34         }
35         
36         let attribute = attributedString.attributes(at: 0, effectiveRange: nil)
37         
38         guard let forgroundColor = attribute[.foregroundColor] as? NSColor else {
39             
40             return
41         }
42         
43         if forgroundColor == .controlTextColor {
44             
45             super.drawInterior(withFrame: cellFrame, in: controlView)
46             
47             return
48         }
49         
50         guard let font = attribute[.font] as? NSFont else {
51             
52             return
53         }
54         
55         let textStorage = NSTextStorage(string: attributedString.string, attributes: attribute)
56         textStorage.addLayoutManager(layoutManager)
57         let range = layoutManager.glyphRange(for: textContainer)
58         let glyph = UnsafeMutablePointer<CGGlyph>.allocate(capacity: range.length)
59         let glyphLength = layoutManager.getGlyphs(in: range,
60                                                   glyphs: glyph,
61                                                   properties: nil,
62                                                   characterIndexes: nil,
63                                                   bidiLevels: nil)
64         var point = NSPoint(x: StrokeTextFieldCell.boarderWidth, y: 0)
65         point.y -= font.descender
66         
67         if controlView.isFlipped {
68             
69             point.y -= controlView.frame.height
70         }
71         
72         let path = NSBezierPath()
73         path.move(to: point)
74         if #available(macOS 13, *) {
75             path.append(withCGGlyphs: glyph, count: glyphLength, in: font)
76         } else {
77             let nsGlyph = UnsafeMutablePointer<NSGlyph>.allocate(capacity: range.length)
78             
79             (0..<range.length).forEach { nsGlyph[$0] = NSGlyph(glyph[$0]) }
80             path.appendGlyphs(nsGlyph, count: glyphLength, in: font)
81         }
82         path.lineWidth = StrokeTextFieldCell.boarderWidth
83         path.lineJoinStyle = .roundLineJoinStyle
84         
85         if controlView.isFlipped {
86             
87             var affineTransform = AffineTransform()
88             affineTransform.scale(x: 1, y: -1)
89             path.transform(using: affineTransform)
90         }
91         
92         NSColor.black.set()
93         path.stroke()
94         forgroundColor.set()
95         path.fill()
96         
97         textStorage.removeLayoutManager(layoutManager)
98     }
99 }