diff options
Diffstat (limited to 'modules/controlcenter')
| -rw-r--r-- | modules/controlcenter/NavRail.qml | 5 | ||||
| -rw-r--r-- | modules/controlcenter/Panes.qml | 8 | ||||
| -rw-r--r-- | modules/controlcenter/Session.qml | 2 | ||||
| -rw-r--r-- | modules/controlcenter/taskbar/TaskbarPane.qml | 402 |
4 files changed, 416 insertions, 1 deletions
diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml index b4fbf94..1f8c6b3 100644 --- a/modules/controlcenter/NavRail.qml +++ b/modules/controlcenter/NavRail.qml @@ -181,6 +181,11 @@ Item { icon: "palette" label: "appearance" } + + NavItem { + icon: "task_alt" + label: "taskbar" + } } component NavItem: Item { diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml index 4f4a337..b30bcf2 100644 --- a/modules/controlcenter/Panes.qml +++ b/modules/controlcenter/Panes.qml @@ -5,6 +5,7 @@ import "bluetooth" import "network" import "audio" import "appearance" +import "taskbar" import qs.components import qs.services import qs.config @@ -60,6 +61,13 @@ ClippingRectangle { } } + Pane { + index: 5 + sourceComponent: TaskbarPane { + session: root.session + } + } + Behavior on y { Anim {} } diff --git a/modules/controlcenter/Session.qml b/modules/controlcenter/Session.qml index f7c07e4..cf31ec3 100644 --- a/modules/controlcenter/Session.qml +++ b/modules/controlcenter/Session.qml @@ -2,7 +2,7 @@ import Quickshell.Bluetooth import QtQuick QtObject { - readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance"] + readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance", "taskbar"] required property var root property bool floating: false diff --git a/modules/controlcenter/taskbar/TaskbarPane.qml b/modules/controlcenter/taskbar/TaskbarPane.qml new file mode 100644 index 0000000..a367635 --- /dev/null +++ b/modules/controlcenter/taskbar/TaskbarPane.qml @@ -0,0 +1,402 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Io +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property Session session + + anchors.fill: parent + + spacing: 0 + + FileView { + id: configFile + + path: `${Paths.config}/shell.json` + watchChanges: true + + onLoaded: { + try { + const config = JSON.parse(text()); + updateFromConfig(config); + } catch (e) { + console.error("Failed to parse config:", e); + } + } + } + + function updateFromConfig(config) { + // Update clock toggle + if (config.bar && config.bar.clock) { + clockShowIconSwitch.checked = config.bar.clock.showIcon !== false; + } + + // Update entries + if (config.bar && config.bar.entries) { + entriesModel.clear(); + for (const entry of config.bar.entries) { + entriesModel.append({ + id: entry.id, + enabled: entry.enabled !== false + }); + } + } + } + + function saveConfig(entryIndex, entryEnabled) { + if (!configFile.loaded) { + root.lastSaveStatus = "Error: Config file not loaded yet"; + root.debugInfo = "Config file not loaded yet, cannot save"; + return; + } + + try { + const config = JSON.parse(configFile.text()); + + // Update clock setting (same simple approach - read directly from the switch) + if (!config.bar) config.bar = {}; + if (!config.bar.clock) config.bar.clock = {}; + config.bar.clock.showIcon = clockShowIconSwitch.checked; + + // Update entries from the model (same approach as clock - use provided value if available) + if (!config.bar.entries) config.bar.entries = []; + config.bar.entries = []; + + let debugInfo = `saveConfig called\n`; + debugInfo += `entryIndex: ${entryIndex}\n`; + debugInfo += `entryEnabled: ${entryEnabled}\n`; + debugInfo += `entriesModel.count: ${entriesModel.count}\n\n`; + + for (let i = 0; i < entriesModel.count; i++) { + const entry = entriesModel.get(i); + // If this is the entry being updated, use the provided value (same as clock toggle reads from switch) + // Otherwise use the value from the model + let enabled = entry.enabled; + if (entryIndex !== undefined && i === entryIndex) { + enabled = entryEnabled; + debugInfo += `Entry ${i} (${entry.id}): Using provided value = ${entryEnabled}\n`; + } else { + debugInfo += `Entry ${i} (${entry.id}): Using model value = ${entry.enabled}\n`; + } + config.bar.entries.push({ + id: entry.id, + enabled: enabled + }); + } + + debugInfo += `\nFinal entries array:\n${JSON.stringify(config.bar.entries, null, 2)}\n`; + debugInfo += `\nFinal clock.showIcon: ${config.bar.clock.showIcon}\n`; + root.debugInfo = debugInfo; + + // Write back to file using setText (same simple approach that worked for clock) + const jsonString = JSON.stringify(config, null, 4); + configFile.setText(jsonString); + root.lastSaveStatus = `Saved! Entries count: ${config.bar.entries.length}`; + } catch (e) { + root.lastSaveStatus = `Error: ${e.message}`; + root.debugInfo = `Failed to save config:\n${e.message}\n${e.stack}`; + } + } + + ListModel { + id: entriesModel + } + + // Debug info + property string debugInfo: "" + property string lastSaveStatus: "" + + Item { + Layout.preferredWidth: Math.floor(parent.width * 0.4) + Layout.minimumWidth: 420 + Layout.fillHeight: true + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2 + + spacing: Appearance.spacing.small + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Settings") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Clock") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Clock display settings") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: clockRow.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + RowLayout { + id: clockRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Show clock icon") + } + + StyledSwitch { + id: clockShowIconSwitch + checked: true + onToggled: { + root.saveConfig(); + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Taskbar Entries") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Enable or disable taskbar entries") + color: Colours.palette.m3outline + } + + StyledListView { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: 0 + + model: entriesModel + spacing: Appearance.spacing.small / 2 + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: parent + } + + delegate: StyledRect { + id: delegate + required property string id + required property bool enabled + required property int index + + anchors.left: parent.left + anchors.right: parent.right + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + + RowLayout { + id: entryRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: id.charAt(0).toUpperCase() + id.slice(1) + font.weight: enabled ? 500 : 400 + } + + StyledSwitch { + checked: enabled + onToggled: { + // Store the values in local variables to ensure they're accessible + // Access index from the delegate + const entryIndex = delegate.index; + const entryEnabled = checked; + console.log(`Entry toggle: index=${entryIndex}, checked=${entryEnabled}`); + // Update the model first + entriesModel.setProperty(entryIndex, "enabled", entryEnabled); + // Save immediately with the value directly (same technique as clock toggle) + // Clock toggle reads directly from clockShowIconSwitch.checked + // We pass the value directly here (same approach) + root.saveConfig(entryIndex, entryEnabled); + } + } + } + + implicitHeight: entryRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } + + InnerBorder { + leftThickness: 0 + rightThickness: Appearance.padding.normal / 2 + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + StyledFlickable { + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + + flickableDirection: Flickable.VerticalFlick + contentHeight: contentLayout.implicitHeight + + StyledScrollBar.vertical: StyledScrollBar { + flickable: parent + } + + ColumnLayout { + id: contentLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "task_alt" + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Taskbar settings") + font.pointSize: Appearance.font.size.large + font.bold: true + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + Layout.alignment: Qt.AlignHCenter + text: qsTr("Clock") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: clockShowIconSwitch.checked ? qsTr("Clock icon enabled") : qsTr("Clock icon disabled") + color: Colours.palette.m3outline + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + Layout.alignment: Qt.AlignHCenter + text: qsTr("Taskbar Entries") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Configure which entries appear in the taskbar") + color: Colours.palette.m3outline + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + Layout.alignment: Qt.AlignHCenter + text: qsTr("Debug Info") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledRect { + Layout.fillWidth: true + Layout.preferredHeight: 200 + Layout.maximumHeight: 300 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + clip: true + + StyledFlickable { + id: debugFlickable + anchors.fill: parent + anchors.margins: Appearance.padding.normal + contentHeight: debugText.implicitHeight + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: debugFlickable + } + + TextEdit { + id: debugText + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + width: parent.width + + text: root.debugInfo || "No debug info yet" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurface + wrapMode: TextEdit.Wrap + readOnly: true + selectByMouse: true + selectByKeyboard: true + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.small + Layout.alignment: Qt.AlignHCenter + text: root.lastSaveStatus || "" + font.pointSize: Appearance.font.size.small + color: root.lastSaveStatus.includes("Error") ? Colours.palette.m3error : Colours.palette.m3primary + } + } + } + + InnerBorder { + leftThickness: Appearance.padding.normal / 2 + } + } +} + |