feat: nicer layout for about preferences
This commit is contained in:
1 parent
6bb73dce92
commit
03a5f77b99
7 files changed
+68
-30
No files matched your search
@@ -28,6 +28,7 @@
|
||||
D04BA9119E2329DB5A35B3C7 /* ThumbnailsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE5BBE182DD5DDFE2E3E /* ThumbnailsPanel.swift */; };
|
||||
D04BA960DDD1D32A3019C835 /* CollectionViewCenterFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA3202A2C22C347E849B3 /* CollectionViewCenterFlowLayout.swift */; };
|
||||
D04BA9CCE02D30C8164A552A /* SystemPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA2D2AD6B1CCA3F3A4DD7 /* SystemPermissions.swift */; };
|
||||
D04BAA3D066D2B428D4DBAA6 /* BoldLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA43552CB1EABDC8ECD9E /* BoldLabel.swift */; };
|
||||
D04BAAD43731608067734ED3 /* DispatchQueues.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA56E285C3FCDA52ED262 /* DispatchQueues.swift */; };
|
||||
D04BAD4DE538FDF7E7532EE2 /* Labels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD32E130E4A061DC8332 /* Labels.swift */; };
|
||||
D04BAE2E8E9B9898A4DF9B3B /* FontIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAED53465957807CBF8B2 /* FontIcon.swift */; };
|
||||
@@ -57,6 +58,7 @@
|
||||
D04BA3F15EAE8D8C39B6F2CF /* Screen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = "<group>"; };
|
||||
D04BA40A4291E4F310527DBF /* AXUIElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AXUIElement.swift; sourceTree = "<group>"; };
|
||||
D04BA4336B6004A0A99849AD /* package.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = package.json; sourceTree = "<group>"; };
|
||||
D04BA43552CB1EABDC8ECD9E /* BoldLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoldLabel.swift; sourceTree = "<group>"; };
|
||||
D04BA459034C1885CA43A807 /* LICENCE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENCE.md; sourceTree = "<group>"; };
|
||||
D04BA4B5292629AA6B560216 /* package_release.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = package_release.sh; sourceTree = "<group>"; };
|
||||
D04BA4F23325560BC0BCDDB7 /* 7 windows - 2 lines - tall window.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "7 windows - 2 lines - tall window.jpg"; sourceTree = "<group>"; };
|
||||
@@ -260,6 +262,7 @@
|
||||
F0298708E2B13DBD4738AE76 /* HyperlinkLabel.swift */,
|
||||
D04BAED53465957807CBF8B2 /* FontIcon.swift */,
|
||||
D04BAE70A24C83D571C77B1A /* TabViewController.swift */,
|
||||
D04BA43552CB1EABDC8ECD9E /* BoldLabel.swift */,
|
||||
);
|
||||
path = ui;
|
||||
sourceTree = "<group>";
|
||||
@@ -392,6 +395,7 @@
|
||||
D04BA2378832FD7E5DE3BC23 /* Applications.swift in Sources */,
|
||||
D04BAAD43731608067734ED3 /* DispatchQueues.swift in Sources */,
|
||||
D04BAE53AE67492CF654B4AE /* TabViewController.swift in Sources */,
|
||||
D04BAA3D066D2B428D4DBAA6 /* BoldLabel.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -92,4 +92,18 @@ extension NSView {
|
||||
widthAnchor.constraint(equalToConstant: fittingSize.width).isActive = true
|
||||
heightAnchor.constraint(equalToConstant: fittingSize.height).isActive = true
|
||||
}
|
||||
|
||||
// constrain size to provided width and height
|
||||
func fit(_ width: CGFloat, _ height: CGFloat) {
|
||||
widthAnchor.constraint(equalToConstant: width).isActive = true
|
||||
heightAnchor.constraint(equalToConstant: height).isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
extension NSGridView {
|
||||
func setRowsHeight(_ height: CGFloat) {
|
||||
for i in 0..<numberOfRows {
|
||||
row(at: i).height = height
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ let cgsMainConnectionId = CGSMainConnectionID()
|
||||
|
||||
class App: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
static let name = "AltTab"
|
||||
static let version = "#VERSION#"
|
||||
var statusItem: NSStatusItem?
|
||||
var thumbnailsPanel: ThumbnailsPanel?
|
||||
var preferencesPanel: PreferencesWindow?
|
||||
@@ -27,9 +28,10 @@ class App: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
Preferences.loadFromDiskAndUpdateValues()
|
||||
statusItem = StatusItem.make(self)
|
||||
initPreferencesDependentComponents()
|
||||
Spaces.initialDiscovery()
|
||||
Applications.initialDiscovery()
|
||||
Keyboard.listenToGlobalEvents(self)
|
||||
// Spaces.initialDiscovery()
|
||||
// Applications.initialDiscovery()
|
||||
// Keyboard.listenToGlobalEvents(self)
|
||||
showPreferencesPanel()
|
||||
}
|
||||
|
||||
// we put application code here which should be executed on init() and Preferences change
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import Cocoa
|
||||
|
||||
class BoldLabel: NSTextField {
|
||||
convenience init(_ string: String) {
|
||||
self.init(labelWithString: string)
|
||||
allowsEditingTextAttributes = true
|
||||
attributedStringValue = NSAttributedString(string: string, attributes: [
|
||||
NSAttributedString.Key.font: NSFont.boldSystemFont(ofSize: NSFont.systemFontSize),
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
import Cocoa
|
||||
|
||||
class HyperlinkLabel: NSTextField {
|
||||
|
||||
public convenience init(labelWithUrl stringValue: String, nsUrl: NSURL) {
|
||||
self.init(labelWithString: stringValue)
|
||||
convenience init(_ string: String, _ url: NSURL) {
|
||||
self.init(labelWithString: string)
|
||||
isSelectable = true
|
||||
allowsEditingTextAttributes = true
|
||||
let linkTextAttributes: [NSAttributedString.Key: Any] = [
|
||||
NSAttributedString.Key.link: nsUrl as Any,
|
||||
attributedStringValue = NSAttributedString(string: string, attributes: [
|
||||
NSAttributedString.Key.link: url as Any,
|
||||
NSAttributedString.Key.font: NSFont.labelFont(ofSize: NSFont.systemFontSize),
|
||||
]
|
||||
|
||||
attributedStringValue = NSAttributedString(string: stringValue, attributes: linkTextAttributes)
|
||||
])
|
||||
}
|
||||
|
||||
// the whole point for this sub-class: always display a pointing-hand cursor (not only when the TextField is focused)
|
||||
override func resetCursorRects() {
|
||||
addCursorRect(bounds, cursor: NSCursor.pointingHand)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
let tabViewController = TabViewController()
|
||||
let padding = CGFloat(20)
|
||||
let interPadding = CGFloat(10)
|
||||
let rowHeight = CGFloat(20)
|
||||
var windowCloseRequested = false
|
||||
|
||||
override init(contentRect: NSRect, styleMask style: StyleMask, backing backingStoreType: BackingStoreType, defer flag: Bool) {
|
||||
@@ -73,14 +74,18 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
return whitelistedKeycodes.contains(int)
|
||||
}
|
||||
|
||||
return makeGridLayout([
|
||||
let view = makeGridLayout([
|
||||
makeLabelWithDropdown("Alt key", "metaKey", Preferences.metaKeyMacro.labels),
|
||||
makeLabelWithInput("Tab key", "tabKeyCode", 33, "KeyCodes Reference", "https://eastmanreference.com/complete-list-of-applescript-key-codes", tabKeyCodeValidator),
|
||||
])
|
||||
view.column(at: 0).xPlacement = .trailing
|
||||
view.rowAlignment = .lastBaseline
|
||||
view.setRowsHeight(rowHeight)
|
||||
return view
|
||||
}
|
||||
|
||||
private func makeAppearanceView() -> NSGridView {
|
||||
return makeGridLayout([
|
||||
let view = makeGridLayout([
|
||||
makeLabelWithDropdown("Theme", "theme", Preferences.themeMacro.labels),
|
||||
makeLabelWithSlider("Max size on screen", "maxScreenUsage", 10, 100, 10, true, "%"),
|
||||
makeLabelWithSlider("Min windows per row", "minCellsPerRow", 1, 20, 20, true),
|
||||
@@ -92,14 +97,27 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
makeLabelWithSlider("Apparition delay", "windowDisplayDelay", 0, 2000, 11, false, "ms"),
|
||||
makeLabelWithCheckbox("Hide space number labels", "hideSpaceNumberLabels"),
|
||||
])
|
||||
view.column(at: 0).xPlacement = .trailing
|
||||
view.rowAlignment = .lastBaseline
|
||||
view.setRowsHeight(rowHeight)
|
||||
return view
|
||||
}
|
||||
|
||||
private func makeAboutView() -> NSGridView {
|
||||
return makeGridLayout([
|
||||
[NSTextField(wrappingLabelWithString: "\(App.name) #VERSION#"), ],
|
||||
[HyperlinkLabel(labelWithUrl: "Source code repository", nsUrl: NSURL(string: "https://github.com/lwouis/alt-tab-macos")!)],
|
||||
[HyperlinkLabel(labelWithUrl: "Latest releases", nsUrl: NSURL(string: "https://github.com/lwouis/alt-tab-macos/releases")!)],
|
||||
let appIcon = NSImageView(image: App.shared.applicationIconImage)
|
||||
appIcon.fit(64, 64)
|
||||
let appText = NSStackView(views: [BoldLabel(App.name), NSTextField(wrappingLabelWithString: "Version \(App.version)")])
|
||||
appText.orientation = .vertical
|
||||
appText.alignment = .left
|
||||
appText.spacing = interPadding / 2
|
||||
let appInfo = NSStackView(views: [appIcon, appText])
|
||||
appInfo.spacing = interPadding
|
||||
let view = makeGridLayout([
|
||||
[appInfo],
|
||||
[HyperlinkLabel("Source code repository", NSURL(string: "https://github.com/lwouis/alt-tab-macos")!)],
|
||||
[HyperlinkLabel("Latest releases", NSURL(string: "https://github.com/lwouis/alt-tab-macos/releases")!)],
|
||||
])
|
||||
return view
|
||||
}
|
||||
|
||||
private func makeGridLayout(_ controls: [[NSView]]) -> NSGridView {
|
||||
@@ -107,18 +125,11 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
gridView.yPlacement = .fill
|
||||
gridView.columnSpacing = interPadding
|
||||
gridView.rowSpacing = interPadding
|
||||
if controls.first!.count > 1 {
|
||||
gridView.column(at: 0).xPlacement = .trailing
|
||||
}
|
||||
gridView.column(at: 0).leadingPadding = padding
|
||||
gridView.column(at: gridView.numberOfColumns - 1).trailingPadding = padding
|
||||
gridView.row(at: 0).topPadding = padding
|
||||
gridView.row(at: gridView.numberOfRows - 1).bottomPadding = padding
|
||||
gridView.fit()
|
||||
gridView.rowAlignment = .lastBaseline
|
||||
for i in 0..<gridView.numberOfRows {
|
||||
gridView.row(at: i).height = 20
|
||||
}
|
||||
return gridView
|
||||
}
|
||||
|
||||
@@ -127,8 +138,7 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
input.validationHandler = validator
|
||||
input.delegate = input
|
||||
input.visualizeValidationState()
|
||||
input.widthAnchor.constraint(equalToConstant: width).isActive = true
|
||||
input.heightAnchor.constraint(equalToConstant: input.fittingSize.height).isActive = true
|
||||
input.fit(width, input.fittingSize.height)
|
||||
let views = makeLabelWithProvidedControl(labelText, rawName, input)
|
||||
return [views[0], NSStackView(views: [views[1], makeSuffix(rawName, suffixText!, suffixUrl)])]
|
||||
}
|
||||
@@ -181,7 +191,7 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
if url == nil {
|
||||
suffix = NSTextField(labelWithString: text)
|
||||
} else {
|
||||
suffix = HyperlinkLabel(labelWithUrl: text, nsUrl: NSURL(string: url!)!)
|
||||
suffix = HyperlinkLabel(text, NSURL(string: url!)!)
|
||||
}
|
||||
suffix.textColor = .gray
|
||||
suffix.identifier = NSUserInterfaceItemIdentifier(controlName + ControlIdentifierDiscriminator.SUFFIX.rawValue)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set -exu
|
||||
|
||||
version="$(cat VERSION.txt)"
|
||||
# set the version for the app menubar menu text
|
||||
sed -i '' -e "s/#VERSION#/$version/" alt-tab-macos/ui/PreferencesWindow.swift
|
||||
# set the version displayed in the app UI
|
||||
sed -i '' -e "s/#VERSION#/$version/" alt-tab-macos/ui/App.swift
|
||||
# set the version in the app meta-data for the AppStore and app "Get Info" panel
|
||||
sed -i '' -e "s/#VERSION#/$version/" alt-tab-macos/Info.plist
|
||||
Reference in new issue
Block a user