feat: preferences can be changed through JSON file
* removed unused Resources from the bundle * thumbnails quality is now a preference
This commit is contained in:
1 parent
f56fd59042
commit
64cb6f067d
12 files changed
+158
-174
No files matched your search
@@ -1,5 +1,6 @@
|
||||
/.idea/
|
||||
xcuserdata/
|
||||
xcshareddata/
|
||||
/node_modules/
|
||||
/build/
|
||||
|
||||
|
||||
@@ -7,41 +7,15 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D04BA0B1D77CA1466BFC13BC /* 3 windows - 1 line - tall window.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BAD82F652C4ED5D8BF7AE /* 3 windows - 1 line - tall window.jpg */; };
|
||||
D04BA183207E20AC28BF4F20 /* dark-background.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA8DDB96B0A60C3394351 /* dark-background.png */; };
|
||||
D04BA20D4A240843293B3B52 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA56355579F78776E6D51 /* Cell.swift */; };
|
||||
D04BA21CD515ACDBCC4437E6 /* commitlint.config.js in Sources */ = {isa = PBXBuildFile; fileRef = D04BAC02D60EF22D9CC7D969 /* commitlint.config.js */; };
|
||||
D04BA21F728100990BA0D007 /* 6 windows - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA2C7B51F68651B3C60E2 /* 6 windows - 1 line.jpg */; };
|
||||
D04BA278D9EFA568C8D18A4C /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD1BED44EAEB77FED8A4 /* WindowManager.swift */; };
|
||||
D04BA2B84D062AA0EB970CFA /* CHANGELOG.md in Sources */ = {isa = PBXBuildFile; fileRef = D04BAFA277EAE3BDDDB61110 /* CHANGELOG.md */; };
|
||||
D04BA3261C7DA5F48310E654 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA90C6C36DB1D65BC2B66 /* Application.swift */; };
|
||||
D04BA35E037C9E1C3B26F296 /* 5 windows - 2 lines.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BAF076A30A1BAFEDBEA66 /* 5 windows - 2 lines.jpg */; };
|
||||
D04BA3999A3D6A308EA41039 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = D04BAD40CE2D3A8AAC3819D0 /* .gitignore */; };
|
||||
D04BA424348403E28A5EEB40 /* package-lock.json in Resources */ = {isa = PBXBuildFile; fileRef = D04BA92541D46EA4F6943A72 /* package-lock.json */; };
|
||||
D04BA4D8D74841AEC2601C80 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D04BA262E9A663B3A85A2A95 /* Assets.xcassets */; };
|
||||
D04BA5474180F00F583177B9 /* package.json in Resources */ = {isa = PBXBuildFile; fileRef = D04BA4336B6004A0A99849AD /* package.json */; };
|
||||
D04BA57A871B7269BEBAFF84 /* Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA35456DA0DDA74F9687E /* Keyboard.swift */; };
|
||||
D04BA5DD787816BB82C4AEFF /* .travis.yml in Resources */ = {isa = PBXBuildFile; fileRef = D04BAD7D8F3CC2C36C8769C6 /* .travis.yml */; };
|
||||
D04BA6C8D3667C49F97C06AD /* 14 windows - 3 lines.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BAB6652494D7575057E86 /* 14 windows - 3 lines.jpg */; };
|
||||
D04BA6D15018C5164724C0D2 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = D04BA0E1C5DBC07108AC2F54 /* README.md */; };
|
||||
D04BA7076AC73E719B733352 /* 7 windows - 2 lines - extra wide window.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BAE1243C9B4BE3ED1B524 /* 7 windows - 2 lines - extra wide window.jpg */; };
|
||||
D04BA70FF7262BF5F9E6E13B /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BADCB1C0F50340A6CAFC2 /* Preferences.swift */; };
|
||||
D04BA86F2E687F573F920D93 /* HighInterpolationImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE70D6AFD2E52A71701D /* HighInterpolationImageView.swift */; };
|
||||
D04BA960DDD1D32A3019C835 /* CollectionViewCenterFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA3202A2C22C347E849B3 /* CollectionViewCenterFlowLayout.swift */; };
|
||||
D04BA9A1B237364C419C3A3F /* 5 windows - 2 lines.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5E4A1745A481CEC1EBA /* 5 windows - 2 lines.png */; };
|
||||
D04BAA6317F099FDFD8CF560 /* release.config.js in Sources */ = {isa = PBXBuildFile; fileRef = D04BA1D80F4EEF2A91BAD29C /* release.config.js */; };
|
||||
D04BAA816B0EE923C6C211DD /* 2 windows - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA9EF65B2E7AF9E3ADCA3 /* 2 windows - 1 line.jpg */; };
|
||||
D04BAAC63A3C077B1DB155B2 /* 5 windows - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5ABFA5457A86536E2E4 /* 5 windows - 1 line.jpg */; };
|
||||
D04BAB25494E5FF86D4C2437 /* 7 windows - 2 lines - wide window.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA0CE87BE264C52987ED1 /* 7 windows - 2 lines - wide window.jpg */; };
|
||||
D04BABF815E9780EAF941E88 /* 3 windows - 1 line.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA27584274BC8C2D9809F /* 3 windows - 1 line.png */; };
|
||||
D04BACB58F00CAC62A46E662 /* 6 windows - 2 lines.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5E9CB56E27CC907F07D /* 6 windows - 2 lines.png */; };
|
||||
D04BACF6FFC99DDD990E0694 /* 3 windows - 1 line - wide window.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA51D43775E57CE91154A /* 3 windows - 1 line - wide window.jpg */; };
|
||||
D04BAD4AF98BD62155749E88 /* 1 window - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA1FC9022590D7AA02486 /* 1 window - 1 line.jpg */; };
|
||||
D04BAD9763C9B59FB46B4F9B /* 4 windows - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA0F5EB832B8E142B654B /* 4 windows - 1 line.jpg */; };
|
||||
D04BADD21FFEE61E926E897F /* too many windows - 4 lines - paginated.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA107C8B8FE7FF8536606 /* too many windows - 4 lines - paginated.jpg */; };
|
||||
D04BAE5CC40654B1F96E8DE9 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D04BA7B6AAB0812631BBC7A2 /* Info.plist */; };
|
||||
D04BAE1A64F5572B19F9E2B1 /* preferences.json in Resources */ = {isa = PBXBuildFile; fileRef = D04BA8924E1644C932B8CBAA /* preferences.json */; };
|
||||
D04BAEF78503D7A2CEFB9E9E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAA44C837F3A67403B9DB /* main.swift */; };
|
||||
D04BAFACEE2C33E66B93664A /* 3 windows - 1 line.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA32F25860B686DFE818A /* 3 windows - 1 line.jpg */; };
|
||||
D04BAFE95F19AD93955904DE /* 7 windows - 2 lines - tall window.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D04BA4F23325560BC0BCDDB7 /* 7 windows - 2 lines - tall window.jpg */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -51,7 +25,6 @@
|
||||
D04BA107C8B8FE7FF8536606 /* too many windows - 4 lines - paginated.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "too many windows - 4 lines - paginated.jpg"; sourceTree = "<group>"; };
|
||||
D04BA1D80F4EEF2A91BAD29C /* release.config.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = release.config.js; sourceTree = "<group>"; };
|
||||
D04BA1FC9022590D7AA02486 /* 1 window - 1 line.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "1 window - 1 line.jpg"; sourceTree = "<group>"; };
|
||||
D04BA262E9A663B3A85A2A95 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
D04BA27584274BC8C2D9809F /* 3 windows - 1 line.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "3 windows - 1 line.png"; sourceTree = "<group>"; };
|
||||
D04BA2C7B51F68651B3C60E2 /* 6 windows - 1 line.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "6 windows - 1 line.jpg"; sourceTree = "<group>"; };
|
||||
D04BA3202A2C22C347E849B3 /* CollectionViewCenterFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCenterFlowLayout.swift; sourceTree = "<group>"; };
|
||||
@@ -66,6 +39,7 @@
|
||||
D04BA5E9CB56E27CC907F07D /* 6 windows - 2 lines.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "6 windows - 2 lines.png"; sourceTree = "<group>"; };
|
||||
D04BA7B6AAB0812631BBC7A2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.info; path = Info.plist; sourceTree = "<group>"; };
|
||||
D04BA82F792DF53958D92572 /* alt-tab-macos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "alt-tab-macos.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D04BA8924E1644C932B8CBAA /* preferences.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = preferences.json; sourceTree = "<group>"; };
|
||||
D04BA8DDB96B0A60C3394351 /* dark-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dark-background.png"; sourceTree = "<group>"; };
|
||||
D04BA90C6C36DB1D65BC2B66 /* Application.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||
D04BA92541D46EA4F6943A72 /* package-lock.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "package-lock.json"; sourceTree = "<group>"; };
|
||||
@@ -78,6 +52,7 @@
|
||||
D04BAD40CE2D3A8AAC3819D0 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = file.gitignore; path = .gitignore; sourceTree = "<group>"; };
|
||||
D04BAD7D8F3CC2C36C8769C6 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = file.yml; path = .travis.yml; sourceTree = "<group>"; };
|
||||
D04BAD82F652C4ED5D8BF7AE /* 3 windows - 1 line - tall window.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "3 windows - 1 line - tall window.jpg"; sourceTree = "<group>"; };
|
||||
D04BADCB1C0F50340A6CAFC2 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||
D04BAE1243C9B4BE3ED1B524 /* 7 windows - 2 lines - extra wide window.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "7 windows - 2 lines - extra wide window.jpg"; sourceTree = "<group>"; };
|
||||
D04BAE70D6AFD2E52A71701D /* HighInterpolationImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighInterpolationImageView.swift; sourceTree = "<group>"; };
|
||||
D04BAF076A30A1BAFEDBEA66 /* 5 windows - 2 lines.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "5 windows - 2 lines.jpg"; sourceTree = "<group>"; };
|
||||
@@ -112,6 +87,14 @@
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D04BA18D1EDDD56CA89604B6 /* resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D04BA8924E1644C932B8CBAA /* preferences.json */,
|
||||
);
|
||||
path = resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D04BA1A461BBB5A9BE15E015 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -157,6 +140,7 @@
|
||||
children = (
|
||||
D04BA35456DA0DDA74F9687E /* Keyboard.swift */,
|
||||
D04BAD1BED44EAEB77FED8A4 /* WindowManager.swift */,
|
||||
D04BADCB1C0F50340A6CAFC2 /* Preferences.swift */,
|
||||
);
|
||||
path = logic;
|
||||
sourceTree = "<group>";
|
||||
@@ -192,12 +176,12 @@
|
||||
D04BAD48B702C4B1DC543557 /* alt-tab-macos */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D04BA262E9A663B3A85A2A95 /* Assets.xcassets */,
|
||||
D04BAD1C9F215BCCD3B620AC /* alt_tab_macos.entitlements */,
|
||||
D04BAAA28315301A906DD201 /* ui */,
|
||||
D04BA7B6AAB0812631BBC7A2 /* Info.plist */,
|
||||
D04BAA44C837F3A67403B9DB /* main.swift */,
|
||||
D04BAA1C553891551B903DA7 /* logic */,
|
||||
D04BA18D1EDDD56CA89604B6 /* resources */,
|
||||
);
|
||||
path = "alt-tab-macos";
|
||||
sourceTree = "<group>";
|
||||
@@ -235,6 +219,7 @@
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = D04BA1463D2A17038222BB84;
|
||||
@@ -252,30 +237,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D04BA4D8D74841AEC2601C80 /* Assets.xcassets in Resources */,
|
||||
D04BAE5CC40654B1F96E8DE9 /* Info.plist in Resources */,
|
||||
D04BA3999A3D6A308EA41039 /* .gitignore in Resources */,
|
||||
D04BAFACEE2C33E66B93664A /* 3 windows - 1 line.jpg in Resources */,
|
||||
D04BA6C8D3667C49F97C06AD /* 14 windows - 3 lines.jpg in Resources */,
|
||||
D04BA0B1D77CA1466BFC13BC /* 3 windows - 1 line - tall window.jpg in Resources */,
|
||||
D04BAFE95F19AD93955904DE /* 7 windows - 2 lines - tall window.jpg in Resources */,
|
||||
D04BA21F728100990BA0D007 /* 6 windows - 1 line.jpg in Resources */,
|
||||
D04BADD21FFEE61E926E897F /* too many windows - 4 lines - paginated.jpg in Resources */,
|
||||
D04BAAC63A3C077B1DB155B2 /* 5 windows - 1 line.jpg in Resources */,
|
||||
D04BAD9763C9B59FB46B4F9B /* 4 windows - 1 line.jpg in Resources */,
|
||||
D04BAD4AF98BD62155749E88 /* 1 window - 1 line.jpg in Resources */,
|
||||
D04BAA816B0EE923C6C211DD /* 2 windows - 1 line.jpg in Resources */,
|
||||
D04BACF6FFC99DDD990E0694 /* 3 windows - 1 line - wide window.jpg in Resources */,
|
||||
D04BA35E037C9E1C3B26F296 /* 5 windows - 2 lines.jpg in Resources */,
|
||||
D04BAB25494E5FF86D4C2437 /* 7 windows - 2 lines - wide window.jpg in Resources */,
|
||||
D04BA7076AC73E719B733352 /* 7 windows - 2 lines - extra wide window.jpg in Resources */,
|
||||
D04BA183207E20AC28BF4F20 /* dark-background.png in Resources */,
|
||||
D04BACB58F00CAC62A46E662 /* 6 windows - 2 lines.png in Resources */,
|
||||
D04BA9A1B237364C419C3A3F /* 5 windows - 2 lines.png in Resources */,
|
||||
D04BABF815E9780EAF941E88 /* 3 windows - 1 line.png in Resources */,
|
||||
D04BA5DD787816BB82C4AEFF /* .travis.yml in Resources */,
|
||||
D04BA5474180F00F583177B9 /* package.json in Resources */,
|
||||
D04BA424348403E28A5EEB40 /* package-lock.json in Resources */,
|
||||
D04BAE1A64F5572B19F9E2B1 /* preferences.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -293,10 +255,7 @@
|
||||
D04BA57A871B7269BEBAFF84 /* Keyboard.swift in Sources */,
|
||||
D04BA278D9EFA568C8D18A4C /* WindowManager.swift in Sources */,
|
||||
D04BA3261C7DA5F48310E654 /* Application.swift in Sources */,
|
||||
D04BA6D15018C5164724C0D2 /* README.md in Sources */,
|
||||
D04BAA6317F099FDFD8CF560 /* release.config.js in Sources */,
|
||||
D04BA21CD515ACDBCC4437E6 /* commitlint.config.js in Sources */,
|
||||
D04BA2B84D062AA0EB970CFA /* CHANGELOG.md in Sources */,
|
||||
D04BA70FF7262BF5F9E6E13B /* Preferences.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -441,8 +400,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -456,6 +414,7 @@
|
||||
D04BA49BCED00029C5289244 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D04BA83C9495F252D87CDF0F /* Build configuration list for PBXProject "alt-tab-macos" */ = {
|
||||
isa = XCConfigurationList;
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -24,15 +24,15 @@ func keyboardHandler(_ cgEvent: CGEvent, _ delegate: Application) -> Unmanaged<C
|
||||
if cgEvent.type == .keyDown || cgEvent.type == .keyUp || cgEvent.type == .flagsChanged {
|
||||
if let event = NSEvent.init(cgEvent: cgEvent) {
|
||||
let keyDown = event.type == .keyDown
|
||||
let optionKeyEvent = event.keyCode == metaKey
|
||||
let tabKeyEvent = event.keyCode == tabKey
|
||||
if optionKeyEvent && event.modifiersDown([metaModifierFlag]) {
|
||||
let optionKeyEvent = event.keyCode == Preferences.metaKey
|
||||
let tabKeyEvent = event.keyCode == Preferences.tabKey
|
||||
if optionKeyEvent && event.modifiersDown([Preferences.metaModifierFlag]) {
|
||||
delegate.keyDownMeta()
|
||||
} else if tabKeyEvent && event.modifiersDown([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([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
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
struct PreferencesDecodable: Decodable {
|
||||
let maxScreenUsage: CGFloat?
|
||||
let windowPadding: CGFloat?
|
||||
let cellPadding: CGFloat?
|
||||
let cellBorderWidth: CGFloat?
|
||||
let maxThumbnailsPerRow: CGFloat?
|
||||
let thumbnailMaxWidth: CGFloat?
|
||||
let thumbnailMaxHeight: CGFloat?
|
||||
let iconSize: CGFloat?
|
||||
let fontHeight: CGFloat?
|
||||
let interItemPadding: CGFloat?
|
||||
let tabKey: UInt16?
|
||||
let metaKey: UInt16?
|
||||
let metaModifierFlagInt: UInt?
|
||||
let highlightColorString : String?
|
||||
let thumbnailQuality : UInt?
|
||||
}
|
||||
|
||||
func fileLines(_ url: URL) throws -> Int {
|
||||
try String(contentsOf: url, encoding: .utf8).split(separator: "\n").count
|
||||
}
|
||||
|
||||
class Preferences: Decodable {
|
||||
private static let decoded: PreferencesDecodable? = decodeFromJson()
|
||||
|
||||
private static func decodeFromJson() -> PreferencesDecodable? {
|
||||
do {
|
||||
let defaultFile = Bundle.main.url(forResource: "preferences", withExtension: "json")!
|
||||
let userFile = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)
|
||||
.first!
|
||||
.appendingPathComponent("Preferences", isDirectory: true)
|
||||
.appendingPathComponent("alt-tab-macos.json")
|
||||
try handleNoFileOrOldFile(userFile: userFile, defaultFile: defaultFile)
|
||||
return try JSONDecoder().decode(PreferencesDecodable.self, from: Data(contentsOf: userFile))
|
||||
} catch {
|
||||
debugPrint("Error parsing preferences.json", error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private static func handleNoFileOrOldFile(userFile: URL, defaultFile: URL) throws {
|
||||
if !FileManager.default.fileExists(atPath: userFile.path) {
|
||||
try FileManager.default.copyItem(at: defaultFile, to: userFile)
|
||||
} else if try fileLines(defaultFile) > fileLines(userFile) {
|
||||
// TODO: handle upgrades in a smarter way (e.g. merge files)
|
||||
let _ = try FileManager.default.replaceItemAt(defaultFile, withItemAt: userFile)
|
||||
}
|
||||
}
|
||||
|
||||
// maximum width/height of the main window, in percentage of screen width/height
|
||||
static let maxScreenUsage = decoded?.maxScreenUsage ?? 0.8
|
||||
// padding in the main window
|
||||
static let windowPadding = decoded?.windowPadding ?? 20
|
||||
// padding in each cell
|
||||
static let cellPadding = decoded?.cellPadding ?? 6
|
||||
// border width of each cell
|
||||
static let cellBorderWidth = decoded?.cellBorderWidth ?? 2
|
||||
// maximum number of thumbnails on each row
|
||||
static let maxThumbnailsPerRow = decoded?.maxThumbnailsPerRow ?? 4
|
||||
// maximum width of each thumbnail
|
||||
static var thumbnailMaxWidth = decoded?.thumbnailMaxWidth ?? 0
|
||||
// maximum height of eacg thumbnail
|
||||
static var thumbnailMaxHeight = decoded?.thumbnailMaxHeight ?? 0
|
||||
// width/height for each cell app icon
|
||||
static let iconSize = decoded?.iconSize ?? 32
|
||||
// font height for each cell title
|
||||
static let fontHeight = decoded?.fontHeight ?? 15
|
||||
// padding between cells within the main window
|
||||
static let interItemPadding = decoded?.interItemPadding ?? 4
|
||||
// NSEvent.keyCode (e.g. leftCommand=55, leftOption=58, leftControl=59, rightCommand=54, rightOption=61)
|
||||
static let tabKey = decoded?.tabKey ?? 48
|
||||
// NSEvent.keyCode (e.g. leftCommand=55, leftOption=58, leftControl=59, rightCommand=54, rightOption=61)
|
||||
static let metaKey = decoded?.metaKey ?? 59
|
||||
// NSImageInterpolation (e.g. none=1, low=2, medium=4, high=3)
|
||||
static let thumbnailQuality = NSImageInterpolation.init(rawValue: decoded?.thumbnailQuality ?? 3) ?? .high
|
||||
// NSEvent.ModifierFlags (e.g. control=262144, command=1048576, shift=131072, option=524288)
|
||||
static let metaModifierFlag = NSEvent.ModifierFlags(rawValue: decoded?.metaModifierFlagInt ?? 262144)
|
||||
// color for the currently selected cell
|
||||
static let highlightColor = NSColor(named: decoded?.highlightColorString ?? "white") ?? .white
|
||||
// derived properties
|
||||
static let font: NSFont = .systemFont(ofSize: Preferences.fontHeight)
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ class OpenWindow {
|
||||
|
||||
func computeDownscaledSize(_ image: NSImage) -> (Int, Int) {
|
||||
let imageRatio = image.size.width / image.size.height
|
||||
let thumbnailWidth = Int(floor(thumbnailMaxHeight * imageRatio))
|
||||
if thumbnailWidth <= Int(thumbnailMaxWidth) {
|
||||
return (thumbnailWidth, Int(thumbnailMaxHeight))
|
||||
let thumbnailWidth = Int(floor(Preferences.thumbnailMaxHeight * imageRatio))
|
||||
if thumbnailWidth <= Int(Preferences.thumbnailMaxWidth) {
|
||||
return (thumbnailWidth, Int(Preferences.thumbnailMaxHeight))
|
||||
} else {
|
||||
return (Int(thumbnailMaxWidth), Int(floor(thumbnailMaxWidth / imageRatio)))
|
||||
return (Int(Preferences.thumbnailMaxWidth), Int(floor(Preferences.thumbnailMaxWidth / imageRatio)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"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,
|
||||
"metaModifierFlagInt": 262144,
|
||||
"highlightColorString": "white",
|
||||
"thumbnailQuality": 4
|
||||
}
|
||||
@@ -1,27 +1,12 @@
|
||||
import Cocoa
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
let maxScreenUsage: CGFloat = 0.8
|
||||
let windowPadding: CGFloat = 20
|
||||
let cellPadding: CGFloat = 6
|
||||
let cellBorderWidth: CGFloat = 2
|
||||
let maxThumbnailsPerRow: CGFloat = 4
|
||||
var thumbnailMaxWidth: CGFloat = 0
|
||||
var thumbnailMaxHeight: CGFloat = 0
|
||||
let iconSize: CGFloat = 32
|
||||
let fontHeight: CGFloat = 15
|
||||
let font: NSFont = .systemFont(ofSize: fontHeight)
|
||||
let interItemPadding: CGFloat = 4
|
||||
let tabKey = 48
|
||||
let metaKey = 0x3B
|
||||
let metaModifierFlag: NSEvent.ModifierFlags = .control
|
||||
let cellId = NSUserInterfaceItemIdentifier("Cell")
|
||||
let highlightColor: NSColor = .white
|
||||
|
||||
func updateThumbnailMaxSize() -> Void {
|
||||
let main = NSScreen.main!.frame
|
||||
thumbnailMaxWidth = (NSScreen.main!.frame.size.width * maxScreenUsage - windowPadding * 2) / maxThumbnailsPerRow - interItemPadding
|
||||
thumbnailMaxHeight = thumbnailMaxWidth * (main.height / main.width)
|
||||
Preferences.thumbnailMaxWidth = (NSScreen.main!.frame.size.width * Preferences.maxScreenUsage - Preferences.windowPadding * 2) / Preferences.maxThumbnailsPerRow - Preferences.interItemPadding
|
||||
Preferences.thumbnailMaxHeight = Preferences.thumbnailMaxWidth * (main.height / main.width)
|
||||
}
|
||||
|
||||
class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCollectionViewDataSource, NSCollectionViewDelegate, NSCollectionViewDelegateFlowLayout {
|
||||
@@ -82,7 +67,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCol
|
||||
|
||||
func makeCollectionView() {
|
||||
let layout = CollectionViewCenterFlowLayout()
|
||||
layout.estimatedItemSize = NSSize(width: thumbnailMaxWidth, height: thumbnailMaxHeight)
|
||||
layout.estimatedItemSize = NSSize(width: Preferences.thumbnailMaxWidth, height: Preferences.thumbnailMaxHeight)
|
||||
layout.minimumInteritemSpacing = 5
|
||||
layout.minimumLineSpacing = 5
|
||||
collectionView_ = NSCollectionView()
|
||||
@@ -146,14 +131,14 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCol
|
||||
}
|
||||
|
||||
func computeThumbnails() {
|
||||
let maxSize = NSSize(width: NSScreen.main!.frame.width * maxScreenUsage, height: NSScreen.main!.frame.height * 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()
|
||||
collectionView_!.layoutSubtreeIfNeeded()
|
||||
window!.setContentSize(NSSize(width: collectionView_!.frame.size.width + windowPadding * 2, height: collectionView_!.frame.size.height + windowPadding * 2))
|
||||
window!.setContentSize(NSSize(width: collectionView_!.frame.size.width + Preferences.windowPadding * 2, height: collectionView_!.frame.size.height + Preferences.windowPadding * 2))
|
||||
backgroundView!.setFrameSize(window!.frame.size)
|
||||
collectionView_!.setFrameOrigin(NSPoint(x: windowPadding, y: windowPadding))
|
||||
collectionView_!.setFrameOrigin(NSPoint(x: Preferences.windowPadding, y: Preferences.windowPadding))
|
||||
window!.center()
|
||||
}
|
||||
|
||||
@@ -173,13 +158,13 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCol
|
||||
debugPrint("collectionView: item size")
|
||||
if indexPath.item < openWindows.count {
|
||||
let (width, height) = computeDownscaledSize(openWindows[indexPath.item].thumbnail)
|
||||
return NSSize(width: CGFloat(width) + cellPadding * 2, height: CGFloat(height) + max(fontHeight, iconSize) + interItemPadding + 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
|
||||
}
|
||||
|
||||
func cellWithStep(_ step: Int) -> Int {
|
||||
return selectedOpenWindow + step < 0 ? openWindows.count - 1 : (selectedOpenWindow + step) % openWindows.count
|
||||
selectedOpenWindow + step < 0 ? openWindows.count - 1 : (selectedOpenWindow + step) % openWindows.count
|
||||
}
|
||||
|
||||
func selectOtherCell(_ step: Int) {
|
||||
@@ -203,7 +188,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCol
|
||||
}
|
||||
|
||||
func currentlySelectedWindow() -> OpenWindow? {
|
||||
return openWindows.count > selectedOpenWindow ? openWindows[selectedOpenWindow] : nil
|
||||
openWindows.count > selectedOpenWindow ? openWindows[selectedOpenWindow] : nil
|
||||
}
|
||||
|
||||
func focusSelectedWindow(_ window: OpenWindow?) {
|
||||
|
||||
+14
-14
@@ -14,13 +14,13 @@ class Cell: NSCollectionViewItem {
|
||||
override func loadView() {
|
||||
let vStackView = NSStackView()
|
||||
vStackView.wantsLayer = true
|
||||
vStackView.layer!.borderWidth = cellBorderWidth
|
||||
vStackView.layer!.borderWidth = Preferences.cellBorderWidth
|
||||
vStackView.layer!.borderColor = .clear
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: cellPadding, left: cellPadding, bottom: cellPadding, right: cellPadding)
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.cellPadding, left: Preferences.cellPadding, bottom: Preferences.cellPadding, right: Preferences.cellPadding)
|
||||
vStackView.orientation = .vertical
|
||||
vStackView.spacing = interItemPadding
|
||||
vStackView.spacing = Preferences.interItemPadding
|
||||
let hStackView = NSStackView()
|
||||
hStackView.spacing = interItemPadding
|
||||
hStackView.spacing = Preferences.interItemPadding
|
||||
let textStorage = NSTextStorage()
|
||||
let layoutManager = NSLayoutManager()
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
@@ -33,8 +33,8 @@ class Cell: NSCollectionViewItem {
|
||||
text.backgroundColor = .clear
|
||||
text.isSelectable = false
|
||||
text.isEditable = false
|
||||
text.font = font
|
||||
text.textColor = highlightColor
|
||||
text.font = Preferences.font
|
||||
text.textColor = Preferences.highlightColor
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = .darkGray
|
||||
shadow.shadowOffset = NSMakeSize(0, 0)
|
||||
@@ -43,11 +43,11 @@ class Cell: NSCollectionViewItem {
|
||||
text.enabledTextCheckingTypes = 0
|
||||
let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
|
||||
paragraphStyle.lineBreakMode = .byTruncatingTail
|
||||
paragraphStyle.maximumLineHeight = fontHeight
|
||||
paragraphStyle.minimumLineHeight = fontHeight
|
||||
paragraphStyle.maximumLineHeight = Preferences.fontHeight
|
||||
paragraphStyle.minimumLineHeight = Preferences.fontHeight
|
||||
paragraphStyle.allowsDefaultTighteningForTruncation = false
|
||||
text.defaultParagraphStyle = paragraphStyle
|
||||
text.heightAnchor.constraint(equalToConstant: fontHeight).isActive = true
|
||||
text.heightAnchor.constraint(equalToConstant: Preferences.fontHeight).isActive = true
|
||||
let shadow2 = NSShadow()
|
||||
shadow2.shadowColor = .gray
|
||||
shadow2.shadowOffset = NSMakeSize(0, 0)
|
||||
@@ -63,7 +63,7 @@ class Cell: NSCollectionViewItem {
|
||||
|
||||
override var isSelected: Bool {
|
||||
didSet {
|
||||
view.layer!.borderColor = isSelected ? highlightColor.cgColor : .clear
|
||||
view.layer!.borderColor = isSelected ? Preferences.highlightColor.cgColor : .clear
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,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: iconSize, height: iconSize)
|
||||
icon.frame.size = NSSize(width: iconSize, height: 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 = font
|
||||
text.textContainer!.size.width = thumbnail.frame.size.width - iconSize - interItemPadding
|
||||
text.font = Preferences.font
|
||||
text.textContainer!.size.width = thumbnail.frame.size.width - Preferences.iconSize - Preferences.interItemPadding
|
||||
mouseDownCallback = fn
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ class CollectionViewCenterFlowLayout: NSCollectionViewFlowLayout {
|
||||
var widestRow = CGFloat(0)
|
||||
var totalHeight = CGFloat(0)
|
||||
attributes.enumerated().forEach {
|
||||
let isNewRow = abs($1.frame.origin.y - currentRowY) > thumbnailMaxHeight
|
||||
let isNewRow = abs($1.frame.origin.y - currentRowY) > Preferences.thumbnailMaxHeight
|
||||
if isNewRow {
|
||||
computeOriginXForAllItems(currentRowWidth - minimumInteritemSpacing, previousRowMaxY, currentRow)
|
||||
currentRow.removeAll()
|
||||
|
||||
@@ -2,7 +2,7 @@ import Cocoa
|
||||
|
||||
class HighInterpolationImageView: NSImageView {
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
NSGraphicsContext.current!.imageInterpolation = .high
|
||||
NSGraphicsContext.current!.imageInterpolation = Preferences.thumbnailQuality
|
||||
super.draw(dirtyRect)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user