diff --git a/alt-tab-macos.xcodeproj/project.pbxproj b/alt-tab-macos.xcodeproj/project.pbxproj index 42ea8a2bd..ad982f6c0 100644 --- a/alt-tab-macos.xcodeproj/project.pbxproj +++ b/alt-tab-macos.xcodeproj/project.pbxproj @@ -68,6 +68,7 @@ D04BA9557A6C9E192D228150 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA2C08725A5F2C34EB809 /* InfoPlist.strings */; }; D04BA9B7A964C5FABFEB9DA2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA053A0E0157E817B2E04 /* Localizable.strings */; }; D04BA9D63A88AF2C20A1E656 /* SF-Pro-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = D04BA60A6D08C041F5BF8CC9 /* SF-Pro-Text-Regular.otf */; }; + D04BAA16F21AC41A23DDA63D /* ControlsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA1B438BF3E65044D1138 /* ControlsTab.swift */; }; D04BAAAF5CFA991D3B078DB8 /* KeyboardEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA4A621A8A15660F973C1 /* KeyboardEvents.swift */; }; D04BAAB5C4E78AE375EA7D3C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAA56B4EEAF17F767C7FD /* Localizable.strings */; }; D04BAABE804F3769CE22BEB6 /* HyperlinkLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA49E45BFFF3D9FC60E43 /* HyperlinkLabel.swift */; }; @@ -130,6 +131,7 @@ D04BA18724DC58FA95DB33DB /* Podfile.lock */ = {isa = PBXFileReference; lastKnownFileType = file.lock; path = Podfile.lock; sourceTree = ""; }; D04BA18B55AA6C9EE41985D0 /* Contributing.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Contributing.md; sourceTree = ""; }; D04BA19E22F2B73DB785E5DB /* subset_fonticon.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = subset_fonticon.sh; sourceTree = ""; }; + D04BA1B438BF3E65044D1138 /* ControlsTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlsTab.swift; sourceTree = ""; }; D04BA1C3E42AC44CA2C5D3D8 /* app-icon.svg */ = {isa = PBXFileReference; lastKnownFileType = file.svg; path = "app-icon.svg"; sourceTree = ""; }; D04BA1D80F4EEF2A91BAD29C /* release.config.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = release.config.js; sourceTree = ""; }; D04BA1DF8CAB2FAB7FE9244B /* ThumbnailFontIconView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailFontIconView.swift; sourceTree = ""; }; @@ -494,6 +496,7 @@ D04BAD60C97E609A759E721E /* PoliciesTab.swift */, D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */, D04BA27695D9A5824720BD7B /* BlacklistsTab.swift */, + D04BA1B438BF3E65044D1138 /* ControlsTab.swift */, ); path = tabs; sourceTree = ""; @@ -1120,6 +1123,7 @@ D04BAFF30A98CF287F85DA1E /* BlacklistsTab.swift in Sources */, D04BA56789A2AF52557A9BFF /* AppCenterCrashes.swift in Sources */, D04BADA3F2DAB820D6FC6E75 /* AppCenterApplication.m in Sources */, + D04BAA16F21AC41A23DDA63D /* ControlsTab.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/resources/l10n/Localizable.strings b/resources/l10n/Localizable.strings index 495644128..075a89309 100644 --- a/resources/l10n/Localizable.strings +++ b/resources/l10n/Localizable.strings @@ -34,6 +34,9 @@ /* No comment provided by engineer. */ "Allowed" = "Allowed"; +/* No comment provided by engineer. */ +"Also select windows using:" = "Also select windows using:"; + /* No comment provided by engineer. */ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -88,9 +91,15 @@ /* No comment provided by engineer. */ "Close window" = "Close window"; +/* No comment provided by engineer. */ +"Controls" = "Controls"; + /* No comment provided by engineer. */ "Crash reports policy:" = "Crash reports policy:"; +/* No comment provided by engineer. */ +"Do nothing" = "Do nothing"; + /* No comment provided by engineer. */ "Don’t check for updates periodically" = "Don’t check for updates periodically"; @@ -187,9 +196,6 @@ /* No comment provided by engineer. */ "Optional: email (if you want a reply)" = "Optional: email (if you want a reply)"; -/* No comment provided by engineer. */ -"or press:" = "or press:"; - /* No comment provided by engineer. */ "Policies" = "Policies"; @@ -229,9 +235,6 @@ /* No comment provided by engineer. */ "Select previous window" = "Select previous window"; -/* No comment provided by engineer. */ -"Select windows using:" = "Select windows using:"; - /* No comment provided by engineer. */ "Send" = "Send"; @@ -253,6 +256,12 @@ /* No comment provided by engineer. */ "Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs"; +/* No comment provided by engineer. */ +"Shortcut 1" = "Shortcut 1"; + +/* No comment provided by engineer. */ +"Shortcut 2" = "Shortcut 2"; + /* Menubar option */ "Show" = "Show"; @@ -295,6 +304,9 @@ /* No comment provided by engineer. */ "View existing discussions" = "View existing discussions"; +/* No comment provided by engineer. */ +"While open, press:" = "While open, press:"; + /* No comment provided by engineer. */ "Window app icon size:" = "Window app icon size:"; diff --git a/resources/l10n/ar.lproj/Localizable.strings b/resources/l10n/ar.lproj/Localizable.strings index a510ff227..7149e1032 100644 --- a/resources/l10n/ar.lproj/Localizable.strings +++ b/resources/l10n/ar.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "إغلاق النافذة"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "لا تبحث عن تحديثات بشكل دوري"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "شارك أفكارك التطويرية، أو بلغ عن أخطاء"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "إظهار"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "أنظر للنقاشات الحالية"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "حجم أيقونة النافذة:"; diff --git a/resources/l10n/de.lproj/Localizable.strings b/resources/l10n/de.lproj/Localizable.strings index a9d38633e..9024c366b 100644 --- a/resources/l10n/de.lproj/Localizable.strings +++ b/resources/l10n/de.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Erlaubt"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab ist bei der letzten Ausführung abgestürzt. Das Absenden von Absturzberichten hilft bei der Fehlerbeseitigung."; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Fenster schließen"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Richtlinie für Absturzberichte:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Nicht regelmäßig nach Updates suchen"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Teile uns deine Vorschläge mit oder melden Fehler"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Anzeigen"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Bestehende Vorschläge anzeigen"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Fenster Icon Größe:"; diff --git a/resources/l10n/en.lproj/Localizable.strings b/resources/l10n/en.lproj/Localizable.strings index 4540b4b89..976433903 100644 --- a/resources/l10n/en.lproj/Localizable.strings +++ b/resources/l10n/en.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Close window"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Don’t check for updates periodically"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Show"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "View existing discussions"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Window app icon size:"; diff --git a/resources/l10n/es.lproj/Localizable.strings b/resources/l10n/es.lproj/Localizable.strings index 9d992871e..da96f6b43 100644 --- a/resources/l10n/es.lproj/Localizable.strings +++ b/resources/l10n/es.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Cerrar ventana"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "No comprobar actualizaciones periódicamente"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Comparta ideas de mejora o informe de errores"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Mostrar"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Ver discusiones existentes"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Tamaño del icono de la ventana de aplicación:"; diff --git a/resources/l10n/fi.lproj/Localizable.strings b/resources/l10n/fi.lproj/Localizable.strings index 5964cdfd7..cc7c576d2 100644 --- a/resources/l10n/fi.lproj/Localizable.strings +++ b/resources/l10n/fi.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Sulje ikkuna"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Älä tarkista päivityksiä"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Jaa parannusehdotuksia tai raportoi bugeja"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Näytä"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Näytä keskustelut"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Ohjelmaikonin koko:"; diff --git a/resources/l10n/fr.lproj/Localizable.strings b/resources/l10n/fr.lproj/Localizable.strings index 1181812ef..241c63b3c 100644 --- a/resources/l10n/fr.lproj/Localizable.strings +++ b/resources/l10n/fr.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Autorisé"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Fermer la fenêtre"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Ne pas chercher de mise-à-jour périodiquement"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Partagez des idées d’amélioration, ou signalez des bugs"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Afficher"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Voir les discussions existantes"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Taille des icones des applications :"; diff --git a/resources/l10n/hu.lproj/Localizable.strings b/resources/l10n/hu.lproj/Localizable.strings index cf7742e40..3f4116e29 100644 --- a/resources/l10n/hu.lproj/Localizable.strings +++ b/resources/l10n/hu.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Engedélyezve"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Ablak bezárása"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Ne keressen frissítéseket automatikusan"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Fejlesztési ötletek megosztása, hibabejelentés"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Mutat"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Aktuális beszélgetések megtekintése"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Ablak alkalmazásikonméret:"; diff --git a/resources/l10n/id.lproj/Localizable.strings b/resources/l10n/id.lproj/Localizable.strings index c269c6c70..f6c9a6a8c 100644 --- a/resources/l10n/id.lproj/Localizable.strings +++ b/resources/l10n/id.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Dibolehkan"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Tutup jendela"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Jangan periksa pembaruan secara berkala"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Bagikan gagasan peningkatan, atau laporkan bug"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Tampilkan"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Lihat diskusi yang ada"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Ukuran ikon aplikasi jendela:"; diff --git a/resources/l10n/it.lproj/Localizable.strings b/resources/l10n/it.lproj/Localizable.strings index d22790b15..6256aa354 100644 --- a/resources/l10n/it.lproj/Localizable.strings +++ b/resources/l10n/it.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Chiudi la finestra"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Non controllare gli aggiornamenti periodicamente"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Condividi idee per miglioramenti oppure riporta problemi"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Mostra"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Mostra discussioni esistenti"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Dimensione dell’icona della finestra dell’applicazione:"; diff --git a/resources/l10n/ja.lproj/Localizable.strings b/resources/l10n/ja.lproj/Localizable.strings index b12e9728c..dc1b9c9f2 100644 --- a/resources/l10n/ja.lproj/Localizable.strings +++ b/resources/l10n/ja.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "ウィンドウを閉じる"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "定期的に更新を確認しない"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "改善点のご共有あるいはバグのご報告"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "アプリを表示"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "既にあるディスカッションを見る"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "ウィンドウに表示されるアイコンサイズ:"; diff --git a/resources/l10n/ko.lproj/Localizable.strings b/resources/l10n/ko.lproj/Localizable.strings index 829f869d9..96a6bd11c 100644 --- a/resources/l10n/ko.lproj/Localizable.strings +++ b/resources/l10n/ko.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "허용됨"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "마지막으로 사용하고 나서 AltTab이 충돌했습니다. 충돌 리포트를 보내는 것은 이 문제를 해결하는데 도움을 줄 수 있습니다"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "윈도우 닫기"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "충돌 리포트 처리 방법:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "주기적으로 업데이트를 확인하지 않기"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "개선방안을 공유하거나 버그를 제보해주세요"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "보기"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "진행중인 논의 보기"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "윈도우 앱 아이콘 크기:"; diff --git a/resources/l10n/lb.lproj/Localizable.strings b/resources/l10n/lb.lproj/Localizable.strings index 43733e360..67fa1a4ac 100644 --- a/resources/l10n/lb.lproj/Localizable.strings +++ b/resources/l10n/lb.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Close window"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Net reegelméisseg no Updates sichen"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Share improvement ideas, or report bugs"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Opbréngen"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "View existing discussions"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Window app icon size:"; diff --git a/resources/l10n/nl.lproj/Localizable.strings b/resources/l10n/nl.lproj/Localizable.strings index 8f7435856..3937b42e0 100644 --- a/resources/l10n/nl.lproj/Localizable.strings +++ b/resources/l10n/nl.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Sluit venster"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Controleer niet regelmatig op updates"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Deel verbetervoorstellen of meld bugs"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Toon"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Bekijk bestaande discussies"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Icoongrootte vensterapplicatie:"; diff --git a/resources/l10n/pt-BR.lproj/Localizable.strings b/resources/l10n/pt-BR.lproj/Localizable.strings index b23421c04..d3c85baf1 100644 --- a/resources/l10n/pt-BR.lproj/Localizable.strings +++ b/resources/l10n/pt-BR.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Fechar janela"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Não verifique periodicamente por atualizações"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Compartilhar sugestões ou reportar falhas"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Exibir"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Ver discussões existentes"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Tamanho do ícone da aplicação:"; diff --git a/resources/l10n/ru.lproj/Localizable.strings b/resources/l10n/ru.lproj/Localizable.strings index d3266f36d..69e989d3f 100644 --- a/resources/l10n/ru.lproj/Localizable.strings +++ b/resources/l10n/ru.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Разрешено"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab аварийно завершился в последний раз, когда вы его использовали. Отправка отчета поможет исправить проблему"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Закрыть окно"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Правило отчетов о вылетах:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Не проверять обновления"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Поделитесь идеями по улучшению или сообщите об ошибках"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Показать"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Посмотреть обсуждения"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Размер иконки окна:"; diff --git a/resources/l10n/tr.lproj/Localizable.strings b/resources/l10n/tr.lproj/Localizable.strings index a9cbf4782..6a8b50692 100644 --- a/resources/l10n/tr.lproj/Localizable.strings +++ b/resources/l10n/tr.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "Pencereyi kapat"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "Güncellemeleri periyodik olarak kontrol etme"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "Fikir yada hata paylaş"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "Göster"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "Mevcut tartışmaları görüntüle"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "Pencere simge boyutu:"; diff --git a/resources/l10n/zh-CN.lproj/Localizable.strings b/resources/l10n/zh-CN.lproj/Localizable.strings index 73fa6e834..e558258f4 100644 --- a/resources/l10n/zh-CN.lproj/Localizable.strings +++ b/resources/l10n/zh-CN.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "允许"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab 在您上次使用时崩溃了, 发送崩溃报告将有助于解决问题"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "关闭窗口"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "崩溃报告政策:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "不自动检查更新"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "反馈建议或报告错误"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "显示"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "查看现有讨论"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "窗口图标大小:"; diff --git a/resources/l10n/zh-TW.lproj/Localizable.strings b/resources/l10n/zh-TW.lproj/Localizable.strings index 91b9cd261..65b7ea263 100644 --- a/resources/l10n/zh-TW.lproj/Localizable.strings +++ b/resources/l10n/zh-TW.lproj/Localizable.strings @@ -35,6 +35,9 @@ /*No comment provided by engineer.*/ "Allowed" = "Allowed"; +/*No comment provided by engineer.*/ +"Also select windows using:" = "Also select windows using:"; + /*No comment provided by engineer.*/ "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed" = "AltTab crashed last time you used it. Sending a crash report will help get the issue fixed"; @@ -89,9 +92,15 @@ /*No comment provided by engineer.*/ "Close window" = "關閉視窗"; +/*No comment provided by engineer.*/ +"Controls" = "Controls"; + /*No comment provided by engineer.*/ "Crash reports policy:" = "Crash reports policy:"; +/*No comment provided by engineer.*/ +"Do nothing" = "Do nothing"; + /*No comment provided by engineer.*/ "Don’t check for updates periodically" = "不要定期自動檢查更新"; @@ -257,6 +266,12 @@ /*No comment provided by engineer.*/ "Share improvement ideas, or report bugs" = "分享改進的想法,或是回報問題"; +/*No comment provided by engineer.*/ +"Shortcut 1" = "Shortcut 1"; + +/*No comment provided by engineer.*/ +"Shortcut 2" = "Shortcut 2"; + /*No comment provided by engineer.*/ "Show" = "顯示"; @@ -299,6 +314,9 @@ /*No comment provided by engineer.*/ "View existing discussions" = "觀看目前的討論"; +/*No comment provided by engineer.*/ +"While open, press:" = "While open, press:"; + /*No comment provided by engineer.*/ "Window app icon size:" = "視窗圖示的大小:"; diff --git a/src/api-wrappers/HelperExtensions.swift b/src/api-wrappers/HelperExtensions.swift index 0e1c93cc2..88b7a5c46 100644 --- a/src/api-wrappers/HelperExtensions.swift +++ b/src/api-wrappers/HelperExtensions.swift @@ -127,3 +127,23 @@ extension DispatchQoS { } } } + +extension NSGridColumn { + func width(_ skipCell: Int? = nil) -> CGFloat { + var maxWidth = CGFloat(0) + for i in (0.. Unmanaged? { if (type == .keyDown || type == .keyUp || type == .flagsChanged) && !App.app.shortcutsShouldBeDisabled { - if let event_ = NSEvent(cgEvent: cgEvent), - // workaround: NSEvent.characters is not safe outside of the main thread; this is not documented by Apple - // see https://github.com/Kentzo/ShortcutRecorder/issues/114#issuecomment-606465340 - let event = NSEvent.keyEvent(with: event_.type, location: event_.locationInWindow, modifierFlags: event_.modifierFlags, - timestamp: event_.timestamp, windowNumber: event_.windowNumber, context: nil, characters: "", - charactersIgnoringModifiers: "", isARepeat: type == .flagsChanged ? false : event_.isARepeat, keyCode: event_.keyCode) { + if let event = NSEvent(cgEvent: cgEvent) { let appWasBeingUsed = App.app.appIsBeingUsed - // ShortcutRecorder handles only exact matches for modifiers-only .up shortcuts. We want to activate holdShortcut even if other modifiers are still pressed - // see https://github.com/lwouis/alt-tab-macos/issues/230 - let holdShortcutAction = GeneralTab.shortcutActions["holdShortcut"]! - let holdShortcut = holdShortcutAction.shortcut! - if holdShortcut.keyCode == .none && type == .flagsChanged && event.sr_keyEventType == .up && - event.modifierFlags.isDisjoint(with: holdShortcut.modifierFlags) { - _ = holdShortcutAction.actionHandler!(holdShortcutAction) - } else { - App.shortcutMonitor.handle(event, withTarget: nil) + if let shortcut = shortcutThatMatches(event, type) { + if shortcut.hasPrefix("nextWindowShortcut") { + App.app.appIsBeingUsed = true + } else if shortcut.hasPrefix("holdShortcut") || shortcut == "cancelShortcut" || shortcut == "focusWindowShortcut" { + App.app.appIsBeingUsed = false + App.app.isFirstSummon = true + } + DispatchQueue.main.async { () -> () in ControlsTab.shortcutsActions[shortcut]!() } } if appWasBeingUsed || App.app.appIsBeingUsed { return nil // focused app won't receive the event @@ -53,3 +48,31 @@ private func keyboardHandler(_: CGEventTapProxy, type: CGEventType, cgEvent: CGE } return Unmanaged.passRetained(cgEvent) // focused app will receive the event } + +// shortcutMonitor.handle only does exact matching; we match manually to allow flexible matching +// see https://github.com/lwouis/alt-tab-macos/issues/230 +private func shortcutThatMatches(_ event: NSEvent, _ type: CGEventType) -> String? { + for shortcutId in ControlsTab.shortcuts.keys { + let postfix = App.app.shortcutIndex == 0 ? "" : "2" + let shortcut = ControlsTab.shortcuts[shortcutId]! + if shortcutId.hasPrefix("holdShortcut") { + if event.sr_keyEventType == .up && type == .flagsChanged && shortcut.keyCode == .none && event.modifierFlags.isDisjoint(with: shortcut.modifierFlags) && + shortcutId == "holdShortcut" + postfix && App.app.appIsBeingUsed && Preferences.shortcutStyle == .focusOnRelease { + return shortcutId + } + } else if event.sr_keyEventType == .down && (shortcut.keyCode == .none || event.keyCode == shortcut.carbonKeyCode) { + if shortcutId.hasPrefix("nextWindowShortcut") { + if event.modifierFlags.intersection(.deviceIndependentFlagsMask) == shortcut.modifierFlags && + (!App.app.appIsBeingUsed || shortcutId == "nextWindowShortcut" + postfix) { + return shortcutId + } + } else { + if event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(shortcut.modifierFlags) && + App.app.appIsBeingUsed { + return shortcutId + } + } + } + } + return nil +} diff --git a/src/ui/App.swift b/src/ui/App.swift index 571d1c64e..b389b48b4 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -13,7 +13,6 @@ class App: AppCenterApplication, NSApplicationDelegate { static let licence = Bundle.main.object(forInfoDictionaryKey: "NSHumanReadableCopyright") as! String static let repository = "https://github.com/lwouis/alt-tab-macos" static var app: App! - static let shortcutMonitor = LocalShortcutMonitor() static var statusItem: NSStatusItem! var thumbnailsPanel: ThumbnailsPanel! var preferencesWindowController: PreferencesWindowController! @@ -81,6 +80,7 @@ class App: AppCenterApplication, NSApplicationDelegate { private func loadPreferencesWindow() { let tabs = [ GeneralTab(), + ControlsTab(), AppearanceTab(), PoliciesTab(), BlacklistsTab(), @@ -88,7 +88,14 @@ class App: AppCenterApplication, NSApplicationDelegate { AcknowledgmentsTab(), ] // pre-load tabs so we can interact with them before the user opens the preferences window - tabs.forEach { (tab: NSViewController) in tab.loadView() } + let widest = tabs.reduce(CGFloat(0), { + $1.loadView() + return max($0, $1.view.subviews[0].fittingSize.width) + }) + tabs.forEach { + $0.view.fit(widest, $0.view.subviews[0].fittingSize.height) + } + preferencesWindowController = PreferencesWindowController(preferencePanes: tabs as! [PreferencePane]) let window = preferencesWindowController.window! @@ -96,10 +103,8 @@ class App: AppCenterApplication, NSApplicationDelegate { let titleBarView = window.standardWindowButton(.closeButton)!.superview! titleBarView.addSubview(quitButton) quitButton.translatesAutoresizingMaskIntoConstraints = false - let topConstraint = NSLayoutConstraint(item: quitButton, attribute: .top, relatedBy: .equal, toItem: titleBarView, attribute: .top, multiplier: 1, constant: 5) - let rightConstraint = NSLayoutConstraint(item: quitButton, attribute: .right, relatedBy: .equal, toItem: titleBarView, attribute: .right, multiplier: 1, constant: -10) - titleBarView.addConstraints([topConstraint, rightConstraint]) - + quitButton.topAnchor.constraint(equalTo: titleBarView.topAnchor, constant: 5).isActive = true + quitButton.rightAnchor.constraint(equalTo: titleBarView.rightAnchor, constant: -8).isActive = true } // keyboard shortcuts are broken without a menu. We generated the default menu from XCode and load it diff --git a/src/ui/generic-components/GridView.swift b/src/ui/generic-components/GridView.swift index 9c58741f1..758b36a47 100644 --- a/src/ui/generic-components/GridView.swift +++ b/src/ui/generic-components/GridView.swift @@ -4,16 +4,16 @@ class GridView: NSGridView { static let padding = CGFloat(20) static let interPadding = CGFloat(10) - convenience init(_ controls: [[NSView]]) { + convenience init(_ controls: [[NSView]], _ padding: CGFloat = GridView.padding) { self.init(views: controls) translatesAutoresizingMaskIntoConstraints = false yPlacement = .fill rowAlignment = .firstBaseline columnSpacing = GridView.interPadding rowSpacing = GridView.interPadding - column(at: 0).leadingPadding = GridView.padding - column(at: numberOfColumns - 1).trailingPadding = GridView.padding - row(at: 0).topPadding = GridView.padding - row(at: numberOfRows - 1).bottomPadding = GridView.padding + column(at: 0).leadingPadding = padding + column(at: numberOfColumns - 1).trailingPadding = padding + row(at: 0).topPadding = padding + row(at: numberOfRows - 1).bottomPadding = padding } } diff --git a/src/ui/preferences-window/LabelAndControl.swift b/src/ui/preferences-window/LabelAndControl.swift index f9944895e..5d9672a66 100644 --- a/src/ui/preferences-window/LabelAndControl.swift +++ b/src/ui/preferences-window/LabelAndControl.swift @@ -10,8 +10,8 @@ enum LabelPosition { class LabelAndControl: NSObject { static func makeLabelWithRecorder(_ labelText: String, _ rawName: String, _ shortcutString: String, _ clearable: Bool = true, labelPosition: LabelPosition = .leftWithSeparator) -> [NSView] { let input = CustomRecorderControl(shortcutString, clearable) - let views = makeLabelWithProvidedControl(labelText, rawName, input, labelPosition: labelPosition, extraAction: { _ in GeneralTab.shortcutChangedCallback(input) }) - GeneralTab.shortcutChangedCallback(input) + let views = makeLabelWithProvidedControl(labelText, rawName, input, labelPosition: labelPosition, extraAction: { _ in ControlsTab.shortcutChangedCallback(input) }) + ControlsTab.shortcutChangedCallback(input) return views } @@ -35,10 +35,10 @@ class LabelAndControl: NSObject { } static func makeLabelWithDropdown(_ labelText: String, _ rawName: String, _ values: [MacroPreference], _ suffixText: String? = nil) -> [NSView] { - return makeLabelWithProvidedControl(labelText, rawName, makeDropDown(rawName, values), suffixText) + return makeLabelWithProvidedControl(labelText, rawName, dropdown_(rawName, values), suffixText) } - static func makeDropDown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSPopUpButton { + static func dropdown_(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSPopUpButton { let popUp = NSPopUpButton() popUp.translatesAutoresizingMaskIntoConstraints = false popUp.addItems(withTitles: macroPreferences.map { $0.localizedString }) @@ -46,6 +46,11 @@ class LabelAndControl: NSObject { return popUp } + static func makeDropdown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSControl { + let dropdown = dropdown_(rawName, macroPreferences) + return setupControl(dropdown, rawName) + } + static func makeRadioButtons(_ macroPreferences: [MacroPreference], _ rawName: String, extraAction: ActionClosure? = nil) -> [NSButton] { var i = 0 return macroPreferences.map { @@ -111,11 +116,14 @@ class LabelAndControl: NSObject { } } - static func makeLabel(_ labelText: String, _ labelPosition: LabelPosition = .leftWithoutSeparator) -> NSTextField { + static func makeLabel(_ labelText: String, _ labelPosition: LabelPosition = .leftWithoutSeparator, shouldFit: Bool = true) -> NSTextField { let label = TextField(labelText) label.isSelectable = false label.usesSingleLineMode = true label.alignment = .right + if shouldFit { + label.fit() + } return label } @@ -170,13 +178,30 @@ enum ControlIdentifierDiscriminator: String { case SUFFIX = "_suffix" } -class TabView: NSTabView { - // without the left/right value, the whole view is shifted to the right for some reason -// let insets = NSEdgeInsets(top: 0, left: 7, bottom: 0, right: 7) -// override var alignmentRectInsets: NSEdgeInsets { get { insets } } +class TabView: NSTabView, NSTabViewDelegate { + // removing insets fixes a bug where tab views shift to the right and bottom by 7px when switching to tab #2 + let insets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) + override var alignmentRectInsets: NSEdgeInsets { get { insets } } + + // workaround: this is the only I found to have NSTabView fittingSize be correct + override var intrinsicContentSize: NSSize { + get { + NSSize(width: selectedTabViewItem!.view!.fittingSize.width + TabView.padding * 2, + height: selectedTabViewItem!.view!.fittingSize.height + TabView.padding * 2 + subviews[0].frame.height) + } + } - convenience init() { + static let padding = CGFloat(7) + + convenience init(_ labelsAndViews: [(String, NSView)]) { self.init(frame: .zero) translatesAutoresizingMaskIntoConstraints = false + labelsAndViews.enumerated().forEach { (i, tuple) in + let tab = NSTabViewItem(identifier: i) + tab.label = tuple.0 + tab.view = tuple.1 + addTabViewItem(tab) + tab.view!.fit() + } } } diff --git a/src/ui/preferences-window/tabs/AboutTab.swift b/src/ui/preferences-window/tabs/AboutTab.swift index 8c4d5cb98..0dff53a14 100644 --- a/src/ui/preferences-window/tabs/AboutTab.swift +++ b/src/ui/preferences-window/tabs/AboutTab.swift @@ -31,6 +31,7 @@ class AboutTab: NSViewController, PreferencePane { sendFeedbackCell.xPlacement = .center sendFeedbackCell.row!.topPadding = GridView.interPadding grid.fit() - view = grid + + setView(grid) } } diff --git a/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift b/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift index 5ed2f2a22..a98a370f2 100644 --- a/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift +++ b/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift @@ -26,6 +26,8 @@ class AcknowledgmentsTab: NSViewController, PreferencePane { subGrid.fit() let scrollView = ScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.documentView!.translatesAutoresizingMaskIntoConstraints = false scrollView.scrollerKnobStyle = .default scrollView.documentView!.subviews = [subGrid] let totalWidth = subGrid.fittingSize.width @@ -35,6 +37,6 @@ class AcknowledgmentsTab: NSViewController, PreferencePane { scrollView.documentView!.frame.size = subGrid.fittingSize scrollView.fit(totalWidth, totalHeight) - view = scrollView + setView(scrollView) } } diff --git a/src/ui/preferences-window/tabs/AppearanceTab.swift b/src/ui/preferences-window/tabs/AppearanceTab.swift index 87cfc8fde..19a729a41 100644 --- a/src/ui/preferences-window/tabs/AppearanceTab.swift +++ b/src/ui/preferences-window/tabs/AppearanceTab.swift @@ -29,6 +29,6 @@ class AppearanceTab: NSViewController, PreferencePane { grid.rowAlignment = .lastBaseline grid.fit() - view = grid + setView(grid) } } diff --git a/src/ui/preferences-window/tabs/BlacklistsTab.swift b/src/ui/preferences-window/tabs/BlacklistsTab.swift index 5abd33693..4aecd1433 100644 --- a/src/ui/preferences-window/tabs/BlacklistsTab.swift +++ b/src/ui/preferences-window/tabs/BlacklistsTab.swift @@ -23,6 +23,7 @@ class BlacklistsTab: NSViewController, PreferencePane { ]) grid.row(at: 2).topPadding = GridView.interPadding * 1.5 grid.fit() - view = grid + + setView(grid) } } diff --git a/src/ui/preferences-window/tabs/ControlsTab.swift b/src/ui/preferences-window/tabs/ControlsTab.swift new file mode 100644 index 000000000..b339649ff --- /dev/null +++ b/src/ui/preferences-window/tabs/ControlsTab.swift @@ -0,0 +1,154 @@ +import Cocoa +import ShortcutRecorder +import Preferences + +class ControlsTab: NSViewController, PreferencePane { + let preferencePaneIdentifier = PreferencePane.Identifier("Controls") + let preferencePaneTitle = NSLocalizedString("Controls", comment: "") + let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)! + + static var nextWindowShortcut: NSControl! + static var nextWindowShortcut2: NSControl! + static var shortcuts = [String: Shortcut]() + static var shortcutsActions = [ + "holdShortcut": { App.app.focusTarget() }, + "holdShortcut2": { App.app.focusTarget() }, + "focusWindowShortcut": { App.app.focusTarget() }, + "nextWindowShortcut": { App.app.showUiOrCycleSelection(0) }, + "nextWindowShortcut2": { App.app.showUiOrCycleSelection(1) }, + "previousWindowShortcut": { App.app.cycleSelection(.trailing) }, + "→": { App.app.cycleSelection(.right) }, + "←": { App.app.cycleSelection(.left) }, + "↑": { App.app.cycleSelection(.up) }, + "↓": { App.app.cycleSelection(.down) }, + "cancelShortcut": { App.app.hideUi() }, + "closeWindowShortcut": { App.app.closeSelectedWindow() }, + "minDeminWindowShortcut": { App.app.minDeminSelectedWindow() }, + "quitAppShortcut": { App.app.quitSelectedApp() }, + "hideShowAppShortcut": { App.app.hideShowSelectedApp() }, + ] + + override func loadView() { + let shortcutStyle = LabelAndControl.makeLabelWithDropdown(NSLocalizedString("then release:", comment: ""), "shortcutStyle", ShortcutStylePreference.allCases) + let focusWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Focus selected window", comment: ""), "focusWindowShortcut", Preferences.focusWindowShortcut, labelPosition: .right) + let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), "previousWindowShortcut", Preferences.previousWindowShortcut, labelPosition: .right) + let cancelShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Cancel and hide", comment: ""), "cancelShortcut", Preferences.cancelShortcut, labelPosition: .right) + let closeWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Close window", comment: ""), "closeWindowShortcut", Preferences.closeWindowShortcut, labelPosition: .right) + let minDeminWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Minimize/Deminimize window", comment: ""), "minDeminWindowShortcut", Preferences.minDeminWindowShortcut, labelPosition: .right) + let quitAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Quit app", comment: ""), "quitAppShortcut", Preferences.quitAppShortcut, labelPosition: .right) + let hideShowAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hide/Show app", comment: ""), "hideShowAppShortcut", Preferences.hideShowAppShortcut, labelPosition: .right) + let enableArrows = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Arrow keys", comment: ""), "arrowKeysEnabled", extraAction: ControlsTab.arrowKeysEnabledCallback, labelPosition: .right) + let enableMouse = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Mouse hover", comment: ""), "mouseHoverEnabled", labelPosition: .right) + let checkboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Also select windows using:", comment: "")) + let checkboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical) + let shortcuts = StackView([focusWindowShortcut, previousWindowShortcut, cancelShortcut, closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { (view: [NSView]) in StackView(view) }, .vertical) + let orPress = LabelAndControl.makeLabel(NSLocalizedString("While open, press:", comment: ""), shouldFit: false) + let (nextWindowShortcut, tab1View) = toShowSection("") + let (nextWindowShortcut2, tab2View) = toShowSection("2") + let tabView = TabView([(NSLocalizedString("Shortcut 1", comment: ""), tab1View), (NSLocalizedString("Shortcut 2", comment: ""), tab2View)]) + + ControlsTab.nextWindowShortcut = nextWindowShortcut[0] as! NSControl + ControlsTab.nextWindowShortcut2 = nextWindowShortcut2[0] as! NSControl + ControlsTab.arrowKeysEnabledCallback(enableArrows[0] as! NSControl) + + let grid = GridView([ + [tabView], + shortcutStyle, + [orPress, shortcuts], + [checkboxesExplanations, checkboxes], + ]) + grid.column(at: 0).xPlacement = .trailing + grid.mergeCells(inHorizontalRange: NSRange(location: 0, length: 2), verticalRange: NSRange(location: 0, length: 1)) + grid.cell(atColumnIndex: 0, rowIndex: 0).xPlacement = .leading + + // TODO: better layout logic. Maybe freeze the width of the preference window and have labels wrap on multiple lines + // currently this looks bad if the right column inside the tabView is larger than the right column of the top gridView + let leftColumnWidthTabView = tab1View.column(at: 0).width() + let leftColumnWidthTopView = grid.column(at: 0).width(0) + debugPrint("hey", leftColumnWidthTabView, leftColumnWidthTopView) + if leftColumnWidthTabView > leftColumnWidthTopView { + orPress.fit(tab1View.column(at: 0).width() + GridView.interPadding + TabView.padding, orPress.fittingSize.height) + } else { + orPress.fit() + tabView.leftAnchor.constraint(equalTo: tabView.superview!.leftAnchor, constant: leftColumnWidthTopView - leftColumnWidthTabView + 3).isActive = true + } + + setView(grid) + } + + private func toShowSection(_ postfix: String) -> ([NSView], GridView) { + let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show the following windows:", comment: "")) + var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), "holdShortcut" + postfix, Preferences.holdShortcut, false, labelPosition: .leftWithoutSeparator) + holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("and press:", comment: ""))) + let holdAndPress = StackView(holdShortcut) + let appsToShow = LabelAndControl.makeDropdown("appsToShow" + postfix, AppsToShowPreference.allCases) + let spacesToShow = LabelAndControl.makeDropdown("spacesToShow" + postfix, SpacesToShowPreference.allCases) + let screensToShow = LabelAndControl.makeDropdown("screensToShow" + postfix, ScreensToShowPreference.allCases) + let showMinimizedWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Minimized", comment: ""), "showMinimizedWindows" + postfix, labelPosition: .right)) + let showHiddenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hidden", comment: ""), "showHiddenWindows" + postfix, labelPosition: .right)) + let showFullscreenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Fullscreen", comment: ""), "showFullscreenWindows" + postfix, labelPosition: .right)) + let nextWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select next window", comment: ""), "nextWindowShortcut" + postfix, Preferences.nextWindowShortcut[postfix == "" ? 0 : 1], labelPosition: .right) + let toShowDropdowns = StackView([appsToShow, spacesToShow, screensToShow, showMinimizedWindows, showHiddenWindows, showFullscreenWindows], .vertical, false) + toShowDropdowns.spacing = TabView.padding + toShowDropdowns.fit() + let tab = GridView([ + [toShowExplanations, toShowDropdowns], + [holdAndPress, StackView(nextWindowShortcut)], + ], TabView.padding) + tab.column(at: 0).xPlacement = .trailing + tab.fit() + return (nextWindowShortcut, tab) + } + + private static func addShortcut(_ type: KeyEventType, _ shortcut: Shortcut, _ controlId: String) { + removeShortcutIfExists(controlId, type) // remove the previous shortcut + shortcuts[controlId] = shortcut + } + + @objc static func shortcutChangedCallback(_ sender: NSControl) { + let controlId = sender.identifier!.rawValue + if controlId == "holdShortcut" { + addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut)!, controlId) + if let s = nextWindowShortcut { + shortcutChangedCallback(s) + } + } else if controlId == "holdShortcut2" { + addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut2)!, controlId) + if let s = nextWindowShortcut2 { + shortcutChangedCallback(s) + } + } else { + let newValue = shortcutStringValue(controlId, sender) + if newValue.isEmpty { + removeShortcutIfExists(controlId, .down) + } else { + addShortcut(.down, Shortcut(keyEquivalent: newValue)!, controlId) + } + } + } + + static func shortcutStringValue(_ controlId: String, _ sender: NSControl) -> String { + let baseValue = (sender as! RecorderControl).stringValue + if controlId == "nextWindowShortcut" || controlId == "nextWindowShortcut2" { + let holdShortcut = controlId == "nextWindowShortcut" ? Preferences.holdShortcut : Preferences.holdShortcut2 + // remove the holdShortcut character in case they also use it in the other shortcuts + return holdShortcut + holdShortcut.reduce(baseValue, { $0.replacingOccurrences(of: String($1), with: "") }) + } + return baseValue + } + + @objc static func arrowKeysEnabledCallback(_ sender: NSControl) { + let keys = ["←", "→", "↑", "↓"] + if (sender as! NSButton).state == .on { + keys.forEach { addShortcut(.down, Shortcut(keyEquivalent: $0)!, $0) } + } else { + keys.forEach { removeShortcutIfExists($0, .down) } + } + } + + private static func removeShortcutIfExists(_ controlId: String, _ type: KeyEventType) { + if let a = shortcuts[controlId] { + shortcuts.removeValue(forKey: controlId) + } + } +} diff --git a/src/ui/preferences-window/tabs/GeneralTab.swift b/src/ui/preferences-window/tabs/GeneralTab.swift index c3c17cfb2..3130e5a93 100644 --- a/src/ui/preferences-window/tabs/GeneralTab.swift +++ b/src/ui/preferences-window/tabs/GeneralTab.swift @@ -1,5 +1,4 @@ import Cocoa -import ShortcutRecorder import Preferences class GeneralTab: NSViewController, PreferencePane { @@ -7,165 +6,21 @@ class GeneralTab: NSViewController, PreferencePane { let preferencePaneTitle = NSLocalizedString("General", comment: "") let toolbarItemIcon = NSImage(named: NSImage.preferencesGeneralName)! - static var shortcutActions = [String: ShortcutAction]() - static var shortcutsDependentOnHoldShortcut = [NSControl]() - static var shortcutsActionsBlocks = [ - "holdShortcut": { App.app.focusTarget() }, - "nextWindowShortcut": { App.app.showUiOrCycleSelection(0) }, - "nextWindowShortcut2": { App.app.showUiOrCycleSelection(1) }, - "previousWindowShortcut": { App.app.cycleSelection(.trailing) }, - "→": { App.app.cycleSelection(.right) }, - "←": { App.app.cycleSelection(.left) }, - "↑": { App.app.cycleSelection(.up) }, - "↓": { App.app.cycleSelection(.down) }, - "cancelShortcut": { App.app.hideUi() }, - "closeWindowShortcut": { App.app.closeSelectedWindow() }, - "minDeminWindowShortcut": { App.app.minDeminSelectedWindow() }, - "quitAppShortcut": { App.app.quitSelectedApp() }, - "hideShowAppShortcut": { App.app.hideShowSelectedApp() }, - ] - override func loadView() { let startAtLogin = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Start at login:", comment: ""), "startAtLogin", extraAction: startAtLoginCallback) let hideMenubarIcon = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hide menubar icon:", comment: ""), "hideMenubarIcon", extraAction: hideMenubarIconCallback) - var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), "holdShortcut", Preferences.holdShortcut, false, labelPosition: .leftWithoutSeparator) - holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("and press:", comment: ""))) - let previousWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select previous window", comment: ""), "previousWindowShortcut", Preferences.previousWindowShortcut, labelPosition: .right) - let cancelShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Cancel and hide", comment: ""), "cancelShortcut", Preferences.cancelShortcut, labelPosition: .right) - let closeWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Close window", comment: ""), "closeWindowShortcut", Preferences.closeWindowShortcut, labelPosition: .right) - let minDeminWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Minimize/Deminimize window", comment: ""), "minDeminWindowShortcut", Preferences.minDeminWindowShortcut, labelPosition: .right) - let quitAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Quit app", comment: ""), "quitAppShortcut", Preferences.quitAppShortcut, labelPosition: .right) - let hideShowAppShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hide/Show app", comment: ""), "hideShowAppShortcut", Preferences.hideShowAppShortcut, labelPosition: .right) - let enableArrows = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Arrow keys", comment: ""), "arrowKeysEnabled", extraAction: GeneralTab.arrowKeysEnabledCallback, labelPosition: .right) - let enableMouse = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Mouse hover", comment: ""), "mouseHoverEnabled", labelPosition: .right) - let holdAndPress = StackView(holdShortcut) - let checkboxesExplanations = LabelAndControl.makeLabel(NSLocalizedString("Select windows using:", comment: "")) - let checkboxes = StackView([StackView(enableArrows), StackView(enableMouse)], .vertical) - let shortcuts = StackView([previousWindowShortcut, cancelShortcut, closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { (view: [NSView]) in StackView(view) }, .vertical) - let thenRelease = LabelAndControl.makeLabel(NSLocalizedString("then release:", comment: "")) - let orPress = LabelAndControl.makeLabel(NSLocalizedString("or press:", comment: "")) - let focusSelectedWindow = LabelAndControl.makeLabel(NSLocalizedString("Focus selected window", comment: "")) - let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show the following windows:", comment: "")) - - let tab1 = NSTabViewItem(identifier: 1) - tab1.label = "1" - let (nextWindowShortcut, tab1View) = toShowSection("") - tab1.view = tab1View - let tab2 = NSTabViewItem(identifier: 2) - tab2.label = "2" - let (nextWindowShortcut2, tab2View) = toShowSection("2") - tab2.view = tab2View - let tabView = TabView() - tabView.addTabViewItem(tab1) - tabView.addTabViewItem(tab2) - tabView.tabPosition = .right - tabView.heightAnchor.constraint(equalToConstant: tabView.fittingSize.height - 8).isActive = true - let vertical1 = StackView([toShowExplanations, holdAndPress], .vertical, false, top: 5, bottom: 3) - vertical1.alignment = .trailing - vertical1.distribution = .equalCentering - vertical1.heightAnchor.constraint(equalToConstant: tabView.fittingSize.height - 14).isActive = true let grid = GridView([ startAtLogin, hideMenubarIcon, - [vertical1, tabView], - [thenRelease, focusSelectedWindow], - [orPress, shortcuts], - [checkboxesExplanations, checkboxes], ]) grid.column(at: 0).xPlacement = .trailing - grid.row(at: 2).rowAlignment = .none - [2, 5].forEach { grid.row(at: $0).topPadding = GridView.interPadding } grid.fit() - GeneralTab.shortcutsDependentOnHoldShortcut.append(contentsOf: [enableArrows[0] as! NSControl] + - [nextWindowShortcut, nextWindowShortcut2, previousWindowShortcut, cancelShortcut, - closeWindowShortcut, minDeminWindowShortcut, quitAppShortcut, hideShowAppShortcut].map { $0[0] as! NSControl }) - GeneralTab.arrowKeysEnabledCallback(enableArrows[0] as! NSControl) + setView(grid) + startAtLoginCallback(startAtLogin[1] as! NSControl) hideMenubarIconCallback(hideMenubarIcon[1] as! NSControl) - - view = grid - } - - private func toShowSection(_ postfix: String) -> ([NSView], NSView) { - let appsToShow = dropdown("appsToShow" + postfix, AppsToShowPreference.allCases) - let spacesToShow = dropdown("spacesToShow" + postfix, SpacesToShowPreference.allCases) - let screensToShow = dropdown("screensToShow" + postfix, ScreensToShowPreference.allCases) - let showMinimizedWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Minimized", comment: ""), "showMinimizedWindows" + postfix, labelPosition: .right)) - let showHiddenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Hidden", comment: ""), "showHiddenWindows" + postfix, labelPosition: .right)) - let showFullscreenWindows = StackView(LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Fullscreen", comment: ""), "showFullscreenWindows" + postfix, labelPosition: .right)) - let nextWindowShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Select next window", comment: ""), "nextWindowShortcut" + postfix, Preferences.nextWindowShortcut[postfix == "" ? 0 : 1], labelPosition: .right) - let toShowDropdowns = StackView([appsToShow, spacesToShow, screensToShow, showMinimizedWindows, showHiddenWindows, showFullscreenWindows], .vertical, false) - toShowDropdowns.spacing = 8 - toShowDropdowns.fit() - let tab = StackView([toShowDropdowns, StackView(nextWindowShortcut)], .vertical, false) - tab.spacing = GridView.padding - tab.fit() - return (nextWindowShortcut, tab) - } - - private func dropdown(_ rawName: String, _ macroPreferences: [MacroPreference]) -> NSControl { - let dropdown = LabelAndControl.makeDropDown(rawName, macroPreferences) - return LabelAndControl.setupControl(dropdown, rawName) - } - - private static func addShortcut(_ type: KeyEventType, _ shortcut: Shortcut, _ controlId: String) { - removeShortcutIfExists(controlId, type) // remove the previous shortcut - shortcutActions[controlId] = ShortcutAction(shortcut: shortcut, actionHandler: { _ in - let isShortcutInitiatingTheApp = ["nextWindowShortcut", "nextWindowShortcut2"].contains(controlId) - if isShortcutInitiatingTheApp { - App.app.appIsBeingUsed = true - } - if App.app.appIsBeingUsed { - let isShortcutClosingTheUi = ["holdShortcut", "cancelShortcut"].contains(controlId) - if isShortcutClosingTheUi { - App.app.appIsBeingUsed = false - App.app.isFirstSummon = true - } - DispatchQueue.main.async { () -> () in shortcutsActionsBlocks[controlId]!() } - } - return true - }) - App.shortcutMonitor.addAction(shortcutActions[controlId]!, forKeyEvent: type) - } - - @objc static func shortcutChangedCallback(_ sender: NSControl) { - let controlId = sender.identifier!.rawValue - if controlId == "holdShortcut" { - addShortcut(.up, Shortcut(keyEquivalent: Preferences.holdShortcut)!, controlId) - shortcutsDependentOnHoldShortcut.forEach { - if $0.identifier!.rawValue == "arrowKeysEnabled" { - GeneralTab.arrowKeysEnabledCallback($0) - } else { - GeneralTab.shortcutChangedCallback($0) - } - } - } else { - // remove the holdShortcut character in case they also use it in the other shortcuts - let newValue = Preferences.holdShortcut.reduce((sender as! RecorderControl).stringValue, { $0.replacingOccurrences(of: String($1), with: "") }) - if newValue.isEmpty { - removeShortcutIfExists(controlId, .down) - return - } - addShortcut(.down, Shortcut(keyEquivalent: Preferences.holdShortcut + newValue)!, controlId) - } - } - - @objc static func arrowKeysEnabledCallback(_ sender: NSControl) { - let keys = ["←", "→", "↑", "↓"] - if (sender as! NSButton).state == .on { - keys.forEach { addShortcut(.down, Shortcut(keyEquivalent: Preferences.holdShortcut + $0)!, $0) } - } else { - keys.forEach { removeShortcutIfExists($0, .down) } - } - } - - private static func removeShortcutIfExists(_ controlId: String, _ type: KeyEventType) { - if let a = shortcutActions[controlId] { - App.shortcutMonitor.removeAction(_: a, forKeyEvent: type) - shortcutActions.removeValue(forKey: controlId) - } } // adding/removing login item depending on the checkbox state diff --git a/src/ui/preferences-window/tabs/PoliciesTab.swift b/src/ui/preferences-window/tabs/PoliciesTab.swift index 8c1db9c85..0322be795 100644 --- a/src/ui/preferences-window/tabs/PoliciesTab.swift +++ b/src/ui/preferences-window/tabs/PoliciesTab.swift @@ -36,7 +36,8 @@ class PoliciesTab: NSViewController, PreferencePane { grid.row(at: 2).topPadding = GridView.interPadding * 1.5 grid.fit() - view = grid + setView(grid) + UserDefaultsEvents.observe() }