OSDN Git Service

staticプロパティをインスタンスプロパティに変更
[kcd/KCD.git] / KCD / SlotItemLevelView.swift
index 9cd5dfe..9560138 100644 (file)
@@ -8,9 +8,11 @@
 
 import Cocoa
 
-class SlotItemLevelView: NSTextField {
+final class SlotItemLevelView: NSTextField {
+    
     private static var sLevelMaskImage: CGImage?
     private static var sAirLevelMaskImage: CGImage?
+    private static var sCharacterProtrudeMaskImageMaskImage: CGImage?
     
     private let offset: CGFloat = 28
     private let padding: CGFloat = 4
@@ -18,245 +20,311 @@ class SlotItemLevelView: NSTextField {
     private let anglePoint: CGFloat = 4.0
     
     override init(frame frameRect: NSRect) {
-        slotItemController = NSObjectController()
+        
         super.init(frame: frameRect)
-        self.bind("slotItemLevel", to: slotItemController, withKeyPath: "selection.level", options: nil)
-        self.bind("slotItemAlv", to: slotItemController, withKeyPath: "selection.alv", options: nil)
+        
+        bind(NSBindingName(#keyPath(slotItemLevel)), to: slotItemController, withKeyPath: "selection.level", options: nil)
+        bind(NSBindingName(#keyPath(slotItemAlv)), to: slotItemController, withKeyPath: "selection.alv", options: nil)
     }
+    
     required init?(coder: NSCoder) {
-        slotItemController = NSObjectController()
+        
         super.init(coder: coder)
-        self.bind("slotItemLevel", to: slotItemController, withKeyPath: "selection.level", options: nil)
-        self.bind("slotItemAlv", to: slotItemController, withKeyPath: "selection.alv", options: nil)
+        
+        bind(NSBindingName(#keyPath(slotItemLevel)), to: slotItemController, withKeyPath: "selection.level", options: nil)
+        bind(NSBindingName(#keyPath(slotItemAlv)), to: slotItemController, withKeyPath: "selection.alv", options: nil)
     }
+    
     deinit {
-        self.unbind("slotItemLevel")
-        self.unbind("slotItemAlv")
+        
+        unbind(NSBindingName(#keyPath(slotItemLevel)))
+        unbind(NSBindingName(#keyPath(slotItemAlv)))
     }
     
     // MARK: - Variable
-    dynamic var slotItemController: NSObjectController
-    dynamic var slotItemLevel: NSNumber? {
-        didSet { needsDisplay = true }
+    @objc dynamic var slotItemController = NSObjectController()
+    @objc dynamic var slotItemLevel: NSNumber? {
+        
+        didSet { needsDisplayInMainThread() }
     }
-    dynamic var slotItemAlv: NSNumber? {
-        didSet { needsDisplay = true }
+    
+    @objc dynamic var slotItemAlv: NSNumber? {
+        
+        didSet { needsDisplayInMainThread() }
     }
-    var slotItemID: NSNumber? {
+    
+    @objc var slotItemID: NSNumber? {
+        
         didSet {
+            
             slotItemController.content = nil
-            guard let itemId = slotItemID as? Int else { return }
-            slotItemController.content = ServerDataStore.default.slotItem(byId: itemId)
-            needsDisplay = true
+            
+            guard let itemId = slotItemID as? Int else {
+                
+                return
+            }
+            
+            slotItemController.content = ServerDataStore.default.slotItem(by: itemId)
+            needsDisplayInMainThread()
         }
     }
+    
     private var maskImage: CGImage? {
-        if let alv = slotItemAlv as? Int, alv != 0 { return airLevelMaskImage }
-        if let lv = slotItemLevel as? Int, lv != 0 { return levelMaskImage }
+        
+        if let alv = slotItemAlv as? Int, alv != 0 {
+            
+            return airLevelMaskImage
+        }
+        if let lv = slotItemLevel as? Int, lv != 0 {
+            
+            return levelMaskImage
+        }
+        
+        if isCharacterProtrude() {
+            
+            return characterProtrudeMaskImage
+        }
+        
         return nil
     }
+    
     private var levelMaskImage: CGImage {
-        if let r = SlotItemLevelView.sLevelMaskImage { return r }
+        
+        if let r = SlotItemLevelView.sLevelMaskImage {
+            
+            return r
+        }
         SlotItemLevelView.sLevelMaskImage = maskImage(middle1: 0.75, middle2: 0.85)
+        
         return SlotItemLevelView.sLevelMaskImage!
     }
+    
     private var airLevelMaskImage: CGImage {
-        if let r = SlotItemLevelView.sAirLevelMaskImage { return r }
+        
+        if let r = SlotItemLevelView.sAirLevelMaskImage {
+            
+            return r
+        }
         SlotItemLevelView.sAirLevelMaskImage = maskImage(middle1: 0.65, middle2: 0.75)
+        
         return SlotItemLevelView.sAirLevelMaskImage!
     }
-    private var levelOneBezierPath: NSBezierPath? {
+    private var characterProtrudeMaskImage: CGImage {
+        
+        if let r = SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage {
+            
+            return r
+        }
+        SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage = maskImage(middle1: 0.9, middle2: 1.0)
+        
+        return SlotItemLevelView.sCharacterProtrudeMaskImageMaskImage!
+    }
+    
+    private var levelOneBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline { [(NSPoint(x: width - offset, y: 0), NSPoint(x: width - offset, y: height))] }
-        path?.lineWidth = 1.0
-        return path
+        
+        return Polygon(lineWidth: 1.0)
+            .move(to: NSPoint(x: width - offset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
     }
-    private var levelTwoBezierPath: NSBezierPath? {
+    
+    private var levelTwoBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline {
-            [(NSPoint, NSPoint)]()
-                .appended { (NSPoint(x: width - offset, y: 0), NSPoint(x: width - offset, y: height)) }
-                .appended {
-                    (NSPoint(x: width - offset - padding, y: 0), NSPoint(x: width - offset - padding, y: height))
-            }
-        }
-        path?.lineWidth = 1.0
-        return path
+        
+        return Polygon(lineWidth: 1.0)
+            .move(to: NSPoint(x: width - offset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
+            .move(to: NSPoint(x: width - offset - padding, y: 0))
+            .line(to: NSPoint(x: width - offset - padding, y: height))
     }
-    private var levelThreeBezierPath: NSBezierPath? {
+    
+    private var levelThreeBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline {
-            [(NSPoint, NSPoint)]()
-                .appended { (NSPoint(x: width - offset, y: 0), NSPoint(x: width - offset, y: height)) }
-                .appended {
-                    (NSPoint(x: width - offset - padding, y: 0), NSPoint(x: width - offset - padding, y: height))
-                }
-                .appended {
-                    (NSPoint(x: width - offset - padding * 2, y: 0),
-                     NSPoint(x: width - offset - padding * 2, y: height))
-            }
-        }
-        path?.lineWidth = 1.0
-        return path
+        
+        return Polygon(lineWidth: 1.0)
+            .move(to: NSPoint(x: width - offset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
+            .move(to: NSPoint(x: width - offset - padding, y: 0))
+            .line(to: NSPoint(x: width - offset - padding, y: height))
+            .move(to: NSPoint(x: width - offset - padding * 2, y: 0))
+            .line(to: NSPoint(x: width - offset - padding * 2, y: height))
     }
-    private var levelFourBezierPath: NSBezierPath? {
+    
+    private var levelFourBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline {
-            [(NSPoint, NSPoint)]()
-                .appended { (NSPoint(x: width - offset - slideOffset, y: 0), NSPoint(x: width - offset, y: height)) }
-        }
-        path?.lineWidth = 2.0
-        return path
+        
+        return Polygon(lineWidth: 2.0)
+            .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
     }
-    private var levelFiveBezierPath: NSBezierPath? {
+    
+    private var levelFiveBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline {
-            [(NSPoint, NSPoint)]()
-                .appended { (NSPoint(x: width - offset - slideOffset, y: 0), NSPoint(x: width - offset, y: height)) }
-                .appended {
-                    (NSPoint(x: width - offset - padding - slideOffset, y: 0),
-                     NSPoint(x: width - offset - padding, y: height))
-            }
-        }
-        path?.lineWidth = 2.0
-        return path
+        
+        return Polygon(lineWidth: 2.0)
+            .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
+            .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset - padding, y: height))
     }
-    private var levelSixBezierPath: NSBezierPath? {
+    
+    private var levelSixBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = multiline {
-            [(NSPoint, NSPoint)]()
-                .appended { (NSPoint(x: width - offset - slideOffset, y: 0), NSPoint(x: width - offset, y: height)) }
-                .appended {
-                    (NSPoint(x: width - offset - padding - slideOffset, y: 0),
-                     NSPoint(x: width - offset - padding, y: height))
-                }
-                .appended {
-                    (NSPoint(x: width - offset - padding * 2 - slideOffset, y: 0),
-                     NSPoint(x: width - offset - padding * 2, y: height))
-            }
-        }
-        path?.lineWidth = 2.0
-        return path
+        
+        return Polygon(lineWidth: 2.0)
+            .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height))
+            .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset - padding, y: height))
+            .move(to: NSPoint(x: width - offset - padding * 2 - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset - padding * 2, y: height))
     }
-    private var levelSevenBezierPath: NSBezierPath? {
+    
+    private var levelSevenBezierPath: Polygon {
+        
         let width = bounds.width
         let height = bounds.height
-        let path = polyline {
-            [NSPoint]()
-                .appended { NSPoint(x: width - offset - slideOffset, y: 0) }
-                .appended { NSPoint(x: width - offset, y: height * 0.5) }
-                .appended { NSPoint(x: width - offset - anglePoint, y: height) }
-        }
-        polyline {
-            [NSPoint]()
-                .appended { NSPoint(x: width - offset - padding - slideOffset, y: 0) }
-                .appended { NSPoint(x: width - offset - padding, y: height * 0.5) }
-                .appended { NSPoint(x: width - offset - padding - anglePoint, y: height) }
-            }
-            .map { path?.append($0) }
-        path?.lineWidth = 2.0
-        return path
+        
+        return Polygon(lineWidth: 2.0)
+            .move(to: NSPoint(x: width - offset - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset, y: height * 0.5))
+            .line(to: NSPoint(x: width - offset - anglePoint, y: height))
+            .move(to: NSPoint(x: width - offset - padding - slideOffset, y: 0))
+            .line(to: NSPoint(x: width - offset - padding, y: height * 0.5))
+            .line(to: NSPoint(x: width - offset - padding - anglePoint, y: height))
     }
+    
     private var levelFont: NSFont {
-        return NSFont.monospacedDigitSystemFont(ofSize: NSFont.smallSystemFontSize(), weight: NSFontWeightRegular)
+        
+        return .monospacedDigitSystemFont(ofSize: NSFont.smallSystemFontSize, weight: .regular)
     }
+    
     private var levelColor: NSColor {
-        return NSColor(calibratedRed: 0.135, green: 0.522, blue: 0.619, alpha: 1.0)
+        
+        return ColorSetManager.current[.slotItemLevelViewLevel]
+        
+        
     }
     
     // MARK: - Function
     override func draw(_ dirtyRect: NSRect) {
-        guard let context = NSGraphicsContext.current()?.cgContext
-            else { fatalError("Con not get current CGContext") }
+        
+        guard let context = NSGraphicsContext.current?.cgContext else {
+            
+            fatalError("Con not get current CGContext")
+        }
+        
         context.saveGState()
         maskImage.map { context.clip(to: bounds, mask: $0) }
+        
         super.draw(dirtyRect)
+        
         context.restoreGState()
         
         drawLevel()
         drawAirLevel()
     }
-    private func maskImage(middle1: CGFloat, middle2: CGFloat) -> CGImage {
-        let colorspace = CGColorSpaceCreateDeviceGray()
-        guard let maskContext = CGContext(data: nil,
-                                          width: Int(bounds.width),
-                                          height: Int(bounds.height),
-                                          bitsPerComponent: 8,
-                                          bytesPerRow: Int(bounds.width),
-                                          space: colorspace,
-                                          bitmapInfo: 0)
-            else { fatalError("Can not create bitmap context") }
-        let maskGraphicsContext = NSGraphicsContext(cgContext: maskContext, flipped: false)
-        NSGraphicsContext.saveGraphicsState()
-        defer { NSGraphicsContext.restoreGraphicsState() }
-        NSGraphicsContext.setCurrent(maskGraphicsContext)
-        
-        let gradient = NSGradient(colorsAndLocations: (NSColor.white, 0.0),
-                                  (NSColor.white, middle1),
-                                  (NSColor.black, middle2),
-                                  (NSColor.black, 1.0))
-        gradient?.draw(in: bounds, angle: 0.0)
-        guard let r = maskContext.makeImage()
-            else { fatalError(" can not create image from context") }
-        return r
-    }
-    private func bezierPathForALevel(level: Int) -> NSBezierPath? {
+    
+    private func bezierPathForALevel(level: Int) -> Polygon? {
+        
         switch level {
+            
         case 1: return levelOneBezierPath
+            
         case 2: return levelTwoBezierPath
+            
         case 3: return levelThreeBezierPath
+            
         case 4: return levelFourBezierPath
+            
         case 5: return levelFiveBezierPath
+            
         case 6: return levelSixBezierPath
+            
         case 7: return levelSevenBezierPath
+            
         default: return nil
+            
         }
     }
+    
     private func colorForALevel(level: Int) -> NSColor? {
+        
         switch level {
-        case 1, 2, 3: return NSColor(calibratedRed: 0.257, green: 0.523, blue: 0.643, alpha: 1.0)
-        case 4, 5, 6, 7: return NSColor(calibratedRed: 0.784, green: 0.549, blue: 0.0, alpha: 1.0)
+            
+        case 1, 2, 3: return ColorSetManager.current[.slotItemLevelViewLowAirLevel]
+            
+        case 4, 5, 6, 7: return ColorSetManager.current[.slotItemLevelViewHighAirLevel]
+            
         default: return nil
+            
         }
     }
+    
     private func shadowForALevel(level: Int) -> NSShadow? {
+        
         switch level {
+            
         case 1, 2, 3:
             let shadow = NSShadow()
-            shadow.shadowColor = NSColor(calibratedRed: 0.095, green: 0.364, blue: 0.917, alpha: 1.0)
+            shadow.shadowColor = ColorSetManager.current[.slotItemLevelViewLowAirLevelShadow]
             shadow.shadowBlurRadius = 4.0
+            
             return shadow
+            
         case 4, 5, 6, 7:
             let shadow = NSShadow()
-            shadow.shadowColor = NSColor.yellow
+            shadow.shadowColor = ColorSetManager.current[.slotItemLevelViewHighAirLevelShadow]
             shadow.shadowBlurRadius = 3.0
+            
             return shadow
+            
         default:
+            
             return nil
         }
     }
+    
     private func drawAirLevel() {
-        guard let alv = slotItemAlv as? Int else { return }
+        
+        guard let alv = slotItemAlv as? Int else {
+            
+            return
+        }
+        
         colorForALevel(level: alv)?.set()
         shadowForALevel(level: alv)?.set()
         bezierPathForALevel(level: alv)?.stroke()
     }
+    
     private func drawLevel() {
-        guard let lv = slotItemLevel as? Int, lv != 0 else { return }
-        let string: String = lv == 10 ? "max" : "★+\(lv)"
-        let attr: [String: Any] = [ NSFontAttributeName: levelFont,
-                                     NSForegroundColorAttributeName: levelColor ]
+        
+        guard let lv = slotItemLevel as? Int, lv != 0 else {
+            
+            return
+        }
+        
+        let string = (lv == 10 ? "max" : "★+\(lv)")
+        let attr: [NSAttributedStringKey: Any] = [.font: levelFont,
+                                                  .foregroundColor: levelColor]
         let attributedString = NSAttributedString(string: string, attributes: attr)
         let boundingRect = attributedString.boundingRect(with: bounds.size)
         var rect = bounds
         rect.origin.x = rect.width - boundingRect.width - 1.0
         rect.origin.y = 0
+        
         attributedString.draw(in: rect)
     }
 }