| 
          // | 
        
        
           | 
          //  PreferencesTabViewController.swift | 
        
        
           | 
          //  Light Table | 
        
        
           | 
          // | 
        
        
           | 
          //  Copyright 2022 Florian Pircher | 
        
        
           | 
          // | 
        
        
           | 
          //  Licensed under the Apache License, Version 2.0 (the "License"); | 
        
        
           | 
          //  you may not use this file except in compliance with the License. | 
        
        
           | 
          //  You may obtain a copy of the License at | 
        
        
           | 
          // | 
        
        
           | 
          //      http://www.apache.org/licenses/LICENSE-2.0 | 
        
        
           | 
          // | 
        
        
           | 
          //  Unless required by applicable law or agreed to in writing, software | 
        
        
           | 
          //  distributed under the License is distributed on an "AS IS" BASIS, | 
        
        
           | 
          //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
        
        
           | 
          //  See the License for the specific language governing permissions and | 
        
        
           | 
          //  limitations under the License. | 
        
        
           | 
          // | 
        
        
           | 
          
 | 
        
        
           | 
          import Cocoa | 
        
        
           | 
          
 | 
        
        
           | 
          final class PreferencesTabViewController: NSTabViewController { | 
        
        
           | 
              private struct ToolbarItemSpecs { | 
        
        
           | 
                  let identifier: NSToolbarItem.Identifier | 
        
        
           | 
                  let index: Int | 
        
        
           | 
                  let label: String | 
        
        
           | 
                  let title: String | 
        
        
           | 
                  let image: NSImage? | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              private var toolbarItemsSpecs: [ToolbarItemSpecs] = [] | 
        
        
           | 
              private var bottomConstraint: NSLayoutConstraint! | 
        
        
           | 
               | 
        
        
           | 
              override func awakeFromNib() { | 
        
        
           | 
                  super.awakeFromNib() | 
        
        
           | 
                   | 
        
        
           | 
                  guard let window = tabView.window else { | 
        
        
           | 
                      return | 
        
        
           | 
                  } | 
        
        
           | 
                  window.toolbarStyle = .preference | 
        
        
           | 
                   | 
        
        
           | 
                  toolbarItemsSpecs = tabView.tabViewItems.enumerated().map { index, tabItem in | 
        
        
           | 
                      ToolbarItemSpecs( | 
        
        
           | 
                          identifier: NSToolbarItem.Identifier("preference:\(index)"), | 
        
        
           | 
                          index: index, | 
        
        
           | 
                          label: tabItem.label, | 
        
        
           | 
                          title: tabItem.viewController?.title ?? tabItem.label, | 
        
        
           | 
                          image: tabItem.image) | 
        
        
           | 
                  } | 
        
        
           | 
                   | 
        
        
           | 
                  let toolbar = NSToolbar() | 
        
        
           | 
                  toolbar.delegate = self | 
        
        
           | 
                  window.toolbar = toolbar | 
        
        
           | 
                   | 
        
        
           | 
                  if let firstSpec = toolbarItemsSpecs.first { | 
        
        
           | 
                      tabView.selectTabViewItem(at: firstSpec.index) | 
        
        
           | 
                      window.title = firstSpec.title | 
        
        
           | 
                      toolbar.selectedItemIdentifier = firstSpec.identifier | 
        
        
           | 
                  } | 
        
        
           | 
                   | 
        
        
           | 
                  if let superview = tabView.superview { | 
        
        
           | 
                      tabView.removeFromSuperview() | 
        
        
           | 
                      superview.addSubview(tabView) | 
        
        
           | 
                      NSLayoutConstraint.activate([ | 
        
        
           | 
                          superview.topAnchor.constraint(equalTo: tabView.topAnchor), | 
        
        
           | 
                          superview.leadingAnchor.constraint(equalTo: tabView.leadingAnchor), | 
        
        
           | 
                          superview.trailingAnchor.constraint(equalTo: tabView.trailingAnchor), | 
        
        
           | 
                      ]) | 
        
        
           | 
                      bottomConstraint = superview.bottomAnchor.constraint(equalTo: tabView.bottomAnchor) | 
        
        
           | 
                      bottomConstraint.isActive = true | 
        
        
           | 
                  } | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { | 
        
        
           | 
                  toolbarItemsSpecs.map { $0.identifier } | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { | 
        
        
           | 
                  toolbarAllowedItemIdentifiers(toolbar) | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { | 
        
        
           | 
                  toolbarAllowedItemIdentifiers(toolbar) | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbarImmovableItemIdentifiers(_ toolbar: NSToolbar) -> Set<NSToolbarItem.Identifier> { | 
        
        
           | 
                  Set(toolbarAllowedItemIdentifiers(toolbar)) | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbar(_ toolbar: NSToolbar, itemIdentifier: NSToolbarItem.Identifier, canBeInsertedAt index: Int) -> Bool { | 
        
        
           | 
                  true | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              override func toolbarWillAddItem(_ notification: Notification) {} | 
        
        
           | 
               | 
        
        
           | 
              override func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { | 
        
        
           | 
                  guard let spec = toolbarItemsSpecs.first(where: { $0.identifier == itemIdentifier }) else { | 
        
        
           | 
                      return nil | 
        
        
           | 
                  } | 
        
        
           | 
                  let item = NSToolbarItem(itemIdentifier: spec.identifier) | 
        
        
           | 
                  item.label = spec.label | 
        
        
           | 
                  item.image = spec.image | 
        
        
           | 
                  item.target = self | 
        
        
           | 
                  item.action = #selector(Self.selectToolbarItem(_:)) | 
        
        
           | 
                  return item | 
        
        
           | 
              } | 
        
        
           | 
               | 
        
        
           | 
              @objc func selectToolbarItem(_ sender: NSToolbarItem) { | 
        
        
           | 
                  guard let spec = toolbarItemsSpecs.first(where: { $0.identifier == sender.itemIdentifier }), | 
        
        
           | 
                        let window = tabView.window, | 
        
        
           | 
                        tabView.tabViewItems.indices.contains(spec.index) | 
        
        
           | 
                  else { | 
        
        
           | 
                      return | 
        
        
           | 
                  } | 
        
        
           | 
                  let newTabViewItem = tabView.tabViewItems[spec.index] | 
        
        
           | 
                  guard let newContentView = newTabViewItem.view else { | 
        
        
           | 
                      return | 
        
        
           | 
                  } | 
        
        
           | 
                   | 
        
        
           | 
                  let contentFrame = tabView.frame | 
        
        
           | 
                  let newContentSize = newContentView.fittingSize | 
        
        
           | 
                  let windowFrame = window.frame | 
        
        
           | 
                  let windowHeightOffset = windowFrame.height - contentFrame.height | 
        
        
           | 
                  let newWindowSize = CGSize( | 
        
        
           | 
                      width: max(windowFrame.width, newContentSize.width), | 
        
        
           | 
                      height: newContentSize.height + windowHeightOffset) | 
        
        
           | 
                  let windowOrigin = windowFrame.origin | 
        
        
           | 
                  let newWindowOrigin = CGPoint( | 
        
        
           | 
                      x: windowOrigin.x + ((newWindowSize.width - windowFrame.width) / -2), | 
        
        
           | 
                      y: windowOrigin.y + (windowFrame.height - newWindowSize.height)) | 
        
        
           | 
                  let newWindowFrame = CGRect(origin: newWindowOrigin, size: newWindowSize) | 
        
        
           | 
                   | 
        
        
           | 
                  tabView.isHidden = true | 
        
        
           | 
                  bottomConstraint.isActive = false | 
        
        
           | 
                   | 
        
        
           | 
                  window.setFrame(newWindowFrame, display: true, animate: true) | 
        
        
           | 
                  tabView.selectTabViewItem(at: spec.index) | 
        
        
           | 
                   | 
        
        
           | 
                  bottomConstraint.isActive = true | 
        
        
           | 
                  tabView.isHidden = false | 
        
        
           | 
                   | 
        
        
           | 
                  window.title = spec.title | 
        
        
           | 
              } | 
        
        
           | 
          } |