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 { needsDisplay = true }
49     }
50     
51     @objc dynamic var slotItemAlv: NSNumber? {
52         
53         didSet { needsDisplay = true }
54     }
55     
56     
57     @objc var slotItemID: NSNumber? {
58         didSet {
59             slotItemController.content = nil
60             
61             guard let itemId = slotItemID as? Int else { return }
62             
63             slotItemController.content = ServerDataStore.default.slotItem(by: itemId)
64             needsDisplay = true
65         }
66     }
67     
68     private var maskImage: CGImage? {
69         
70         if let alv = slotItemAlv as? Int, alv != 0 { return airLevelMaskImage }
71         if let lv = slotItemLevel as? Int, lv != 0 { return levelMaskImage }
72         
73         if isCharacterProtrude() { return characterProtrudeMaskImage }
74         
75         return nil
76     }
77     
78     private var levelMaskImage: CGImage {
79         
80         if let r = SlotItemLevelView.sLevelMaskImage { return r }
81         SlotItemLevelView.sLevelMaskImage = maskImage(middle1: 0.75, middle2: 0.85)
82         
83         return SlotItemLevelView.sLevelMaskImage!
84     }
85     
86     private var airLevelMaskImage: CGImage {
87         
88         if let r = SlotItemLevelView.sAirLevelMaskImage { return r }
89         SlotItemLevelView.sAirLevelMaskImage = maskImage(middle1: 0.65, middle2: 0.75)
90         
91         return SlotItemLevelView.sAirLevelMaskImage!
92     }
93     private var characterProtrudeMaskImage: CGImage {
94         
95         if let r = SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage { return r }
96         SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage = maskImage(middle1: 0.9, middle2: 1.0)
97         
98         return SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage!
99     }
100     
101     private var levelOneBezierPath: NSBezierPath? {
102         
103         let width = bounds.width
104         let height = bounds.height
105         let path = multiline(lines: [
106             (
107                 NSPoint(x: width - offset, y: 0),
108                 NSPoint(x: width - offset, y: height)
109             )
110             ])
111         path.lineWidth = 1.0
112         
113         return path
114     }
115     
116     private var levelTwoBezierPath: NSBezierPath? {
117         
118         let width = bounds.width
119         let height = bounds.height
120         let path = multiline(lines:
121             [
122                 (
123                     NSPoint(x: width - offset, y: 0),
124                     NSPoint(x: width - offset, y: height)
125                 ),
126                 (
127                     NSPoint(x: width - offset - padding, y: 0),
128                     NSPoint(x: width - offset - padding, y: height)
129                 )
130             ])
131         path.lineWidth = 1.0
132         
133         return path
134     }
135     
136     private var levelThreeBezierPath: NSBezierPath? {
137         
138         let width = bounds.width
139         let height = bounds.height
140         let path = multiline(lines:
141             [
142                 (
143                     NSPoint(x: width - offset, y: 0),
144                     NSPoint(x: width - offset, y: height)
145                 ),
146                 (
147                     NSPoint(x: width - offset - padding, y: 0),
148                     NSPoint(x: width - offset - padding, y: height)
149                 ),
150                 (
151                     NSPoint(x: width - offset - padding * 2, y: 0),
152                     NSPoint(x: width - offset - padding * 2, y: height)
153                 )
154             ])
155         path.lineWidth = 1.0
156         
157         return path
158     }
159     
160     private var levelFourBezierPath: NSBezierPath? {
161         
162         let width = bounds.width
163         let height = bounds.height
164         let path = multiline(lines:
165             [
166                 (
167                     NSPoint(x: width - offset - slideOffset, y: 0),
168                     NSPoint(x: width - offset, y: height)
169                 )
170             ])
171         path.lineWidth = 2.0
172         
173         return path
174     }
175     
176     private var levelFiveBezierPath: NSBezierPath? {
177         
178         let width = bounds.width
179         let height = bounds.height
180         let path = multiline(lines:
181             [
182                 (
183                     NSPoint(x: width - offset - slideOffset, y: 0),
184                     NSPoint(x: width - offset, y: height)
185                 ),
186                 (
187                     NSPoint(x: width - offset - padding - slideOffset, y: 0),
188                     NSPoint(x: width - offset - padding, y: height)
189                 )
190             ])
191         path.lineWidth = 2.0
192         
193         return path
194     }
195     
196     private var levelSixBezierPath: NSBezierPath? {
197         
198         let width = bounds.width
199         let height = bounds.height
200         let path = multiline(lines:
201             [
202                 (
203                     NSPoint(x: width - offset - slideOffset, y: 0),
204                     NSPoint(x: width - offset, y: height)
205                 ),
206                 (
207                     NSPoint(x: width - offset - padding - slideOffset, y: 0),
208                     NSPoint(x: width - offset - padding, y: height)
209                 ),
210                 (
211                     NSPoint(x: width - offset - padding * 2 - slideOffset, y: 0),
212                     NSPoint(x: width - offset - padding * 2, y: height)
213                 )
214             ])
215         path.lineWidth = 2.0
216         
217         return path
218     }
219     
220     private var levelSevenBezierPath: NSBezierPath? {
221         
222         let width = bounds.width
223         let height = bounds.height
224         let path = polyline(points:
225             [
226                 NSPoint(x: width - offset - slideOffset, y: 0),
227                 NSPoint(x: width - offset, y: height * 0.5),
228                 NSPoint(x: width - offset - anglePoint, y: height)
229             ])
230         polyline(points:
231             [
232                 NSPoint(x: width - offset - padding - slideOffset, y: 0),
233                 NSPoint(x: width - offset - padding, y: height * 0.5),
234                 NSPoint(x: width - offset - padding - anglePoint, y: height)
235             ])
236             .map { path?.append($0) }
237         path?.lineWidth = 2.0
238         
239         return path
240     }
241     
242     private var levelFont: NSFont {
243         
244         return NSFont.monospacedDigitSystemFont(ofSize: NSFont.smallSystemFontSize, weight: .regular)
245     }
246     
247     private var levelColor: NSColor {
248         
249         return #colorLiteral(red: 0.135, green: 0.522, blue: 0.619, alpha: 1)
250     }
251     
252     // MARK: - Function
253     override func draw(_ dirtyRect: NSRect) {
254         
255         guard let context = NSGraphicsContext.current?.cgContext else { fatalError("Con not get current CGContext") }
256         
257         context.saveGState()
258         maskImage.map { context.clip(to: bounds, mask: $0) }
259         
260         super.draw(dirtyRect)
261         
262         context.restoreGState()
263         
264         drawLevel()
265         drawAirLevel()
266     }
267     
268     private func bezierPathForALevel(level: Int) -> NSBezierPath? {
269         
270         switch level {
271         case 1: return levelOneBezierPath
272         case 2: return levelTwoBezierPath
273         case 3: return levelThreeBezierPath
274         case 4: return levelFourBezierPath
275         case 5: return levelFiveBezierPath
276         case 6: return levelSixBezierPath
277         case 7: return levelSevenBezierPath
278         default: return nil
279         }
280     }
281     
282     private func colorForALevel(level: Int) -> NSColor? {
283         
284         switch level {
285         case 1, 2, 3: return #colorLiteral(red: 0.257, green: 0.523, blue: 0.643, alpha: 1)
286         case 4, 5, 6, 7: return #colorLiteral(red: 0.784, green: 0.549, blue: 0.000, alpha: 1)
287         default: return nil
288         }
289     }
290     
291     private func shadowForALevel(level: Int) -> NSShadow? {
292         
293         switch level {
294         case 1, 2, 3:
295             let shadow = NSShadow()
296             shadow.shadowColor = #colorLiteral(red: 0.095, green: 0.364, blue: 0.917, alpha: 1)
297             shadow.shadowBlurRadius = 4.0
298             return shadow
299             
300         case 4, 5, 6, 7:
301             let shadow = NSShadow()
302             shadow.shadowColor = NSColor.yellow
303             shadow.shadowBlurRadius = 3.0
304             return shadow
305             
306         default:
307             return nil
308         }
309     }
310     
311     private func drawAirLevel() {
312         
313         guard let alv = slotItemAlv as? Int else { return }
314         
315         colorForALevel(level: alv)?.set()
316         shadowForALevel(level: alv)?.set()
317         bezierPathForALevel(level: alv)?.stroke()
318     }
319     
320     private func drawLevel() {
321         
322         guard let lv = slotItemLevel as? Int, lv != 0 else { return }
323         
324         let string = (lv == 10 ? "max" : "★+\(lv)")
325         let attr: [NSAttributedStringKey: Any] = [.font: levelFont,
326                                                   .foregroundColor: levelColor]
327         let attributedString = NSAttributedString(string: string, attributes: attr)
328         let boundingRect = attributedString.boundingRect(with: bounds.size)
329         var rect = bounds
330         rect.origin.x = rect.width - boundingRect.width - 1.0
331         rect.origin.y = 0
332         
333         attributedString.draw(in: rect)
334     }
335 }