2 // BroserWindowController.swift
5 // Created by Hori,Masaki on 2016/12/31.
6 // Copyright © 2016年 Hori,Masaki. All rights reserved.
12 fileprivate extension Selector {
13 static let reloadContent = #selector(BroserWindowController.reloadContent(_:))
14 static let deleteCacheAndReload = #selector(BroserWindowController.deleteCacheAndReload(_:))
15 static let clearQuestList = #selector(BroserWindowController.clearQuestList(_:))
16 static let selectView = #selector(BroserWindowController.selectView(_:))
17 static let changeMainTab = #selector(BroserWindowController.changeMainTab(_:))
18 static let screenShot = #selector(BroserWindowController.screenShot(_:))
19 static let toggleAnchorageSize = #selector(BroserWindowController.toggleAnchorageSize(_:))
20 static let showHideCombinedView = #selector(BroserWindowController.showHideCombinedView(_:))
21 static let fleetListAbove = #selector(BroserWindowController.fleetListAbove(_:))
22 static let fleetListBelow = #selector(BroserWindowController.fleetListBelow(_:))
23 static let fleetListDivide = #selector(BroserWindowController.fleetListDivide(_:))
24 static let fleetListSimple = #selector(BroserWindowController.fleetListSimple(_:))
25 static let reorderToDoubleLine = #selector(BroserWindowController.reorderToDoubleLine(_:))
26 static let reorderToLeftToRight = #selector(BroserWindowController.reorderToLeftToRight(_:))
27 static let selectNextFleet = #selector(BroserWindowController.selectNextFleet(_:))
28 static let selectPreviousFleet = #selector(BroserWindowController.selectPreviousFleet(_:))
31 class BroserWindowController: NSWindowController {
32 enum FleetViewPosition: Int {
36 case oldStyle = 0xffffffff
39 class func keyPathsForValuesAffectingFlagShipName() -> Set<String> {
43 let managedObjectContext = ServerDataStore.default.managedObjectContext
46 NotificationCenter.default.removeObserver(self)
49 @IBOutlet weak var placeholder: NSView!
50 @IBOutlet weak var combinedViewPlaceholder: NSView!
51 @IBOutlet weak var deckPlaceholder: NSView!
52 @IBOutlet weak var resourcePlaceholder: NSView!
53 @IBOutlet weak var ancherageRepariTimerPlaceholder: NSView!
54 @IBOutlet weak var informations: NSTabView!
55 @IBOutlet var deckContoller: NSArrayController!
57 override var windowNibName: String! {
58 return "BroserWindowController"
60 var flagShipID: Int = 0
61 var flagShipName: String? {
62 return ServerDataStore.default.ship(byId: flagShipID)?.name
64 var changeMainTabHandler: ((Int) -> Void)? = nil
65 dynamic var selectedMainTabIndex: Int = 0 {
67 changeMainTabHandler?(selectedMainTabIndex)
71 fileprivate var gameViewController: GameViewController!
72 fileprivate var fleetViewController: FleetViewController!
73 fileprivate var tabViewItemViewControllers: [MainTabVIewItemViewController] = []
74 private var resourceViewController: ResourceViewController!
75 private var ancherageRepariTimerViewController: AncherageRepairTimerViewController!
76 private var docksViewController: DocksViewController!
77 private var shipViewController: ShipViewController!
78 private var powerUpViewController: PowerUpSupportViewController!
79 private var strengthedListViewController: StrengthenListViewController!
80 private var repairListViewController: RepairListViewController!
81 private var combinedViewController: CombileViewController!
83 fileprivate var fleetViewPosition: FleetViewPosition = .above
84 fileprivate var isCombinedMode = false
87 override func windowDidLoad() {
90 gameViewController = GameViewController()
91 replace(placeholder, with: gameViewController)
93 resourceViewController = ResourceViewController()
94 replace(resourcePlaceholder, with: resourceViewController)
96 ancherageRepariTimerViewController = AncherageRepairTimerViewController()
97 replace(ancherageRepariTimerPlaceholder, with: ancherageRepariTimerViewController)
98 if UserDefaults.standard.screenshotButtonSize == .small { toggleAnchorageSize(nil) }
100 tabViewItemViewControllers = [
101 DocksViewController(),
102 ShipViewController(),
103 PowerUpSupportViewController(),
104 StrengthenListViewController(),
105 RepairListViewController()
107 tabViewItemViewControllers.enumerated().forEach {
108 let _ = $0.element.view
109 let item = informations.tabViewItem(at: $0.offset)
110 item.viewController = $0.element
113 fleetViewController = FleetViewController(viewType: .detailViewType)
114 replace(deckPlaceholder, with: fleetViewController)
115 setFleetView(position: UserDefaults.standard.fleetViewPosition, animate: false)
116 fleetViewController.enableAnimation = false
117 fleetViewController.shipOrder = UserDefaults.standard.fleetViewShipOrder
118 fleetViewController.enableAnimation = true
120 bind("flagShipID", to: deckContoller, withKeyPath: "selection.ship_0", options: nil)
122 NotificationCenter.default
123 .addObserver(forName: .CombinedDidCange, object: nil, queue: nil) { (notification) in
124 guard UserDefaults.standard.autoCombinedView,
125 let type = notification.userInfo?[CombinedType] as? CombineType
127 if !Thread.isMainThread { Thread.sleep(forTimeInterval: 0.1) }
128 DispatchQueue.main.async {
131 self.hideCombinedView()
132 case .maneuver, .water, .transportation:
133 self.showCombinedView()
138 if UserDefaults.standard.lastHasCombinedView { showCombinedView() }
140 override func swipe(with event: NSEvent) {
141 guard UserDefaults.standard.useSwipeChangeCombinedView else { return }
142 if event.deltaX > 0 {
145 if event.deltaX < 0 {
150 func windowWillClose(_ notification: Notification) {
151 UserDefaults.standard.lastHasCombinedView = isCombinedMode
154 fileprivate func replace(_ view: NSView, with viewController: NSViewController) {
155 viewController.view.frame = view.frame
156 viewController.view.autoresizingMask = view.autoresizingMask
157 self.window?.contentView?.replaceSubview(view, with: viewController.view)
159 fileprivate func showCombinedView() {
160 if isCombinedMode { return }
161 if fleetViewPosition == .oldStyle { return }
162 isCombinedMode = true
163 if combinedViewController == nil {
164 combinedViewController = CombileViewController()
165 combinedViewController.view.isHidden = true
166 replace(combinedViewPlaceholder, with: combinedViewController)
169 var winFrame = window!.frame
170 let incWid = NSMaxX(combinedViewController.view.frame)
171 winFrame.size.width += incWid
172 winFrame.origin.x -= incWid
173 combinedViewController.view.isHidden = false
174 window?.setFrame(winFrame, display: true, animate: true)
176 fileprivate func hideCombinedView() {
177 if !isCombinedMode { return }
178 isCombinedMode = false
179 var winFrame = window!.frame
180 let decWid = NSMaxX(combinedViewController.view.frame)
181 winFrame.size.width -= decWid
182 winFrame.origin.x += decWid
183 window?.setFrame(winFrame, display: true, animate: true)
184 combinedViewController.view.isHidden = true
186 private func showView(number: Int) {
187 informations.selectTabViewItem(at: number)
191 @IBAction func reloadContent(_ sender: AnyObject?) {
192 gameViewController.reloadContent(sender)
194 @IBAction func deleteCacheAndReload(_ sender: AnyObject?) {
195 gameViewController.deleteCacheAndReload(sender)
197 @IBAction func clearQuestList(_ sender: AnyObject?) {
198 let store = ServerDataStore.oneTimeEditor()
199 store.quests().forEach { store.delete($0) }
201 @IBAction func selectView(_ sender: AnyObject?) {
202 guard let tag = sender?.tag else { return }
203 showView(number: tag)
205 @IBAction func changeMainTab(_ sender: AnyObject?) {
206 guard let segment = sender?.selectedSegment else { return }
207 showView(number: segment)
209 @IBAction func screenShot(_ sender: AnyObject?) {
210 gameViewController.screenShot(sender)
212 @IBAction func toggleAnchorageSize(_ sender: AnyObject?) {
213 let current = ancherageRepariTimerViewController.controlSize
214 var diff = AncherageRepairTimerViewController.regularHeight - AncherageRepairTimerViewController.smallHeight
215 let newSize: NSControlSize = {
216 if current == .regular {
222 ancherageRepariTimerViewController.controlSize = newSize
224 var frame = informations.frame
225 frame.size.height -= diff
226 frame.origin.y += diff
227 informations.frame = frame
229 UserDefaults.standard.screenshotButtonSize = newSize
231 @IBAction func showHideCombinedView(_ sender: AnyObject?) {
232 if isCombinedMode { hideCombinedView() }
233 else { showCombinedView() }
236 @IBAction func fleetListAbove(_ sender: AnyObject?) {
237 setFleetView(position: .above, animate: true)
239 @IBAction func fleetListBelow(_ sender: AnyObject?) {
240 setFleetView(position: .below, animate: true)
242 @IBAction func fleetListDivide(_ sender: AnyObject?) {
243 setFleetView(position: .divided, animate: true)
245 @IBAction func fleetListSimple(_ sender: AnyObject?) {
246 setFleetView(position: .oldStyle, animate: true)
248 @IBAction func reorderToDoubleLine(_ sender: AnyObject?) {
249 fleetViewController.shipOrder = .doubleLine
250 UserDefaults.standard.fleetViewShipOrder = .doubleLine
252 @IBAction func reorderToLeftToRight(_ sender: AnyObject?) {
253 fleetViewController.shipOrder = .leftToRight
254 UserDefaults.standard.fleetViewShipOrder = .leftToRight
256 @IBAction func selectNextFleet(_ sender: AnyObject?) {
257 fleetViewController.selectNextFleet(sender)
259 @IBAction func selectPreviousFleet(_ sender: AnyObject?) {
260 fleetViewController.selectPreviousFleet(sender)
263 override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
264 guard let action: Selector = menuItem.action else { return false }
266 case Selector.reloadContent, Selector.screenShot, Selector.deleteCacheAndReload:
267 return gameViewController.validateMenuItem(menuItem)
268 case Selector.selectView, Selector.selectNextFleet, Selector.selectPreviousFleet:
270 case Selector.fleetListAbove:
271 menuItem.state = fleetViewPosition == .above ? NSOnState : NSOffState
273 case Selector.fleetListBelow:
274 menuItem.state = fleetViewPosition == .below ? NSOnState : NSOffState
276 case Selector.fleetListDivide:
277 menuItem.state = fleetViewPosition == .divided ? NSOnState : NSOffState
279 case Selector.fleetListSimple:
280 menuItem.state = fleetViewPosition == .oldStyle ? NSOnState : NSOffState
282 case Selector.reorderToDoubleLine:
283 menuItem.state = fleetViewController.shipOrder == .doubleLine ? NSOnState : NSOffState
285 case Selector.reorderToLeftToRight:
286 menuItem.state = fleetViewController.shipOrder == .leftToRight ? NSOnState: NSOffState
288 case Selector.clearQuestList:
290 case Selector.showHideCombinedView:
292 menuItem.title = NSLocalizedString("Hide Combined View", comment: "View menu, hide combined view")
294 menuItem.title = NSLocalizedString("Show Combined View", comment: "View menu, show combined view")
296 if fleetViewPosition == .oldStyle { return false }
298 case Selector.toggleAnchorageSize:
306 extension BroserWindowController {
307 private static let margin: CGFloat = 1.0
308 private static let flashTopMargin: CGFloat = 4.0
310 private func changeFleetViewForFleetViewPositionIfNeeded(position newPosition: FleetViewPosition) {
311 if fleetViewPosition == newPosition { return }
312 if fleetViewPosition != .oldStyle && newPosition != .oldStyle { return }
313 if newPosition == .oldStyle && isCombinedMode { hideCombinedView() }
314 let type: FleetViewType = (newPosition == .oldStyle) ? .minimumViewType : .detailViewType
315 guard let newController = FleetViewController(viewType: type) else { return }
316 newController.enableAnimation = true
317 newController.shipOrder = fleetViewController.shipOrder
318 replace(fleetViewController.view, with: newController)
319 fleetViewController = newController
321 private func windowHeightForFleetViewPosition(position newPosition: FleetViewPosition) -> CGFloat {
322 guard var contentHeight = window!.contentView?.frame.size.height else { return 0.0 }
323 if fleetViewPosition == newPosition { return contentHeight }
324 if fleetViewPosition == .oldStyle {
325 contentHeight += FleetViewController.heightDifference
327 if newPosition == .oldStyle {
328 contentHeight -= FleetViewController.heightDifference
332 private func windowFrameForFleetViewPosition(position newPosition: FleetViewPosition) -> NSRect {
333 var contentRect = window!.frame
334 if fleetViewPosition == newPosition { return contentRect }
335 if fleetViewPosition == .oldStyle {
336 contentRect.size.height += FleetViewController.heightDifference
337 contentRect.origin.y -= FleetViewController.heightDifference
339 if newPosition == .oldStyle {
340 contentRect.size.height -= FleetViewController.heightDifference
341 contentRect.origin.y += FleetViewController.heightDifference
345 private func flashFrameForFleetViewPosition(position newPosition: FleetViewPosition) -> NSRect {
346 let contentHeight = windowHeightForFleetViewPosition(position: newPosition)
347 var flashRect = gameViewController.view.frame
351 flashY = contentHeight - NSHeight(flashRect) - fleetViewController.normalHeight
353 flashY = contentHeight - NSHeight(flashRect)
355 flashY = contentHeight - NSHeight(flashRect) - fleetViewController.upsideHeight - BroserWindowController.margin
357 flashY = contentHeight - NSHeight(flashRect) - BroserWindowController.flashTopMargin
359 flashRect.origin.y = flashY
362 private func fleetViewFrameForFleetViewPosition(position newPosition: FleetViewPosition) -> NSRect {
363 let contentHeight = windowHeightForFleetViewPosition(position: newPosition)
364 let flashRect = gameViewController.view.frame
365 var fleetListRect = fleetViewController.view.frame
367 var fleetViewHeight: CGFloat
368 var fleetViewY: CGFloat
371 fleetViewHeight = fleetViewController.normalHeight
372 fleetViewY = contentHeight - fleetViewHeight
374 fleetViewHeight = fleetViewController.normalHeight
375 fleetViewY = contentHeight - fleetViewHeight - NSHeight(flashRect) - BroserWindowController.margin
377 fleetViewHeight = fleetViewController.normalHeight + NSHeight(flashRect) + BroserWindowController.margin + BroserWindowController.margin
378 fleetViewY = contentHeight - fleetViewHeight
380 fleetViewHeight = FleetViewController.oldStyleFleetViewHeight
381 fleetViewY = contentHeight - fleetViewHeight - NSHeight(flashRect) - BroserWindowController.margin - BroserWindowController.flashTopMargin
383 fleetListRect.size.height = fleetViewHeight
384 fleetListRect.origin.y = fleetViewY
387 fileprivate func setFleetView(position newPosition: FleetViewPosition, animate: Bool) {
388 changeFleetViewForFleetViewPositionIfNeeded(position: newPosition)
389 let winFrame = windowFrameForFleetViewPosition(position: newPosition)
390 let flashRect = flashFrameForFleetViewPosition(position: newPosition)
391 let fleetListRect = fleetViewFrameForFleetViewPosition(position: newPosition)
393 fleetViewPosition = newPosition
394 UserDefaults.standard.fleetViewPosition = newPosition
397 let winAnime: [String: Any] = [ NSViewAnimationTargetKey: window!,
398 NSViewAnimationEndFrameKey: NSValue(rect: winFrame) ]
399 let flashAnime: [String: Any] = [ NSViewAnimationTargetKey: gameViewController.view,
400 NSViewAnimationEndFrameKey: NSValue(rect: flashRect) ]
401 let fleetAnime: [String: Any] = [ NSViewAnimationTargetKey: fleetViewController.view,
402 NSViewAnimationEndFrameKey: NSValue(rect: fleetListRect) ]
403 let anime = NSViewAnimation(viewAnimations: [winAnime, flashAnime, fleetAnime])
406 window!.setFrame(winFrame, display: false)
407 gameViewController.view.frame = flashRect
408 fleetViewController.view.frame = fleetListRect
414 @available(OSX 10.12.2, *)
415 fileprivate var mainTouchBars: [Int: NSTouchBar] = [:]
416 @available(OSX 10.12.2, *)
417 fileprivate var shipTypeButtons: [Int: NSPopoverTouchBarItem] = [:]
418 @available(OSX 10.12.2, *)
419 fileprivate var shipTypeSegments: [Int: NSSegmentedControl] = [:]
421 @available(OSX 10.12.2, *)
422 extension BroserWindowController {
423 @IBOutlet var mainTouchBar: NSTouchBar! {
425 return mainTouchBars[hashValue]
428 mainTouchBars[hashValue] = newValue
431 @IBOutlet var shipTypeButton: NSPopoverTouchBarItem! {
433 return shipTypeButtons[hashValue]
436 shipTypeButtons[hashValue] = newValue
439 @IBOutlet var shipTypeSegment: NSSegmentedControl! {
441 return shipTypeSegments[hashValue]
444 shipTypeSegments[hashValue] = newValue
448 override func makeTouchBar() -> NSTouchBar? {
449 if mainTouchBar == nil {
450 var array: NSArray = []
451 Bundle.main.loadNibNamed("BroswerTouchBar", owner: self, topLevelObjects: &array)
453 shipTypeSegment.bind(NSSelectedIndexBinding, to: tabViewItemViewControllers[0], withKeyPath: "selectedShipType", options: nil)
454 let o = selectedMainTabIndex
455 selectedMainTabIndex = o
457 changeMainTabHandler = { [unowned self] (newValue) in
458 self.shipTypeButton.dismissPopover(nil)
459 self.shipTypeSegment.unbind(NSSelectedIndexBinding)
460 guard let button = self.shipTypeButton.view as? NSButton else { return }
461 let vc = self.tabViewItemViewControllers[newValue]
462 button.isHidden = !vc.hasShipTypeSelector
463 self.shipTypeSegment.bind(NSSelectedIndexBinding, to: vc, withKeyPath: "selectedShipType", options: nil)