feat: add mac theme and improve preferences (closes #21)
This commit is contained in:
1 parent
0a164c731c
commit
4a5bbe9d1c
7 files changed
+162
-132
No files matched your search
@@ -30,15 +30,15 @@ func keyboardHandler(_ cgEvent: CGEvent, _ delegate: Application) -> Unmanaged<C
|
||||
if cgEvent.type == .keyDown || cgEvent.type == .keyUp || cgEvent.type == .flagsChanged {
|
||||
if let event = NSEvent(cgEvent: cgEvent) {
|
||||
let keyDown = event.type == .keyDown
|
||||
let optionKeyEvent = event.keyCode == Preferences.metaKey
|
||||
let optionKeyEvent = event.keyCode == Preferences.metaKeyCode
|
||||
let tabKeyEvent = event.keyCode == Preferences.tabKey
|
||||
if optionKeyEvent && event.modifiersDown([Preferences.metaModifierFlag]) {
|
||||
if optionKeyEvent && event.modifiersDown([Preferences.metaModifierFlag!]) {
|
||||
delegate.keyDownMeta()
|
||||
} else if tabKeyEvent && event.modifiersDown([Preferences.metaModifierFlag]) && keyDown {
|
||||
} else if tabKeyEvent && event.modifiersDown([Preferences.metaModifierFlag!]) && keyDown {
|
||||
delegate.keyDownMetaTab()
|
||||
// focused app will not receive the event (will not press tab key in that app)
|
||||
return nil
|
||||
} else if tabKeyEvent && event.modifiersDown([Preferences.metaModifierFlag, .shift]) && keyDown {
|
||||
} else if tabKeyEvent && event.modifiersDown([Preferences.metaModifierFlag!, .shift]) && keyDown {
|
||||
delegate.keyDownMetaShiftTab()
|
||||
// focused app will not receive the event (will not press tab key in that app)
|
||||
return nil
|
||||
|
||||
@@ -2,97 +2,99 @@ import Foundation
|
||||
import Cocoa
|
||||
|
||||
let defaults = [
|
||||
"version": "1", // bump this anytime the dictionary is changed
|
||||
"maxScreenUsage": "0.8",
|
||||
"windowPadding": "20",
|
||||
"cellPadding": "6",
|
||||
"cellBorderWidth": "2",
|
||||
"maxThumbnailsPerRow": "4",
|
||||
"thumbnailMaxWidth": "0",
|
||||
"thumbnailMaxHeight": "0",
|
||||
"iconSize": "32",
|
||||
"fontHeight": "15",
|
||||
"interItemPadding": "4",
|
||||
"tabKey": "48",
|
||||
"metaKey": "59",
|
||||
"metaModifierFlag": "262144",
|
||||
"highlightColor": "white",
|
||||
"thumbnailQuality": "4",
|
||||
"windowDisplayDelay": "200",
|
||||
"metaKey": Preferences.metaKeyArray[0],
|
||||
"windowDisplayDelay": "0",
|
||||
"theme": Preferences.themeArray[0]
|
||||
]
|
||||
|
||||
class Preferences {
|
||||
static var rawValues = [String: String]()
|
||||
static var maxScreenUsage: CGFloat = 0
|
||||
static var windowPadding: CGFloat = 0
|
||||
static var cellPadding: CGFloat = 0
|
||||
static var cellBorderWidth: CGFloat = 0
|
||||
static var maxThumbnailsPerRow: CGFloat = 0
|
||||
static var thumbnailMaxWidth: CGFloat = 0
|
||||
static var thumbnailMaxHeight: CGFloat = 0
|
||||
static var iconSize: CGFloat = 0
|
||||
static var fontHeight: CGFloat = 0
|
||||
static var interItemPadding: CGFloat = 0
|
||||
static var tabKey: UInt16 = 0
|
||||
static var metaKey: UInt16 = 0
|
||||
static var metaModifierFlag: NSEvent.ModifierFlags = .control
|
||||
static var highlightColor: NSColor = .white
|
||||
static var thumbnailQuality: NSImageInterpolation = .high
|
||||
static var windowDisplayDelay: DispatchTimeInterval = .milliseconds(200)
|
||||
static var font: NSFont = .systemFont(ofSize: 15)
|
||||
static var thumbnailMaxWidth: CGFloat = 200
|
||||
static var thumbnailMaxHeight: CGFloat = 200
|
||||
static var fontColor: NSColor = .white
|
||||
static var windowMaterial: NSVisualEffectView.Material = .dark
|
||||
static var windowPadding: CGFloat = 23
|
||||
static var interItemPadding: CGFloat = 4
|
||||
static var cellPadding: CGFloat = 6
|
||||
static var cellBorderWidth: CGFloat?
|
||||
static var cellCornerRadius: CGFloat?
|
||||
static var maxScreenUsage: CGFloat?
|
||||
static var maxThumbnailsPerRow: CGFloat?
|
||||
static var iconSize: CGFloat?
|
||||
static var fontHeight: CGFloat?
|
||||
static var tabKey: UInt16?
|
||||
static var highlightBorderColor: NSColor?
|
||||
static var highlightBackgroundColor: NSColor?
|
||||
static var metaKeyCode: UInt16?
|
||||
static var metaModifierFlag: NSEvent.ModifierFlags?
|
||||
static var windowDisplayDelay: DispatchTimeInterval?
|
||||
static var windowCornerRadius: CGFloat?
|
||||
static var font: NSFont?
|
||||
static var themeArray = [" macOS", "❖ Windows 10"]
|
||||
static var metaKeyArray = ["⌥ option", "⌃ control", "⌘ command", "⇪ caps lock", "fn"]
|
||||
static var metaKeyMap: [String: (UInt16, NSEvent.ModifierFlags)] = [
|
||||
metaKeyArray[0]: (58, .option),
|
||||
metaKeyArray[1]: (59, .control),
|
||||
metaKeyArray[2]: (55, .command),
|
||||
metaKeyArray[3]: (57, .capsLock),
|
||||
metaKeyArray[4]: (63, .function),
|
||||
]
|
||||
|
||||
|
||||
private static let defaultsFile = fileFromPreferencesFolder("alt-tab-macos-defaults.json")
|
||||
private static let userFile = fileFromPreferencesFolder("alt-tab-macos.json")
|
||||
|
||||
static func loadFromDiskAndUpdateValues() {
|
||||
do {
|
||||
rawValues = try loadFromDisk()
|
||||
try rawValues.forEach {
|
||||
try updateAndValidateValue($0.key, $0.value)
|
||||
}
|
||||
try handleNoFileOrOldFile(userFile)
|
||||
rawValues = try loadFromDisk(userFile)
|
||||
try rawValues
|
||||
.filter {
|
||||
$0.key != "version"
|
||||
}
|
||||
.forEach {
|
||||
try updateAndValidateFromString($0.key, $0.value)
|
||||
}
|
||||
} catch {
|
||||
debugPrint("Error loading preferences from JSON file on disk", error)
|
||||
debugPrint("Error loading preferences", error)
|
||||
NSApp.terminate(NSApplication.shared)
|
||||
}
|
||||
}
|
||||
|
||||
static func updateAndValidateValue(_ valueName: String, _ value: String) throws {
|
||||
static func updateAndValidateFromString(_ valueName: String, _ value: String) throws {
|
||||
switch valueName {
|
||||
case "maxScreenUsage":
|
||||
maxScreenUsage = try CGFloat(value).orThrow()
|
||||
case "windowPadding":
|
||||
windowPadding = try CGFloat(value).orThrow()
|
||||
case "cellPadding":
|
||||
cellPadding = try CGFloat(value).orThrow()
|
||||
case "cellBorderWidth":
|
||||
cellBorderWidth = try CGFloat(value).orThrow()
|
||||
case "maxThumbnailsPerRow":
|
||||
maxThumbnailsPerRow = try CGFloat(value).orThrow()
|
||||
case "thumbnailMaxWidth":
|
||||
thumbnailMaxWidth = try CGFloat(value).orThrow()
|
||||
case "thumbnailMaxHeight":
|
||||
thumbnailMaxHeight = try CGFloat(value).orThrow()
|
||||
case "iconSize":
|
||||
iconSize = try CGFloat(value).orThrow()
|
||||
case "fontHeight":
|
||||
fontHeight = try CGFloat(value).orThrow()
|
||||
case "interItemPadding":
|
||||
interItemPadding = try CGFloat(value).orThrow()
|
||||
font = NSFont.systemFont(ofSize: fontHeight!)
|
||||
case "tabKey":
|
||||
tabKey = try UInt16(value).orThrow()
|
||||
case "metaKey":
|
||||
metaKey = try UInt16(value).orThrow()
|
||||
case "metaModifierFlag":
|
||||
metaModifierFlag = NSEvent.ModifierFlags(rawValue: try UInt(value).orThrow())
|
||||
case "highlightColor":
|
||||
highlightColor = NSColor.white
|
||||
case "thumbnailQuality":
|
||||
thumbnailQuality = NSImageInterpolation(rawValue: try UInt(value).orThrow())!
|
||||
let (keyCode, modifierFlag) = try metaKeyMap[value].orThrow()
|
||||
metaKeyCode = keyCode
|
||||
metaModifierFlag = modifierFlag
|
||||
case "theme":
|
||||
let isMac = value == themeArray[0]
|
||||
cellBorderWidth = isMac ? 0 : 2
|
||||
cellCornerRadius = isMac ? 5 : 0
|
||||
highlightBorderColor = isMac ? .clear : .white
|
||||
highlightBackgroundColor = isMac ? NSColor(red: 0, green: 0, blue: 0, alpha: 0.15) : .clear
|
||||
windowCornerRadius = isMac ? 20 : 0
|
||||
case "windowDisplayDelay":
|
||||
windowDisplayDelay = DispatchTimeInterval.milliseconds(try Int(value).orThrow())
|
||||
case "font":
|
||||
font = NSFont.systemFont(ofSize: fontHeight)
|
||||
default:
|
||||
throw "Tried to update an unknown preference"
|
||||
throw "Tried to update an unknown preference: '\(valueName)' = '\(value)'"
|
||||
}
|
||||
rawValues[valueName] = value
|
||||
}
|
||||
@@ -101,23 +103,20 @@ class Preferences {
|
||||
try saveToDisk(rawValues, userFile)
|
||||
}
|
||||
|
||||
private static func fileLines(_ url: URL) throws -> Int {
|
||||
try String(contentsOf: url, encoding: .utf8).split(separator: "\n").count
|
||||
private static func preferencesVersion(_ url: URL) throws -> Int {
|
||||
try Int(loadFromDisk(url)["version"] ?? "0").orThrow()
|
||||
}
|
||||
|
||||
private static func loadFromDisk() throws -> [String: String] {
|
||||
try handleNoFileOrOldFile(userFile)
|
||||
return try JSONDecoder().decode([String: String].self, from: Data(contentsOf: userFile))
|
||||
private static func loadFromDisk(_ url: URL) throws -> [String: String] {
|
||||
try JSONDecoder().decode([String: String].self, from: Data(contentsOf: url))
|
||||
}
|
||||
|
||||
private static func handleNoFileOrOldFile(_ userFile: URL) throws {
|
||||
if !FileManager.default.fileExists(atPath: defaultsFile.path) {
|
||||
try saveDefaultsToDisk()
|
||||
}
|
||||
try saveDefaultsToDisk()
|
||||
if !FileManager.default.fileExists(atPath: userFile.path) {
|
||||
try FileManager.default.copyItem(at: defaultsFile, to: userFile)
|
||||
} else {
|
||||
if try fileLines(defaultsFile) > fileLines(userFile) {
|
||||
if try preferencesVersion(defaultsFile) > preferencesVersion(userFile) {
|
||||
// TODO: handle upgrades in a smarter way (e.g. merge files)
|
||||
try FileManager.default.removeItem(at: userFile)
|
||||
try FileManager.default.copyItem(at: defaultsFile, to: userFile)
|
||||
@@ -163,6 +162,9 @@ extension Optional {
|
||||
case .some(let value):
|
||||
return value
|
||||
case .none:
|
||||
Thread.callStackSymbols.forEach {
|
||||
print($0)
|
||||
}
|
||||
throw "Optional contained nil"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,18 +13,10 @@ class Screen {
|
||||
}
|
||||
|
||||
static func updateThumbnailMaxSize() -> Void {
|
||||
if Preferences.thumbnailMaxWidth == 0 && Preferences.thumbnailMaxHeight == 0 {
|
||||
do {
|
||||
let main = NSScreen.main!.frame
|
||||
try Preferences.updateAndValidateValue("thumbnailMaxWidth",
|
||||
String((NSScreen.main!.frame.size.width * Preferences.maxScreenUsage - Preferences.windowPadding * 2) / Preferences.maxThumbnailsPerRow - Preferences.interItemPadding).orThrow())
|
||||
try Preferences.updateAndValidateValue("thumbnailMaxHeight",
|
||||
String(Preferences.thumbnailMaxWidth * (main.height / main.width)).orThrow())
|
||||
try Preferences.saveRawToDisk()
|
||||
} catch {
|
||||
debugPrint("Error updating preferences based on screen size", error)
|
||||
NSApp.terminate(NSApplication.shared)
|
||||
}
|
||||
if Preferences.thumbnailMaxWidth == 200 && Preferences.thumbnailMaxHeight == 200 {
|
||||
let main = NSScreen.main!.frame
|
||||
Preferences.thumbnailMaxWidth = (NSScreen.main!.frame.size.width * Preferences.maxScreenUsage! - Preferences.windowPadding * 2) / Preferences.maxThumbnailsPerRow! - Preferences.interItemPadding
|
||||
Preferences.thumbnailMaxHeight = Preferences.thumbnailMaxWidth * (main.height / main.width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
self.showCenteredPanel(self.thumbnailsPanel!)
|
||||
}
|
||||
workItems.append(workItem)
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Preferences.windowDisplayDelay, execute: workItem)
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Preferences.windowDisplayDelay!, execute: workItem)
|
||||
} else {
|
||||
self.thumbnailsPanel!.highlightThumbnail(step)
|
||||
}
|
||||
|
||||
+14
-11
@@ -14,7 +14,9 @@ class Cell: NSCollectionViewItem {
|
||||
override func loadView() {
|
||||
let vStackView = NSStackView()
|
||||
vStackView.wantsLayer = true
|
||||
vStackView.layer!.borderWidth = Preferences.cellBorderWidth
|
||||
vStackView.layer!.backgroundColor = .clear
|
||||
vStackView.layer!.cornerRadius = Preferences.cellCornerRadius!
|
||||
vStackView.layer!.borderWidth = Preferences.cellBorderWidth!
|
||||
vStackView.layer!.borderColor = .clear
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.cellPadding, left: Preferences.cellPadding, bottom: Preferences.cellPadding, right: Preferences.cellPadding)
|
||||
vStackView.orientation = .vertical
|
||||
@@ -33,8 +35,8 @@ class Cell: NSCollectionViewItem {
|
||||
text.backgroundColor = .clear
|
||||
text.isSelectable = false
|
||||
text.isEditable = false
|
||||
text.font = Preferences.font
|
||||
text.textColor = Preferences.highlightColor
|
||||
text.font = Preferences.font!
|
||||
text.textColor = Preferences.fontColor
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = .darkGray
|
||||
shadow.shadowOffset = NSMakeSize(0, 0)
|
||||
@@ -43,11 +45,11 @@ class Cell: NSCollectionViewItem {
|
||||
text.enabledTextCheckingTypes = 0
|
||||
let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
|
||||
paragraphStyle.lineBreakMode = .byTruncatingTail
|
||||
paragraphStyle.maximumLineHeight = Preferences.fontHeight
|
||||
paragraphStyle.minimumLineHeight = Preferences.fontHeight
|
||||
paragraphStyle.maximumLineHeight = Preferences.fontHeight!
|
||||
paragraphStyle.minimumLineHeight = Preferences.fontHeight!
|
||||
paragraphStyle.allowsDefaultTighteningForTruncation = false
|
||||
text.defaultParagraphStyle = paragraphStyle
|
||||
text.heightAnchor.constraint(equalToConstant: Preferences.fontHeight).isActive = true
|
||||
text.heightAnchor.constraint(equalToConstant: Preferences.fontHeight!).isActive = true
|
||||
let shadow2 = NSShadow()
|
||||
shadow2.shadowColor = .gray
|
||||
shadow2.shadowOffset = NSMakeSize(0, 0)
|
||||
@@ -63,7 +65,8 @@ class Cell: NSCollectionViewItem {
|
||||
|
||||
override var isSelected: Bool {
|
||||
didSet {
|
||||
view.layer!.borderColor = isSelected ? Preferences.highlightColor.cgColor : .clear
|
||||
view.layer!.backgroundColor = isSelected ? Preferences.highlightBackgroundColor!.cgColor : .clear
|
||||
view.layer!.borderColor = isSelected ? Preferences.highlightBorderColor!.cgColor : .clear
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +77,12 @@ class Cell: NSCollectionViewItem {
|
||||
thumbnail.image!.size = NSSize(width: width, height: height)
|
||||
thumbnail.frame.size = NSSize(width: width, height: height)
|
||||
icon.image = element.icon
|
||||
icon.image!.size = NSSize(width: Preferences.iconSize, height: Preferences.iconSize)
|
||||
icon.frame.size = NSSize(width: Preferences.iconSize, height: Preferences.iconSize)
|
||||
icon.image!.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!)
|
||||
icon.frame.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!)
|
||||
text.string = element.cgTitle
|
||||
// workaround: setting string on NSTextView change the font (most likely a Cocoa bug)
|
||||
text.font = Preferences.font
|
||||
text.textContainer!.size.width = thumbnail.frame.size.width - Preferences.iconSize - Preferences.interItemPadding
|
||||
text.font = Preferences.font!
|
||||
text.textContainer!.size.width = thumbnail.frame.size.width - Preferences.iconSize! - Preferences.interItemPadding
|
||||
mouseDownCallback = fn
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,20 @@
|
||||
import Cocoa
|
||||
|
||||
class PreferencesPanel: NSPanel, NSTextViewDelegate {
|
||||
var maxScreenUsage: NSTextView?
|
||||
var windowPadding: NSTextView?
|
||||
var cellPadding: NSTextView?
|
||||
var cellBorderWidth: NSTextView?
|
||||
var maxThumbnailsPerRow: NSTextView?
|
||||
var thumbnailMaxWidth: NSTextView?
|
||||
var thumbnailMaxHeight: NSTextView?
|
||||
var iconSize: NSTextView?
|
||||
var fontHeight: NSTextView?
|
||||
var interItemPadding: NSTextView?
|
||||
var tabKey: NSTextView?
|
||||
var windowDisplayDelay: NSTextView?
|
||||
var metaKey: NSPopUpButton?
|
||||
var theme: NSPopUpButton?
|
||||
var inputsMap = [NSTextView: String]()
|
||||
|
||||
override init(contentRect: NSRect, styleMask style: StyleMask, backing backingStoreType: BackingStoreType, defer flag: Bool) {
|
||||
@@ -13,38 +27,24 @@ class PreferencesPanel: NSPanel, NSTextViewDelegate {
|
||||
contentView = gridView
|
||||
}
|
||||
|
||||
private func makeLabelsAndInputs() -> [[NSTextView]] {
|
||||
var rows = [[NSTextView]]()
|
||||
private func makeLabelsAndInputs() -> [[NSView]] {
|
||||
[
|
||||
("maxScreenUsage", "Maximum size of the main window, in percentage of screen size"),
|
||||
("windowPadding", "Padding in the main window"),
|
||||
("cellPadding", "Padding in each cell"),
|
||||
("cellBorderWidth", "Border width of each cell"),
|
||||
("maxThumbnailsPerRow", "Maximum number of thumbnails on each row"),
|
||||
("thumbnailMaxWidth", "Maximum width of each thumbnail"),
|
||||
("thumbnailMaxHeight", "Maximum height of each thumbnail"),
|
||||
("iconSize", "Width/height for each cell app icon"),
|
||||
("fontHeight", "Font height for each cell title"),
|
||||
("interItemPadding", "Padding between cells within the main window"),
|
||||
("tabKey", "Tab key (NSEvent.keyCode)"),
|
||||
("metaKey", "Meta key (NSEvent.keyCode)"),
|
||||
("metaModifierFlag", "Meta key (NSEvent.ModifierFlags)"),
|
||||
// ("highlightColor", "Color for the currently selected cell"),
|
||||
("thumbnailQuality", "NSImageInterpolation (e.g. none=1, low=2, medium=4, high=3)"),
|
||||
("windowDisplayDelay", "Delay in ms before the window is displayed after pressing the shortcut"),
|
||||
].forEach {
|
||||
let p = makePreference($1, Preferences.rawValues[$0]!)
|
||||
rows.append(p)
|
||||
inputsMap[p[1]] = $0
|
||||
}
|
||||
return rows
|
||||
makeLabelWithDropdown(\PreferencesPanel.theme, "Main window theme", "theme", Preferences.themeArray),
|
||||
makeLabelWithDropdown(\PreferencesPanel.metaKey, "Meta key to activate the app", "metaKey", Preferences.metaKeyArray),
|
||||
makePreference(\PreferencesPanel.tabKey, "Tab key (NSEvent.keyCode)", "tabKey"),
|
||||
makePreference(\PreferencesPanel.maxScreenUsage, "Max window size (screen %)", "maxScreenUsage"),
|
||||
makePreference(\PreferencesPanel.maxThumbnailsPerRow, "Max thumbnails per row", "maxThumbnailsPerRow"),
|
||||
makePreference(\PreferencesPanel.iconSize, "Apps icon size (px)", "iconSize"),
|
||||
makePreference(\PreferencesPanel.fontHeight, "Font size (px)", "fontHeight"),
|
||||
makePreference(\PreferencesPanel.windowDisplayDelay, "Window apparition delay (ms)", "windowDisplayDelay"),
|
||||
]
|
||||
}
|
||||
|
||||
private func makeGridView(_ rows: [[NSTextView]]) -> NSGridView {
|
||||
private func makeGridView(_ rows: [[NSView]]) -> NSGridView {
|
||||
let gridView = NSGridView(views: rows)
|
||||
gridView.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||
gridView.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||
gridView.widthAnchor.constraint(greaterThanOrEqualToConstant: 580).isActive = true
|
||||
gridView.widthAnchor.constraint(greaterThanOrEqualToConstant: 360).isActive = true
|
||||
return gridView
|
||||
}
|
||||
|
||||
@@ -56,18 +56,45 @@ class PreferencesPanel: NSPanel, NSTextViewDelegate {
|
||||
gridView.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: gridView.numberOfRows - 1, length: 1))
|
||||
}
|
||||
|
||||
private func makePreference(_ labelText: String, _ initialValue: String) -> [NSTextView] {
|
||||
private func makePreference(_ keyPath: ReferenceWritableKeyPath<PreferencesPanel, NSTextView?>, _ labelText: String, _ rawName: String) -> [NSTextView] {
|
||||
let label = makeLabel(labelText)
|
||||
label.alignment = .right
|
||||
|
||||
let input = NSTextView()
|
||||
input.delegate = self
|
||||
input.font = Preferences.font
|
||||
input.string = initialValue
|
||||
input.widthAnchor.constraint(equalToConstant: 65).isActive = true
|
||||
input.string = Preferences.rawValues[rawName]!
|
||||
input.widthAnchor.constraint(equalToConstant: 32).isActive = true
|
||||
self[keyPath: keyPath] = input
|
||||
inputsMap[input] = rawName
|
||||
return [label, input]
|
||||
}
|
||||
|
||||
private func makeLabelWithDropdown(_ keyPath: ReferenceWritableKeyPath<PreferencesPanel, NSPopUpButton?>, _ labelText: String, _ rawName: String, _ values: [String]) -> [NSView] {
|
||||
let label = makeLabel(labelText)
|
||||
label.alignment = .right
|
||||
let input = NSPopUpButton()
|
||||
input.addItems(withTitles: values)
|
||||
input.selectItem(withTitle: Preferences.rawValues[rawName]!)
|
||||
input.action = #selector(dropdownDidChange)
|
||||
input.target = self
|
||||
self[keyPath: keyPath] = input
|
||||
return [label, input]
|
||||
}
|
||||
|
||||
@objc func dropdownDidChange(sender: AnyObject) throws {
|
||||
if let popUpButton = sender as? NSPopUpButton {
|
||||
switch popUpButton {
|
||||
case theme:
|
||||
try! Preferences.updateAndValidateFromString("theme", popUpButton.titleOfSelectedItem!)
|
||||
case metaKey:
|
||||
try! Preferences.updateAndValidateFromString("metaKey", popUpButton.titleOfSelectedItem!)
|
||||
default:
|
||||
throw "Tried to update an unknown popUpButton: '\(popUpButton)' = '\(popUpButton.titleOfSelectedItem!)'"
|
||||
}
|
||||
try! Preferences.saveRawToDisk()
|
||||
}
|
||||
}
|
||||
|
||||
private func makeLabel(_ text: String) -> NSTextView {
|
||||
let label = NSTextView()
|
||||
label.drawsBackground = true
|
||||
@@ -77,7 +104,7 @@ class PreferencesPanel: NSPanel, NSTextViewDelegate {
|
||||
label.font = Preferences.font
|
||||
label.string = text
|
||||
label.enabledTextCheckingTypes = 0
|
||||
label.heightAnchor.constraint(greaterThanOrEqualToConstant: Preferences.fontHeight + Preferences.interItemPadding).isActive = true
|
||||
label.heightAnchor.constraint(greaterThanOrEqualToConstant: Preferences.fontHeight! + Preferences.interItemPadding).isActive = true
|
||||
return label
|
||||
}
|
||||
|
||||
@@ -85,9 +112,10 @@ class PreferencesPanel: NSPanel, NSTextViewDelegate {
|
||||
if let textView = notification.object as? NSTextView {
|
||||
let key = inputsMap[textView]!
|
||||
do {
|
||||
try Preferences.updateAndValidateValue(key, textView.string)
|
||||
try Preferences.updateAndValidateFromString(key, textView.string)
|
||||
try Preferences.saveRawToDisk()
|
||||
} catch {
|
||||
debugPrint(key, error)
|
||||
textView.string = Preferences.rawValues[key]!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,20 +13,25 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
convenience init(_ application: Application) {
|
||||
self.init()
|
||||
self.application = application
|
||||
styleMask = [.borderless]
|
||||
isFloatingPanel = true
|
||||
animationBehavior = NSWindow.AnimationBehavior.none
|
||||
backgroundColor = .clear
|
||||
hidesOnDeactivate = false
|
||||
hasShadow = false
|
||||
titleVisibility = .hidden
|
||||
styleMask.remove(.titled)
|
||||
backgroundColor = .clear
|
||||
makeThumbnailsPanelBackgroundView()
|
||||
contentView = backgroundView!
|
||||
contentView!.addSubview(backgroundView!)
|
||||
|
||||
}
|
||||
|
||||
private func makeThumbnailsPanelBackgroundView() {
|
||||
backgroundView = NSVisualEffectView()
|
||||
backgroundView!.blendingMode = .behindWindow
|
||||
backgroundView!.material = .dark
|
||||
backgroundView!.translatesAutoresizingMaskIntoConstraints = false
|
||||
backgroundView!.material = Preferences.windowMaterial
|
||||
backgroundView!.state = .active
|
||||
backgroundView!.wantsLayer = true
|
||||
backgroundView!.layer!.cornerRadius = Preferences.windowCornerRadius!
|
||||
makeCollectionView()
|
||||
backgroundView!.addSubview(collectionView_!)
|
||||
}
|
||||
@@ -66,7 +71,7 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
// debugPrint("collectionView: item size")
|
||||
if indexPath.item < application!.openWindows.count {
|
||||
let (width, height) = computeDownscaledSize(application!.openWindows[indexPath.item].thumbnail)
|
||||
return NSSize(width: CGFloat(width) + Preferences.cellPadding * 2, height: CGFloat(height) + max(Preferences.fontHeight, Preferences.iconSize) + Preferences.interItemPadding + Preferences.cellPadding * 2)
|
||||
return NSSize(width: CGFloat(width) + Preferences.cellPadding * 2, height: CGFloat(height) + max(Preferences.fontHeight!, Preferences.iconSize!) + Preferences.interItemPadding + Preferences.cellPadding * 2)
|
||||
}
|
||||
return .zero
|
||||
}
|
||||
@@ -77,7 +82,7 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
}
|
||||
|
||||
func computeThumbnails() {
|
||||
let maxSize = NSSize(width: NSScreen.main!.frame.width * Preferences.maxScreenUsage, height: NSScreen.main!.frame.height * Preferences.maxScreenUsage)
|
||||
let maxSize = NSSize(width: NSScreen.main!.frame.width * Preferences.maxScreenUsage!, height: NSScreen.main!.frame.height * Preferences.maxScreenUsage!)
|
||||
collectionView_!.setFrameSize(maxSize)
|
||||
collectionView_!.collectionViewLayout!.invalidateLayout()
|
||||
collectionView_!.reloadData()
|
||||
|
||||
Reference in new issue
Block a user