From 9c1bce0fe450d0f1ea6ed62e2e1b59cba9ccd969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20=C3=87etinkaya?= Date: Mon, 3 Nov 2025 15:54:24 +0300 Subject: [PATCH] feat(bar): add workspace numbers to TaskbarGrouped widget Add workspace number badges to TaskbarGrouped widget that display in the top-left corner of task groups, similar to existing Workspace widget styling. Features: - Circular workspace number badges with negative margins for border overlap - Color states: focused (primary), urgent (error), occupied (secondary), empty (outline) - Burst animation effects when workspace becomes focused - User-configurable settings: showWorkspaceNumbers, showNumbersOnlyWhenOccupied - Comprehensive internationalization support for all supported locales Implementation: - Enhanced TaskbarGrouped.qml with workspace number display and animation system - Created TaskbarGroupedSettings.qml for user configuration - Updated BarWidgetRegistry.qml with default settings metadata - Added settings dialog mapping in BarWidgetSettingsDialog.qml - Added translations for all supported locales (en, de, es, fr, pt, zh-CN, uk-UA) The workspace numbers provide quick visual identification of workspace assignment while maintaining the clean aesthetic of the taskbar. --- Assets/Translations/de.json | 10 ++ Assets/Translations/en.json | 10 ++ Assets/Translations/es.json | 10 ++ Assets/Translations/fr.json | 10 ++ Assets/Translations/pt.json | 10 ++ Assets/Translations/uk-UA.json | 10 ++ Assets/Translations/zh-CN.json | 10 ++ Modules/Bar/Widgets/TaskbarGrouped.qml | 165 ++++++++++++++++++ .../Settings/Bar/BarWidgetSettingsDialog.qml | 1 + .../WidgetSettings/TaskbarGroupedSettings.qml | 42 +++++ Services/BarWidgetRegistry.qml | 4 +- 11 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 Modules/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index f9224eef..c1f0b709 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1258,6 +1258,16 @@ "description": "Theme-Farben auf Taskbar-Symbole anwenden." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Arbeitsbereichsnummern anzeigen", + "description": "Arbeitsbereichsnummern in der oberen linken Ecke der Task-Gruppen anzeigen." + }, + "show-numbers-only-when-occupied": { + "label": "Nur bei belegten Arbeitsbereichen anzeigen", + "description": "Arbeitsbereichsnummern nur für Arbeitsbereiche mit geöffneten Fenstern anzeigen." + } + }, "tray": { "colorize-icons": { "label": "Symbole einfärben", diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 76b87f64..6738e256 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1241,6 +1241,16 @@ "description": "Apply theme colors to taskbar icons." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Show workspace numbers", + "description": "Display workspace numbers in the top-left corner of task groups." + }, + "show-numbers-only-when-occupied": { + "label": "Show numbers only when occupied", + "description": "Only show workspace numbers for workspaces that have open windows." + } + }, "tray": { "colorize-icons": { "label": "Colorize Icons", diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 7252dbf9..3f9c3773 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1241,6 +1241,16 @@ "description": "Aplicar colores del tema a los iconos de la barra de tareas." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Mostrar números de espacio de trabajo", + "description": "Mostrar números de espacio de trabajo en la esquina superior izquierda de los grupos de tareas." + }, + "show-numbers-only-when-occupied": { + "label": "Mostrar números solo cuando estén ocupados", + "description": "Mostrar números de espacio de trabajo solo para espacios de trabajo con ventanas abiertas." + } + }, "tray": { "colorize-icons": { "label": "Colorear iconos", diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 1e0b879d..8d2df536 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1241,6 +1241,16 @@ "description": "Appliquer les couleurs du thème aux icônes de la barre des tâches." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Afficher les numéros d'espace de travail", + "description": "Afficher les numéros d'espace de travail dans le coin supérieur gauche des groupes de tâches." + }, + "show-numbers-only-when-occupied": { + "label": "Afficher les numéros seulement lorsqu'occupés", + "description": "Afficher les numéros d'espace de travail uniquement pour les espaces de travail avec des fenêtres ouvertes." + } + }, "tray": { "colorize-icons": { "label": "Coloriser les icônes", diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 7b3722cd..2825fb05 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1241,6 +1241,16 @@ "description": "Controla como o widget se comporta quando não há janelas correspondentes." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Mostrar números do espaço de trabalho", + "description": "Exibir números do espaço de trabalho no canto superior esquerdo dos grupos de tarefas." + }, + "show-numbers-only-when-occupied": { + "label": "Mostrar números apenas quando ocupados", + "description": "Mostrar números do espaço de trabalho apenas para espaços de trabalho com janelas abertas." + } + }, "tray": { "colorize-icons": { "label": "Colorir ícones", diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index 9e238ecb..babb0f4b 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -1241,6 +1241,16 @@ "description": "Застосувати кольори теми до значків панелі завдань." } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "Показувати номери робочих просторів", + "description": "Показувати номери робочих просторів у лівому верхньому куті групи завдань" + }, + "show-numbers-only-when-occupied": { + "label": "Показувати номера лише коли зайнято", + "description": "Показувати номери лише для робочих просторів з відкритими вікнами" + } + }, "tray": { "colorize-icons": { "label": "Розфарбувати значки", diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index d107d181..63cf9230 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1241,6 +1241,16 @@ "description": "将主题颜色应用到任务栏图标。" } }, + "taskbar-grouped": { + "show-workspace-numbers": { + "label": "显示工作区编号", + "description": "在任务组左上角显示工作区编号" + }, + "show-numbers-only-when-occupied": { + "label": "仅在有窗口时显示编号", + "description": "只为有打开窗口的工作区显示编号" + } + }, "tray": { "colorize-icons": { "label": "着色图标", diff --git a/Modules/Bar/Widgets/TaskbarGrouped.qml b/Modules/Bar/Widgets/TaskbarGrouped.qml index 73895274..ea43d51a 100644 --- a/Modules/Bar/Widgets/TaskbarGrouped.qml +++ b/Modules/Bar/Widgets/TaskbarGrouped.qml @@ -33,7 +33,12 @@ Item { return {} } readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : false + readonly property bool showWorkspaceNumbers: (widgetSettings.showWorkspaceNumbers !== undefined) ? widgetSettings.showWorkspaceNumbers : true + readonly property bool showNumbersOnlyWhenOccupied: (widgetSettings.showNumbersOnlyWhenOccupied !== undefined) ? widgetSettings.showNumbersOnlyWhenOccupied : true property ListModel localWorkspaces: ListModel {} + property real masterProgress: 0.0 + property bool effectsActive: false + property color effectColor: Color.mPrimary function refreshWorkspaces() { localWorkspaces.clear() @@ -56,6 +61,22 @@ Item { localWorkspaces.append(workspaceData) } + updateWorkspaceFocus() + } + + function triggerUnifiedWave() { + effectColor = Color.mPrimary + masterAnimation.restart() + } + + function updateWorkspaceFocus() { + for (var i = 0; i < localWorkspaces.count; i++) { + const ws = localWorkspaces.get(i) + if (ws.isFocused === true) { + root.triggerUnifiedWave() + break + } + } } Component.onCompleted: { @@ -79,6 +100,33 @@ Item { } } + SequentialAnimation { + id: masterAnimation + PropertyAction { + target: root + property: "effectsActive" + value: true + } + NumberAnimation { + target: root + property: "masterProgress" + from: 0.0 + to: 1.0 + duration: Style.animationSlow * 2 + easing.type: Easing.OutQuint + } + PropertyAction { + target: root + property: "effectsActive" + value: false + } + PropertyAction { + target: root + property: "masterProgress" + value: 0.0 + } + } + Component { id: workspaceRepeaterDelegate @@ -106,6 +154,123 @@ Item { } } + Item { + id: workspaceNumberContainer + + visible: root.showWorkspaceNumbers && (!root.showNumbersOnlyWhenOccupied || hasWindows) + + anchors { + left: parent.left + top: parent.top + leftMargin: -Style.fontSizeXS * 0.5 + topMargin: -Style.fontSizeXS * 0.5 + } + + width: Math.max(workspaceNumber.implicitWidth + Style.marginXS, Style.fontSizeXXS * 2) + height: Math.max(workspaceNumber.implicitHeight + Style.marginXS, Style.fontSizeXXS * 2) + + Rectangle { + id: workspaceNumberBackground + + anchors.fill: parent + radius: width * 0.5 + + color: { + if (workspaceModel.isFocused) + return Color.mPrimary + if (workspaceModel.isUrgent) + return Color.mError + if (hasWindows) + return Color.mSecondary + + return Qt.alpha(Color.mOutline, 0.3) + } + + scale: workspaceModel.isActive ? 1.0 : 0.9 + + Behavior on scale { + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.OutBack + } + } + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + } + + // Burst effect overlay for focused workspace number (smaller outline) + Rectangle { + id: workspaceNumberBurst + anchors.centerIn: workspaceNumberContainer + width: workspaceNumberContainer.width + 12 * root.masterProgress + height: workspaceNumberContainer.height + 12 * root.masterProgress + radius: width / 2 + color: Color.transparent + border.color: root.effectColor + border.width: Math.max(1, Math.round((2 + 4 * (1.0 - root.masterProgress)))) + opacity: root.effectsActive && workspaceModel.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0 + visible: root.effectsActive && workspaceModel.isFocused + z: 1 + } + + NText { + id: workspaceNumber + + anchors.centerIn: parent + + text: workspaceModel.idx.toString() + + family: Settings.data.ui.fontFixed + font { + pointSize: Style.fontSizeXXS + weight: Style.fontWeightBold + capitalization: Font.AllUppercase + } + applyUiScale: false + + color: { + if (workspaceModel.isFocused) + return Color.mOnPrimary + if (workspaceModel.isUrgent) + return Color.mOnError + if (hasWindows) + return Color.mOnSecondary + + return Color.mOnSurface + } + + opacity: { + if (workspaceModel.isFocused) + return 1.0 + if (workspaceModel.isUrgent) + return 0.9 + if (hasWindows) + return 0.8 + + return 0.6 + } + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + } + Flow { id: iconsFlow diff --git a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml index b6169eee..6e7a644e 100644 --- a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml +++ b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml @@ -134,6 +134,7 @@ Popup { "NotificationHistory": "WidgetSettings/NotificationHistorySettings.qml", "Spacer": "WidgetSettings/SpacerSettings.qml", "SystemMonitor": "WidgetSettings/SystemMonitorSettings.qml", + "TaskbarGrouped": "WidgetSettings/TaskbarGroupedSettings.qml", "Volume": "WidgetSettings/VolumeSettings.qml", "WiFi": "WidgetSettings/WiFiSettings.qml", "Workspace": "WidgetSettings/WorkspaceSettings.qml", diff --git a/Modules/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml b/Modules/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml new file mode 100644 index 00000000..301671a9 --- /dev/null +++ b/Modules/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml @@ -0,0 +1,42 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Widgets +import qs.Services + +ColumnLayout { + id: root + spacing: Style.marginM + + // Properties to receive data from parent + property var widgetData: null + property var widgetMetadata: null + + property bool valueShowWorkspaceNumbers: widgetData.showWorkspaceNumbers !== undefined ? widgetData.showWorkspaceNumbers : widgetMetadata.showWorkspaceNumbers + property bool valueShowNumbersOnlyWhenOccupied: widgetData.showNumbersOnlyWhenOccupied !== undefined ? widgetData.showNumbersOnlyWhenOccupied : widgetMetadata.showNumbersOnlyWhenOccupied + + function saveSettings() { + var settings = Object.assign({}, widgetData || {}) + settings.showWorkspaceNumbers = valueShowWorkspaceNumbers + settings.showNumbersOnlyWhenOccupied = valueShowNumbersOnlyWhenOccupied + return settings + } + + NToggle { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.taskbar-grouped.show-workspace-numbers.label") + description: I18n.tr("bar.widget-settings.taskbar-grouped.show-workspace-numbers.description") + checked: root.valueShowWorkspaceNumbers + onToggled: checked => root.valueShowWorkspaceNumbers = checked + } + + NToggle { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.taskbar-grouped.show-numbers-only-when-occupied.label") + description: I18n.tr("bar.widget-settings.taskbar-grouped.show-numbers-only-when-occupied.description") + checked: root.valueShowNumbersOnlyWhenOccupied + onToggled: checked => root.valueShowNumbersOnlyWhenOccupied = checked + visible: root.valueShowWorkspaceNumbers + } +} \ No newline at end of file diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index b4425195..3bccd148 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -146,7 +146,9 @@ Singleton { "colorizeIcons": false }, "TaskbarGrouped": { - "allowUserSettings": true + "allowUserSettings": true, + "showWorkspaceNumbers": true, + "showNumbersOnlyWhenOccupied": true }, "Tray": { "allowUserSettings": true,