From 6a2218c52e76350be459b5089917093a7b50fe17 Mon Sep 17 00:00:00 2001 From: Sighthesia Date: Tue, 14 Oct 2025 23:36:23 +0800 Subject: [PATCH 1/2] feat(taskbar): add auto hide mode functionality for widget visibility control --- Assets/Translations/de.json | 6 ++- Assets/Translations/en.json | 49 ++++++++++--------- Assets/Translations/es.json | 6 ++- Assets/Translations/fr.json | 6 ++- Assets/Translations/pt.json | 6 ++- Assets/Translations/zh-CN.json | 6 ++- Modules/Bar/Widgets/Taskbar.qml | 47 ++++++++++++++++-- .../Bar/WidgetSettings/TaskbarSettings.qml | 28 +++++++++++ Services/BarWidgetRegistry.qml | 1 + 9 files changed, 122 insertions(+), 33 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 779f6227..9fd75046 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1107,6 +1107,10 @@ } }, "taskbar": { + "hide-mode": { + "label": "Ausblendmodus", + "description": "Steuert das Verhalten des Widgets, wenn keine übereinstimmenden Fenster vorhanden sind." + }, "only-active-workspaces": { "label": "Nur von aktiven Arbeitsbereichen", "description": "Zeige nur Apps von aktiven Arbeitsbereichen an." @@ -1606,4 +1610,4 @@ "description": "Das Control-Center-Widget wurde aus der Leiste entfernt. Um es erneut über die Leiste zu öffnen, fügen Sie das Widget wieder hinzu. Sie können es auch durch Rechtsklick auf die Leiste öffnen." } } -} +} \ No newline at end of file diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 2390684b..16a9b048 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -59,7 +59,6 @@ } } } - }, "audio": { "title": "Audio", @@ -722,29 +721,29 @@ } }, "control-center": { - "title": "Control Center", + "title": "Control Center", + "section": { + "label": "Appearance", + "description": "Configure the Control Center panel positioning and behavior." + }, + "position": { + "label": "Position", + "description": "Choose where the Control Center panel appears when opened." + }, + "cards": { "section": { - "label": "Appearance", - "description": "Configure the Control Center panel positioning and behavior." - }, - "position": { - "label": "Position", - "description": "Choose where the Control Center panel appears when opened." - }, - "cards": { - "section": { - "label": "Cards", - "description": "Customize which controls appear in the Control Center and in what order." - } - }, - "shortcuts": { - "section": { - "label": "Shortcuts widgets", - "description": "Configure and manage the shortcuts widgets." - }, - "sectionLeft": "Left", - "sectionRight": "Right" + "label": "Cards", + "description": "Customize which controls appear in the Control Center and in what order." } + }, + "shortcuts": { + "section": { + "label": "Shortcuts widgets", + "description": "Configure and manage the shortcuts widgets." + }, + "sectionLeft": "Left", + "sectionRight": "Right" + } }, "user-interface": { "title": "User interface", @@ -1091,6 +1090,10 @@ "preview": "Preview" }, "taskbar": { + "hide-mode": { + "label": "Hiding mode", + "description": "Controls how the widget behaves when there are no matching windows." + }, "only-active-workspaces": { "label": "Only from active workspaces", "description": "Show only apps from active workspaces." @@ -1607,4 +1610,4 @@ "charging": "Charging.", "discharging": "Discharging." } -} +} \ No newline at end of file diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 480f6f04..9ce6a348 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1090,6 +1090,10 @@ } }, "taskbar": { + "hide-mode": { + "label": "Modo de ocultación", + "description": "Controla cómo se comporta el widget cuando no hay ventanas coincidentes." + }, "only-active-workspaces": { "description": "Mostrar solo las aplicaciones de los espacios de trabajo activos.", "label": "Solo desde espacios de trabajo activos" @@ -1606,4 +1610,4 @@ "charging": "Cargando.", "discharging": "Descargando." } -} +} \ No newline at end of file diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 6ef274e4..cf9cc41b 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1090,6 +1090,10 @@ } }, "taskbar": { + "hide-mode": { + "label": "Mode de masquage", + "description": "Contrôle le comportement du widget lorsqu'il n'y a pas de fenêtres correspondantes." + }, "only-active-workspaces": { "description": "Afficher uniquement les applications des espaces de travail actifs.", "label": "Seulement depuis les espaces de travail actifs." @@ -1606,4 +1610,4 @@ "charging": "En charge.", "discharging": "En décharge." } -} +} \ No newline at end of file diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 30b3d5f9..83f23a93 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1101,6 +1101,10 @@ "colorize-icons": { "label": "Colorir ícones", "description": "Aplicar cores do tema aos ícones da barra de tarefas." + }, + "hide-mode": { + "label": "Modo de ocultação", + "description": "Controla como o widget se comporta quando não há janelas correspondentes." } }, "tray": { @@ -1606,4 +1610,4 @@ "charging": "Carregando.", "discharging": "Descarregando." } -} +} \ No newline at end of file diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 801fd614..65065596 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1090,6 +1090,10 @@ } }, "taskbar": { + "hide-mode": { + "label": "隐藏模式", + "description": "当没有匹配的窗口时控制小部件的行为。" + }, "only-active-workspaces": { "label": "仅显示活动工作区", "description": "仅显示来自活动工作区的应用程序" @@ -1606,4 +1610,4 @@ "charging": "正在充电。", "discharging": "正在放电。" } -} +} \ No newline at end of file diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index 8dcab751..79765ea5 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -20,7 +20,7 @@ Rectangle { property int sectionWidgetsCount: 0 readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right" - readonly property bool density: Settings.data.bar.density + readonly property string density: Settings.data.bar.density readonly property real itemSize: (density === "compact") ? Style.capsuleHeight * 0.9 : Style.capsuleHeight * 0.8 property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId] @@ -34,9 +34,46 @@ Rectangle { return {} } - // Always visible when there are toplevels - implicitWidth: isVerticalBar ? Style.capsuleHeight : Math.round(taskbarLayout.implicitWidth + Style.marginM * 2) - implicitHeight: isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginM * 2) : Style.capsuleHeight + readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : (widgetMetadata.hideMode !== undefined ? widgetMetadata.hideMode : "hidden") + + property int __filteredCount: 0 + readonly property bool __onlySameOutput: widgetSettings.onlySameOutput === undefined ? widgetMetadata.onlySameOutput : widgetSettings.onlySameOutput + readonly property bool __onlyActiveWorkspaces: widgetSettings.onlyActiveWorkspaces === undefined ? widgetMetadata.onlyActiveWorkspaces : widgetSettings.onlyActiveWorkspaces + function __updateFilteredCount() { + try { + var count = 0 + var total = CompositorService.windows.count || 0 + var activeIds = CompositorService.getActiveWorkspaces().map(function(ws) { return ws.id }) + for (var i = 0; i < total; i++) { + var w = CompositorService.windows.get(i) + if (!w) + continue + var passOutput = (!__onlySameOutput) || (w.output == screen.name) + var passWorkspace = (!__onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId)) + if (passOutput && passWorkspace) { + count++ + } + } + __filteredCount = count + } catch (e) { + __filteredCount = 0 + } + } + + Component.onCompleted: __updateFilteredCount() + Connections { + target: CompositorService + function onWindowListChanged() { __updateFilteredCount() } + function onWorkspaceChanged() { __updateFilteredCount() } + } + onScreenChanged: __updateFilteredCount() + + visible: hideMode !== "hidden" || __filteredCount > 0 + opacity: (hideMode !== "transparent" || __filteredCount > 0) ? 1.0 : 0 + Behavior on opacity { NumberAnimation { duration: Style.animationNormal; easing.type: Easing.OutCubic } } + + implicitWidth: visible ? (isVerticalBar ? Style.capsuleHeight : Math.round(taskbarLayout.implicitWidth + Style.marginM * 2)) : 0 + implicitHeight: visible ? (isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginM * 2) : Style.capsuleHeight) : 0 radius: Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent @@ -64,7 +101,7 @@ Rectangle { required property var modelData property ShellScreen screen: root.screen - visible: (!widgetSettings.onlySameOutput || modelData.output == screen.name) && (!widgetSettings.onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(ws => ws.id).includes(modelData.workspaceId)) + visible: (!__onlySameOutput || modelData.output == screen.name) && (!__onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function(ws){ return ws.id }).includes(modelData.workspaceId)) Layout.preferredWidth: root.itemSize Layout.preferredHeight: root.itemSize diff --git a/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml b/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml index e98c0eaa..a99fec68 100644 --- a/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml @@ -14,18 +14,46 @@ ColumnLayout { property var widgetMetadata: null // Local state + property string valueHideMode: "hidden" property bool valueOnlyActiveWorkspaces: widgetData.onlyActiveWorkspaces !== undefined ? widgetData.onlyActiveWorkspaces : widgetMetadata.onlyActiveWorkspaces property bool valueOnlySameOutput: widgetData.onlySameOutput !== undefined ? widgetData.onlySameOutput : widgetMetadata.onlySameOutput property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons + Component.onCompleted: { + if (widgetData && widgetData.hideMode !== undefined) { + valueHideMode = widgetData.hideMode + } else if (widgetMetadata && widgetMetadata.hideMode !== undefined) { + valueHideMode = widgetMetadata.hideMode + } + } + function saveSettings() { var settings = Object.assign({}, widgetData || {}) + settings.hideMode = valueHideMode settings.onlySameOutput = valueOnlySameOutput settings.onlyActiveWorkspaces = valueOnlyActiveWorkspaces settings.colorizeIcons = valueColorizeIcons return settings } + NComboBox { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.taskbar.hide-mode.label") + description: I18n.tr("bar.widget-settings.taskbar.hide-mode.description") + model: [{ + "key": "visible", + "name": I18n.tr("options.hide-modes.visible") + }, { + "key": "hidden", + "name": I18n.tr("options.hide-modes.hidden") + }, { + "key": "transparent", + "name": I18n.tr("options.hide-modes.transparent") + }] + currentKey: root.valueHideMode + onSelected: key => root.valueHideMode = key + } + NToggle { Layout.fillWidth: true label: I18n.tr("bar.widget-settings.taskbar.only-same-output.label") diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index 1bb0199c..15263558 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -118,6 +118,7 @@ Singleton { "allowUserSettings": true, "onlySameOutput": true, "onlyActiveWorkspaces": true, + "hideMode": "hidden", "colorizeIcons": false }, "Tray": { From e65092ce2537edf86ff45d7852efd367e8a328e9 Mon Sep 17 00:00:00 2001 From: Sighthesia Date: Wed, 15 Oct 2025 12:52:39 +0800 Subject: [PATCH 2/2] style(Taskbar): improve code style --- Modules/Bar/Widgets/Taskbar.qml | 39 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index 79765ea5..5308e2dc 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -34,42 +34,45 @@ Rectangle { return {} } - readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : (widgetMetadata.hideMode !== undefined ? widgetMetadata.hideMode : "hidden") + readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : widgetMetadata.hideMode - property int __filteredCount: 0 - readonly property bool __onlySameOutput: widgetSettings.onlySameOutput === undefined ? widgetMetadata.onlySameOutput : widgetSettings.onlySameOutput - readonly property bool __onlyActiveWorkspaces: widgetSettings.onlyActiveWorkspaces === undefined ? widgetMetadata.onlyActiveWorkspaces : widgetSettings.onlyActiveWorkspaces - function __updateFilteredCount() { + property bool hasWindow: false + readonly property bool onlySameOutput: (widgetSettings.onlySameOutput !== undefined) ? widgetSettings.onlySameOutput : (widgetMetadata.onlySameOutput !== undefined ? widgetMetadata.onlySameOutput : false) + readonly property bool onlyActiveWorkspaces: (widgetSettings.onlyActiveWorkspaces !== undefined) ? widgetSettings.onlyActiveWorkspaces : (widgetMetadata.onlyActiveWorkspaces !== undefined ? widgetMetadata.onlyActiveWorkspaces : false) + + function updateHasWindow() { try { - var count = 0 var total = CompositorService.windows.count || 0 var activeIds = CompositorService.getActiveWorkspaces().map(function(ws) { return ws.id }) + var found = false for (var i = 0; i < total; i++) { var w = CompositorService.windows.get(i) if (!w) continue - var passOutput = (!__onlySameOutput) || (w.output == screen.name) - var passWorkspace = (!__onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId)) + var passOutput = (!onlySameOutput) || (w.output == screen.name) + var passWorkspace = (!onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId)) if (passOutput && passWorkspace) { - count++ + found = true + break } } - __filteredCount = count + hasWindow = found } catch (e) { - __filteredCount = 0 + hasWindow = false } } - Component.onCompleted: __updateFilteredCount() + Component.onCompleted: updateHasWindow() Connections { target: CompositorService - function onWindowListChanged() { __updateFilteredCount() } - function onWorkspaceChanged() { __updateFilteredCount() } + function onWindowListChanged() { updateHasWindow() } + function onWorkspaceChanged() { updateHasWindow() } } - onScreenChanged: __updateFilteredCount() + onScreenChanged: updateHasWindow() - visible: hideMode !== "hidden" || __filteredCount > 0 - opacity: (hideMode !== "transparent" || __filteredCount > 0) ? 1.0 : 0 + // "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty + visible: hideMode !== "hidden" || hasWindow + opacity: (hideMode !== "transparent" || hasWindow) ? 1.0 : 0 Behavior on opacity { NumberAnimation { duration: Style.animationNormal; easing.type: Easing.OutCubic } } implicitWidth: visible ? (isVerticalBar ? Style.capsuleHeight : Math.round(taskbarLayout.implicitWidth + Style.marginM * 2)) : 0 @@ -101,7 +104,7 @@ Rectangle { required property var modelData property ShellScreen screen: root.screen - visible: (!__onlySameOutput || modelData.output == screen.name) && (!__onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function(ws){ return ws.id }).includes(modelData.workspaceId)) + visible: (!onlySameOutput || modelData.output == screen.name) && (!onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function(ws){ return ws.id }).includes(modelData.workspaceId)) Layout.preferredWidth: root.itemSize Layout.preferredHeight: root.itemSize