diff --git a/Assets/Screenshots/noctalia-dark-1.png b/Assets/Screenshots/noctalia-dark-1.png index cff528ddb..bc40edcb0 100644 Binary files a/Assets/Screenshots/noctalia-dark-1.png and b/Assets/Screenshots/noctalia-dark-1.png differ diff --git a/Assets/Screenshots/noctalia-dark-2.png b/Assets/Screenshots/noctalia-dark-2.png index cab6eb55a..f6a3d793e 100644 Binary files a/Assets/Screenshots/noctalia-dark-2.png and b/Assets/Screenshots/noctalia-dark-2.png differ diff --git a/Assets/Screenshots/noctalia-dark-3.png b/Assets/Screenshots/noctalia-dark-3.png index 11190b037..4660f7baf 100644 Binary files a/Assets/Screenshots/noctalia-dark-3.png and b/Assets/Screenshots/noctalia-dark-3.png differ diff --git a/Assets/Screenshots/noctalia-light-1.png b/Assets/Screenshots/noctalia-light-1.png index 327dfb993..5046ebf59 100644 Binary files a/Assets/Screenshots/noctalia-light-1.png and b/Assets/Screenshots/noctalia-light-1.png differ diff --git a/Assets/Screenshots/noctalia-light-2.png b/Assets/Screenshots/noctalia-light-2.png index 0d1c46e9a..ecfd23439 100644 Binary files a/Assets/Screenshots/noctalia-light-2.png and b/Assets/Screenshots/noctalia-light-2.png differ diff --git a/Assets/Screenshots/noctalia-light-3.png b/Assets/Screenshots/noctalia-light-3.png index 171fbf6d1..cb7ad2b4c 100644 Binary files a/Assets/Screenshots/noctalia-light-3.png and b/Assets/Screenshots/noctalia-light-3.png differ diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 3595b249b..31aa467ae 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1675,6 +1675,28 @@ "label": "Allgemein" } }, + "types": { + "brightness": { + "description": "OSD anzeigen, wenn sich die Bildschirmhelligkeit ändert.", + "label": "Helligkeit" + }, + "input-volume": { + "description": "OSD anzeigen, wenn sich die Mikrofonlautstärke ändert.", + "label": "Eingangslautstärke" + }, + "lockkey": { + "description": "OSD anzeigen, wenn Feststelltaste, Num-Taste oder Rollen-Taste umgeschaltet werden.", + "label": "Feststelltasten" + }, + "section": { + "description": "Wähle, welche Ereignisse das On-Screen Display auslösen.", + "label": "OSD-Typen" + }, + "volume": { + "description": "OSD anzeigen, wenn sich die Ausgabelautstärke ändert.", + "label": "Ausgangslautstärke" + } + }, "show-lock-key-notifications": { "description": "Benachrichtigungen anzeigen, wenn sich der Status von Feststelltaste, Num-Taste oder Rollen-Taste ändert.", "label": "Tastensperr-Benachrichtigungen anzeigen" diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 37c6fe45f..7f14d91b1 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1675,11 +1675,29 @@ "label": "General" } }, - "show-lock-key-notifications": { - "description": "Show notifications when Caps Lock, Num Lock, or Scroll Lock keys are toggled.", - "label": "Show lock key notifications" - }, - "title": "On-Screen Display" + "title": "On-Screen Display", + "types": { + "brightness": { + "description": "Show OSD when screen brightness changes.", + "label": "Brightness" + }, + "input-volume": { + "description": "Show OSD when microphone volume changes.", + "label": "Input Volume" + }, + "lockkey": { + "description": "Show OSD when Caps Lock, Num Lock, or Scroll Lock are toggled.", + "label": "Lock Keys" + }, + "section": { + "description": "Choose which events trigger the on-screen display.", + "label": "OSD Types" + }, + "volume": { + "description": "Show OSD when audio output volume changes.", + "label": "Output Volume" + } + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 6097ce79a..1ec9b6519 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1675,6 +1675,28 @@ "label": "General" } }, + "types": { + "brightness": { + "description": "Mostrar el OSD cuando cambie el brillo de la pantalla.", + "label": "Brillo" + }, + "input-volume": { + "description": "Mostrar el OSD cuando cambie el volumen del micrófono.", + "label": "Volumen de entrada" + }, + "lockkey": { + "description": "Mostrar el OSD cuando se activen o desactiven Bloq Mayús, Bloq Num o Bloq Despl.", + "label": "Teclas de bloqueo" + }, + "section": { + "description": "Elige qué eventos activan la visualización en pantalla.", + "label": "Tipos de OSD" + }, + "volume": { + "description": "Mostrar el OSD cuando cambie el volumen de salida de audio.", + "label": "Volumen de salida" + } + }, "show-lock-key-notifications": { "description": "Mostrar notificaciones cuando se activen o desactiven las teclas Bloq Mayús, Bloq Num o Bloq Despl.", "label": "Mostrar notificaciones de teclas de bloqueo" diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 425650f94..763e80944 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1675,6 +1675,28 @@ "label": "Général" } }, + "types": { + "brightness": { + "description": "Afficher l'OSD lorsque la luminosité de l'écran change.", + "label": "Luminosité" + }, + "input-volume": { + "description": "Afficher l'OSD lorsque le volume du microphone change.", + "label": "Volume d'entrée" + }, + "lockkey": { + "description": "Afficher l'OSD lorsque Verr Maj, Verr Num ou Arrêt défil est activée ou désactivée.", + "label": "Touches de verrouillage" + }, + "section": { + "description": "Choisissez quels événements déclenchent l'affichage à l'écran.", + "label": "Types d'OSD" + }, + "volume": { + "description": "Afficher l'OSD lorsque le volume de sortie audio change.", + "label": "Volume de sortie" + } + }, "show-lock-key-notifications": { "description": "Afficher les notifications lorsque les touches Verr. Maj., Verr. Num. ou Arrêt défil. sont activées/désactivées.", "label": "Afficher les notifications des touches de verrouillage" diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index 215ffc51c..8927d2f56 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -1675,6 +1675,28 @@ "label": "Algemeen" } }, + "types": { + "brightness": { + "description": "Toon het OSD wanneer de schermhelderheid verandert.", + "label": "Helderheid" + }, + "input-volume": { + "description": "Toon het OSD wanneer het microfoonvolume verandert.", + "label": "Invoervolume" + }, + "lockkey": { + "description": "Toon het OSD wanneer Caps Lock, Num Lock of Scroll Lock wordt omgeschakeld.", + "label": "Vergrendeltoetsen" + }, + "section": { + "description": "Kies welke gebeurtenissen de on-screenweergave activeren.", + "label": "OSD-typen" + }, + "volume": { + "description": "Toon het OSD wanneer het uitvoervolume verandert.", + "label": "Uitvoervolume" + } + }, "show-lock-key-notifications": { "description": "Toon meldingen wanneer Caps Lock, Num Lock of Scroll Lock toetsen worden omgeschakeld.", "label": "Vergrendeltoetsmeldingen tonen" diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 9bebce308..02b449e69 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1675,6 +1675,28 @@ "label": "Geral" } }, + "types": { + "brightness": { + "description": "Mostrar o OSD quando o brilho da tela mudar.", + "label": "Brilho" + }, + "input-volume": { + "description": "Mostrar o OSD quando o volume do microfone mudar.", + "label": "Volume de entrada" + }, + "lockkey": { + "description": "Mostrar o OSD quando Caps Lock, Num Lock ou Scroll Lock forem alternadas.", + "label": "Teclas de bloqueio" + }, + "section": { + "description": "Escolha quais eventos disparam a exibição na tela.", + "label": "Tipos de OSD" + }, + "volume": { + "description": "Mostrar o OSD quando o volume de saída de áudio mudar.", + "label": "Volume de saída" + } + }, "show-lock-key-notifications": { "description": "Mostrar notificações quando as teclas Caps Lock, Num Lock ou Scroll Lock forem alternadas.", "label": "Mostrar notificações das teclas de bloqueio" diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index 14c0aef8f..9fa894687 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -1675,6 +1675,28 @@ "label": "Общие" } }, + "types": { + "brightness": { + "description": "Показывать OSD при изменении яркости экрана.", + "label": "Яркость" + }, + "input-volume": { + "description": "Показывать OSD при изменении громкости микрофона.", + "label": "Входная громкость" + }, + "lockkey": { + "description": "Показывать OSD при переключении клавиш Caps Lock, Num Lock или Scroll Lock.", + "label": "Клавиши блокировки" + }, + "section": { + "description": "Выберите события, которые запускают экранное отображение.", + "label": "Типы OSD" + }, + "volume": { + "description": "Показывать OSD при изменении громкости аудиовыхода.", + "label": "Выходная громкость" + } + }, "show-lock-key-notifications": { "description": "Показывать уведомления при переключении клавиш Caps Lock, Num Lock или Scroll Lock.", "label": "Показывать уведомления о состоянии клавиш" diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index d1720844d..7ffcc6925 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -1675,6 +1675,28 @@ "label": "Genel" } }, + "types": { + "brightness": { + "description": "Ekran parlaklığı değiştiğinde OSD'yi göster.", + "label": "Parlaklık" + }, + "input-volume": { + "description": "Mikrofon ses düzeyi değiştiğinde OSD'yi göster.", + "label": "Giriş sesi" + }, + "lockkey": { + "description": "Caps Lock, Num Lock veya Scroll Lock değiştirildiğinde OSD'yi göster.", + "label": "Kilit tuşları" + }, + "section": { + "description": "Ekran göstergesini tetikleyen olayları seçin.", + "label": "OSD türleri" + }, + "volume": { + "description": "Ses çıkış düzeyi değiştiğinde OSD'yi göster.", + "label": "Çıkış sesi" + } + }, "show-lock-key-notifications": { "description": "Caps Lock, Num Lock veya Scroll Lock tuşları değiştirildiğinde bildirimleri göster.", "label": "Kilit tuşu bildirimlerini göster" diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index 7eb0d75cd..cd51518f3 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -1675,6 +1675,28 @@ "label": "Загальні" } }, + "types": { + "brightness": { + "description": "Показувати OSD, коли змінюється яскравість екрана.", + "label": "Яскравість" + }, + "input-volume": { + "description": "Показувати OSD, коли змінюється гучність мікрофона.", + "label": "Вхідна гучність" + }, + "lockkey": { + "description": "Показувати OSD, коли перемикаються Caps Lock, Num Lock або Scroll Lock.", + "label": "Клавіші блокування" + }, + "section": { + "description": "Виберіть події, які запускають екранну індикацію.", + "label": "Типи OSD" + }, + "volume": { + "description": "Показувати OSD, коли змінюється гучність аудіовиходу.", + "label": "Вихідна гучність" + } + }, "show-lock-key-notifications": { "description": "Показувати сповіщення, коли перемикаються клавіші Caps Lock, Num Lock або Scroll Lock.", "label": "Показувати сповіщення про стан клавіш" diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 064946a8f..7efc5c35d 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1675,6 +1675,28 @@ "label": "常规" } }, + "types": { + "brightness": { + "description": "当屏幕亮度发生变化时显示 OSD。", + "label": "亮度" + }, + "input-volume": { + "description": "当麦克风音量发生变化时显示 OSD。", + "label": "输入音量" + }, + "lockkey": { + "description": "当切换大写锁定、数字锁定或滚动锁定时显示 OSD。", + "label": "锁定键" + }, + "section": { + "description": "选择哪些事件会触发屏显菜单。", + "label": "OSD 类型" + }, + "volume": { + "description": "当音频输出音量发生变化时显示 OSD。", + "label": "输出音量" + } + }, "show-lock-key-notifications": { "description": "当大写锁定键、数字锁定键或滚动锁定键被切换时显示通知。", "label": "显示锁定键通知" diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 44b129f48..ec5773a1f 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -1,5 +1,5 @@ { - "settingsVersion": 23, + "settingsVersion": 24, "setupCompleted": false, "bar": { "position": "top", @@ -280,12 +280,12 @@ }, "osd": { "enabled": true, + "enabledTypes": [0, 1, 2, 3], "location": "top_right", "monitors": [], "autoHideMs": 2000, "overlayLayer": true, - "backgroundOpacity": 1, - "showLockKeyNotifications": true + "backgroundOpacity": 1 }, "audio": { "volumeStep": 5, diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 9d793d55b..0ec81bd36 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -14,7 +14,7 @@ Singleton { readonly property alias data: adapter property bool isLoaded: false property bool directoriesCreated: false - property int settingsVersion: 23 + property int settingsVersion: 24 property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" // Define our app directories @@ -455,12 +455,12 @@ Singleton { // on-screen display property JsonObject osd: JsonObject { property bool enabled: true + property var enabledTypes: [0, 1, 2, 3] property string location: "top_right" property list monitors: [] property int autoHideMs: 2000 property bool overlayLayer: true property real backgroundOpacity: 1.0 - property bool showLockKeyNotifications: true } // audio @@ -802,7 +802,100 @@ Singleton { } // ----------------- - // 8th. Migrate ShellState-related files from old cache files to ShellState + // 9th. Normalize OSD enabled types and migrate legacy show* toggles + try { + var osdRawJson = settingsFileView.text(); + if (osdRawJson) { + var osdParsed = JSON.parse(osdRawJson); + if (osdParsed.osd) { + var legacyHandled = false; + + if (osdParsed.osd.enabledTypes === undefined) { + // Some configurations (<= v23) stored booleans like showVolume/showBrightness/etc. + // Convert them into the new enabledTypes array as soon as we detect the legacy shape. + var legacyOsd = osdParsed.osd; + var typeMappings = [ + { + key: "showVolume", + type: 0 + }, + { + key: "showInputVolume", + type: 1 + }, + { + key: "showBrightness", + type: 2 + }, + { + key: "showLockKey", + type: 3 + } + ]; + + var migratedTypes = []; + var sawLegacyKey = false; + + for (var i = 0; i < typeMappings.length; i++) { + var mapping = typeMappings[i]; + if (legacyOsd[mapping.key] !== undefined) + sawLegacyKey = true; + + var enabled = legacyOsd[mapping.key]; + if (enabled === undefined) + enabled = true; // default behaviour before enabledTypes existed + + if (enabled && migratedTypes.indexOf(mapping.type) === -1) + migratedTypes.push(mapping.type); + } + + if (legacyOsd.showLockKeyNotifications !== undefined) { + sawLegacyKey = true; + if (legacyOsd.showLockKeyNotifications) { + if (migratedTypes.indexOf(3) === -1) + migratedTypes.push(3); + } else { + migratedTypes = migratedTypes.filter(function (type) { + return type !== 3; + }); + } + } + + if (sawLegacyKey) { + if (migratedTypes.length === 0) { + migratedTypes = [0, 1, 2, 3]; + } + adapter.osd.enabledTypes = migratedTypes; + Logger.i("Settings", "Migrated legacy OSD toggles to enabledTypes = " + JSON.stringify(migratedTypes)); + legacyHandled = true; + } + } + + // No matter which format the JSON used, hydrate the runtime value from disk so we don't + // accidentally keep the default [0,1,2,3] array after a restart. + if (!legacyHandled && osdParsed.osd.enabledTypes !== undefined) { + var parsedTypes = osdParsed.osd.enabledTypes; + if (Array.isArray(parsedTypes)) { + adapter.osd.enabledTypes = parsedTypes.slice(); + } else if (parsedTypes && typeof parsedTypes === "object" && parsedTypes.length !== undefined) { + // QJsonArray can materialise as a list-like object; convert it to a plain array + var normalized = []; + for (var idx = 0; idx < parsedTypes.length; idx++) { + var value = parsedTypes[idx]; + if (value !== undefined) + normalized.push(value); + } + adapter.osd.enabledTypes = normalized; + } + } + } + } + } catch (error) { + Logger.w("Settings", "Failed to normalize OSD enabledTypes:", error); + } + + // ----------------- + // Migrate ShellState-related files from old cache files to ShellState // This consolidates migrations that were previously in individual service files if (typeof ShellState !== 'undefined' && ShellState.isLoaded) { migrateShellStateFiles(); diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index b8a1f135a..b73a749bc 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -11,6 +11,15 @@ import qs.Widgets // Unified OSD component that displays volume, input volume, and brightness changes Variants { + id: osd + // Do not change the order or it will break settings. + enum Type { + Volume, + InputVolume, + Brightness, + LockKey + } + model: Quickshell.screens.filter(screen => (Settings.data.osd.monitors.includes(screen.name) || Settings.data.osd.monitors.length === 0) && Settings.data.osd.enabled) delegate: Loader { @@ -21,7 +30,7 @@ Variants { active: false // OSD State - property string currentOSDType: "" // "volume", "inputVolume", "brightness", "lockkey", or "" + property int currentOSDType: -1 // OSD.Type enum value, -1 means none property bool startupComplete: false property real currentBrightness: 0 @@ -37,17 +46,17 @@ Variants { // Helper Functions function getIcon() { switch (currentOSDType) { - case "volume": + case OSD.Type.Volume: if (isMuted) return "volume-mute"; if (currentVolume <= Number.EPSILON) return "volume-zero"; return currentVolume <= 0.5 ? "volume-low" : "volume-high"; - case "inputVolume": + case OSD.Type.InputVolume: return isInputMuted ? "microphone-off" : "microphone"; - case "brightness": + case OSD.Type.Brightness: return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high"; - case "lockkey": + case OSD.Type.LockKey: return "keyboard"; default: return ""; @@ -56,13 +65,13 @@ Variants { function getCurrentValue() { switch (currentOSDType) { - case "volume": + case OSD.Type.Volume: return isMuted ? 0 : currentVolume; - case "inputVolume": + case OSD.Type.InputVolume: return isInputMuted ? 0 : currentInputVolume; - case "brightness": + case OSD.Type.Brightness: return currentBrightness; - case "lockkey": + case OSD.Type.LockKey: return 1.0; // Always show 100% when showing lock key status default: return 0; @@ -70,21 +79,21 @@ Variants { } function getMaxValue() { - if (currentOSDType === "volume" || currentOSDType === "inputVolume") { + if (currentOSDType === OSD.Type.Volume || currentOSDType === OSD.Type.InputVolume) { return Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; } return 1.0; } function getDisplayPercentage() { - if (currentOSDType === "lockkey") { + if (currentOSDType === OSD.Type.LockKey) { // For lock keys, return the pre-determined status text return lastLockKeyChanged; } const value = getCurrentValue(); const max = getMaxValue(); - if ((currentOSDType === "volume" || currentOSDType === "inputVolume") && Settings.data.audio.volumeOverdrive) { + if ((currentOSDType === OSD.Type.Volume || currentOSDType === OSD.Type.InputVolume) && Settings.data.audio.volumeOverdrive) { const pct = Math.round(value * 100); return pct + "%"; } @@ -93,30 +102,30 @@ Variants { } function getProgressColor() { - const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted); + const isMutedState = (currentOSDType === OSD.Type.Volume && isMuted) || (currentOSDType === OSD.Type.InputVolume && isInputMuted); if (isMutedState) { return Color.mError; } // When volumeOverdrive is enabled, show error color if volume is above 100% - if ((currentOSDType === "volume" || currentOSDType === "inputVolume") && Settings.data.audio.volumeOverdrive) { + if ((currentOSDType === OSD.Type.Volume || currentOSDType === OSD.Type.InputVolume) && Settings.data.audio.volumeOverdrive) { const value = getCurrentValue(); if (value > 1.0) { return Color.mError; } } // For lock keys, use a different color to indicate the lock state - if (currentOSDType === "lockkey") { + if (currentOSDType === OSD.Type.LockKey) { return LockKeysService.capsLockOn || LockKeysService.numLockOn || LockKeysService.scrollLockOn ? Color.mPrimary : Color.mOnSurfaceVariant; } return Color.mPrimary; } function getIconColor() { - const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted); + const isMutedState = (currentOSDType === OSD.Type.Volume && isMuted) || (currentOSDType === OSD.Type.InputVolume && isInputMuted); if (isMutedState) return Color.mError; - if (currentOSDType === "lockkey") { + if (currentOSDType === OSD.Type.LockKey) { return LockKeysService.capsLockOn || LockKeysService.numLockOn || LockKeysService.scrollLockOn ? Color.mPrimary : Color.mOnSurfaceVariant; } @@ -134,7 +143,16 @@ Variants { function onBrightnessChanged(newBrightness) { currentBrightness = newBrightness; - showOSD("brightness"); + showOSD(OSD.Type.Brightness); + } + + // Check if a specific OSD type is enabled + function isTypeEnabled(type) { + const enabledTypes = Settings.data.osd.enabledTypes || []; + // If enabledTypes is empty, all types are enabled (backwards compatibility) + if (enabledTypes.length === 0) + return true; + return enabledTypes.includes(type); } // OSD Display Control @@ -143,6 +161,10 @@ Variants { if (!startupComplete) return; + // Check if this OSD type is enabled + if (!isTypeEnabled(type)) + return; + currentOSDType = type; if (!root.active) { @@ -174,21 +196,21 @@ Variants { target: AudioService function onVolumeChanged() { - showOSD("volume"); + showOSD(OSD.Type.Volume); } function onMutedChanged() { - showOSD("volume"); + showOSD(OSD.Type.Volume); } function onInputVolumeChanged() { if (AudioService.hasInput) - showOSD("inputVolume"); + showOSD(OSD.Type.InputVolume); } function onInputMutedChanged() { if (AudioService.hasInput) - showOSD("inputVolume"); + showOSD(OSD.Type.InputVolume); } } @@ -205,36 +227,18 @@ Variants { target: LockKeysService function onCapsLockChanged(active) { - if (!Settings.data.osd.showLockKeyNotifications) - return; - root.currentOSDType = "lockkey"; root.lastLockKeyChanged = active ? "CAPS ON" : "CAPS OFF"; - if (!root.active) - root.active = true; - if (root.item) - root.item.showOSD(); + root.showOSD(OSD.Type.LockKey); } function onNumLockChanged(active) { - if (!Settings.data.osd.showLockKeyNotifications) - return; - root.currentOSDType = "lockkey"; root.lastLockKeyChanged = active ? "NUM ON" : "NUM OFF"; - if (!root.active) - root.active = true; - if (root.item) - root.item.showOSD(); + root.showOSD(OSD.Type.LockKey); } function onScrollLockChanged(active) { - if (!Settings.data.osd.showLockKeyNotifications) - return; - root.currentOSDType = "lockkey"; root.lastLockKeyChanged = active ? "SCROLL ON" : "SCROLL OFF"; - if (!root.active) - root.active = true; - if (root.item) - root.item.showOSD(); + root.showOSD(OSD.Type.LockKey); } } @@ -263,7 +267,7 @@ Variants { readonly property bool verticalMode: location === "left" || location === "right" // Dimensions - readonly property bool isShortMode: root.currentOSDType === "lockkey" + readonly property bool isShortMode: root.currentOSDType === OSD.Type.LockKey readonly property int longHWidth: Math.round(320 * Style.uiScaleRatio) readonly property int longHHeight: Math.round(72 * Style.uiScaleRatio) readonly property int shortHWidth: Math.round(180 * Style.uiScaleRatio) @@ -340,7 +344,7 @@ Variants { interval: Style.animationNormal + 50 onTriggered: { osdItem.visible = false; - root.currentOSDType = ""; + root.currentOSDType = -1; root.lastLockKeyChanged = ""; // Reset the lock key change indicator root.active = false; } @@ -408,7 +412,7 @@ Variants { // Lock Key Status Text (replaces progress bar) NText { - visible: root.currentOSDType === "lockkey" + visible: root.currentOSDType === OSD.Type.LockKey text: root.getDisplayPercentage() color: root.getProgressColor() pointSize: Style.fontSizeM @@ -421,7 +425,7 @@ Variants { // Progress Bar for Volume/Brightness Rectangle { - visible: root.currentOSDType !== "lockkey" + visible: root.currentOSDType !== OSD.Type.LockKey Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter height: panel.barThickness @@ -453,7 +457,7 @@ Variants { // Percentage Text for Volume/Brightness NText { - visible: root.currentOSDType !== "lockkey" + visible: root.currentOSDType !== OSD.Type.LockKey text: root.getDisplayPercentage() color: Color.mOnSurface pointSize: Style.fontSizeS @@ -475,27 +479,27 @@ Variants { anchors.fill: parent anchors.topMargin: Style.marginL anchors.bottomMargin: Style.marginL - spacing: root.currentOSDType === "lockkey" ? Style.marginM : Style.marginS + spacing: root.currentOSDType === OSD.Type.LockKey ? Style.marginM : Style.marginS clip: true // Unified Text display for Percentage or Lock Status NText { text: root.getDisplayPercentage() - color: root.currentOSDType === "lockkey" ? root.getProgressColor() : Color.mOnSurface - pointSize: root.currentOSDType === "lockkey" ? Style.fontSizeM : Style.fontSizeS + color: root.currentOSDType === OSD.Type.LockKey ? root.getProgressColor() : Color.mOnSurface + pointSize: root.currentOSDType === OSD.Type.LockKey ? Style.fontSizeM : Style.fontSizeS family: Settings.data.ui.fontFixed - font.weight: root.currentOSDType === "lockkey" ? Style.fontWeightMedium : Style.fontWeightNormal + font.weight: root.currentOSDType === OSD.Type.LockKey ? Style.fontWeightMedium : Style.fontWeightNormal Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter // Only set preferredHeight for the standard case to maintain layout - Layout.preferredHeight: root.currentOSDType === "lockkey" ? -1 : Math.round(20 * Style.uiScaleRatio) + Layout.preferredHeight: root.currentOSDType === OSD.Type.LockKey ? -1 : Math.round(20 * Style.uiScaleRatio) } // Progress Bar for Volume/Brightness Item { - visible: root.currentOSDType !== "lockkey" + visible: root.currentOSDType !== OSD.Type.LockKey Layout.fillWidth: true Layout.fillHeight: true @@ -535,8 +539,8 @@ Variants { NIcon { icon: root.getIcon() color: root.getIconColor() - pointSize: root.currentOSDType === "lockkey" ? Style.fontSizeXL : Style.fontSizeL - Layout.alignment: root.currentOSDType === "lockkey" ? Qt.AlignHCenter : (Qt.AlignHCenter | Qt.AlignBottom) + pointSize: root.currentOSDType === OSD.Type.LockKey ? Style.fontSizeXL : Style.fontSizeL + Layout.alignment: root.currentOSDType === OSD.Type.LockKey ? Qt.AlignHCenter : (Qt.AlignHCenter | Qt.AlignBottom) Behavior on color { ColorAnimation { @@ -575,7 +579,7 @@ Variants { osdItem.opacity = 0; osdItem.scale = 0.85; osdItem.visible = false; - root.currentOSDType = ""; + root.currentOSDType = -1; root.active = false; } } diff --git a/Modules/Panels/Settings/Tabs/OsdTab.qml b/Modules/Panels/Settings/Tabs/OsdTab.qml index 7c218d2b3..84c219661 100644 --- a/Modules/Panels/Settings/Tabs/OsdTab.qml +++ b/Modules/Panels/Settings/Tabs/OsdTab.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import Quickshell import qs.Commons +import qs.Modules.OSD import qs.Services.Compositor import qs.Widgets @@ -21,6 +22,17 @@ ColumnLayout { return n !== name; }); } + function addType(list, type) { + const arr = (list || []).slice(); + if (!arr.includes(type)) + arr.push(type); + return arr; + } + function removeType(list, type) { + return (list || []).filter(function (t) { + return t !== type; + }); + } // Display ColumnLayout { @@ -99,13 +111,6 @@ ColumnLayout { onToggled: checked => Settings.data.osd.overlayLayer = checked } - NToggle { - label: I18n.tr("settings.osd.show-lock-key-notifications.label", "Show lock key notifications") - description: I18n.tr("settings.osd.show-lock-key-notifications.description", "Show notifications when Caps Lock, Num Lock, or Scroll Lock keys are toggled.") - checked: Settings.data.osd.showLockKeyNotifications - onToggled: checked => Settings.data.osd.showLockKeyNotifications = checked - } - NLabel { label: I18n.tr("settings.osd.background-opacity.label", "Background opacity") description: I18n.tr("settings.osd.background-opacity.description", "Controls the transparency of the OSD background.") @@ -143,6 +148,58 @@ ColumnLayout { Layout.bottomMargin: Style.marginL } + // OSD Types Configuration + ColumnLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NHeader { + label: I18n.tr("settings.osd.types.section.label") + description: I18n.tr("settings.osd.types.section.description") + } + + Repeater { + model: [ + { + type: OSD.Type.Volume, + key: "volume" + }, + { + type: OSD.Type.InputVolume, + key: "input-volume" + }, + { + type: OSD.Type.Brightness, + key: "brightness" + }, + { + type: OSD.Type.LockKey, + key: "lockkey" + } + ] + delegate: NCheckbox { + required property var modelData + Layout.fillWidth: true + label: I18n.tr("settings.osd.types." + modelData.key + ".label") + description: I18n.tr("settings.osd.types." + modelData.key + ".description") + checked: (Settings.data.osd.enabledTypes || []).includes(modelData.type) + onToggled: checked => { + if (checked) { + Settings.data.osd.enabledTypes = addType(Settings.data.osd.enabledTypes, modelData.type); + } else { + Settings.data.osd.enabledTypes = removeType(Settings.data.osd.enabledTypes, modelData.type); + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginL + Layout.bottomMargin: Style.marginL + } + // Monitor Configuration ColumnLayout { spacing: Style.marginL