173 lines
5.0 KiB
Swift
Executable File
173 lines
5.0 KiB
Swift
Executable File
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
|
// ====================
|
|
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
|
|
|
import Cocoa
|
|
|
|
extension NSWindow.FrameAutosaveName {
|
|
static let preferences: NSWindow.FrameAutosaveName = "com.sindresorhus.Preferences.FrameAutosaveName"
|
|
}
|
|
|
|
public final class PreferencesWindowController: NSWindowController {
|
|
private let tabViewController = PreferencesTabViewController()
|
|
|
|
public var isAnimated: Bool {
|
|
get { tabViewController.isAnimated }
|
|
set {
|
|
tabViewController.isAnimated = newValue
|
|
}
|
|
}
|
|
|
|
public var hidesToolbarForSingleItem: Bool {
|
|
didSet {
|
|
updateToolbarVisibility()
|
|
}
|
|
}
|
|
|
|
private func updateToolbarVisibility() {
|
|
window?.toolbar?.isVisible =
|
|
(hidesToolbarForSingleItem == false)
|
|
|| (tabViewController.preferencePanesCount > 1)
|
|
}
|
|
|
|
public init(
|
|
preferencePanes: [PreferencePane],
|
|
style: SSPreferences.Style = .toolbarItems,
|
|
animated: Bool = true,
|
|
hidesToolbarForSingleItem: Bool = true
|
|
) {
|
|
precondition(!preferencePanes.isEmpty, "You need to set at least one view controller")
|
|
|
|
let window = UserInteractionPausableWindow(
|
|
contentRect: preferencePanes[0].view.bounds,
|
|
styleMask: [
|
|
.titled,
|
|
.closable,
|
|
],
|
|
backing: .buffered,
|
|
defer: true
|
|
)
|
|
self.hidesToolbarForSingleItem = hidesToolbarForSingleItem
|
|
super.init(window: window)
|
|
|
|
window.contentViewController = tabViewController
|
|
|
|
window.titleVisibility = {
|
|
switch style {
|
|
case .toolbarItems:
|
|
return .visible
|
|
case .segmentedControl:
|
|
return preferencePanes.count <= 1 ? .visible : .hidden
|
|
}
|
|
}()
|
|
|
|
if #available(macOS 11.0, *), style == .toolbarItems {
|
|
window.toolbarStyle = .preference
|
|
}
|
|
|
|
tabViewController.isAnimated = animated
|
|
tabViewController.configure(preferencePanes: preferencePanes, style: style)
|
|
updateToolbarVisibility()
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
override public init(window _: NSWindow?) {
|
|
fatalError("init(window:) is not supported, use init(preferences:style:animated:)")
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
public required init?(coder _: NSCoder) {
|
|
fatalError("init(coder:) is not supported, use init(preferences:style:animated:)")
|
|
}
|
|
|
|
/**
|
|
Show the preferences window and brings it to front.
|
|
|
|
If you pass a `SSPreferences.PaneIdentifier`, the window will activate the corresponding tab.
|
|
|
|
- Parameter preferencePane: Identifier of the preference pane to display, or `nil` to show the tab that was open when the user last closed the window.
|
|
|
|
- Note: Unless you need to open a specific pane, prefer not to pass a parameter at all or `nil`.
|
|
|
|
- See `close()` to close the window again.
|
|
- See `showWindow(_:)` to show the window without the convenience of activating the app.
|
|
*/
|
|
public func show(preferencePane preferenceIdentifier: SSPreferences.PaneIdentifier? = nil) {
|
|
if let preferenceIdentifier = preferenceIdentifier {
|
|
tabViewController.activateTab(preferenceIdentifier: preferenceIdentifier, animated: false)
|
|
} else {
|
|
tabViewController.restoreInitialTab()
|
|
}
|
|
|
|
showWindow(self)
|
|
restoreWindowPosition()
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
}
|
|
|
|
private func restoreWindowPosition() {
|
|
guard
|
|
let window = window,
|
|
let screenContainingWindow = window.screen
|
|
else {
|
|
return
|
|
}
|
|
|
|
window.setFrameOrigin(
|
|
CGPoint(
|
|
x: screenContainingWindow.visibleFrame.midX - window.frame.width / 2,
|
|
y: screenContainingWindow.visibleFrame.midY - window.frame.height / 2
|
|
))
|
|
window.setFrameUsingName(.preferences)
|
|
window.setFrameAutosaveName(.preferences)
|
|
}
|
|
}
|
|
|
|
public extension PreferencesWindowController {
|
|
/// Returns the active pane if it responds to the given action.
|
|
override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
|
|
if let target = super.supplementalTarget(forAction: action, sender: sender) {
|
|
return target
|
|
}
|
|
|
|
guard let activeViewController = tabViewController.activeViewController else {
|
|
return nil
|
|
}
|
|
|
|
if let target = NSApp.target(forAction: action, to: activeViewController, from: sender) as? NSResponder,
|
|
target.responds(to: action)
|
|
{
|
|
return target
|
|
}
|
|
|
|
if let target = activeViewController.supplementalTarget(forAction: action, sender: sender) as? NSResponder,
|
|
target.responds(to: action)
|
|
{
|
|
return target
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, *)
|
|
public extension PreferencesWindowController {
|
|
/**
|
|
Create a preferences window from only SwiftUI-based preference panes.
|
|
*/
|
|
convenience init(
|
|
panes: [PreferencePaneConvertible],
|
|
style: SSPreferences.Style = .toolbarItems,
|
|
animated: Bool = true,
|
|
hidesToolbarForSingleItem: Bool = true
|
|
) {
|
|
let preferencePanes = panes.map { $0.asPreferencePane() }
|
|
|
|
self.init(
|
|
preferencePanes: preferencePanes,
|
|
style: style,
|
|
animated: animated,
|
|
hidesToolbarForSingleItem: hidesToolbarForSingleItem
|
|
)
|
|
}
|
|
}
|