TaskbarGrouped is now consolidated in the Workspace widget.

This commit is contained in:
Lemmy
2025-12-12 09:01:06 -05:00
parent 5f0a34314a
commit 95a67718ad
19 changed files with 558 additions and 832 deletions
+8 -6
View File
@@ -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"
}
}
}
+8 -6
View File
@@ -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"
}
}
}
+8 -6
View File
@@ -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."
}
}
}
+8 -6
View File
@@ -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é."
}
}
}
+8 -6
View File
@@ -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": "占有されている場合のみラベルを表示する"
}
}
}
+8 -6
View File
@@ -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."
}
}
}
+8 -6
View File
@@ -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."
}
}
}
+8 -6
View File
@@ -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": "Показывать метки только при наличии содержимого"
}
}
}
+8 -6
View File
@@ -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"
}
}
}
+8 -6
View File
@@ -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": "Показувати мітки лише коли поле заповнене"
}
}
}
+8 -6
View File
@@ -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": "仅在被占用时显示标签"
}
}
}
+37
View File
@@ -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;
}
}
+3 -1
View File
@@ -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 {}
}
+1 -1
View File
@@ -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 + "/"
-639
View File
@@ -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;
}
}
}
+381 -18
View File
@@ -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;
}
}
}
@@ -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
}
}
@@ -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
}
}
+4 -14
View File
@@ -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");
}