diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index d251e9dcc..30c55730e 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -368,12 +368,6 @@ "reset-tooltip": "Titelbreite zurücksetzen" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Zeige nur die Workspace-Bezeichnung für Workspaces an, die offene Fenster haben.", - "label": "Zeige Label nur bei Belegung" - } - }, "tray": { "colorize-icons": { "description": "Theme-Farben auf Tray-Symbole anwenden.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Wählen Sie, wie Arbeitsbereichs-Beschriftungen angezeigt werden.", "label": "Beschriftungsmodus" + }, + "show-applications": { + "description": "Anwendungssymbole in jedem Arbeitsbereich anzeigen.", + "label": "Anwendungen anzeigen" + }, + "show-labels-only-when-occupied": { + "description": "Arbeitsbereichsbezeichnungen nur anzeigen, wenn sie Fenster enthalten.", + "label": "Beschriftungen nur anzeigen, wenn belegt" } } } diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 68bfce26c..6160a139e 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -368,12 +368,6 @@ "reset-tooltip": "Reset title width" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Only show workspace label for workspaces that have open windows.", - "label": "Show label only when occupied" - } - }, "tray": { "colorize-icons": { "description": "Apply theme colors to tray icons.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Choose how workspace labels are displayed.", "label": "Label mode" + }, + "show-applications": { + "description": "Display application icons inside each workspace.", + "label": "Show applications" + }, + "show-labels-only-when-occupied": { + "description": "Only show workspace labels when they contain windows.", + "label": "Show labels only when occupied" } } } diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 7883149fe..a97c21b45 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -368,12 +368,6 @@ "reset-tooltip": "Restablecer ancho del título" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Mostrar solo la etiqueta del espacio de trabajo para los espacios de trabajo que tienen ventanas abiertas.", - "label": "Mostrar etiqueta solo cuando esté ocupado." - } - }, "tray": { "colorize-icons": { "description": "Aplicar colores del tema a los iconos de la bandeja del sistema.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Elegir cómo se muestran las etiquetas de los espacios de trabajo.", "label": "Modo de etiqueta" + }, + "show-applications": { + "description": "Mostrar los iconos de las aplicaciones dentro de cada espacio de trabajo.", + "label": "Mostrar aplicaciones" + }, + "show-labels-only-when-occupied": { + "description": "Mostrar solo las etiquetas del espacio de trabajo cuando contengan ventanas.", + "label": "Mostrar etiquetas solo cuando esté ocupado." } } } diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 4429828e1..92bd4d036 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -368,12 +368,6 @@ "reset-tooltip": "Réinitialiser la largeur du titre" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Afficher uniquement l'étiquette de l'espace de travail pour les espaces de travail qui ont des fenêtres ouvertes.", - "label": "Afficher l'étiquette uniquement lorsque c'est occupé." - } - }, "tray": { "colorize-icons": { "description": "Appliquer les couleurs du thème aux icônes de la barre système.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Choisir comment les étiquettes d'espace de travail sont affichées.", "label": "Mode d'étiquette" + }, + "show-applications": { + "description": "Afficher les icônes des applications dans chaque espace de travail.", + "label": "Afficher les applications" + }, + "show-labels-only-when-occupied": { + "description": "Afficher uniquement les étiquettes d'espace de travail lorsqu'elles contiennent des fenêtres.", + "label": "Afficher les étiquettes uniquement lorsque le champ est occupé." } } } diff --git a/Assets/Translations/ja.json b/Assets/Translations/ja.json index ff223bd69..6abaa0f3e 100644 --- a/Assets/Translations/ja.json +++ b/Assets/Translations/ja.json @@ -368,12 +368,6 @@ "reset-tooltip": "タイトル幅をリセット" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "ウィンドウが開いているワークスペースにのみラベルを表示します。", - "label": "ウィンドウがある時のみラベルを表示" - } - }, "tray": { "colorize-icons": { "description": "トレイのアイコンにテーマカラーを適用します。", @@ -410,6 +404,14 @@ "label-mode": { "description": "ワークスペースラベルの表示方法を選択します。", "label": "ラベルモード" + }, + "show-applications": { + "description": "ワークスペース内にアプリケーションのアイコンを表示する。", + "label": "アプリケーションを表示 (Apuriikeeshon o hyōji)" + }, + "show-labels-only-when-occupied": { + "description": "ウィンドウを含む場合にのみ、ワークスペースのラベルを表示する。", + "label": "占有されている場合のみラベルを表示する" } } } diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index dc7beff67..1a09cd83a 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -368,12 +368,6 @@ "reset-tooltip": "Titelbreedte resetten" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Toon alleen de werkomgevinglabels voor werkomgevingen met open vensters.", - "label": "Label alleen tonen wanneer bezet" - } - }, "tray": { "colorize-icons": { "description": "Pas themakleuren toe op systeemvakpictogrammen.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Kies hoe labels van werkruimten worden weergegeven.", "label": "Labelmodus" + }, + "show-applications": { + "description": "Toon applicatiepictogrammen in elke werkruimte.", + "label": "Toon applicaties" + }, + "show-labels-only-when-occupied": { + "description": "Toon alleen werkruimtelabels wanneer ze vensters bevatten.", + "label": "Toon labels alleen wanneer bezet." } } } diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index f126c520a..4189fd26e 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -368,12 +368,6 @@ "reset-tooltip": "Redefinir largura do título" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Mostrar apenas o rótulo da área de trabalho para áreas de trabalho que têm janelas abertas.", - "label": "Mostrar rótulo somente quando ocupado." - } - }, "tray": { "colorize-icons": { "description": "Aplicar cores do tema aos ícones da bandeja do sistema.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Escolher como os rótulos de espaço de trabalho são exibidos.", "label": "Modo de rótulo" + }, + "show-applications": { + "description": "Exibir ícones de aplicativos dentro de cada espaço de trabalho.", + "label": "Mostrar aplicativos" + }, + "show-labels-only-when-occupied": { + "description": "Mostrar rótulos de área de trabalho apenas quando contiverem janelas.", + "label": "Mostrar rótulos apenas quando ocupado." } } } diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index 84877bf4d..13ad588b7 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -368,12 +368,6 @@ "reset-tooltip": "Сбросить ширину заголовка" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Отображать метку рабочего пространства только для тех рабочих пространств, в которых есть открытые окна.", - "label": "Показывать метку только когда занято" - } - }, "tray": { "colorize-icons": { "description": "Применить цвета темы к иконкам трея.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Выберите, как отображаются метки рабочих пространств.", "label": "Режим метки" + }, + "show-applications": { + "description": "Отображать значки приложений внутри каждого рабочего пространства.", + "label": "Показать приложения" + }, + "show-labels-only-when-occupied": { + "description": "Показывать метки рабочих пространств только тогда, когда они содержат окна.", + "label": "Показывать метки только при наличии содержимого" } } } diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index e2a13503e..37e3dcc8d 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -368,12 +368,6 @@ "reset-tooltip": "Başlık genişliğini sıfırla" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Sadece açık pencereleri olan çalışma alanları için çalışma alanı etiketini göster.", - "label": "Sadece dolu olduğunda etiketi göster." - } - }, "tray": { "colorize-icons": { "description": "Tepsi simgelerine tema renklerini uygula.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Çalışma alanı etiketlerinin nasıl gösterileceğini seçin.", "label": "Etiket Modu" + }, + "show-applications": { + "description": "Her çalışma alanının içinde uygulama simgelerini görüntüle.", + "label": "Uygulamaları göster" + }, + "show-labels-only-when-occupied": { + "description": "Yalnızca pencere içeren çalışma alanı etiketlerini göster.", + "label": "Yalnızca dolu olduğunda etiketleri göster" } } } diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index ec2ee092a..648c26117 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -368,12 +368,6 @@ "reset-tooltip": "Скинути ширину заголовка" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "Показувати мітку робочого простору лише для робочих просторів, які мають відкриті вікна.", - "label": "Показувати мітку лише коли зайнято" - } - }, "tray": { "colorize-icons": { "description": "Застосувати кольори теми до значків трея.", @@ -410,6 +404,14 @@ "label-mode": { "description": "Виберіть, як відображаються мітки робочих просторів.", "label": "Режим міток" + }, + "show-applications": { + "description": "Відображати значки програм у кожному робочому просторі.", + "label": "Показати застосунки" + }, + "show-labels-only-when-occupied": { + "description": "Показувати мітки робочих просторів лише тоді, коли вони містять вікна.", + "label": "Показувати мітки лише коли поле заповнене" } } } diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 2a5861e80..0bf292428 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -368,12 +368,6 @@ "reset-tooltip": "重置标题宽度" } }, - "taskbar-grouped": { - "show-labels-only-when-occupied": { - "description": "只显示有打开窗口的工作区标签。", - "label": "仅在被占用时显示标签" - } - }, "tray": { "colorize-icons": { "description": "将主题颜色应用到系统托盘图标。", @@ -410,6 +404,14 @@ "label-mode": { "description": "选择工作区标签的显示方式。", "label": "标签模式" + }, + "show-applications": { + "description": "在每个工作区内显示应用程序图标。", + "label": "显示应用程序" + }, + "show-labels-only-when-occupied": { + "description": "仅在工作区包含窗口时显示工作区标签。", + "label": "仅在被占用时显示标签" } } } diff --git a/Commons/Migrations/Migration28.qml b/Commons/Migrations/Migration28.qml new file mode 100644 index 000000000..d3ef7b726 --- /dev/null +++ b/Commons/Migrations/Migration28.qml @@ -0,0 +1,37 @@ +import QtQuick + +QtObject { + id: root + + // Migrate TaskbarGrouped widgets to Workspace with showApplications: true + function migrate(adapter, logger, rawJson) { + logger.i("Settings", "Migrating settings to v28"); + + // Check bar widgets in all sections + const sections = ["left", "center", "right"]; + + for (const section of sections) { + if (!rawJson?.bar?.widgets?.[section]) + continue; + + const widgets = rawJson.bar.widgets[section]; + for (let i = 0; i < widgets.length; i++) { + if (widgets[i].id === "TaskbarGrouped") { + // Convert TaskbarGrouped to Workspace with showApplications + const oldWidget = widgets[i]; + adapter.bar.widgets[section][i] = { + id: "Workspace", + showApplications: true, + labelMode: oldWidget.labelMode || "index", + hideUnoccupied: oldWidget.hideUnoccupied || false, + showLabelsOnlyWhenOccupied: oldWidget.showLabelsOnlyWhenOccupied ?? true, + colorizeIcons: oldWidget.colorizeIcons || false + }; + logger.i("Settings", "Migrated TaskbarGrouped to Workspace in " + section + " section"); + } + } + } + + return true; + } +} diff --git a/Commons/Migrations/MigrationRegistry.qml b/Commons/Migrations/MigrationRegistry.qml index e75b64f48..87932c78f 100644 --- a/Commons/Migrations/MigrationRegistry.qml +++ b/Commons/Migrations/MigrationRegistry.qml @@ -7,9 +7,11 @@ QtObject { // Map of version number to migration component readonly property var migrations: ({ - 27: migration27Component + 27: migration27Component, + 28: migration28Component }) // Migration components property Component migration27Component: Migration27 {} + property Component migration28Component: Migration28 {} } diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 2e0f113ef..32858163a 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -23,7 +23,7 @@ Singleton { - Default cache directory: ~/.cache/noctalia */ readonly property alias data: adapter // Used to access via Settings.data.xxx.yyy - readonly property int settingsVersion: 27 + readonly property int settingsVersion: 28 readonly property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" readonly property string shellName: "noctalia" readonly property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" diff --git a/Modules/Bar/Widgets/TaskbarGrouped.qml b/Modules/Bar/Widgets/TaskbarGrouped.qml deleted file mode 100644 index fe8c3217c..000000000 --- a/Modules/Bar/Widgets/TaskbarGrouped.qml +++ /dev/null @@ -1,639 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Commons -import qs.Modules.Bar.Extras -import qs.Services.Compositor -import qs.Services.UI -import qs.Widgets - -Item { - id: root - - property ShellScreen screen - - // Widget properties passed from Bar.qml for per-instance settings - property string widgetId: "" - property string section: "" - property int sectionWidgetIndex: -1 - property int sectionWidgetsCount: 0 - - readonly property string barPosition: Settings.data.bar.position - readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right" - 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] - property var widgetSettings: { - if (section && sectionWidgetIndex >= 0) { - var widgets = Settings.data.bar.widgets[section]; - if (widgets && sectionWidgetIndex < widgets.length) { - return widgets[sectionWidgetIndex]; - } - } - return {}; - } - - readonly property int characterCount: 2 - readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied - readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode - readonly property bool showLabelsOnlyWhenOccupied: (widgetSettings.showLabelsOnlyWhenOccupied !== undefined) ? widgetSettings.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied - readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons - - property ListModel localWorkspaces: ListModel {} - property real masterProgress: 0.0 - property bool effectsActive: false - property color effectColor: Color.mPrimary - - // Wheel scroll handling - property int wheelAccumulatedDelta: 0 - property bool wheelCooldown: false - - // Context menu state - property var selectedWindow: null - property string selectedAppName: "" - property int modelUpdateTrigger: 0 // Dummy property to force model re-evaluation - - function refreshWorkspaces() { - localWorkspaces.clear(); - if (!screen) - return; - const screenName = screen.name.toLowerCase(); - - for (var i = 0; i < CompositorService.workspaces.count; i++) { - const ws = CompositorService.workspaces.get(i); - - if (ws.output.toLowerCase() !== screenName) - continue; - if (hideUnoccupied && !ws.isOccupied && !ws.isFocused) - continue; - - // Copy all properties from ws and add windows - var workspaceData = Object.assign({}, ws); - workspaceData.windows = CompositorService.getWindowsForWorkspace(ws.id); - - 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; - } - } - } - - function getFocusedLocalIndex() { - for (var i = 0; i < localWorkspaces.count; i++) { - if (localWorkspaces.get(i).isFocused === true) - return i; - } - return -1; - } - - function switchByOffset(offset) { - if (localWorkspaces.count === 0) - return; - var current = getFocusedLocalIndex(); - if (current < 0) - current = 0; - var next = (current + offset) % localWorkspaces.count; - if (next < 0) - next = localWorkspaces.count - 1; - const ws = localWorkspaces.get(next); - if (ws && ws.idx !== undefined) - CompositorService.switchToWorkspace(ws); - } - - Component.onCompleted: { - refreshWorkspaces(); - } - - onScreenChanged: refreshWorkspaces() - onHideUnoccupiedChanged: refreshWorkspaces() - - implicitWidth: isVerticalBar ? taskbarGrid.implicitWidth + Style.marginM * 2 : Math.round(taskbarGrid.implicitWidth + Style.marginM * 2) - implicitHeight: isVerticalBar ? Math.round(taskbarGrid.implicitHeight + Style.marginM * 2) : Style.barHeight - - Connections { - target: CompositorService - - function onWorkspacesChanged() { - refreshWorkspaces(); - } - - function onWindowListChanged() { - refreshWorkspaces(); - } - } - - 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 - } - } - - NPopupContextMenu { - id: contextMenu - - model: { - // Reference modelUpdateTrigger to make binding reactive - const _ = root.modelUpdateTrigger; - - var items = []; - if (root.selectedWindow) { - items.push({ - "label": I18n.tr("context-menu.activate-app", { - "app": root.selectedAppName - }), - "action": "activate", - "icon": "focus" - }); - items.push({ - "label": I18n.tr("context-menu.close-app", { - "app": root.selectedAppName - }), - "action": "close", - "icon": "x" - }); - } - items.push({ - "label": I18n.tr("context-menu.widget-settings"), - "action": "widget-settings", - "icon": "settings" - }); - return items; - } - - onTriggered: action => { - var popupMenuWindow = PanelService.getPopupMenuWindow(screen); - if (popupMenuWindow) { - popupMenuWindow.close(); - } - - if (action === "activate" && selectedWindow) { - CompositorService.focusWindow(selectedWindow); - } else if (action === "close" && selectedWindow) { - CompositorService.closeWindow(selectedWindow); - } else if (action === "widget-settings") { - BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings); - } - selectedWindow = null; - selectedAppName = ""; - } - } - - // Debounce timer for wheel interactions - Timer { - id: wheelDebounce - interval: 150 - repeat: false - onTriggered: { - root.wheelCooldown = false; - root.wheelAccumulatedDelta = 0; - } - } - - // Scroll to switch workspaces - WheelHandler { - id: wheelHandler - target: root - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - onWheel: function (event) { - if (root.wheelCooldown) - return; - // Prefer vertical delta, fall back to horizontal if needed - var dy = event.angleDelta.y; - var dx = event.angleDelta.x; - var useDy = Math.abs(dy) >= Math.abs(dx); - var delta = useDy ? dy : dx; - // One notch is typically 120 - root.wheelAccumulatedDelta += delta; - var step = 120; - if (Math.abs(root.wheelAccumulatedDelta) >= step) { - var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1; - // For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign) - // For horizontal layout, same mapping using vertical wheel - root.switchByOffset(direction); - root.wheelCooldown = true; - wheelDebounce.restart(); - root.wheelAccumulatedDelta = 0; - event.accepted = true; - } - } - } - - Component { - id: workspaceRepeaterDelegate - - Rectangle { - id: container - - required property var model - property var workspaceModel: model - property bool hasWindows: workspaceModel.windows.count > 0 - - radius: Style.radiusS - border.color: workspaceModel.isFocused ? Color.mPrimary : Color.mOutline - border.width: Style.borderS - width: (hasWindows ? iconsFlow.implicitWidth : root.itemSize * 0.8) + (root.isVerticalBar ? Style.marginXS : Style.marginL) - height: (hasWindows ? iconsFlow.implicitHeight : root.itemSize * 0.8) + (root.isVerticalBar ? Style.marginL : Style.marginXS) - color: Style.capsuleColor - - MouseArea { - anchors.fill: parent - hoverEnabled: true - enabled: !hasWindows - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - preventStealing: true - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) { - CompositorService.switchToWorkspace(workspaceModel); - } - } - onReleased: mouse => { - if (mouse.button === Qt.RightButton) { - mouse.accepted = true; - TooltipService.hide(); - root.selectedWindow = ""; - root.selectedAppName = ""; - - // Store position and size for timer callback - const globalPos = container.mapToItem(root, 0, 0); - contextMenuOpenTimer1.globalX = globalPos.x; - contextMenuOpenTimer1.globalY = globalPos.y; - contextMenuOpenTimer1.itemWidth = container.width; - contextMenuOpenTimer1.itemHeight = container.height; - contextMenuOpenTimer1.restart(); - } - } - } - - Flow { - id: iconsFlow - - anchors.centerIn: parent - spacing: 4 - flow: root.isVerticalBar ? Flow.TopToBottom : Flow.LeftToRight - - Repeater { - model: workspaceModel.windows - - delegate: Item { - id: taskbarItem - - property bool itemHovered: false - - width: root.itemSize * 0.8 - height: root.itemSize * 0.8 - - // Smooth scale animation on hover - scale: itemHovered ? 1.1 : 1.0 - - Behavior on scale { - NumberAnimation { - duration: Style.animationNormal - easing.type: Easing.OutBack - } - } - - IconImage { - id: appIcon - - width: parent.width - height: parent.height - source: ThemeIcons.iconForAppId(model.appId) - smooth: true - asynchronous: true - opacity: model.isFocused ? Style.opacityFull : 0.6 - layer.enabled: root.colorizeIcons && !model.isFocused - - Behavior on opacity { - NumberAnimation { - duration: Style.animationNormal - easing.type: Easing.InOutCubic - } - } - - Rectangle { - id: focusIndicator - anchors.bottomMargin: -2 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - width: model.isFocused ? 4 : 0 - height: model.isFocused ? 4 : 0 - color: model.isFocused ? Color.mPrimary : Color.transparent - radius: Math.min(Style.radiusXXS, width / 2) - } - - layer.effect: ShaderEffect { - property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant - property real colorizeMode: 0 - fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - preventStealing: true - - onPressed: mouse => { - if (!model) { - return; - } - - if (mouse.button === Qt.LeftButton) { - CompositorService.focusWindow(model); - } - } - - onReleased: mouse => { - if (!model) { - return; - } - - if (mouse.button === Qt.RightButton) { - mouse.accepted = true; - TooltipService.hide(); - root.selectedWindow = model; - root.selectedAppName = CompositorService.getCleanAppName(model.appId, model.title); - - // Store position and size for timer callback - const globalPos = taskbarItem.mapToItem(root, 0, 0); - contextMenuOpenTimer2.globalX = globalPos.x; - contextMenuOpenTimer2.globalY = globalPos.y; - contextMenuOpenTimer2.itemWidth = taskbarItem.width; - contextMenuOpenTimer2.itemHeight = taskbarItem.height; - contextMenuOpenTimer2.restart(); - } - } - onEntered: { - taskbarItem.itemHovered = true; - TooltipService.show(taskbarItem, model.title || model.appId || "Unknown app.", BarService.getTooltipDirection()); - } - onExited: { - taskbarItem.itemHovered = false; - TooltipService.hide(); - } - } - } - } - } - - Item { - id: workspaceNumberContainer - - visible: root.labelMode !== "none" && (!root.showLabelsOnlyWhenOccupied || container.hasWindows) - - anchors { - left: parent.left - top: parent.top - leftMargin: -Style.fontSizeXS * 0.5 - topMargin: -Style.fontSizeXS * 0.5 - } - - // Doube width margin necessary here for Name or Name+Index, but double height not needed. - width: Math.max(workspaceNumber.implicitWidth + (Style.marginXS * 2), Style.fontSizeXXS * 2) - height: Math.max(workspaceNumber.implicitHeight + Style.marginXS, Style.fontSizeXXS * 2) - - Rectangle { - id: workspaceNumberBackground - - anchors.fill: parent - radius: Math.min(Style.radiusL, width / 2) - - color: { - if (workspaceModel.isFocused) - return Color.mPrimary; - if (workspaceModel.isUrgent) - return Color.mError; - if (hasWindows) - return Color.mSecondary; - - if (Settings.data.colorSchemes.darkMode) { - return Qt.darker(Color.mSecondary, 1.5); - } else { - return Qt.lighter(Color.mSecondary, 1.5); - } - } - - 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: { - if (workspaceModel.name && workspaceModel.name.length > 0) { - if (root.labelMode === "name") { - return workspaceModel.name.substring(0, root.characterCount); - } - if (root.labelMode === "index+name") { - return (workspaceModel.idx.toString() + workspaceModel.name.substring(0, 1)); - } - } - return 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.mOnSecondary; - } - - Behavior on opacity { - NumberAnimation { - duration: Style.animationFast - easing.type: Easing.InOutCubic - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Style.animationFast - easing.type: Easing.InOutCubic - } - } - } - } - } - - Flow { - id: taskbarGrid - - anchors.verticalCenter: isVerticalBar ? undefined : parent.verticalCenter - anchors.left: isVerticalBar ? undefined : parent.left - anchors.leftMargin: isVerticalBar ? 0 : Style.marginM - anchors.horizontalCenter: isVerticalBar ? parent.horizontalCenter : undefined - anchors.top: isVerticalBar ? parent.top : undefined - anchors.topMargin: isVerticalBar ? Style.marginM : 0 - - spacing: Style.marginS - flow: isVerticalBar ? Flow.TopToBottom : Flow.LeftToRight - - Repeater { - model: localWorkspaces - delegate: workspaceRepeaterDelegate - } - } - - Timer { - id: contextMenuOpenTimer1 - interval: 10 - repeat: false - property real globalX: 0 - property real globalY: 0 - property real itemWidth: 0 - property real itemHeight: 0 - onTriggered: openContextMenu(globalX, globalY, itemWidth, itemHeight) - } - - Timer { - id: contextMenuOpenTimer2 - interval: 10 - repeat: false - property real globalX: 0 - property real globalY: 0 - property real itemWidth: 0 - property real itemHeight: 0 - onTriggered: openContextMenu(globalX, globalY, itemWidth, itemHeight) - } - - // -------------------------------------------------- - function openContextMenu(globalX, globalY, itemWidth, itemHeight) { - // Directly build and set model as a new array (bypass binding issues) - var items = []; - if (root.selectedWindow) { - items.push({ - "label": I18n.tr("context-menu.activate-app", { - "app": root.selectedAppName - }), - "action": "activate", - "icon": "focus" - }); - items.push({ - "label": I18n.tr("context-menu.close-app", { - "app": root.selectedAppName - }), - "action": "close", - "icon": "x" - }); - } - items.push({ - "label": I18n.tr("context-menu.widget-settings"), - "action": "widget-settings", - "icon": "settings" - }); - - // Set the model directly - contextMenu.model = items; - - var popupMenuWindow = PanelService.getPopupMenuWindow(screen); - if (popupMenuWindow) { - popupMenuWindow.open(); - - // Calculate menu position - let menuX, menuY; - if (root.barPosition === "top") { - menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2); - menuY = Style.barHeight + Style.marginS; - } else if (root.barPosition === "bottom") { - const menuHeight = 12 + contextMenu.model.length * contextMenu.itemHeight; - menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2); - menuY = -menuHeight - Style.marginS; - } else if (root.barPosition === "left") { - menuX = Style.barHeight + Style.marginS; - menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2); - } else { - // right - menuX = -contextMenu.implicitWidth - Style.marginS; - menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2); - } - - contextMenu.openAtItem(root, menuX, menuY); - popupMenuWindow.contentItem = contextMenu; - } - } -} diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index b54fe46c2..6358a9971 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import QtQuick.Window import Quickshell import Quickshell.Io +import Quickshell.Widgets import qs.Commons import qs.Modules.Bar.Extras import qs.Services.Compositor @@ -49,6 +50,17 @@ Item { readonly property bool followFocusedScreen: (widgetSettings.followFocusedScreen !== undefined) ? widgetSettings.followFocusedScreen : widgetMetadata.followFocusedScreen readonly property int characterCount: isVertical ? 2 : ((widgetSettings.characterCount !== undefined) ? widgetSettings.characterCount : widgetMetadata.characterCount) + // Grouped mode (show applications) settings + readonly property bool showApplications: (widgetSettings.showApplications !== undefined) ? widgetSettings.showApplications : widgetMetadata.showApplications + readonly property bool showLabelsOnlyWhenOccupied: (widgetSettings.showLabelsOnlyWhenOccupied !== undefined) ? widgetSettings.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied + readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons + readonly property real itemSize: (density === "compact") ? Style.capsuleHeight * 0.9 : Style.capsuleHeight * 0.8 + + // Context menu state for grouped mode + property var selectedWindow: null + property string selectedAppName: "" + property int modelUpdateTrigger: 0 + property bool isDestroying: false property bool hovered: false @@ -66,8 +78,8 @@ Item { signal workspaceChanged(int workspaceId, color accentColor) - implicitWidth: isVertical ? Style.barHeight : computeWidth() - implicitHeight: isVertical ? computeHeight() : Style.barHeight + implicitWidth: showApplications ? (isVertical ? groupedGrid.implicitWidth + Style.marginM * 2 : Math.round(groupedGrid.implicitWidth + Style.marginM * 2)) : (isVertical ? Style.barHeight : computeWidth()) + implicitHeight: showApplications ? (isVertical ? Math.round(groupedGrid.implicitHeight + Style.marginM * 2) : Style.barHeight) : (isVertical ? computeHeight() : Style.barHeight) function getWorkspaceWidth(ws) { const d = Style.capsuleHeight * root.baseDimensionRatio; @@ -159,6 +171,10 @@ Item { function onWorkspacesChanged() { refreshWorkspaces(); } + function onWindowListChanged() { + if (showApplications || showLabelsOnlyWhenOccupied) + refreshWorkspaces(); + } } function refreshWorkspaces() { @@ -174,12 +190,22 @@ Item { } if (screen !== null) { + const screenName = screen.name.toLowerCase(); for (var i = 0; i < CompositorService.workspaces.count; i++) { const ws = CompositorService.workspaces.get(i); - if ((followFocusedScreen && ws.output.toLowerCase() == focusedOutput) || (!followFocusedScreen && ws.output.toLowerCase() == screen.name.toLowerCase())) { - if (hideUnoccupied && !ws.isOccupied && !ws.isFocused) { - continue; - } + const matchesScreen = (followFocusedScreen && ws.output.toLowerCase() == focusedOutput) || (!followFocusedScreen && ws.output.toLowerCase() == screenName); + + if (!matchesScreen) + continue; + if (hideUnoccupied && !ws.isOccupied && !ws.isFocused) + continue; + + if (showApplications) { + // For grouped mode, attach windows to each workspace + var workspaceData = Object.assign({}, ws); + workspaceData.windows = CompositorService.getWindowsForWorkspace(ws.id); + localWorkspaces.append(workspaceData); + } else { localWorkspaces.append(ws); } } @@ -235,13 +261,31 @@ Item { NPopupContextMenu { id: contextMenu - model: [ - { - "label": I18n.tr("context-menu.widget-settings"), - "action": "widget-settings", - "icon": "settings" - }, - ] + model: { + var items = []; + if (root.selectedWindow) { + items.push({ + "label": I18n.tr("context-menu.activate-app", { + "app": root.selectedAppName + }), + "action": "activate", + "icon": "focus" + }); + items.push({ + "label": I18n.tr("context-menu.close-app", { + "app": root.selectedAppName + }), + "action": "close", + "icon": "x" + }); + } + items.push({ + "label": I18n.tr("context-menu.widget-settings"), + "action": "widget-settings", + "icon": "settings" + }); + return items; + } onTriggered: action => { var popupMenuWindow = PanelService.getPopupMenuWindow(screen); @@ -249,14 +293,21 @@ Item { popupMenuWindow.close(); } - if (action === "widget-settings") { + if (action === "activate" && selectedWindow) { + CompositorService.focusWindow(selectedWindow); + } else if (action === "close" && selectedWindow) { + CompositorService.closeWindow(selectedWindow); + } else if (action === "widget-settings") { BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings); } + selectedWindow = null; + selectedAppName = ""; } } Rectangle { id: workspaceBackground + visible: !showApplications width: isVertical ? Style.capsuleHeight : parent.width height: isVertical ? parent.height : Style.capsuleHeight radius: Style.radiusM @@ -327,7 +378,7 @@ Item { spacing: spacingBetweenPills anchors.verticalCenter: workspaceBackground.verticalCenter x: horizontalPadding - visible: !isVertical + visible: !isVertical && !showApplications Repeater { id: workspaceRepeaterHorizontal @@ -342,7 +393,7 @@ Item { anchors.fill: parent Loader { - active: (labelMode !== "none") + active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied || model.isFocused) sourceComponent: Component { NText { x: (pill.width - width) / 2 @@ -476,7 +527,7 @@ Item { spacing: spacingBetweenPills anchors.horizontalCenter: workspaceBackground.horizontalCenter y: horizontalPadding - visible: isVertical + visible: isVertical && !showApplications Repeater { id: workspaceRepeaterVertical @@ -491,7 +542,7 @@ Item { anchors.fill: parent Loader { - active: (labelMode !== "none") + active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied) sourceComponent: Component { NText { x: (pillVertical.width - width) / 2 @@ -618,4 +669,316 @@ Item { } } } + + // ======================================== + // Grouped mode (showApplications = true) + // ======================================== + + Component { + id: groupedWorkspaceDelegate + + Rectangle { + id: groupedContainer + + required property var model + property var workspaceModel: model + + radius: Style.radiusS + border.color: workspaceModel.isFocused ? Color.mPrimary : Color.mOutline + border.width: Style.borderS + width: (workspaceModel.isOccupied ? groupedIconsFlow.implicitWidth : root.itemSize * 0.8) + (root.isVertical ? Style.marginXS : Style.marginL) + height: (workspaceModel.isOccupied ? groupedIconsFlow.implicitHeight : root.itemSize * 0.8) + (root.isVertical ? Style.marginL : Style.marginXS) + color: Style.capsuleColor + + MouseArea { + anchors.fill: parent + hoverEnabled: true + enabled: !groupedContainer.workspaceModel.isOccupied + cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton + preventStealing: true + onPressed: mouse => { + if (mouse.button === Qt.LeftButton) { + CompositorService.switchToWorkspace(groupedContainer.workspaceModel); + } + } + onReleased: mouse => { + if (mouse.button === Qt.RightButton) { + mouse.accepted = true; + TooltipService.hide(); + root.selectedWindow = null; + root.selectedAppName = ""; + openGroupedContextMenu(groupedContainer); + } + } + } + + Flow { + id: groupedIconsFlow + + anchors.centerIn: parent + spacing: 4 + flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight + + Repeater { + model: groupedContainer.workspaceModel.windows + + delegate: Item { + id: groupedTaskbarItem + + property bool itemHovered: false + + width: root.itemSize * 0.8 + height: root.itemSize * 0.8 + + scale: itemHovered ? 1.1 : 1.0 + + Behavior on scale { + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.OutBack + } + } + + IconImage { + id: groupedAppIcon + + width: parent.width + height: parent.height + source: ThemeIcons.iconForAppId(model.appId) + smooth: true + asynchronous: true + opacity: model.isFocused ? Style.opacityFull : 0.6 + layer.enabled: root.colorizeIcons && !model.isFocused + + Behavior on opacity { + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.InOutCubic + } + } + + Rectangle { + id: groupedFocusIndicator + anchors.bottomMargin: -2 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: model.isFocused ? 4 : 0 + height: model.isFocused ? 4 : 0 + color: model.isFocused ? Color.mPrimary : Color.transparent + radius: Math.min(Style.radiusXXS, width / 2) + } + + layer.effect: ShaderEffect { + property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant + property real colorizeMode: 0 + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton + preventStealing: true + + onPressed: mouse => { + if (!model) + return; + if (mouse.button === Qt.LeftButton) { + CompositorService.focusWindow(model); + } + } + + onReleased: mouse => { + if (!model) + return; + if (mouse.button === Qt.RightButton) { + mouse.accepted = true; + TooltipService.hide(); + root.selectedWindow = model; + root.selectedAppName = CompositorService.getCleanAppName(model.appId, model.title); + openGroupedContextMenu(groupedTaskbarItem); + } + } + onEntered: { + groupedTaskbarItem.itemHovered = true; + TooltipService.show(groupedTaskbarItem, model.title || model.appId || "Unknown app.", BarService.getTooltipDirection()); + } + onExited: { + groupedTaskbarItem.itemHovered = false; + TooltipService.hide(); + } + } + } + } + } + + Item { + id: groupedWorkspaceNumberContainer + + visible: root.labelMode !== "none" && (!root.showLabelsOnlyWhenOccupied || groupedContainer.workspaceModel.isOccupied) + + anchors { + left: parent.left + top: parent.top + leftMargin: -Style.fontSizeXS * 0.5 + topMargin: -Style.fontSizeXS * 0.5 + } + + width: Math.max(groupedWorkspaceNumber.implicitWidth + (Style.marginXS * 2), Style.fontSizeXXS * 2) + height: Math.max(groupedWorkspaceNumber.implicitHeight + Style.marginXS, Style.fontSizeXXS * 2) + + Rectangle { + id: groupedWorkspaceNumberBackground + + anchors.fill: parent + radius: Math.min(Style.radiusL, width / 2) + + color: { + if (groupedContainer.workspaceModel.isFocused) + return Color.mPrimary; + if (groupedContainer.workspaceModel.isUrgent) + return Color.mError; + if (groupedContainer.workspaceModel.isOccupied) + return Color.mSecondary; + + if (Settings.data.colorSchemes.darkMode) { + return Qt.darker(Color.mSecondary, 1.5); + } else { + return Qt.lighter(Color.mSecondary, 1.5); + } + } + + scale: groupedContainer.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 + Rectangle { + id: groupedWorkspaceNumberBurst + anchors.centerIn: groupedWorkspaceNumberContainer + width: groupedWorkspaceNumberContainer.width + 12 * root.masterProgress + height: groupedWorkspaceNumberContainer.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 && groupedContainer.workspaceModel.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0 + visible: root.effectsActive && groupedContainer.workspaceModel.isFocused + z: 1 + } + + NText { + id: groupedWorkspaceNumber + + anchors.centerIn: parent + + text: { + if (groupedContainer.workspaceModel.name && groupedContainer.workspaceModel.name.length > 0) { + if (root.labelMode === "name") { + return groupedContainer.workspaceModel.name.substring(0, root.characterCount); + } + if (root.labelMode === "index+name") { + return (groupedContainer.workspaceModel.idx.toString() + groupedContainer.workspaceModel.name.substring(0, 1)); + } + } + return groupedContainer.workspaceModel.idx.toString(); + } + + family: Settings.data.ui.fontFixed + font { + pointSize: Style.fontSizeXXS + weight: Style.fontWeightBold + capitalization: Font.AllUppercase + } + applyUiScale: false + + color: { + if (groupedContainer.workspaceModel.isFocused) + return Color.mOnPrimary; + if (groupedContainer.workspaceModel.isUrgent) + return Color.mOnError; + + return Color.mOnSecondary; + } + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + } + + Behavior on opacity { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + } + } + } + + Flow { + id: groupedGrid + visible: showApplications + + anchors.verticalCenter: isVertical ? undefined : parent.verticalCenter + anchors.left: isVertical ? undefined : parent.left + anchors.leftMargin: isVertical ? 0 : Style.marginM + anchors.horizontalCenter: isVertical ? parent.horizontalCenter : undefined + anchors.top: isVertical ? parent.top : undefined + anchors.topMargin: isVertical ? Style.marginM : 0 + + spacing: Style.marginS + flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight + + Repeater { + model: showApplications ? localWorkspaces : null + delegate: groupedWorkspaceDelegate + } + } + + function openGroupedContextMenu(item) { + var popupMenuWindow = PanelService.getPopupMenuWindow(screen); + if (popupMenuWindow) { + popupMenuWindow.open(); + + const globalPos = item.mapToItem(root, 0, 0); + let menuX, menuY; + if (root.barPosition === "top") { + menuX = globalPos.x + (item.width / 2) - (contextMenu.implicitWidth / 2); + menuY = Style.barHeight + Style.marginS; + } else if (root.barPosition === "bottom") { + const menuHeight = 12 + contextMenu.model.length * contextMenu.itemHeight; + menuX = globalPos.x + (item.width / 2) - (contextMenu.implicitWidth / 2); + menuY = -menuHeight - Style.marginS; + } else if (root.barPosition === "left") { + menuX = Style.barHeight + Style.marginS; + menuY = globalPos.y + (item.height / 2) - (contextMenu.implicitHeight / 2); + } else { + menuX = -contextMenu.implicitWidth - Style.marginS; + menuY = globalPos.y + (item.height / 2) - (contextMenu.implicitHeight / 2); + } + + contextMenu.openAtItem(root, menuX, menuY); + popupMenuWindow.contentItem = contextMenu; + } + } } diff --git a/Modules/Panels/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml b/Modules/Panels/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml deleted file mode 100644 index 6bc6ba720..000000000 --- a/Modules/Panels/Settings/Bar/WidgetSettings/TaskbarGroupedSettings.qml +++ /dev/null @@ -1,79 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import qs.Commons -import qs.Widgets - -ColumnLayout { - id: root - spacing: Style.marginM - - // Properties to receive data from parent - property var widgetData: null - property var widgetMetadata: null - - property bool valueHideUnoccupied: widgetData.hideUnoccupied !== undefined ? widgetData.hideUnoccupied : widgetMetadata.hideUnoccupied - property string valueLabelMode: widgetData.labelMode !== undefined ? widgetData.labelMode : widgetMetadata.labelMode - property bool valueShowLabelsOnlyWhenOccupied: widgetData.showLabelsOnlyWhenOccupied !== undefined ? widgetData.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied - property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons - - function saveSettings() { - var settings = Object.assign({}, widgetData || {}); - - settings.hideUnoccupied = valueHideUnoccupied; - settings.labelMode = valueLabelMode; - settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied; - settings.colorizeIcons = valueColorizeIcons; - return settings; - } - - NToggle { - label: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.label") - description: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.description") - checked: valueHideUnoccupied - onToggled: checked => valueHideUnoccupied = checked - } - - NComboBox { - id: labelModeCombo - label: I18n.tr("bar.widget-settings.workspace.label-mode.label") - description: I18n.tr("bar.widget-settings.workspace.label-mode.description") - model: [ - { - "key": "none", - "name": I18n.tr("options.workspace-labels.none") - }, - { - "key": "index", - "name": I18n.tr("options.workspace-labels.index") - }, - { - "key": "name", - "name": I18n.tr("options.workspace-labels.name") - }, - { - "key": "index+name", - "name": I18n.tr("options.workspace-labels.index+name") - } - ] - currentKey: widgetData.labelMode - onSelected: key => valueLabelMode = key - minimumWidth: 200 - } - - NToggle { - Layout.fillWidth: true - label: I18n.tr("bar.widget-settings.taskbar-grouped.show-labels-only-when-occupied.label") - description: I18n.tr("bar.widget-settings.taskbar-grouped.show-labels-only-when-occupied.description") - checked: root.valueShowLabelsOnlyWhenOccupied - onToggled: checked => root.valueShowLabelsOnlyWhenOccupied = checked - } - - NToggle { - Layout.fillWidth: true - label: I18n.tr("bar.widget-settings.active-window.colorize-icons.label") - description: I18n.tr("bar.widget-settings.active-window.colorize-icons.description") - checked: root.valueColorizeIcons - onToggled: checked => root.valueColorizeIcons = checked - } -} diff --git a/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml b/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml index e807a1316..5b3c09158 100644 --- a/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml +++ b/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml @@ -17,12 +17,20 @@ ColumnLayout { property bool valueFollowFocusedScreen: widgetData.followFocusedScreen !== undefined ? widgetData.followFocusedScreen : widgetMetadata.followFocusedScreen property int valueCharacterCount: widgetData.characterCount !== undefined ? widgetData.characterCount : widgetMetadata.characterCount + // Grouped mode settings + property bool valueShowApplications: widgetData.showApplications !== undefined ? widgetData.showApplications : widgetMetadata.showApplications + property bool valueShowLabelsOnlyWhenOccupied: widgetData.showLabelsOnlyWhenOccupied !== undefined ? widgetData.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied + property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons + function saveSettings() { var settings = Object.assign({}, widgetData || {}); settings.labelMode = valueLabelMode; settings.hideUnoccupied = valueHideUnoccupied; settings.characterCount = valueCharacterCount; settings.followFocusedScreen = valueFollowFocusedScreen; + settings.showApplications = valueShowApplications; + settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied; + settings.colorizeIcons = valueColorizeIcons; return settings; } @@ -53,20 +61,6 @@ ColumnLayout { minimumWidth: 200 } - NToggle { - label: I18n.tr("bar.widget-settings.workspace.follow-focused-screen.label") - description: I18n.tr("bar.widget-settings.workspace.follow-focused-screen.description") - checked: valueFollowFocusedScreen - onToggled: checked => valueFollowFocusedScreen = checked - } - - NToggle { - label: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.label") - description: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.description") - checked: valueHideUnoccupied - onToggled: checked => valueHideUnoccupied = checked - } - NSpinBox { label: I18n.tr("bar.widget-settings.workspace.character-count.label") description: I18n.tr("bar.widget-settings.workspace.character-count.description") @@ -76,4 +70,40 @@ ColumnLayout { onValueChanged: valueCharacterCount = value visible: valueLabelMode === "name" } + + NToggle { + label: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.label") + description: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.description") + checked: valueHideUnoccupied + onToggled: checked => valueHideUnoccupied = checked + } + + NToggle { + label: I18n.tr("bar.widget-settings.workspace.show-labels-only-when-occupied.label") + description: I18n.tr("bar.widget-settings.workspace.show-labels-only-when-occupied.description") + checked: valueShowLabelsOnlyWhenOccupied + onToggled: checked => valueShowLabelsOnlyWhenOccupied = checked + } + + NToggle { + label: I18n.tr("bar.widget-settings.workspace.follow-focused-screen.label") + description: I18n.tr("bar.widget-settings.workspace.follow-focused-screen.description") + checked: valueFollowFocusedScreen + onToggled: checked => valueFollowFocusedScreen = checked + } + + NToggle { + label: I18n.tr("bar.widget-settings.workspace.show-applications.label") + description: I18n.tr("bar.widget-settings.workspace.show-applications.description") + checked: valueShowApplications + onToggled: checked => valueShowApplications = checked + } + + NToggle { + label: I18n.tr("bar.widget-settings.active-window.colorize-icons.label") + description: I18n.tr("bar.widget-settings.active-window.colorize-icons.description") + checked: valueColorizeIcons + onToggled: checked => valueColorizeIcons = checked + visible: valueShowApplications + } } diff --git a/Services/UI/BarWidgetRegistry.qml b/Services/UI/BarWidgetRegistry.qml index dc7acb969..00d5f49e9 100644 --- a/Services/UI/BarWidgetRegistry.qml +++ b/Services/UI/BarWidgetRegistry.qml @@ -33,7 +33,6 @@ Singleton { "Spacer": spacerComponent, "SystemMonitor": systemMonitorComponent, "Taskbar": taskbarComponent, - "TaskbarGrouped": taskbarGroupedComponent, "Tray": trayComponent, "Volume": volumeComponent, "VPN": vpnComponent, @@ -60,7 +59,6 @@ Singleton { "Spacer": "WidgetSettings/SpacerSettings.qml", "SystemMonitor": "WidgetSettings/SystemMonitorSettings.qml", "Taskbar": "WidgetSettings/TaskbarSettings.qml", - "TaskbarGrouped": "WidgetSettings/TaskbarGroupedSettings.qml", "Tray": "WidgetSettings/TraySettings.qml", "Volume": "WidgetSettings/VolumeSettings.qml", "VPN": "WidgetSettings/VPNSettings.qml", @@ -211,13 +209,6 @@ Singleton { "smartWidth": true, "maxTaskbarWidth": 40 }, - "TaskbarGrouped": { - "allowUserSettings": true, - "hideUnoccupied": false, - "labelMode": "index", - "showLabelsOnlyWhenOccupied": true, - "colorizeIcons": false - }, "Tray": { "allowUserSettings": true, "blacklist": [], @@ -238,7 +229,10 @@ Singleton { "labelMode": "index", "followFocusedScreen": false, "hideUnoccupied": false, - "characterCount": 2 + "characterCount": 2, + "showApplications": false, + "showLabelsOnlyWhenOccupied": true, + "colorizeIcons": false }, "Volume": { "allowUserSettings": true, @@ -334,10 +328,6 @@ Singleton { property Component taskbarComponent: Component { Taskbar {} } - property Component taskbarGroupedComponent: Component { - TaskbarGrouped {} - } - function init() { Logger.i("BarWidgetRegistry", "Service started"); }