OSDN Git Service

スクリーンショットの撮影にSierraまでは今までの実装を使用するようにした
[kcd/KCD.git] / KCD / ShipDetailViewController.swift
1 //
2 //  ShipDetailViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/25.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 enum ShipDetailViewType {
12     
13     case full
14     case medium
15     case minimum
16 }
17
18 private func nibNameFor(_ type: ShipDetailViewType) -> NSNib.Name {
19     
20     switch type {
21     case .full: return ShipDetailViewController.nibName
22     case .medium: return NSNib.Name("MediumShipViewController")
23     case .minimum: return NSNib.Name("MediumShipViewController")
24     }
25 }
26
27 private var shipContext: Int = 0
28 private var equippedItem0Context: Int = 0
29 private var equippedItem1Context: Int = 0
30 private var equippedItem2Context: Int = 0
31 private var equippedItem3Context: Int = 0
32 private var equippedItem4Context: Int = 0
33
34 final class ShipDetailViewController: NSViewController {
35     
36     let type: ShipDetailViewType
37     @objc let managedObjectContext = ServerDataStore.default.context
38     
39     init?(type: ShipDetailViewType) {
40         
41         self.type = type
42         
43         super.init(nibName: nibNameFor(type), bundle: nil)
44         
45         NotificationCenter
46             .default
47             .addObserver(forName: .DidUpdateGuardEscape, object: nil, queue: nil) { [weak self] _ in
48                 
49                 guard let `self` = self else { return }
50                 
51                 self.guardEscaped = self.ship?.guardEscaped ?? false
52         }
53     }
54     
55     required init?(coder: NSCoder) {
56         
57         fatalError("not implemented")
58     }
59     
60     deinit {
61         
62         NotificationCenter.default.removeObserver(self)
63         damageView.unbind(NSBindingName(#keyPath(DamageView.damageType)))
64         supply.unbind(NSBindingName(#keyPath(SuppliesView.shipStatus)))
65         [slot00Field, slot01Field, slot02Field, slot03Field]
66             .forEach { $0?.unbind(NSBindingName(#keyPath(SlotItemLevelView.slotItemID))) }
67         
68         shipController.removeObject(self)
69     }
70     
71     
72     @IBOutlet weak var supply: SuppliesView!
73     @IBOutlet weak var guardEscapedView: GuardEscapedView!
74     @IBOutlet weak var damageView: DamageView!
75     @IBOutlet weak var slot00Field: SlotItemLevelView!
76     @IBOutlet weak var slot01Field: SlotItemLevelView!
77     @IBOutlet weak var slot02Field: SlotItemLevelView!
78     @IBOutlet weak var slot03Field: SlotItemLevelView!
79     @IBOutlet var shipController: NSObjectController!
80     
81     @objc dynamic var guardEscaped: Bool = false {
82         
83         didSet {
84             guardEscapedView.isHidden = !guardEscaped
85         }
86     }
87     
88     @objc dynamic var ship: Ship? {
89         
90         get { return shipController.content as? Ship }
91         set {
92             shipController.fetchPredicate = NSPredicate(#keyPath(Ship.id), equal: newValue?.id ?? 0)
93         }
94     }
95     
96     override func viewDidLoad() {
97         
98         super.viewDidLoad()
99         
100         damageView.setFrameOrigin(.zero)
101         view.addSubview(damageView)
102         damageView.bind(NSBindingName(#keyPath(DamageView.damageType)),
103                         to: shipController,
104                         withKeyPath: "selection.status", options: nil)
105         
106         supply.bind(NSBindingName(#keyPath(SuppliesView.shipStatus)),
107                     to: shipController,
108                     withKeyPath: "selection.self", options: nil)
109         
110         guardEscapedView.setFrameOrigin(.zero)
111         view.addSubview(guardEscapedView)
112         switch type {
113         case .medium, .minimum:
114             guardEscapedView.controlSize = .mini
115             
116         default: break
117         }
118         
119         let fields = [slot00Field, slot01Field, slot02Field, slot03Field]
120         let keypath = ["selection.slot_0", "selection.slot_1", "selection.slot_2", "selection.slot_3"]
121         zip(fields, keypath).forEach {
122             
123             $0.0?.bind(NSBindingName(#keyPath(SlotItemLevelView.slotItemID)), to: shipController, withKeyPath: $0.1, options: nil)
124         }
125         
126         // observe slotitems count
127         shipController.addObserver(self, forKeyPath: "selection", context: &shipContext)
128         
129         shipController.addObserver(self, forKeyPath: "selection.slot_0", context: &equippedItem0Context)
130         shipController.addObserver(self, forKeyPath: "selection.onslot_0", context: &equippedItem0Context)
131         shipController.addObserver(self, forKeyPath: "selection.master_ship.maxeq_0", context: &equippedItem0Context)
132         
133         shipController.addObserver(self, forKeyPath: "selection.slot_1", context: &equippedItem1Context)
134         shipController.addObserver(self, forKeyPath: "selection.onslot_1", context: &equippedItem1Context)
135         shipController.addObserver(self, forKeyPath: "selection.master_ship.maxeq_1", context: &equippedItem1Context)
136         
137         shipController.addObserver(self, forKeyPath: "selection.slot_2", context: &equippedItem2Context)
138         shipController.addObserver(self, forKeyPath: "selection.onslot_2", context: &equippedItem2Context)
139         shipController.addObserver(self, forKeyPath: "selection.master_ship.maxeq_2", context: &equippedItem2Context)
140         
141         shipController.addObserver(self, forKeyPath: "selection.slot_3", context: &equippedItem3Context)
142         shipController.addObserver(self, forKeyPath: "selection.onslot_3", context: &equippedItem3Context)
143         shipController.addObserver(self, forKeyPath: "selection.master_ship.maxeq_3", context: &equippedItem3Context)
144         
145         shipController.addObserver(self, forKeyPath: "selection.slot_4", context: &equippedItem4Context)
146         shipController.addObserver(self, forKeyPath: "selection.onslot_4", context: &equippedItem4Context)
147         shipController.addObserver(self, forKeyPath: "selection.master_ship.maxeq_4", context: &equippedItem4Context)
148         
149     }
150     
151     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
152         
153         if context == &shipContext {
154             
155             notifyChangeValue(forKey: #keyPath(planeString0))
156             notifyChangeValue(forKey: #keyPath(planeString0Color))
157             notifyChangeValue(forKey: #keyPath(planeString1))
158             notifyChangeValue(forKey: #keyPath(planeString1Color))
159             notifyChangeValue(forKey: #keyPath(planeString2))
160             notifyChangeValue(forKey: #keyPath(planeString2Color))
161             notifyChangeValue(forKey: #keyPath(planeString3))
162             notifyChangeValue(forKey: #keyPath(planeString3Color))
163             notifyChangeValue(forKey: #keyPath(planeString4))
164             notifyChangeValue(forKey: #keyPath(planeString4Color))
165             
166             return
167         }
168         if context == &equippedItem0Context {
169             
170             notifyChangeValue(forKey: #keyPath(planeString0))
171             notifyChangeValue(forKey: #keyPath(planeString0Color))
172             
173             return
174         }
175         if context == &equippedItem1Context {
176             
177             notifyChangeValue(forKey: #keyPath(planeString1))
178             notifyChangeValue(forKey: #keyPath(planeString1Color))
179             
180             return
181         }
182         if context == &equippedItem2Context {
183             
184             notifyChangeValue(forKey: #keyPath(planeString2))
185             notifyChangeValue(forKey: #keyPath(planeString2Color))
186             
187             return
188         }
189         if context == &equippedItem3Context {
190             
191             notifyChangeValue(forKey: #keyPath(planeString3))
192             notifyChangeValue(forKey: #keyPath(planeString3Color))
193             
194             return
195         }
196         if context == &equippedItem4Context {
197             
198             notifyChangeValue(forKey: #keyPath(planeString4))
199             notifyChangeValue(forKey: #keyPath(planeString4Color))
200             
201             return
202         }
203         
204         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
205     }
206 }
207
208
209 private let allPlaneTypes: [Int] = [6, 7, 8, 9, 10, 11, 25, 26, 41, 45, 56, 57, 58, 59]
210
211
212 extension ShipDetailViewController {
213     
214     // MARK: - Plane count strings
215     private enum PlaneState {
216         
217         case cannotEquip
218         case notEquip(Int)
219         case equiped(Int, Int)
220     }
221     
222     private func planState(_ index: Int) -> PlaneState {
223         
224         guard let ship = ship else { return .cannotEquip }
225         
226         let itemId = ship.slotItemId(index)
227         let maxCount = ship.slotItemMax(index)
228         
229         if maxCount == 0 { return .cannotEquip }
230         if itemId == -1 { return .notEquip(maxCount) }
231         
232         if let item = ship.slotItem(index),
233             allPlaneTypes.contains(item.master_slotItem.type_2) {
234             
235             return .equiped(ship.slotItemCount(index), maxCount)
236         }
237         
238         return .notEquip(maxCount)
239     }
240     
241     private func planeString(_ index: Int) -> String? {
242         
243         switch planState(index) {
244         case .cannotEquip:
245             return nil
246         case .notEquip(let max):
247             return "\(max)"
248         case .equiped(let count, let max):
249             return "\(count)/\(max)"
250         }
251     }
252     
253     @objc dynamic var planeString0: String? { return planeString(0) }
254     
255     @objc dynamic var planeString1: String? { return planeString(1) }
256     
257     @objc dynamic var planeString2: String? { return planeString(2) }
258     
259     @objc dynamic var planeString3: String? { return planeString(3) }
260     
261     @objc dynamic var planeString4: String? { return planeString(4) }
262     
263     // MARK: - Plane count string color
264     private func planeStringColor(_ index: Int) -> NSColor {
265         
266         switch planState(index) {
267         case .cannotEquip: return NSColor.controlTextColor
268         case .notEquip: return NSColor.disabledControlTextColor
269         case .equiped: return NSColor.controlTextColor
270         }
271     }
272     
273     @objc dynamic var planeString0Color: NSColor { return planeStringColor(0) }
274     
275     @objc dynamic var planeString1Color: NSColor { return planeStringColor(1) }
276     
277     @objc dynamic var planeString2Color: NSColor { return planeStringColor(2) }
278     
279     @objc dynamic var planeString3Color: NSColor { return planeStringColor(3) }
280     
281     @objc dynamic var planeString4Color: NSColor { return planeStringColor(4) }
282 }
283
284 extension ShipDetailViewController: NibLoadable {}