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.context
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)?
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 fileprivate var ancherageRepariTimerViewController: AncherageRepairTimerViewController!
75 private var resourceViewController: ResourceViewController!
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?[CombinedCommand.userInfoKey] 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 = combinedViewController.view.frame.maxX
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 = combinedViewController.view.frame.maxX
181 winFrame.size.width -= decWid
182 winFrame.origin.x += decWid
183 window?.setFrame(winFrame, display: true, animate: true)
184 combinedViewController.view.isHidden = true
188 extension BroserWindowController {
189 private func showView(number: Int) {
190 informations.selectTabViewItem(at: number)
192 @IBAction func reloadContent(_ sender: AnyObject?) {
193 gameViewController.reloadContent(sender)
195 @IBAction func deleteCacheAndReload(_ sender: AnyObject?) {
196 gameViewController.deleteCacheAndReload(sender)
198 @IBAction func clearQuestList(_ sender: AnyObject?) {
199 let store = ServerDataStore.oneTimeEditor()
200 store.quests().forEach { store.delete($0) }
202 @IBAction func selectView(_ sender: AnyObject?) {
203 guard let tag = sender?.tag else { return }
204 showView(number: tag)
206 @IBAction func changeMainTab(_ sender: AnyObject?) {
207 guard let segment = sender?.selectedSegment else { return }
208 showView(number: segment)
210 @IBAction func screenShot(_ sender: AnyObject?) {
211 gameViewController.screenShot(sender)
213 @IBAction func toggleAnchorageSize(_ sender: AnyObject?) {
214 let current = ancherageRepariTimerViewController.controlSize
215 var diff = AncherageRepairTimerViewController.regularHeight - AncherageRepairTimerViewController.smallHeight
216 let newSize: NSControlSize = {
217 if current == .regular {
223 ancherageRepariTimerViewController.controlSize = newSize
225 var frame = informations.frame
226 frame.size.height -= diff
227 frame.origin.y += diff
228 informations.frame = frame
230 UserDefaults.standard.screenshotButtonSize = newSize
232 @IBAction func showHideCombinedView(_ sender: AnyObject?) {
233 isCombinedMode ? hideCombinedView() : 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 - flashRect.height - fleetViewController.normalHeight
353 flashY = contentHeight - flashRect.height
355 flashY = contentHeight
357 - fleetViewController.upsideHeight
358 - BroserWindowController.margin
360 flashY = contentHeight - flashRect.height - BroserWindowController.flashTopMargin
362 flashRect.origin.y = flashY
365 private func fleetViewFrameForFleetViewPosition(position newPosition: FleetViewPosition) -> NSRect {
366 let contentHeight = windowHeightForFleetViewPosition(position: newPosition)
367 let flashRect = gameViewController.view.frame
368 var fleetListRect = fleetViewController.view.frame
370 var fleetViewHeight: CGFloat
371 var fleetViewY: CGFloat
374 fleetViewHeight = fleetViewController.normalHeight
375 fleetViewY = contentHeight - fleetViewHeight
377 fleetViewHeight = fleetViewController.normalHeight
378 fleetViewY = contentHeight
381 - BroserWindowController.margin
383 fleetViewHeight = fleetViewController.normalHeight
385 + BroserWindowController.margin
386 + BroserWindowController.margin
387 fleetViewY = contentHeight - fleetViewHeight
389 fleetViewHeight = FleetViewController.oldStyleFleetViewHeight
390 fleetViewY = contentHeight
393 - BroserWindowController.margin
394 - BroserWindowController.flashTopMargin
396 fleetListRect.size.height = fleetViewHeight
397 fleetListRect.origin.y = fleetViewY
400 fileprivate func setFleetView(position newPosition: FleetViewPosition, animate: Bool) {
401 changeFleetViewForFleetViewPositionIfNeeded(position: newPosition)
402 let winFrame = windowFrameForFleetViewPosition(position: newPosition)
403 let flashRect = flashFrameForFleetViewPosition(position: newPosition)
404 let fleetListRect = fleetViewFrameForFleetViewPosition(position: newPosition)
406 fleetViewPosition = newPosition
407 UserDefaults.standard.fleetViewPosition = newPosition
410 let winAnime: [String: Any] = [ NSViewAnimationTargetKey: window!,
411 NSViewAnimationEndFrameKey: NSValue(rect: winFrame) ]
412 let flashAnime: [String: Any] = [ NSViewAnimationTargetKey: gameViewController.view,
413 NSViewAnimationEndFrameKey: NSValue(rect: flashRect) ]
414 let fleetAnime: [String: Any] = [ NSViewAnimationTargetKey: fleetViewController.view,
415 NSViewAnimationEndFrameKey: NSValue(rect: fleetListRect) ]
416 let anime = NSViewAnimation(viewAnimations: [winAnime, flashAnime, fleetAnime])
419 window!.setFrame(winFrame, display: false)
420 gameViewController.view.frame = flashRect
421 fleetViewController.view.frame = fleetListRect
427 @available(OSX 10.12.2, *)
428 fileprivate var mainTouchBars: [Int: NSTouchBar] = [:]
429 @available(OSX 10.12.2, *)
430 fileprivate var shipTypeButtons: [Int: NSPopoverTouchBarItem] = [:]
431 @available(OSX 10.12.2, *)
432 fileprivate var shipTypeSegments: [Int: NSSegmentedControl] = [:]
434 @available(OSX 10.12.2, *)
435 extension BroserWindowController {
436 @IBOutlet var mainTouchBar: NSTouchBar! {
437 get { return mainTouchBars[hashValue] }
438 set { mainTouchBars[hashValue] = newValue }
440 @IBOutlet var shipTypeButton: NSPopoverTouchBarItem! {
441 get { return shipTypeButtons[hashValue] }
442 set { shipTypeButtons[hashValue] = newValue }
444 @IBOutlet var shipTypeSegment: NSSegmentedControl! {
445 get { return shipTypeSegments[hashValue] }
446 set { shipTypeSegments[hashValue] = newValue }
449 override func makeTouchBar() -> NSTouchBar? {
450 if let mainTouchBar = mainTouchBar { return mainTouchBar }
451 var array: NSArray = []
452 Bundle.main.loadNibNamed("BroswerTouchBar", owner: self, topLevelObjects: &array)
454 shipTypeSegment.bind(NSSelectedIndexBinding,
455 to: tabViewItemViewControllers[0],
456 withKeyPath: "selectedShipType",
458 let o = selectedMainTabIndex
459 selectedMainTabIndex = o
461 changeMainTabHandler = { [unowned self] newValue in
462 self.shipTypeButton.dismissPopover(nil)
463 self.shipTypeSegment.unbind(NSSelectedIndexBinding)
464 guard let button = self.shipTypeButton.view as? NSButton else { return }
465 let vc = self.tabViewItemViewControllers[newValue]
466 button.isHidden = !vc.hasShipTypeSelector
467 self.shipTypeSegment.bind(NSSelectedIndexBinding,
469 withKeyPath: "selectedShipType",