OSDN Git Service

関数名を変更
[kcd/KCD.git] / KCD / SlotItemLevelView.swift
1 //
2 //  SlotItemLevelView.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/01/02.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 final class SlotItemLevelView: NSTextField {
12     
13     private static var sLevelMaskImage: CGImage?
14     private static var sAirLevelMaskImage: CGImage?
15     private static var sCharacterProtrudeMaskImageMaskImage: CGImage?
16     
17     private let offset: CGFloat = 28
18     private let padding: CGFloat = 4
19     private let slideOffset: CGFloat = 3.5
20     private let anglePoint: CGFloat = 4.0
21     
22     override init(frame frameRect: NSRect) {
23         
24         super.init(frame: frameRect)
25         
26         bind(NSBindingName(#keyPath(slotItemLevel)), to: slotItemController, withKeyPath: "selection.level", options: nil)
27         bind(NSBindingName(#keyPath(slotItemAlv)), to: slotItemController, withKeyPath: "selection.alv", options: nil)
28     }
29     
30     required init?(coder: NSCoder) {
31         
32         super.init(coder: coder)
33         
34         bind(NSBindingName(#keyPath(slotItemLevel)), to: slotItemController, withKeyPath: "selection.level", options: nil)
35         bind(NSBindingName(#keyPath(slotItemAlv)), to: slotItemController, withKeyPath: "selection.alv", options: nil)
36     }
37     
38     deinit {
39         
40         unbind(NSBindingName(#keyPath(slotItemLevel)))
41         unbind(NSBindingName(#keyPath(slotItemAlv)))
42     }
43     
44     // MARK: - Variable
45     @objc dynamic var slotItemController = NSObjectController()
46     @objc dynamic var slotItemLevel: NSNumber? {
47         
48         didSet { needsDisplayInMainThread() }
49     }
50     
51     @objc dynamic var slotItemAlv: NSNumber? {
52         
53         didSet { needsDisplayInMainThread() }
54     }
55     
56     @objc var slotItemID: NSNumber? {
57         didSet {
58             slotItemController.content = nil
59             
60             guard let itemId = slotItemID as? Int else { return }
61             
62             slotItemController.content = ServerDataStore.default.slotItem(by: itemId)
63             needsDisplayInMainThread()
64         }
65     }
66     
67     private var maskImage: CGImage? {
68         
69         if let alv = slotItemAlv as? Int, alv != 0 { return airLevelMaskImage }
70         if let lv = slotItemLevel as? Int, lv != 0 { return levelMaskImage }
71         
72         if isCharacterProtrude() { return characterProtrudeMaskImage }
73         
74         return nil
75     }
76     
77     private var levelMaskImage: CGImage {
78         
79         if let r = SlotItemLevelView.sLevelMaskImage { return r }
80         SlotItemLevelView.sLevelMaskImage = maskImage(middle1: 0.75, middle2: 0.85)
81         
82         return SlotItemLevelView.sLevelMaskImage!
83     }
84     
85     private var airLevelMaskImage: CGImage {
86         
87         if let r = SlotItemLevelView.sAirLevelMaskImage { return r }
88         SlotItemLevelView.sAirLevelMaskImage = maskImage(middle1: 0.65, middle2: 0.75)
89         
90         return SlotItemLevelView.sAirLevelMaskImage!
91     }
92     private var characterProtrudeMaskImage: CGImage {
93         
94         if let r = SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage { return r }
95         SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage = maskImage(middle1: 0.9, middle2: 1.0)
96         
97         return SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage!
98     }
99     
100     private var levelOneBezierPath: Polygon {
101         
102         let width = bounds.width
103         let height = bounds.height
104         return Polygon(lineWidth: 1.0)
105             .move(to: NSPoint(x: width - offset, y: 0))
106             .line(to: NSPoint(x: width - offset, y: height))
107     }
108     
109     private var levelTwoBezierPath: Polygon {
110         
111         let width = bounds.width
112         let height = bounds.height
113         return Polygon(lineWidth: 1.0)
114             .move(to: NSPoint(x: width - offset, y: 0))
115             .line(to: NSPoint(x: width - offset, y: height))
116             .move(to: NSPoint(x: width - offset - padding, y: 0))
117             .line(to: NSPoint(x: width - offset - padding, y: height))
118     }
119     
120     private var levelThreeBezierPath: Polygon {
121         
122         let width = bounds.width
123         let height = bounds.height
124         return Polygon(lineWidth: 1.0)
125             .move(to: NSPoint(x: width - offset, y: 0))
126             .line(to: NSPoint(x: width - offset, y: height))
127             .move(to: NSPoint(x: width - offset - padding, y: 0))
128             .line(to: NSPoint(x: width - offset - padding, y: height))
129             .move(to: NSPoint(x: width - offset - padding * 2, y: 0))
130             .line(to: NSPoint(x: width - offset - padding * 2, y: height))
131     }
132     
133     private var levelFourBezierPath: Polygon {
134         
135         let width = bounds.width
136         let height = bounds.height
137         return Polygon(lineWidth: 2.0)
138             .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
139             .line(to: NSPoint(x: width - offset, y: height))
140     }
141     
142     private var levelFiveBezierPath: Polygon {
143         
144         let width = bounds.width
145         let height = bounds.height
146         return Polygon(lineWidth: 2.0)
147             .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
148             .line(to: NSPoint(x: width - offset, y: height))
149             .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
150             .line(to: NSPoint(x: width - offset - padding, y: height))
151     }
152     
153     private var levelSixBezierPath: Polygon {
154         
155         let width = bounds.width
156         let height = bounds.height
157         return Polygon(lineWidth: 2.0)
158             .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
159             .line(to: NSPoint(x: width - offset, y: height))
160             .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
161             .line(to: NSPoint(x: width - offset - padding, y: height))
162             .move(to: NSPoint(x: width - offset - padding * 2 - slideOffset, y: 0))
163             .line(to: NSPoint(x: width - offset - padding * 2, y: height))
164     }
165     
166     private var levelSevenBezierPath: Polygon {
167         
168         let width = bounds.width
169         let height = bounds.height
170         return Polygon(lineWidth: 2.0)
171             .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
172             .line(to: NSPoint(x: width - offset, y: height * 0.5))
173             .line(to: NSPoint(x: width - offset - anglePoint, y: height))
174             .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
175             .line(to: NSPoint(x: width - offset - padding, y: height * 0.5))
176             .line(to: NSPoint(x: width - offset - padding - anglePoint, y: height))
177     }
178     
179     private var levelFont: NSFont {
180         
181         return .monospacedDigitSystemFont(ofSize: NSFont.smallSystemFontSize, weight: .regular)
182     }
183     
184     private var levelColor: NSColor {
185         
186         return #colorLiteral(red: 0.135, green: 0.522, blue: 0.619, alpha: 1)
187     }
188     
189     // MARK: - Function
190     override func draw(_ dirtyRect: NSRect) {
191         
192         guard let context = NSGraphicsContext.current?.cgContext else { fatalError("Con not get current CGContext") }
193         
194         context.saveGState()
195         maskImage.map { context.clip(to: bounds, mask: $0) }
196         
197         super.draw(dirtyRect)
198         
199         context.restoreGState()
200         
201         drawLevel()
202         drawAirLevel()
203     }
204     
205     private func bezierPathForALevel(level: Int) -> Polygon? {
206         
207         switch level {
208         case 1: return levelOneBezierPath
209         case 2: return levelTwoBezierPath
210         case 3: return levelThreeBezierPath
211         case 4: return levelFourBezierPath
212         case 5: return levelFiveBezierPath
213         case 6: return levelSixBezierPath
214         case 7: return levelSevenBezierPath
215         default: return nil
216         }
217     }
218     
219     private func colorForALevel(level: Int) -> NSColor? {
220         
221         switch level {
222         case 1, 2, 3: return #colorLiteral(red: 0.257, green: 0.523, blue: 0.643, alpha: 1)
223         case 4, 5, 6, 7: return #colorLiteral(red: 0.784, green: 0.549, blue: 0.000, alpha: 1)
224         default: return nil
225         }
226     }
227     
228     private func shadowForALevel(level: Int) -> NSShadow? {
229         
230         switch level {
231         case 1, 2, 3:
232             let shadow = NSShadow()
233             shadow.shadowColor = #colorLiteral(red: 0.095, green: 0.364, blue: 0.917, alpha: 1)
234             shadow.shadowBlurRadius = 4.0
235             return shadow
236             
237         case 4, 5, 6, 7:
238             let shadow = NSShadow()
239             shadow.shadowColor = .yellow
240             shadow.shadowBlurRadius = 3.0
241             return shadow
242             
243         default:
244             return nil
245         }
246     }
247     
248     private func drawAirLevel() {
249         
250         guard let alv = slotItemAlv as? Int else { return }
251         
252         colorForALevel(level: alv)?.set()
253         shadowForALevel(level: alv)?.set()
254         bezierPathForALevel(level: alv)?.stroke()
255     }
256     
257     private func drawLevel() {
258         
259         guard let lv = slotItemLevel as? Int, lv != 0 else { return }
260         
261         let string = (lv == 10 ? "max" : "★+\(lv)")
262         let attr: [NSAttributedStringKey: Any] = [.font: levelFont,
263                                                   .foregroundColor: levelColor]
264         let attributedString = NSAttributedString(string: string, attributes: attr)
265         let boundingRect = attributedString.boundingRect(with: bounds.size)
266         var rect = bounds
267         rect.origin.x = rect.width - boundingRect.width - 1.0
268         rect.origin.y = 0
269         
270         attributedString.draw(in: rect)
271     }
272 }