From de9aba3c108c56f923642f782ff3a46ae0cdf0f2 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:27:25 -0600 Subject: [PATCH 01/12] Enable side panels by default and widen edge trigger --- Assets/settings-default.json | 14 +- Commons/Settings.qml | 15 ++ Modules/MainScreen/MainScreen.qml | 54 +++++- Modules/MainScreen/SideWidgetPanel.qml | 220 +++++++++++++++++++++++++ 4 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 Modules/MainScreen/SideWidgetPanel.qml diff --git a/Assets/settings-default.json b/Assets/settings-default.json index a4f469f505..5ec4fc3156 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -65,7 +65,19 @@ } ] }, - "screenOverrides": [] + "screenOverrides": [], + "sidePanels": { + "leftEnabled": true, + "rightEnabled": true, + "widthMode": "auto", + "width": 320, + "minWidth": 220, + "maxWidth": 520, + "triggerSize": 8, + "hideDelay": 250, + "padding": 12, + "spacing": 8 + } }, "general": { "avatarImage": "", diff --git a/Commons/Settings.qml b/Commons/Settings.qml index a2991fb334..b8458c8648 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -253,6 +253,21 @@ Singleton { // Per-screen overrides for position and widgets // Format: [{ "name": "HDMI-1", "position": "left" }, { "name": "DP-1", "position": "bottom", "widgets": {...} }] property list screenOverrides: [] + + // Side widget panels (left and/or right) + property JsonObject sidePanels + sidePanels: JsonObject { + property bool leftEnabled: true + property bool rightEnabled: true + property string widthMode: "auto" // "auto" or "fixed" + property int width: 320 + property int minWidth: 220 + property int maxWidth: 520 + property int triggerSize: 8 + property int hideDelay: 250 + property int padding: 12 + property int spacing: 8 + } } // general diff --git a/Modules/MainScreen/MainScreen.qml b/Modules/MainScreen/MainScreen.qml index c66f8996bf..749e217db7 100644 --- a/Modules/MainScreen/MainScreen.qml +++ b/Modules/MainScreen/MainScreen.qml @@ -128,7 +128,7 @@ PanelWindow { // Only include regions that are actually needed // panelRegions is handled by PanelService, bar is local to this screen - regions: [barMaskRegion, backgroundMaskRegion] + regions: [barMaskRegion, backgroundMaskRegion, leftSidePanelMaskRegion, rightSidePanelMaskRegion, leftSideTriggerMaskRegion, rightSideTriggerMaskRegion] // Bar region - subtract bar area from mask (only if bar should be shown on this screen) Region { @@ -198,6 +198,42 @@ PanelWindow { height: root.isAnyPanelOpen ? root.height : 0 intersection: Intersection.Subtract } + + Region { + id: leftSidePanelMaskRegion + x: leftSidePanel.visiblePanel ? leftSidePanel.panelBody.x : 0 + y: leftSidePanel.visiblePanel ? leftSidePanel.panelBody.y : 0 + width: leftSidePanel.visiblePanel ? leftSidePanel.panelBody.width : 0 + height: leftSidePanel.visiblePanel ? leftSidePanel.panelBody.height : 0 + intersection: Intersection.Subtract + } + + Region { + id: rightSidePanelMaskRegion + x: rightSidePanel.visiblePanel ? rightSidePanel.panelBody.x : 0 + y: rightSidePanel.visiblePanel ? rightSidePanel.panelBody.y : 0 + width: rightSidePanel.visiblePanel ? rightSidePanel.panelBody.width : 0 + height: rightSidePanel.visiblePanel ? rightSidePanel.panelBody.height : 0 + intersection: Intersection.Subtract + } + + Region { + id: leftSideTriggerMaskRegion + x: leftSidePanel.visiblePanel ? leftSidePanel.triggerZone.x : 0 + y: leftSidePanel.visiblePanel ? leftSidePanel.triggerZone.y : 0 + width: leftSidePanel.visiblePanel ? leftSidePanel.triggerZone.width : 0 + height: leftSidePanel.visiblePanel ? leftSidePanel.triggerZone.height : 0 + intersection: Intersection.Subtract + } + + Region { + id: rightSideTriggerMaskRegion + x: rightSidePanel.visiblePanel ? rightSidePanel.triggerZone.x : 0 + y: rightSidePanel.visiblePanel ? rightSidePanel.triggerZone.y : 0 + width: rightSidePanel.visiblePanel ? rightSidePanel.triggerZone.width : 0 + height: rightSidePanel.visiblePanel ? rightSidePanel.triggerZone.height : 0 + intersection: Intersection.Subtract + } } // -------------------------------------- @@ -232,6 +268,22 @@ PanelWindow { z: 0 // Behind panels and bar } + SideWidgetPanel { + id: leftSidePanel + screen: root.screen + side: "left" + anchors.fill: parent + z: 20 + } + + SideWidgetPanel { + id: rightSidePanel + screen: root.screen + side: "right" + anchors.fill: parent + z: 20 + } + // --------------------------------------- // All panels always exist // --------------------------------------- diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml new file mode 100644 index 0000000000..52a6f97eeb --- /dev/null +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -0,0 +1,220 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.Commons +import qs.Services.Noctalia +import qs.Services.UI + +Item { + id: root + + required property ShellScreen screen + required property string side // "left" or "right" + + readonly property bool isLeft: side === "left" + readonly property bool isRight: side === "right" + + readonly property var settings: Settings.data.bar.sidePanels + readonly property bool panelEnabled: { + if (!settings) + return true; + return isLeft ? (settings?.leftEnabled ?? true) : (settings?.rightEnabled ?? true); + } + + readonly property var panelWidgets: { + var widgets = Settings.getBarWidgetsForScreen(screen?.name); + if (!widgets) + return []; + return isLeft ? (widgets.left || []) : (widgets.right || []); + } + + readonly property real panelPadding: settings?.padding ?? Style.marginM + readonly property real panelSpacing: settings?.spacing ?? Style.marginS + readonly property int triggerSize: Math.max(1, settings?.triggerSize ?? 8) + readonly property int hideDelay: Math.max(0, settings?.hideDelay ?? 250) + readonly property int panelMinWidth: Math.max(120, settings?.minWidth ?? 220) + readonly property int panelMaxWidth: Math.max(panelMinWidth, settings?.maxWidth ?? 520) + readonly property bool useAutoWidth: (settings?.widthMode || "auto") === "auto" + readonly property int configuredWidth: Math.max(panelMinWidth, settings?.width ?? 320) + + readonly property real computedPanelWidth: { + var width = useAutoWidth ? (contentColumn.implicitWidth + panelPadding * 2) : configuredWidth; + return Math.min(panelMaxWidth, Math.max(panelMinWidth, width)); + } + + readonly property bool visiblePanel: panelEnabled && panelWidgets.length > 0 + + property bool revealed: false + + property alias panelBody: panelBody + property alias triggerZone: triggerZone + + readonly property real shownX: isLeft ? 0 : (parent ? parent.width - panelBody.width : 0) + readonly property real hiddenX: isLeft ? -panelBody.width : (parent ? parent.width : 0) + + function reveal() { + if (!visiblePanel) + return; + hideTimer.stop(); + revealed = true; + } + + function conceal() { + if (!visiblePanel) + return; + hideTimer.restart(); + } + + function concealNow() { + hideTimer.stop(); + revealed = false; + } + + onVisiblePanelChanged: { + if (!visiblePanel) { + concealNow(); + } + } + + Timer { + id: hideTimer + interval: hideDelay + repeat: false + onTriggered: { + if (!triggerZone.containsMouse && !panelMouseArea.containsMouse) { + root.revealed = false; + } + } + } + + MouseArea { + id: triggerZone + visible: root.visiblePanel + enabled: root.visiblePanel + width: root.triggerSize + anchors { + top: parent.top + bottom: parent.bottom + left: root.isLeft ? parent.left : undefined + right: root.isRight ? parent.right : undefined + } + hoverEnabled: true + acceptedButtons: Qt.NoButton + onEntered: root.reveal() + onExited: root.conceal() + z: 60 + } + + Rectangle { + id: panelBody + visible: root.visiblePanel + width: Math.round(root.computedPanelWidth) + height: parent ? parent.height : 0 + x: root.revealed ? root.shownX : root.hiddenX + y: 0 + + color: Qt.alpha(Color.mSurface, 0.96) + border.color: Color.mOutline + border.width: 1 + radius: Style.radiusL + + topLeftRadius: root.isLeft ? 0 : radius + bottomLeftRadius: root.isLeft ? 0 : radius + topRightRadius: root.isRight ? 0 : radius + bottomRightRadius: root.isRight ? 0 : radius + + Behavior on x { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.OutCubic + } + } + + MouseArea { + id: panelMouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + onEntered: root.reveal() + onExited: root.conceal() + z: 1 + } + + Flickable { + id: flick + anchors.fill: parent + anchors.margins: root.panelPadding + contentWidth: width + contentHeight: contentColumn.implicitHeight + clip: true + interactive: contentHeight > height + + ColumnLayout { + id: contentColumn + width: flick.width + spacing: root.panelSpacing + + Repeater { + model: root.panelWidgets + + delegate: Loader { + id: widgetLoader + required property var modelData + required property int index + + readonly property var entry: modelData || {} + readonly property string widgetId: entry.id || "" + + active: widgetId !== "" && BarWidgetRegistry.hasWidget(widgetId) + sourceComponent: active ? BarWidgetRegistry.getWidget(widgetId) : null + + onLoaded: { + if (!item) + return; + + item.anchors = undefined; + item.x = 0; + item.y = 0; + + if (item.hasOwnProperty("screen")) { + item.screen = root.screen; + } + + if (item.hasOwnProperty("widgetId")) { + item.widgetId = widgetId; + } + + if (item.hasOwnProperty("section")) { + item.section = root.isLeft ? "left" : "right"; + } + + if (item.hasOwnProperty("sectionWidgetIndex")) { + item.sectionWidgetIndex = index; + } + + if (item.hasOwnProperty("sectionWidgetsCount")) { + item.sectionWidgetsCount = root.panelWidgets.length; + } + + for (var key in entry) { + if (key === "id") + continue; + if (item.hasOwnProperty(key)) { + item[key] = entry[key]; + } + } + + if (BarWidgetRegistry.isPluginWidget(widgetId)) { + var pluginId = widgetId.replace("plugin:", ""); + var api = PluginService.getPluginAPI(pluginId); + if (api && item.hasOwnProperty("pluginApi")) { + item.pluginApi = api; + } + } + } + } + } + } + } + } +} From 7d8bcc94af45b695b3dad1ff6ab2f213fab791d2 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:03:01 -0600 Subject: [PATCH 02/12] Add configurable side panel widgets and attach panels to bar edges --- Assets/settings-default.json | 18 +- Commons/Settings.qml | 16 ++ Modules/MainScreen/SideWidgetPanel.qml | 54 +++-- Modules/Panels/Settings/Tabs/Bar/BarTab.qml | 106 ++++++++++ .../Settings/Tabs/Bar/SidePanelsSubTab.qml | 186 ++++++++++++++++++ 5 files changed, 368 insertions(+), 12 deletions(-) create mode 100644 Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 5ec4fc3156..5deeaec4c7 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -76,7 +76,23 @@ "triggerSize": 8, "hideDelay": 250, "padding": 12, - "spacing": 8 + "spacing": 8, + "leftWidgets": [ + { + "id": "Clock" + }, + { + "id": "SystemMonitor" + } + ], + "rightWidgets": [ + { + "id": "Network" + }, + { + "id": "Volume" + } + ] } }, "general": { diff --git a/Commons/Settings.qml b/Commons/Settings.qml index b8458c8648..228f16c67e 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -267,6 +267,22 @@ Singleton { property int hideDelay: 250 property int padding: 12 property int spacing: 8 + property list leftWidgets: [ + { + "id": "Clock" + }, + { + "id": "SystemMonitor" + } + ] + property list rightWidgets: [ + { + "id": "Network" + }, + { + "id": "Volume" + } + ] } } diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 52a6f97eeb..43dcd7e9f9 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -22,10 +22,19 @@ Item { } readonly property var panelWidgets: { - var widgets = Settings.getBarWidgetsForScreen(screen?.name); - if (!widgets) + // Depend on revision so this recomputes when settings arrays are mutated + var _rev = BarService.widgetsRevision; + + var fromSidePanels = isLeft ? settings?.leftWidgets : settings?.rightWidgets; + if (fromSidePanels && fromSidePanels.length !== undefined) { + return fromSidePanels; + } + + // Backward compatibility: if side panel widgets don't exist, fallback to bar sections + var barWidgets = Settings.getBarWidgetsForScreen(screen?.name); + if (!barWidgets) return []; - return isLeft ? (widgets.left || []) : (widgets.right || []); + return isLeft ? (barWidgets.left || []) : (barWidgets.right || []); } readonly property real panelPadding: settings?.padding ?? Style.marginM @@ -49,8 +58,30 @@ Item { property alias panelBody: panelBody property alias triggerZone: triggerZone - readonly property real shownX: isLeft ? 0 : (parent ? parent.width - panelBody.width : 0) - readonly property real hiddenX: isLeft ? -panelBody.width : (parent ? parent.width : 0) + readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name) + readonly property bool barShouldShow: { + if (!BarService.effectivelyVisible) + return false; + var monitors = Settings.data.bar.monitors || []; + var screenName = screen?.name || ""; + return monitors.length === 0 || monitors.includes(screenName); + } + readonly property bool barFloating: Settings.data.bar.floating || false + readonly property real barHeight: Style.getBarHeightForScreen(screen?.name) + readonly property real barMarginH: barFloating ? Math.floor(Settings.data.bar.marginHorizontal || 0) : 0 + readonly property real barMarginV: barFloating ? Math.floor(Settings.data.bar.marginVertical || 0) : 0 + + // Keep side panel attached to screen/bar layout so it doesn't overlap the bar + readonly property real insetTop: (barShouldShow && barPosition === "top") ? (barHeight + barMarginV) : 0 + readonly property real insetBottom: (barShouldShow && barPosition === "bottom") ? (barHeight + barMarginV) : 0 + readonly property real insetLeft: (barShouldShow && barPosition === "left") ? (barHeight + barMarginH) : 0 + readonly property real insetRight: (barShouldShow && barPosition === "right") ? (barHeight + barMarginH) : 0 + + readonly property bool attachedToTopBar: insetTop > 0 + readonly property bool attachedToBottomBar: insetBottom > 0 + + readonly property real shownX: isLeft ? insetLeft : (parent ? parent.width - insetRight - panelBody.width : 0) + readonly property real hiddenX: isLeft ? (insetLeft - panelBody.width) : (parent ? parent.width - insetRight : 0) function reveal() { if (!visiblePanel) @@ -109,19 +140,20 @@ Item { id: panelBody visible: root.visiblePanel width: Math.round(root.computedPanelWidth) - height: parent ? parent.height : 0 + height: Math.max(0, (parent ? parent.height : 0) - root.insetTop - root.insetBottom) x: root.revealed ? root.shownX : root.hiddenX - y: 0 + y: root.insetTop color: Qt.alpha(Color.mSurface, 0.96) border.color: Color.mOutline border.width: 1 radius: Style.radiusL - topLeftRadius: root.isLeft ? 0 : radius - bottomLeftRadius: root.isLeft ? 0 : radius - topRightRadius: root.isRight ? 0 : radius - bottomRightRadius: root.isRight ? 0 : radius + // Keep screen-edge side flush; flatten corners where attached to top/bottom bar for seamless junction + topLeftRadius: root.isLeft || root.attachedToTopBar ? 0 : radius + bottomLeftRadius: root.isLeft || root.attachedToBottomBar ? 0 : radius + topRightRadius: root.isRight || root.attachedToTopBar ? 0 : radius + bottomRightRadius: root.isRight || root.attachedToBottomBar ? 0 : radius Behavior on x { NumberAnimation { diff --git a/Modules/Panels/Settings/Tabs/Bar/BarTab.qml b/Modules/Panels/Settings/Tabs/Bar/BarTab.qml index e3df17db91..3f9fb4d1dd 100644 --- a/Modules/Panels/Settings/Tabs/Bar/BarTab.qml +++ b/Modules/Panels/Settings/Tabs/Bar/BarTab.qml @@ -88,6 +88,98 @@ ColumnLayout { } } + + function _ensureSidePanelWidgets() { + if (!Settings.data.bar.sidePanels) { + return; + } + if (!Settings.data.bar.sidePanels.leftWidgets) { + Settings.data.bar.sidePanels.leftWidgets = []; + } + if (!Settings.data.bar.sidePanels.rightWidgets) { + Settings.data.bar.sidePanels.rightWidgets = []; + } + } + + function _addSidePanelWidgetToSection(widgetId, section) { + _ensureSidePanelWidgets(); + + var newWidget = { + "id": widgetId + }; + if (BarWidgetRegistry.widgetHasUserSettings(widgetId)) { + var metadata = BarWidgetRegistry.widgetMetadata[widgetId]; + if (metadata) { + Object.keys(metadata).forEach(function (key) { + newWidget[key] = metadata[key]; + }); + } + } + + var key = section + "Widgets"; + Settings.data.bar.sidePanels[key].push(newWidget); + BarService.widgetsRevision++; + } + + function _removeSidePanelWidgetFromSection(section, index) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < widgets.length) { + var newArray = widgets.slice(); + newArray.splice(index, 1); + Settings.data.bar.sidePanels[key] = newArray; + BarService.widgetsRevision++; + } + } + + function _reorderSidePanelWidgetInSection(section, fromIndex, toIndex) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (fromIndex >= 0 && fromIndex < widgets.length && toIndex >= 0 && toIndex < widgets.length) { + var newArray = widgets.slice(); + var item = newArray[fromIndex]; + newArray.splice(fromIndex, 1); + newArray.splice(toIndex, 0, item); + Settings.data.bar.sidePanels[key] = newArray; + BarService.widgetsRevision++; + } + } + + function _updateSidePanelWidgetSettingsInSection(section, index, settings) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < widgets.length) { + widgets[index] = settings; + Settings.data.bar.sidePanels[key] = widgets.slice(); + } + } + + function _moveSidePanelWidgetBetweenSections(fromSection, index, toSection) { + _ensureSidePanelWidgets(); + + var fromKey = fromSection + "Widgets"; + var toKey = toSection + "Widgets"; + var fromWidgets = Settings.data.bar.sidePanels[fromKey] || []; + var toWidgets = Settings.data.bar.sidePanels[toKey] || []; + + if (index >= 0 && index < fromWidgets.length) { + var widget = fromWidgets[index]; + var sourceArray = fromWidgets.slice(); + sourceArray.splice(index, 1); + var targetArray = toWidgets.slice(); + targetArray.push(widget); + Settings.data.bar.sidePanels[fromKey] = sourceArray; + Settings.data.bar.sidePanels[toKey] = targetArray; + BarService.widgetsRevision++; + } + } + function getWidgetLocations(widgetId) { if (!BarService) return []; @@ -191,6 +283,11 @@ ColumnLayout { tabIndex: 2 checked: subTabBar.currentIndex === 2 } + NTabButton { + text: "Side panels" + tabIndex: 3 + checked: subTabBar.currentIndex === 3 + } } Item { @@ -216,6 +313,15 @@ ColumnLayout { addMonitor: root.addMonitor removeMonitor: root.removeMonitor } + SidePanelsSubTab { + availableWidgets: availableWidgets + addWidgetToSection: root._addSidePanelWidgetToSection + removeWidgetFromSection: root._removeSidePanelWidgetFromSection + reorderWidgetInSection: root._reorderSidePanelWidgetInSection + updateWidgetSettingsInSection: root._updateSidePanelWidgetSettingsInSection + moveWidgetBetweenSections: root._moveSidePanelWidgetBetweenSections + onOpenPluginSettings: manifest => pluginSettingsDialog.openPluginSettings(manifest) + } } NPluginSettingsPopup { diff --git a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml new file mode 100644 index 0000000000..1ec6c675e8 --- /dev/null +++ b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml @@ -0,0 +1,186 @@ +import QtQuick +import QtQuick.Controls +import Quickshell +import QtQuick.Layouts +import qs.Commons +import qs.Services.UI +import qs.Widgets + +ColumnLayout { + id: root + spacing: Style.marginL + Layout.fillWidth: true + + property var availableWidgets + property var addWidgetToSection + property var removeWidgetFromSection + property var reorderWidgetInSection + property var updateWidgetSettingsInSection + property var moveWidgetBetweenSections + + signal openPluginSettings(var manifest) + + readonly property var sidePanels: Settings.data.bar.sidePanels + + function getSectionIcons() { + return { + "left": "arrow-bar-to-left", + "right": "arrow-bar-to-right" + }; + } + + NText { + text: "Configure side panels and choose widgets shown on each side." + wrapMode: Text.WordWrap + Layout.fillWidth: true + color: Color.mOnSurfaceVariant + } + + NToggle { + label: "Enable left side panel" + description: "Show a hover-revealed side panel on the left screen edge." + checked: sidePanels.leftEnabled + onToggled: checked => sidePanels.leftEnabled = checked + } + + NToggle { + label: "Enable right side panel" + description: "Show a hover-revealed side panel on the right screen edge." + checked: sidePanels.rightEnabled + onToggled: checked => sidePanels.rightEnabled = checked + } + + NComboBox { + label: "Panel width mode" + description: "Auto fits to widget content or use a fixed width." + model: [ + {"key": "auto", "name": "Auto"}, + {"key": "fixed", "name": "Fixed"} + ] + currentKey: sidePanels.widthMode + onSelected: key => sidePanels.widthMode = key + } + + NLabel { + label: "Fixed width" + description: "Used when width mode is fixed." + visible: sidePanels.widthMode === "fixed" + } + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginM + visible: sidePanels.widthMode === "fixed" + + NSlider { + id: fixedWidthSlider + Layout.fillWidth: true + from: 180 + to: 700 + stepSize: 1 + value: sidePanels.width + onPressedChanged: { + if (!pressed) + sidePanels.width = Math.round(value); + } + } + + NText { + text: Math.round(fixedWidthSlider.value) + "px" + pointSize: Style.fontSizeM + color: Color.mOnSurfaceVariant + } + } + + NLabel { + label: "Edge trigger size" + description: "How wide the hover activation strip is on each side." + } + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginM + + NSlider { + id: triggerSlider + Layout.fillWidth: true + from: 1 + to: 32 + stepSize: 1 + value: sidePanels.triggerSize + onPressedChanged: { + if (!pressed) + sidePanels.triggerSize = Math.round(value); + } + } + + NText { + text: Math.round(triggerSlider.value) + "px" + pointSize: Style.fontSizeM + color: Color.mOnSurfaceVariant + } + } + + NLabel { + label: "Auto-hide delay" + description: "Delay before panel hides after leaving its area." + } + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginM + + NSlider { + id: hideDelaySlider + Layout.fillWidth: true + from: 0 + to: 2000 + stepSize: 10 + value: sidePanels.hideDelay + onPressedChanged: { + if (!pressed) + sidePanels.hideDelay = Math.round(value); + } + } + + NText { + text: Math.round(hideDelaySlider.value) + "ms" + pointSize: Style.fontSizeM + color: Color.mOnSurfaceVariant + } + } + + NSectionEditor { + sectionName: I18n.tr("positions.left") + sectionId: "left" + barIsVertical: false + settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") + widgetRegistry: BarWidgetRegistry + widgetModel: sidePanels.leftWidgets + sectionIcons: root.getSectionIcons() + availableWidgets: root.availableWidgets + onAddWidget: (widgetId, section) => root.addWidgetToSection(widgetId, section) + onRemoveWidget: (section, index) => root.removeWidgetFromSection(section, index) + onReorderWidget: (section, fromIndex, toIndex) => root.reorderWidgetInSection(section, fromIndex, toIndex) + onUpdateWidgetSettings: (section, index, settings) => root.updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => root.moveWidgetBetweenSections(fromSection, index, toSection) + onOpenPluginSettingsRequested: manifest => root.openPluginSettings(manifest) + } + + NSectionEditor { + sectionName: I18n.tr("positions.right") + sectionId: "right" + barIsVertical: false + settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") + widgetRegistry: BarWidgetRegistry + widgetModel: sidePanels.rightWidgets + sectionIcons: root.getSectionIcons() + availableWidgets: root.availableWidgets + onAddWidget: (widgetId, section) => root.addWidgetToSection(widgetId, section) + onRemoveWidget: (section, index) => root.removeWidgetFromSection(section, index) + onReorderWidget: (section, fromIndex, toIndex) => root.reorderWidgetInSection(section, fromIndex, toIndex) + onUpdateWidgetSettings: (section, index, settings) => root.updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => root.moveWidgetBetweenSections(fromSection, index, toSection) + onOpenPluginSettingsRequested: manifest => root.openPluginSettings(manifest) + } +} From b1c3b0ae881dc394f80bb5aa9ffeca772606b7f7 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:16:44 -0600 Subject: [PATCH 03/12] Fix SidePanelsSubTab compatibility with older NSectionEditor --- Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml index 1ec6c675e8..5a0ebf7f7f 100644 --- a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml @@ -153,7 +153,6 @@ ColumnLayout { NSectionEditor { sectionName: I18n.tr("positions.left") sectionId: "left" - barIsVertical: false settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") widgetRegistry: BarWidgetRegistry widgetModel: sidePanels.leftWidgets @@ -170,7 +169,6 @@ ColumnLayout { NSectionEditor { sectionName: I18n.tr("positions.right") sectionId: "right" - barIsVertical: false settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") widgetRegistry: BarWidgetRegistry widgetModel: sidePanels.rightWidgets From acc4eb2b3f5024a7942e7a130dd461f03446dd20 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:21:49 -0600 Subject: [PATCH 04/12] Add dedicated Side Panels settings tab and fix side widget loading --- Assets/settings-search-index.json | 266 +++++++++--------- Modules/MainScreen/SideWidgetPanel.qml | 12 +- Modules/Panels/Settings/SettingsContent.qml | 11 + Modules/Panels/Settings/SettingsPanel.qml | 1 + Modules/Panels/Settings/Tabs/Bar/BarTab.qml | 14 - .../Tabs/SidePanels/SidePanelsTab.qml | 163 +++++++++++ 6 files changed, 318 insertions(+), 149 deletions(-) create mode 100644 Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml diff --git a/Assets/settings-search-index.json b/Assets/settings-search-index.json index 5eef66912d..58bbf8b067 100644 --- a/Assets/settings-search-index.json +++ b/Assets/settings-search-index.json @@ -3,7 +3,7 @@ "labelKey": "panels.about.telemetry-enabled", "descriptionKey": "panels.about.telemetry-desc", "widget": "NToggle", - "tab": 20, + "tab": 21, "tabLabel": "panels.about.title", "subTab": 0, "subTabLabel": "common.info" @@ -12,7 +12,7 @@ "labelKey": "panels.audio.devices-output-device-label", "descriptionKey": "panels.audio.devices-output-device-description", "widget": "NLabel", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 1, "subTabLabel": "common.devices" @@ -21,7 +21,7 @@ "labelKey": "panels.audio.devices-input-device-label", "descriptionKey": "panels.audio.devices-input-device-description", "widget": "NLabel", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 1, "subTabLabel": "common.devices" @@ -30,7 +30,7 @@ "labelKey": "panels.audio.media-primary-player-label", "descriptionKey": "panels.audio.media-primary-player-description", "widget": "NTextInput", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 2, "subTabLabel": "common.media" @@ -39,7 +39,7 @@ "labelKey": "panels.audio.media-excluded-player-label", "descriptionKey": "panels.audio.media-excluded-player-description", "widget": "NTextInputButton", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 2, "subTabLabel": "common.media" @@ -48,7 +48,7 @@ "labelKey": "panels.audio.visualizer-type-label", "descriptionKey": "panels.audio.visualizer-type-description", "widget": "NComboBox", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 3, "subTabLabel": "common.visualizer" @@ -57,7 +57,7 @@ "labelKey": "panels.audio.media-frame-rate-label", "descriptionKey": "panels.audio.media-frame-rate-description", "widget": "NComboBox", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 3, "subTabLabel": "common.visualizer" @@ -66,7 +66,7 @@ "labelKey": "panels.osd.types-volume-label", "descriptionKey": "panels.audio.volumes-output-volume-description", "widget": "NValueSlider", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -75,7 +75,7 @@ "labelKey": "panels.audio.volumes-mute-output-label", "descriptionKey": "panels.audio.volumes-mute-output-description", "widget": "NToggle", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -84,7 +84,7 @@ "labelKey": "panels.audio.volumes-volume-feedback-label", "descriptionKey": "panels.audio.volumes-volume-feedback-description", "widget": "NToggle", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -93,7 +93,7 @@ "labelKey": "panels.osd.types-input-volume-label", "descriptionKey": "panels.audio.volumes-input-volume-description", "widget": "NValueSlider", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -102,7 +102,7 @@ "labelKey": "panels.audio.volumes-mute-input-label", "descriptionKey": "panels.audio.volumes-mute-input-description", "widget": "NToggle", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -111,7 +111,7 @@ "labelKey": "panels.audio.volumes-step-size-label", "descriptionKey": "panels.audio.volumes-step-size-description", "widget": "NSpinBox", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -120,7 +120,7 @@ "labelKey": "panels.audio.volumes-volume-overdrive-label", "descriptionKey": "panels.audio.volumes-volume-overdrive-description", "widget": "NToggle", - "tab": 13, + "tab": 14, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -381,7 +381,7 @@ "labelKey": "common.position", "descriptionKey": "panels.control-center.position-description", "widget": "NComboBox", - "tab": 7, + "tab": 8, "tabLabel": "panels.control-center.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -390,7 +390,7 @@ "labelKey": "panels.control-center.system-monitor-disk-path-label", "descriptionKey": "panels.control-center.system-monitor-disk-path-description", "widget": "NComboBox", - "tab": 7, + "tab": 8, "tabLabel": "panels.control-center.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -399,7 +399,7 @@ "labelKey": "panels.desktop-widgets.enabled-label", "descriptionKey": "panels.desktop-widgets.enabled-description", "widget": "NToggle", - "tab": 6, + "tab": 7, "tabLabel": "panels.desktop-widgets.title", "subTab": null }, @@ -407,7 +407,7 @@ "labelKey": "panels.display.monitors-brightness-step-label", "descriptionKey": "panels.display.monitors-brightness-step-description", "widget": "NSpinBox", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -416,7 +416,7 @@ "labelKey": "panels.display.monitors-enforce-minimum-label", "descriptionKey": "panels.display.monitors-enforce-minimum-description", "widget": "NToggle", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -425,7 +425,7 @@ "labelKey": "panels.display.monitors-external-brightness-label", "descriptionKey": "panels.display.monitors-external-brightness-description", "widget": "NToggle", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -434,7 +434,7 @@ "labelKey": "panels.display.night-light-enable-label", "descriptionKey": "panels.display.night-light-enable-description", "widget": "NToggle", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -443,7 +443,7 @@ "labelKey": "panels.display.night-light-temperature-night", "descriptionKey": "panels.display.night-light-temperature-night-description", "widget": "NLabel", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -452,7 +452,7 @@ "labelKey": "panels.display.night-light-temperature-day", "descriptionKey": "panels.display.night-light-temperature-day-description", "widget": "NLabel", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -461,7 +461,7 @@ "labelKey": "panels.display.night-light-auto-schedule-label", "descriptionKey": "panels.display.night-light-auto-schedule-description", "widget": "NToggle", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -470,7 +470,7 @@ "labelKey": "panels.display.night-light-force-activation-label", "descriptionKey": "panels.display.night-light-force-activation-description", "widget": "NToggle", - "tab": 14, + "tab": 15, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -479,7 +479,7 @@ "labelKey": "panels.dock.enabled-label", "descriptionKey": "panels.dock.enabled-description", "widget": "NToggle", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -488,7 +488,7 @@ "labelKey": "panels.dock.appearance-position-label", "descriptionKey": "panels.dock.appearance-position-description", "widget": "NComboBox", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -497,7 +497,7 @@ "labelKey": "panels.display.title", "descriptionKey": "panels.dock.appearance-display-description", "widget": "NComboBox", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -506,7 +506,7 @@ "labelKey": "panels.osd.background-opacity-label", "descriptionKey": "panels.dock.appearance-background-opacity-description", "widget": "NValueSlider", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -515,7 +515,7 @@ "labelKey": "panels.dock.appearance-dead-opacity-label", "descriptionKey": "panels.dock.appearance-dead-opacity-description", "widget": "NValueSlider", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -524,7 +524,7 @@ "labelKey": "panels.dock.appearance-floating-distance-label", "descriptionKey": "panels.dock.appearance-floating-distance-description", "widget": "NValueSlider", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -533,7 +533,7 @@ "labelKey": "panels.dock.appearance-icon-size-label", "descriptionKey": "panels.dock.appearance-icon-size-description", "widget": "NValueSlider", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -542,7 +542,7 @@ "labelKey": "panels.dock.appearance-hide-show-speed-label", "descriptionKey": "panels.dock.appearance-hide-show-speed-description", "widget": "NValueSlider", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -551,7 +551,7 @@ "labelKey": "panels.dock.appearance-inactive-indicators-label", "descriptionKey": "panels.dock.appearance-inactive-indicators-description", "widget": "NToggle", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -560,7 +560,7 @@ "labelKey": "panels.dock.appearance-pinned-static-label", "descriptionKey": "panels.dock.appearance-pinned-static-description", "widget": "NToggle", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -569,7 +569,7 @@ "labelKey": "panels.dock.monitors-only-same-monitor-label", "descriptionKey": "panels.dock.monitors-only-same-monitor-description", "widget": "NToggle", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -578,7 +578,7 @@ "labelKey": "panels.dock.appearance-colorize-icons-label", "descriptionKey": "panels.dock.appearance-colorize-icons-description", "widget": "NToggle", - "tab": 5, + "tab": 6, "tabLabel": "panels.dock.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -635,7 +635,7 @@ "labelKey": "panels.hooks.system-hooks-enable-label", "descriptionKey": "panels.hooks.system-hooks-enable-description", "widget": "NToggle", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 0, "subTabLabel": "common.general" @@ -644,7 +644,7 @@ "labelKey": "panels.hooks.info-parameters-label", "descriptionKey": "panels.hooks.info-parameters-description", "widget": "NLabel", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 0, "subTabLabel": "common.general" @@ -653,7 +653,7 @@ "labelKey": "panels.hooks.noctalia-started-label", "descriptionKey": "panels.hooks.noctalia-started-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -662,7 +662,7 @@ "labelKey": "panels.hooks.wallpaper-changed-label", "descriptionKey": "panels.hooks.wallpaper-changed-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -671,7 +671,7 @@ "labelKey": "panels.hooks.theme-changed-label", "descriptionKey": "panels.hooks.theme-changed-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -680,7 +680,7 @@ "labelKey": "panels.hooks.screen-lock-label", "descriptionKey": "panels.hooks.screen-lock-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -689,7 +689,7 @@ "labelKey": "panels.hooks.screen-unlock-label", "descriptionKey": "panels.hooks.screen-unlock-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -698,7 +698,7 @@ "labelKey": "panels.hooks.performance-mode-enabled-label", "descriptionKey": "panels.hooks.performance-mode-enabled-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -707,7 +707,7 @@ "labelKey": "panels.hooks.performance-mode-disabled-label", "descriptionKey": "panels.hooks.performance-mode-disabled-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -716,7 +716,7 @@ "labelKey": "panels.hooks.session-label", "descriptionKey": "panels.hooks.session-description", "widget": "HookRow", - "tab": 19, + "tab": 20, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -725,7 +725,7 @@ "labelKey": "panels.launcher.settings-clipboard-history-label", "descriptionKey": "panels.launcher.settings-clipboard-history-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -734,7 +734,7 @@ "labelKey": "panels.launcher.settings-clip-preview-label", "descriptionKey": "panels.launcher.settings-clip-preview-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -743,7 +743,7 @@ "labelKey": "panels.launcher.settings-clip-wrap-text-label", "descriptionKey": "panels.launcher.settings-clip-wrap-text-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -752,7 +752,7 @@ "labelKey": "panels.launcher.settings-auto-paste-label", "descriptionKey": "panels.launcher.settings-auto-paste-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -761,7 +761,7 @@ "labelKey": "panels.launcher.settings-clipboard-watch-text-label", "descriptionKey": "panels.launcher.settings-clipboard-watch-text-description", "widget": "NTextInput", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -770,7 +770,7 @@ "labelKey": "panels.launcher.settings-clipboard-watch-image-label", "descriptionKey": "panels.launcher.settings-clipboard-watch-image-description", "widget": "NTextInput", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 1, "subTabLabel": "common.clipboard" @@ -779,7 +779,7 @@ "labelKey": "panels.launcher.settings-use-app2unit-label", "descriptionKey": "panels.launcher.settings-use-app2unit-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 2, "subTabLabel": "common.execute" @@ -788,7 +788,7 @@ "labelKey": "panels.launcher.settings-terminal-command-label", "descriptionKey": "panels.launcher.settings-terminal-command-description", "widget": "NTextInput", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 2, "subTabLabel": "common.execute" @@ -797,7 +797,7 @@ "labelKey": "panels.launcher.settings-custom-launch-prefix-enabled-label", "descriptionKey": "panels.launcher.settings-custom-launch-prefix-enabled-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 2, "subTabLabel": "common.execute" @@ -806,7 +806,7 @@ "labelKey": "panels.launcher.settings-custom-launch-prefix-label", "descriptionKey": "panels.launcher.settings-custom-launch-prefix-description", "widget": "NTextInput", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 2, "subTabLabel": "common.execute" @@ -815,7 +815,7 @@ "labelKey": "panels.launcher.settings-annotation-tool-label", "descriptionKey": "panels.launcher.settings-annotation-tool-description", "widget": "NTextInput", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 2, "subTabLabel": "common.execute" @@ -824,7 +824,7 @@ "labelKey": "panels.launcher.settings-overlay-layer-label", "descriptionKey": "panels.launcher.settings-overlay-layer-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -833,7 +833,7 @@ "labelKey": "panels.launcher.settings-view-mode-label", "descriptionKey": "panels.launcher.settings-view-mode-description", "widget": "NComboBox", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -842,7 +842,7 @@ "labelKey": "panels.launcher.settings-density-label", "descriptionKey": "panels.launcher.settings-density-description", "widget": "NComboBox", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -851,7 +851,7 @@ "labelKey": "panels.launcher.settings-show-categories-label", "descriptionKey": "panels.launcher.settings-show-categories-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -860,7 +860,7 @@ "labelKey": "panels.launcher.settings-icon-mode-label", "descriptionKey": "panels.launcher.settings-icon-mode-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -869,7 +869,7 @@ "labelKey": "panels.launcher.settings-show-icon-background-label", "descriptionKey": "panels.launcher.settings-show-icon-background-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -878,7 +878,7 @@ "labelKey": "panels.launcher.settings-sort-by-usage-label", "descriptionKey": "panels.launcher.settings-sort-by-usage-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -887,7 +887,7 @@ "labelKey": "panels.launcher.settings-enable-settings-search-label", "descriptionKey": "panels.launcher.settings-enable-settings-search-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -896,7 +896,7 @@ "labelKey": "panels.launcher.settings-enable-windows-search-label", "descriptionKey": "panels.launcher.settings-enable-windows-search-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -905,7 +905,7 @@ "labelKey": "panels.launcher.settings-enable-session-search-label", "descriptionKey": "panels.launcher.settings-enable-session-search-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -914,7 +914,7 @@ "labelKey": "panels.launcher.settings-ignore-mouse-input-label", "descriptionKey": "panels.launcher.settings-ignore-mouse-input-description", "widget": "NToggle", - "tab": 8, + "tab": 9, "tabLabel": "panels.launcher.title", "subTab": 0, "subTabLabel": "common.general" @@ -923,7 +923,7 @@ "labelKey": "panels.lock-screen.clock-style-label", "descriptionKey": "panels.lock-screen.clock-style-description", "widget": "NComboBox", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -932,7 +932,7 @@ "labelKey": "panels.lock-screen.clock-format-label", "descriptionKey": "panels.lock-screen.clock-format-description", "widget": "NTextInput", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -941,7 +941,7 @@ "labelKey": "panels.lock-screen.lock-on-suspend-label", "descriptionKey": "panels.lock-screen.lock-on-suspend-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -950,7 +950,7 @@ "labelKey": "panels.lock-screen.compact-lockscreen-label", "descriptionKey": "panels.lock-screen.compact-lockscreen-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -959,7 +959,7 @@ "labelKey": "panels.lock-screen.lock-screen-animations-label", "descriptionKey": "panels.lock-screen.lock-screen-animations-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -968,7 +968,7 @@ "labelKey": "panels.lock-screen.auto-start-auth-label", "descriptionKey": "panels.lock-screen.auto-start-auth-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -977,7 +977,7 @@ "labelKey": "panels.lock-screen.allow-password-with-fprintd-label", "descriptionKey": "panels.lock-screen.allow-password-with-fprintd-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -986,7 +986,7 @@ "labelKey": "panels.lock-screen.show-session-buttons-label", "descriptionKey": "panels.lock-screen.show-session-buttons-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -995,7 +995,7 @@ "labelKey": "panels.lock-screen.show-hibernate-label", "descriptionKey": "panels.lock-screen.show-hibernate-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -1004,7 +1004,7 @@ "labelKey": "panels.session-menu.enable-countdown-label", "descriptionKey": "panels.session-menu.enable-countdown-description", "widget": "NToggle", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -1013,7 +1013,7 @@ "labelKey": "panels.session-menu.countdown-duration-label", "descriptionKey": "panels.session-menu.countdown-duration-description", "widget": "NValueSlider", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -1022,7 +1022,7 @@ "labelKey": "panels.lock-screen.lock-screen-blur-strength-label", "descriptionKey": "panels.lock-screen.lock-screen-blur-strength-description", "widget": "NValueSlider", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -1031,7 +1031,7 @@ "labelKey": "panels.lock-screen.lock-screen-tint-strength-label", "descriptionKey": "panels.lock-screen.lock-screen-tint-strength-description", "widget": "NValueSlider", - "tab": 11, + "tab": 12, "tabLabel": "panels.lock-screen.title", "subTab": 0, "subTabLabel": "common.appearance" @@ -1040,7 +1040,7 @@ "labelKey": "actions.enable-wifi", "descriptionKey": "panels.network.wifi-description", "widget": "NToggle", - "tab": 15, + "tab": 16, "tabLabel": "common.network", "subTab": null }, @@ -1048,7 +1048,7 @@ "labelKey": "actions.enable-bluetooth", "descriptionKey": "panels.network.bluetooth-description", "widget": "NToggle", - "tab": 15, + "tab": 16, "tabLabel": "common.network", "subTab": null }, @@ -1056,7 +1056,7 @@ "labelKey": "panels.network.bluetooth-rssi-polling-label", "descriptionKey": "panels.network.bluetooth-rssi-polling-description", "widget": "NToggle", - "tab": 15, + "tab": 16, "tabLabel": "common.network", "subTab": null }, @@ -1064,7 +1064,7 @@ "labelKey": "panels.notifications.duration-respect-expire-label", "descriptionKey": "panels.notifications.duration-respect-expire-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 1, "subTabLabel": "common.duration" @@ -1073,7 +1073,7 @@ "labelKey": "panels.notifications.duration-low-urgency-label", "descriptionKey": "panels.notifications.duration-low-urgency-description", "widget": "NValueSlider", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 1, "subTabLabel": "common.duration" @@ -1082,7 +1082,7 @@ "labelKey": "panels.notifications.duration-normal-urgency-label", "descriptionKey": "panels.notifications.duration-normal-urgency-description", "widget": "NValueSlider", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 1, "subTabLabel": "common.duration" @@ -1091,7 +1091,7 @@ "labelKey": "panels.notifications.duration-critical-urgency-label", "descriptionKey": "panels.notifications.duration-critical-urgency-description", "widget": "NValueSlider", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 1, "subTabLabel": "common.duration" @@ -1100,7 +1100,7 @@ "labelKey": "panels.notifications.settings-enabled-label", "descriptionKey": "panels.notifications.settings-enabled-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 0, "subTabLabel": "common.appearance" @@ -1109,7 +1109,7 @@ "labelKey": "panels.notifications.settings-density-label", "descriptionKey": "panels.notifications.settings-density-description", "widget": "NComboBox", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 0, "subTabLabel": "common.appearance" @@ -1118,7 +1118,7 @@ "labelKey": "tooltips.do-not-disturb-enabled", "descriptionKey": "panels.notifications.settings-do-not-disturb-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 0, "subTabLabel": "common.appearance" @@ -1127,7 +1127,7 @@ "labelKey": "panels.osd.always-on-top-label", "descriptionKey": "panels.notifications.settings-always-on-top-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 0, "subTabLabel": "common.appearance" @@ -1136,7 +1136,7 @@ "labelKey": "panels.notifications.history-low-urgency-label", "descriptionKey": "panels.notifications.history-low-urgency-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 2, "subTabLabel": "common.history" @@ -1145,7 +1145,7 @@ "labelKey": "panels.notifications.history-normal-urgency-label", "descriptionKey": "panels.notifications.history-normal-urgency-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 2, "subTabLabel": "common.history" @@ -1154,7 +1154,7 @@ "labelKey": "panels.notifications.history-critical-urgency-label", "descriptionKey": "panels.notifications.history-critical-urgency-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 2, "subTabLabel": "common.history" @@ -1163,7 +1163,7 @@ "labelKey": "panels.notifications.sounds-unavailable-label", "descriptionKey": "panels.notifications.sounds-unavailable-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1172,7 +1172,7 @@ "labelKey": "panels.notifications.sounds-enabled-label", "descriptionKey": "panels.notifications.sounds-enabled-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1181,7 +1181,7 @@ "labelKey": "panels.notifications.sounds-volume-label", "descriptionKey": "panels.notifications.sounds-volume-description", "widget": "NValueSlider", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1190,7 +1190,7 @@ "labelKey": "panels.notifications.sounds-separate-label", "descriptionKey": "panels.notifications.sounds-separate-description", "widget": "NToggle", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1199,7 +1199,7 @@ "labelKey": "panels.notifications.sounds-files-unified-label", "descriptionKey": "panels.notifications.sounds-files-unified-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1208,7 +1208,7 @@ "labelKey": "panels.notifications.sounds-files-low-label", "descriptionKey": "panels.notifications.sounds-files-low-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1217,7 +1217,7 @@ "labelKey": "panels.notifications.sounds-files-normal-label", "descriptionKey": "panels.notifications.sounds-files-normal-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1226,7 +1226,7 @@ "labelKey": "panels.notifications.sounds-files-critical-label", "descriptionKey": "panels.notifications.sounds-files-critical-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1235,7 +1235,7 @@ "labelKey": "panels.notifications.sounds-excluded-apps-label", "descriptionKey": "panels.notifications.sounds-excluded-apps-description", "widget": "NLabel", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 3, "subTabLabel": "common.sound" @@ -1244,7 +1244,7 @@ "labelKey": "panels.notifications.toast-media-label", "descriptionKey": "panels.notifications.toast-media-description", "widget": "NCheckbox", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 4, "subTabLabel": "common.toast" @@ -1253,7 +1253,7 @@ "labelKey": "panels.notifications.toast-keyboard-label", "descriptionKey": "panels.notifications.toast-keyboard-description", "widget": "NCheckbox", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 4, "subTabLabel": "common.toast" @@ -1262,7 +1262,7 @@ "labelKey": "panels.notifications.toast-battery-label", "descriptionKey": "panels.notifications.toast-battery-description", "widget": "NCheckbox", - "tab": 9, + "tab": 10, "tabLabel": "common.notifications", "subTab": 4, "subTabLabel": "common.toast" @@ -1271,7 +1271,7 @@ "labelKey": "panels.osd.enabled-label", "descriptionKey": "panels.osd.enabled-description", "widget": "NToggle", - "tab": 10, + "tab": 11, "tabLabel": "panels.osd.title", "subTab": 0, "subTabLabel": "common.general" @@ -1280,7 +1280,7 @@ "labelKey": "panels.osd.duration-auto-hide-label", "descriptionKey": "panels.osd.duration-auto-hide-description", "widget": "NValueSlider", - "tab": 10, + "tab": 11, "tabLabel": "panels.osd.title", "subTab": 0, "subTabLabel": "common.general" @@ -1289,7 +1289,7 @@ "labelKey": "panels.plugins.available-no-plugins-label", "descriptionKey": "panels.plugins.available-no-plugins-description", "widget": "NLabel", - "tab": 18, + "tab": 19, "tabLabel": "panels.plugins.title", "subTab": 1, "subTabLabel": "common.available" @@ -1298,7 +1298,7 @@ "labelKey": "panels.plugins.auto-update", "descriptionKey": "panels.plugins.auto-update-description", "widget": "NToggle", - "tab": 18, + "tab": 19, "tabLabel": "panels.plugins.title", "subTab": 0, "subTabLabel": "common.installed" @@ -1307,7 +1307,7 @@ "labelKey": "panels.plugins.installed-no-plugins-label", "descriptionKey": "panels.plugins.installed-no-plugins-description", "widget": "NLabel", - "tab": 18, + "tab": 19, "tabLabel": "panels.plugins.title", "subTab": 0, "subTabLabel": "common.installed" @@ -1316,7 +1316,7 @@ "labelKey": "panels.plugins.sources-add-dialog-name", "descriptionKey": null, "widget": "NTextInput", - "tab": 18, + "tab": 19, "tabLabel": "panels.plugins.title", "subTab": 2, "subTabLabel": "common.sources" @@ -1325,7 +1325,7 @@ "labelKey": "panels.plugins.sources-add-dialog-url", "descriptionKey": null, "widget": "NTextInput", - "tab": 18, + "tab": 19, "tabLabel": "panels.plugins.title", "subTab": 2, "subTabLabel": "common.sources" @@ -1334,7 +1334,7 @@ "labelKey": "panels.location.date-time-use-analog-label", "descriptionKey": "panels.location.date-time-use-analog-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1343,7 +1343,7 @@ "labelKey": "panels.location.date-time-week-numbers-label", "descriptionKey": "panels.location.date-time-week-numbers-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1352,7 +1352,7 @@ "labelKey": "panels.location.date-time-show-events-label", "descriptionKey": "panels.location.date-time-show-events-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1361,7 +1361,7 @@ "labelKey": "panels.location.date-time-12hour-format-label", "descriptionKey": "panels.location.date-time-12hour-format-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 1, "subTabLabel": "common.date" @@ -1370,7 +1370,7 @@ "labelKey": "panels.location.date-time-first-day-of-week-label", "descriptionKey": "panels.location.date-time-first-day-of-week-description", "widget": "NComboBox", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 1, "subTabLabel": "common.date" @@ -1379,7 +1379,7 @@ "labelKey": "panels.general.language-select-label", "descriptionKey": "panels.general.language-select-description", "widget": "NComboBox", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1388,7 +1388,7 @@ "labelKey": "panels.location.location-search-label", "descriptionKey": "panels.location.location-search-description", "widget": "NTextInput", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1397,7 +1397,7 @@ "labelKey": "panels.location.weather-enabled-label", "descriptionKey": "panels.location.weather-enabled-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1406,7 +1406,7 @@ "labelKey": "panels.location.weather-fahrenheit-label", "descriptionKey": "panels.location.weather-fahrenheit-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1415,7 +1415,7 @@ "labelKey": "panels.location.weather-show-effects-label", "descriptionKey": "panels.location.weather-show-effects-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1424,7 +1424,7 @@ "labelKey": "panels.location.weather-hide-city-label", "descriptionKey": "panels.location.weather-hide-city-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1433,7 +1433,7 @@ "labelKey": "panels.location.weather-hide-timezone-label", "descriptionKey": "panels.location.weather-hide-timezone-description", "widget": "NToggle", - "tab": 16, + "tab": 17, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1442,7 +1442,7 @@ "labelKey": "panels.session-menu.large-buttons-style-label", "descriptionKey": "panels.session-menu.large-buttons-style-description", "widget": "NToggle", - "tab": 12, + "tab": 13, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1451,7 +1451,7 @@ "labelKey": "panels.session-menu.large-buttons-layout-label", "descriptionKey": "panels.session-menu.large-buttons-layout-description", "widget": "NComboBox", - "tab": 12, + "tab": 13, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1460,7 +1460,7 @@ "labelKey": "panels.session-menu.show-header-label", "descriptionKey": "panels.session-menu.show-header-description", "widget": "NToggle", - "tab": 12, + "tab": 13, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1469,7 +1469,7 @@ "labelKey": "panels.system-monitor.enable-dgpu-monitoring-label", "descriptionKey": "panels.system-monitor.enable-dgpu-monitoring-description", "widget": "NToggle", - "tab": 17, + "tab": 18, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" @@ -1478,7 +1478,7 @@ "labelKey": "panels.system-monitor.use-custom-highlight-colors-label", "descriptionKey": "panels.system-monitor.use-custom-highlight-colors-description", "widget": "NToggle", - "tab": 17, + "tab": 18, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" @@ -1487,7 +1487,7 @@ "labelKey": "panels.system-monitor.external-monitor-label", "descriptionKey": "panels.system-monitor.external-monitor-description", "widget": "NTextInput", - "tab": 17, + "tab": 18, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 43dcd7e9f9..17e1d68780 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -204,7 +204,6 @@ Item { if (!item) return; - item.anchors = undefined; item.x = 0; item.y = 0; @@ -221,13 +220,22 @@ Item { } if (item.hasOwnProperty("sectionWidgetIndex")) { - item.sectionWidgetIndex = index; + // Side panels use dedicated widget arrays, so disable bar-index based lookup + item.sectionWidgetIndex = -1; } if (item.hasOwnProperty("sectionWidgetsCount")) { item.sectionWidgetsCount = root.panelWidgets.length; } + + if (item.hasOwnProperty("widgetSettings")) { + item.widgetSettings = entry; + } + + if (item.hasOwnProperty("widgetMetadata")) { + item.widgetMetadata = BarWidgetRegistry.widgetMetadata[widgetId] || {}; + } for (var key in entry) { if (key === "id") continue; diff --git a/Modules/Panels/Settings/SettingsContent.qml b/Modules/Panels/Settings/SettingsContent.qml index b6d9f8a4bd..ef7a5b955a 100644 --- a/Modules/Panels/Settings/SettingsContent.qml +++ b/Modules/Panels/Settings/SettingsContent.qml @@ -20,6 +20,7 @@ import qs.Modules.Panels.Settings.Tabs.Osd import qs.Modules.Panels.Settings.Tabs.Plugins import qs.Modules.Panels.Settings.Tabs.Region import qs.Modules.Panels.Settings.Tabs.SessionMenu +import qs.Modules.Panels.Settings.Tabs.SidePanels import qs.Modules.Panels.Settings.Tabs.SystemMonitor import qs.Modules.Panels.Settings.Tabs.UserInterface import qs.Modules.Panels.Settings.Tabs.Wallpaper @@ -446,6 +447,10 @@ Item { id: dockTab DockTab {} } + Component { + id: sidePanelsTab + SidePanelsTab {} + } Component { id: notificationsTab NotificationsTab {} @@ -511,6 +516,12 @@ Item { "icon": "settings-bar", "source": barTab }, + { + "id": SettingsPanel.Tab.SidePanels, + "label": "Side Panels", + "icon": "layout-sidebar-left", + "source": sidePanelsTab + }, { "id": SettingsPanel.Tab.Dock, "label": "panels.dock.title", diff --git a/Modules/Panels/Settings/SettingsPanel.qml b/Modules/Panels/Settings/SettingsPanel.qml index 331d6eaa9e..92e6843eeb 100644 --- a/Modules/Panels/Settings/SettingsPanel.qml +++ b/Modules/Panels/Settings/SettingsPanel.qml @@ -73,6 +73,7 @@ SmartPanel { About, Audio, Bar, + SidePanels, ColorScheme, LockScreen, ControlCenter, diff --git a/Modules/Panels/Settings/Tabs/Bar/BarTab.qml b/Modules/Panels/Settings/Tabs/Bar/BarTab.qml index 3f9fb4d1dd..a6327b1398 100644 --- a/Modules/Panels/Settings/Tabs/Bar/BarTab.qml +++ b/Modules/Panels/Settings/Tabs/Bar/BarTab.qml @@ -283,11 +283,6 @@ ColumnLayout { tabIndex: 2 checked: subTabBar.currentIndex === 2 } - NTabButton { - text: "Side panels" - tabIndex: 3 - checked: subTabBar.currentIndex === 3 - } } Item { @@ -313,15 +308,6 @@ ColumnLayout { addMonitor: root.addMonitor removeMonitor: root.removeMonitor } - SidePanelsSubTab { - availableWidgets: availableWidgets - addWidgetToSection: root._addSidePanelWidgetToSection - removeWidgetFromSection: root._removeSidePanelWidgetFromSection - reorderWidgetInSection: root._reorderSidePanelWidgetInSection - updateWidgetSettingsInSection: root._updateSidePanelWidgetSettingsInSection - moveWidgetBetweenSections: root._moveSidePanelWidgetBetweenSections - onOpenPluginSettings: manifest => pluginSettingsDialog.openPluginSettings(manifest) - } } NPluginSettingsPopup { diff --git a/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml new file mode 100644 index 0000000000..4f271d7d89 --- /dev/null +++ b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml @@ -0,0 +1,163 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Modules.Panels.Settings.Tabs.Bar +import qs.Services.Noctalia +import qs.Services.UI +import qs.Widgets + +ColumnLayout { + id: root + spacing: 0 + + function _ensureSidePanelWidgets() { + if (!Settings.data.bar.sidePanels) { + return; + } + if (!Settings.data.bar.sidePanels.leftWidgets) { + Settings.data.bar.sidePanels.leftWidgets = []; + } + if (!Settings.data.bar.sidePanels.rightWidgets) { + Settings.data.bar.sidePanels.rightWidgets = []; + } + } + + function _addSidePanelWidgetToSection(widgetId, section) { + _ensureSidePanelWidgets(); + + var newWidget = { + "id": widgetId + }; + if (BarWidgetRegistry.widgetHasUserSettings(widgetId)) { + var metadata = BarWidgetRegistry.widgetMetadata[widgetId]; + if (metadata) { + Object.keys(metadata).forEach(function (key) { + newWidget[key] = metadata[key]; + }); + } + } + + var key = section + "Widgets"; + Settings.data.bar.sidePanels[key].push(newWidget); + BarService.widgetsRevision++; + } + + function _removeSidePanelWidgetFromSection(section, index) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < widgets.length) { + var newArray = widgets.slice(); + newArray.splice(index, 1); + Settings.data.bar.sidePanels[key] = newArray; + BarService.widgetsRevision++; + } + } + + function _reorderSidePanelWidgetInSection(section, fromIndex, toIndex) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (fromIndex >= 0 && fromIndex < widgets.length && toIndex >= 0 && toIndex < widgets.length) { + var newArray = widgets.slice(); + var item = newArray[fromIndex]; + newArray.splice(fromIndex, 1); + newArray.splice(toIndex, 0, item); + Settings.data.bar.sidePanels[key] = newArray; + BarService.widgetsRevision++; + } + } + + function _updateSidePanelWidgetSettingsInSection(section, index, settings) { + _ensureSidePanelWidgets(); + + var key = section + "Widgets"; + var widgets = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < widgets.length) { + widgets[index] = settings; + Settings.data.bar.sidePanels[key] = widgets.slice(); + } + } + + function _moveSidePanelWidgetBetweenSections(fromSection, index, toSection) { + _ensureSidePanelWidgets(); + + var fromKey = fromSection + "Widgets"; + var toKey = toSection + "Widgets"; + var fromWidgets = Settings.data.bar.sidePanels[fromKey] || []; + var toWidgets = Settings.data.bar.sidePanels[toKey] || []; + + if (index >= 0 && index < fromWidgets.length) { + var widget = fromWidgets[index]; + var sourceArray = fromWidgets.slice(); + sourceArray.splice(index, 1); + var targetArray = toWidgets.slice(); + targetArray.push(widget); + Settings.data.bar.sidePanels[fromKey] = sourceArray; + Settings.data.bar.sidePanels[toKey] = targetArray; + BarService.widgetsRevision++; + } + } + + function updateAvailableWidgetsModel() { + availableWidgets.clear(); + const widgets = BarWidgetRegistry.getAvailableWidgets(); + widgets.forEach(entry => { + const isPlugin = BarWidgetRegistry.isPluginWidget(entry); + let displayName = entry; + if (isPlugin) { + const pluginId = entry.replace("plugin:", ""); + const manifest = PluginRegistry.getPluginManifest(pluginId); + if (manifest && manifest.name) { + displayName = manifest.name; + } else { + displayName = pluginId; + } + } + availableWidgets.append({ + "key": entry, + "name": displayName, + "badges": isPlugin ? [{"icon": "plugin", "color": Color.mSecondary}] : [] + }); + }); + } + + ListModel { + id: availableWidgets + } + + Component.onCompleted: updateAvailableWidgetsModel() + + Connections { + target: BarWidgetRegistry + function onPluginWidgetRegistryUpdated() { + updateAvailableWidgetsModel(); + } + } + + Connections { + target: BarService + function onActiveWidgetsChanged() { + updateAvailableWidgetsModel(); + } + } + + SidePanelsSubTab { + availableWidgets: availableWidgets + addWidgetToSection: root._addSidePanelWidgetToSection + removeWidgetFromSection: root._removeSidePanelWidgetFromSection + reorderWidgetInSection: root._reorderSidePanelWidgetInSection + updateWidgetSettingsInSection: root._updateSidePanelWidgetSettingsInSection + moveWidgetBetweenSections: root._moveSidePanelWidgetBetweenSections + onOpenPluginSettings: manifest => pluginSettingsDialog.openPluginSettings(manifest) + } + + NPluginSettingsPopup { + id: pluginSettingsDialog + parent: Overlay.overlay + showToastOnSave: false + } +} From 1e5f10ea1c4692efbc0299e1b6d2b6c0e94f17aa Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:45:17 -0600 Subject: [PATCH 05/12] Fix SettingsContent lockscreen import by loading tab via source URL --- Assets/settings-search-index.json | 251 ++++++-------------- Modules/Panels/Settings/SettingsContent.qml | 12 +- 2 files changed, 81 insertions(+), 182 deletions(-) diff --git a/Assets/settings-search-index.json b/Assets/settings-search-index.json index 58bbf8b067..d1482820e4 100644 --- a/Assets/settings-search-index.json +++ b/Assets/settings-search-index.json @@ -3,7 +3,7 @@ "labelKey": "panels.about.telemetry-enabled", "descriptionKey": "panels.about.telemetry-desc", "widget": "NToggle", - "tab": 21, + "tab": 20, "tabLabel": "panels.about.title", "subTab": 0, "subTabLabel": "common.info" @@ -12,7 +12,7 @@ "labelKey": "panels.audio.devices-output-device-label", "descriptionKey": "panels.audio.devices-output-device-description", "widget": "NLabel", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 1, "subTabLabel": "common.devices" @@ -21,7 +21,7 @@ "labelKey": "panels.audio.devices-input-device-label", "descriptionKey": "panels.audio.devices-input-device-description", "widget": "NLabel", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 1, "subTabLabel": "common.devices" @@ -30,7 +30,7 @@ "labelKey": "panels.audio.media-primary-player-label", "descriptionKey": "panels.audio.media-primary-player-description", "widget": "NTextInput", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 2, "subTabLabel": "common.media" @@ -39,7 +39,7 @@ "labelKey": "panels.audio.media-excluded-player-label", "descriptionKey": "panels.audio.media-excluded-player-description", "widget": "NTextInputButton", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 2, "subTabLabel": "common.media" @@ -48,7 +48,7 @@ "labelKey": "panels.audio.visualizer-type-label", "descriptionKey": "panels.audio.visualizer-type-description", "widget": "NComboBox", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 3, "subTabLabel": "common.visualizer" @@ -57,7 +57,7 @@ "labelKey": "panels.audio.media-frame-rate-label", "descriptionKey": "panels.audio.media-frame-rate-description", "widget": "NComboBox", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 3, "subTabLabel": "common.visualizer" @@ -66,7 +66,7 @@ "labelKey": "panels.osd.types-volume-label", "descriptionKey": "panels.audio.volumes-output-volume-description", "widget": "NValueSlider", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -75,7 +75,7 @@ "labelKey": "panels.audio.volumes-mute-output-label", "descriptionKey": "panels.audio.volumes-mute-output-description", "widget": "NToggle", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -84,7 +84,7 @@ "labelKey": "panels.audio.volumes-volume-feedback-label", "descriptionKey": "panels.audio.volumes-volume-feedback-description", "widget": "NToggle", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -93,7 +93,7 @@ "labelKey": "panels.osd.types-input-volume-label", "descriptionKey": "panels.audio.volumes-input-volume-description", "widget": "NValueSlider", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -102,7 +102,7 @@ "labelKey": "panels.audio.volumes-mute-input-label", "descriptionKey": "panels.audio.volumes-mute-input-description", "widget": "NToggle", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -111,7 +111,7 @@ "labelKey": "panels.audio.volumes-step-size-label", "descriptionKey": "panels.audio.volumes-step-size-description", "widget": "NSpinBox", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -120,7 +120,7 @@ "labelKey": "panels.audio.volumes-volume-overdrive-label", "descriptionKey": "panels.audio.volumes-volume-overdrive-description", "widget": "NToggle", - "tab": 14, + "tab": 13, "tabLabel": "panels.audio.title", "subTab": 0, "subTabLabel": "common.volumes" @@ -407,7 +407,7 @@ "labelKey": "panels.display.monitors-brightness-step-label", "descriptionKey": "panels.display.monitors-brightness-step-description", "widget": "NSpinBox", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -416,7 +416,7 @@ "labelKey": "panels.display.monitors-enforce-minimum-label", "descriptionKey": "panels.display.monitors-enforce-minimum-description", "widget": "NToggle", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -425,7 +425,7 @@ "labelKey": "panels.display.monitors-external-brightness-label", "descriptionKey": "panels.display.monitors-external-brightness-description", "widget": "NToggle", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 0, "subTabLabel": "common.brightness" @@ -434,7 +434,7 @@ "labelKey": "panels.display.night-light-enable-label", "descriptionKey": "panels.display.night-light-enable-description", "widget": "NToggle", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -443,7 +443,7 @@ "labelKey": "panels.display.night-light-temperature-night", "descriptionKey": "panels.display.night-light-temperature-night-description", "widget": "NLabel", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -452,7 +452,7 @@ "labelKey": "panels.display.night-light-temperature-day", "descriptionKey": "panels.display.night-light-temperature-day-description", "widget": "NLabel", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -461,7 +461,7 @@ "labelKey": "panels.display.night-light-auto-schedule-label", "descriptionKey": "panels.display.night-light-auto-schedule-description", "widget": "NToggle", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -470,7 +470,7 @@ "labelKey": "panels.display.night-light-force-activation-label", "descriptionKey": "panels.display.night-light-force-activation-description", "widget": "NToggle", - "tab": 15, + "tab": 14, "tabLabel": "panels.display.title", "subTab": 1, "subTabLabel": "common.night-light" @@ -635,7 +635,7 @@ "labelKey": "panels.hooks.system-hooks-enable-label", "descriptionKey": "panels.hooks.system-hooks-enable-description", "widget": "NToggle", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 0, "subTabLabel": "common.general" @@ -644,7 +644,7 @@ "labelKey": "panels.hooks.info-parameters-label", "descriptionKey": "panels.hooks.info-parameters-description", "widget": "NLabel", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 0, "subTabLabel": "common.general" @@ -653,7 +653,7 @@ "labelKey": "panels.hooks.noctalia-started-label", "descriptionKey": "panels.hooks.noctalia-started-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -662,7 +662,7 @@ "labelKey": "panels.hooks.wallpaper-changed-label", "descriptionKey": "panels.hooks.wallpaper-changed-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -671,7 +671,7 @@ "labelKey": "panels.hooks.theme-changed-label", "descriptionKey": "panels.hooks.theme-changed-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -680,7 +680,7 @@ "labelKey": "panels.hooks.screen-lock-label", "descriptionKey": "panels.hooks.screen-lock-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -689,7 +689,7 @@ "labelKey": "panels.hooks.screen-unlock-label", "descriptionKey": "panels.hooks.screen-unlock-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -698,7 +698,7 @@ "labelKey": "panels.hooks.performance-mode-enabled-label", "descriptionKey": "panels.hooks.performance-mode-enabled-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -707,7 +707,7 @@ "labelKey": "panels.hooks.performance-mode-disabled-label", "descriptionKey": "panels.hooks.performance-mode-disabled-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -716,7 +716,7 @@ "labelKey": "panels.hooks.session-label", "descriptionKey": "panels.hooks.session-description", "widget": "HookRow", - "tab": 20, + "tab": 19, "tabLabel": "panels.hooks.title", "subTab": 1, "subTabLabel": "panels.hooks.title" @@ -919,128 +919,11 @@ "subTab": 0, "subTabLabel": "common.general" }, - { - "labelKey": "panels.lock-screen.clock-style-label", - "descriptionKey": "panels.lock-screen.clock-style-description", - "widget": "NComboBox", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.clock-format-label", - "descriptionKey": "panels.lock-screen.clock-format-description", - "widget": "NTextInput", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.lock-on-suspend-label", - "descriptionKey": "panels.lock-screen.lock-on-suspend-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.compact-lockscreen-label", - "descriptionKey": "panels.lock-screen.compact-lockscreen-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.lock-screen-animations-label", - "descriptionKey": "panels.lock-screen.lock-screen-animations-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.auto-start-auth-label", - "descriptionKey": "panels.lock-screen.auto-start-auth-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.allow-password-with-fprintd-label", - "descriptionKey": "panels.lock-screen.allow-password-with-fprintd-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.show-session-buttons-label", - "descriptionKey": "panels.lock-screen.show-session-buttons-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.show-hibernate-label", - "descriptionKey": "panels.lock-screen.show-hibernate-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.session-menu.enable-countdown-label", - "descriptionKey": "panels.session-menu.enable-countdown-description", - "widget": "NToggle", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.session-menu.countdown-duration-label", - "descriptionKey": "panels.session-menu.countdown-duration-description", - "widget": "NValueSlider", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.lock-screen-blur-strength-label", - "descriptionKey": "panels.lock-screen.lock-screen-blur-strength-description", - "widget": "NValueSlider", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, - { - "labelKey": "panels.lock-screen.lock-screen-tint-strength-label", - "descriptionKey": "panels.lock-screen.lock-screen-tint-strength-description", - "widget": "NValueSlider", - "tab": 12, - "tabLabel": "panels.lock-screen.title", - "subTab": 0, - "subTabLabel": "common.appearance" - }, { "labelKey": "actions.enable-wifi", "descriptionKey": "panels.network.wifi-description", "widget": "NToggle", - "tab": 16, + "tab": 15, "tabLabel": "common.network", "subTab": null }, @@ -1048,7 +931,7 @@ "labelKey": "actions.enable-bluetooth", "descriptionKey": "panels.network.bluetooth-description", "widget": "NToggle", - "tab": 16, + "tab": 15, "tabLabel": "common.network", "subTab": null }, @@ -1056,7 +939,7 @@ "labelKey": "panels.network.bluetooth-rssi-polling-label", "descriptionKey": "panels.network.bluetooth-rssi-polling-description", "widget": "NToggle", - "tab": 16, + "tab": 15, "tabLabel": "common.network", "subTab": null }, @@ -1289,7 +1172,7 @@ "labelKey": "panels.plugins.available-no-plugins-label", "descriptionKey": "panels.plugins.available-no-plugins-description", "widget": "NLabel", - "tab": 19, + "tab": 18, "tabLabel": "panels.plugins.title", "subTab": 1, "subTabLabel": "common.available" @@ -1298,7 +1181,7 @@ "labelKey": "panels.plugins.auto-update", "descriptionKey": "panels.plugins.auto-update-description", "widget": "NToggle", - "tab": 19, + "tab": 18, "tabLabel": "panels.plugins.title", "subTab": 0, "subTabLabel": "common.installed" @@ -1307,7 +1190,7 @@ "labelKey": "panels.plugins.installed-no-plugins-label", "descriptionKey": "panels.plugins.installed-no-plugins-description", "widget": "NLabel", - "tab": 19, + "tab": 18, "tabLabel": "panels.plugins.title", "subTab": 0, "subTabLabel": "common.installed" @@ -1316,7 +1199,7 @@ "labelKey": "panels.plugins.sources-add-dialog-name", "descriptionKey": null, "widget": "NTextInput", - "tab": 19, + "tab": 18, "tabLabel": "panels.plugins.title", "subTab": 2, "subTabLabel": "common.sources" @@ -1325,7 +1208,7 @@ "labelKey": "panels.plugins.sources-add-dialog-url", "descriptionKey": null, "widget": "NTextInput", - "tab": 19, + "tab": 18, "tabLabel": "panels.plugins.title", "subTab": 2, "subTabLabel": "common.sources" @@ -1334,7 +1217,7 @@ "labelKey": "panels.location.date-time-use-analog-label", "descriptionKey": "panels.location.date-time-use-analog-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1343,7 +1226,7 @@ "labelKey": "panels.location.date-time-week-numbers-label", "descriptionKey": "panels.location.date-time-week-numbers-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1352,7 +1235,7 @@ "labelKey": "panels.location.date-time-show-events-label", "descriptionKey": "panels.location.date-time-show-events-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 2, "subTabLabel": "common.calendar-panel" @@ -1361,7 +1244,7 @@ "labelKey": "panels.location.date-time-12hour-format-label", "descriptionKey": "panels.location.date-time-12hour-format-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 1, "subTabLabel": "common.date" @@ -1370,7 +1253,7 @@ "labelKey": "panels.location.date-time-first-day-of-week-label", "descriptionKey": "panels.location.date-time-first-day-of-week-description", "widget": "NComboBox", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 1, "subTabLabel": "common.date" @@ -1379,7 +1262,7 @@ "labelKey": "panels.general.language-select-label", "descriptionKey": "panels.general.language-select-description", "widget": "NComboBox", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1388,7 +1271,7 @@ "labelKey": "panels.location.location-search-label", "descriptionKey": "panels.location.location-search-description", "widget": "NTextInput", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1397,7 +1280,7 @@ "labelKey": "panels.location.weather-enabled-label", "descriptionKey": "panels.location.weather-enabled-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1406,7 +1289,7 @@ "labelKey": "panels.location.weather-fahrenheit-label", "descriptionKey": "panels.location.weather-fahrenheit-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1415,7 +1298,7 @@ "labelKey": "panels.location.weather-show-effects-label", "descriptionKey": "panels.location.weather-show-effects-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1424,7 +1307,7 @@ "labelKey": "panels.location.weather-hide-city-label", "descriptionKey": "panels.location.weather-hide-city-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1433,7 +1316,7 @@ "labelKey": "panels.location.weather-hide-timezone-label", "descriptionKey": "panels.location.weather-hide-timezone-description", "widget": "NToggle", - "tab": 17, + "tab": 16, "tabLabel": "panels.region.title", "subTab": 0, "subTabLabel": "common.location" @@ -1442,7 +1325,7 @@ "labelKey": "panels.session-menu.large-buttons-style-label", "descriptionKey": "panels.session-menu.large-buttons-style-description", "widget": "NToggle", - "tab": 13, + "tab": 12, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1451,7 +1334,7 @@ "labelKey": "panels.session-menu.large-buttons-layout-label", "descriptionKey": "panels.session-menu.large-buttons-layout-description", "widget": "NComboBox", - "tab": 13, + "tab": 12, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1460,7 +1343,25 @@ "labelKey": "panels.session-menu.show-header-label", "descriptionKey": "panels.session-menu.show-header-description", "widget": "NToggle", - "tab": 13, + "tab": 12, + "tabLabel": "session-menu.title", + "subTab": 0, + "subTabLabel": "common.general" + }, + { + "labelKey": "panels.session-menu.enable-countdown-label", + "descriptionKey": "panels.session-menu.enable-countdown-description", + "widget": "NToggle", + "tab": 12, + "tabLabel": "session-menu.title", + "subTab": 0, + "subTabLabel": "common.general" + }, + { + "labelKey": "panels.session-menu.countdown-duration-label", + "descriptionKey": "panels.session-menu.countdown-duration-description", + "widget": "NValueSlider", + "tab": 12, "tabLabel": "session-menu.title", "subTab": 0, "subTabLabel": "common.general" @@ -1469,7 +1370,7 @@ "labelKey": "panels.system-monitor.enable-dgpu-monitoring-label", "descriptionKey": "panels.system-monitor.enable-dgpu-monitoring-description", "widget": "NToggle", - "tab": 18, + "tab": 17, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" @@ -1478,7 +1379,7 @@ "labelKey": "panels.system-monitor.use-custom-highlight-colors-label", "descriptionKey": "panels.system-monitor.use-custom-highlight-colors-description", "widget": "NToggle", - "tab": 18, + "tab": 17, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" @@ -1487,7 +1388,7 @@ "labelKey": "panels.system-monitor.external-monitor-label", "descriptionKey": "panels.system-monitor.external-monitor-description", "widget": "NTextInput", - "tab": 18, + "tab": 17, "tabLabel": "system-monitor.title", "subTab": 0, "subTabLabel": "common.general" diff --git a/Modules/Panels/Settings/SettingsContent.qml b/Modules/Panels/Settings/SettingsContent.qml index ef7a5b955a..e96cfa6919 100644 --- a/Modules/Panels/Settings/SettingsContent.qml +++ b/Modules/Panels/Settings/SettingsContent.qml @@ -14,7 +14,6 @@ import qs.Modules.Panels.Settings.Tabs.Display import qs.Modules.Panels.Settings.Tabs.Dock import qs.Modules.Panels.Settings.Tabs.Hooks import qs.Modules.Panels.Settings.Tabs.Launcher -import qs.Modules.Panels.Settings.Tabs.LockScreen import qs.Modules.Panels.Settings.Tabs.Notifications import qs.Modules.Panels.Settings.Tabs.Osd import qs.Modules.Panels.Settings.Tabs.Plugins @@ -62,6 +61,8 @@ Item { readonly property bool panelVeryTransparent: Settings.data.ui.panelBackgroundOpacity <= 0.75 + readonly property url lockScreenTabUrl: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Tabs/LockScreen/LockScreenTab.qml") + onSearchResultsChanged: { searchSelectedIndex = 0; ignoreMouseHover = true; @@ -463,10 +464,6 @@ Item { id: userInterfaceTab UserInterfaceTab {} } - Component { - id: lockScreenTab - LockScreenTab {} - } Component { id: sessionMenuTab SessionMenuTab {} @@ -562,7 +559,7 @@ Item { "id": SettingsPanel.Tab.LockScreen, "label": "panels.lock-screen.title", "icon": "settings-lock-screen", - "source": lockScreenTab + "sourceUrl": lockScreenTabUrl }, { "id": SettingsPanel.Tab.SessionMenu, @@ -1241,7 +1238,8 @@ Item { Loader { active: true - sourceComponent: root.tabsModel[index]?.source + source: root.tabsModel[index]?.sourceUrl || "" + sourceComponent: root.tabsModel[index]?.sourceUrl ? undefined : root.tabsModel[index]?.source width: scrollView.availableWidth onLoaded: { if (item && item.hasOwnProperty("screen")) { From 929c954660f7436483ae83ad048b062f7e7f561d Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:02:42 -0600 Subject: [PATCH 06/12] Harden side widget property assignment and fix side panel tab icon --- Modules/MainScreen/SideWidgetPanel.qml | 10 +++++++++- Modules/Panels/Settings/SettingsContent.qml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 17e1d68780..8419ba8ced 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -239,8 +239,16 @@ Item { for (var key in entry) { if (key === "id") continue; - if (item.hasOwnProperty(key)) { + if (!item.hasOwnProperty(key)) + continue; + + // Some widgets expose settings as readonly computed props (ex: displayMode), + // so direct assignment can throw. Keep loader resilient and let widgetSettings + // drive those values. + try { item[key] = entry[key]; + } catch (e) { + Logger.d("SideWidgetPanel", "Skipping read-only setting", key, "for", widgetId); } } diff --git a/Modules/Panels/Settings/SettingsContent.qml b/Modules/Panels/Settings/SettingsContent.qml index e96cfa6919..ee80c40338 100644 --- a/Modules/Panels/Settings/SettingsContent.qml +++ b/Modules/Panels/Settings/SettingsContent.qml @@ -516,7 +516,7 @@ Item { { "id": SettingsPanel.Tab.SidePanels, "label": "Side Panels", - "icon": "layout-sidebar-left", + "icon": "settings-bar", "source": sidePanelsTab }, { From 775d67808be5e8d5a8fa9d8a45d94c7fae8c8a1e Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:42:54 -0600 Subject: [PATCH 07/12] Switch side panels from widget hosts to panel launchers --- Assets/settings-default.json | 12 +- Commons/Settings.qml | 12 +- Modules/MainScreen/SideWidgetPanel.qml | 143 +++++++--------- .../Settings/Tabs/Bar/SidePanelsSubTab.qml | 48 +++--- .../Tabs/SidePanels/SidePanelsTab.qml | 159 ++++++++---------- 5 files changed, 170 insertions(+), 204 deletions(-) diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 5deeaec4c7..51caecc159 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -77,20 +77,20 @@ "hideDelay": 250, "padding": 12, "spacing": 8, - "leftWidgets": [ + "leftPanels": [ { - "id": "Clock" + "id": "controlCenterPanel" }, { - "id": "SystemMonitor" + "id": "notificationHistoryPanel" } ], - "rightWidgets": [ + "rightPanels": [ { - "id": "Network" + "id": "networkPanel" }, { - "id": "Volume" + "id": "sessionMenuPanel" } ] } diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 228f16c67e..67ebb6671b 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -267,20 +267,20 @@ Singleton { property int hideDelay: 250 property int padding: 12 property int spacing: 8 - property list leftWidgets: [ + property list leftPanels: [ { - "id": "Clock" + "id": "controlCenterPanel" }, { - "id": "SystemMonitor" + "id": "notificationHistoryPanel" } ] - property list rightWidgets: [ + property list rightPanels: [ { - "id": "Network" + "id": "networkPanel" }, { - "id": "Volume" + "id": "sessionMenuPanel" } ] } diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 8419ba8ced..bf454f0e43 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Layouts import Quickshell import qs.Commons -import qs.Services.Noctalia import qs.Services.UI +import qs.Widgets Item { id: root @@ -21,20 +21,21 @@ Item { return isLeft ? (settings?.leftEnabled ?? true) : (settings?.rightEnabled ?? true); } - readonly property var panelWidgets: { - // Depend on revision so this recomputes when settings arrays are mutated + readonly property var panelEntries: { var _rev = BarService.widgetsRevision; - var fromSidePanels = isLeft ? settings?.leftWidgets : settings?.rightWidgets; + var fromSidePanels = isLeft ? settings?.leftPanels : settings?.rightPanels; if (fromSidePanels && fromSidePanels.length !== undefined) { return fromSidePanels; } - // Backward compatibility: if side panel widgets don't exist, fallback to bar sections - var barWidgets = Settings.getBarWidgetsForScreen(screen?.name); - if (!barWidgets) - return []; - return isLeft ? (barWidgets.left || []) : (barWidgets.right || []); + // Backward compatibility with older settings keys + var fromLegacy = isLeft ? settings?.leftWidgets : settings?.rightWidgets; + if (fromLegacy && fromLegacy.length !== undefined) { + return fromLegacy; + } + + return []; } readonly property real panelPadding: settings?.padding ?? Style.marginM @@ -51,7 +52,7 @@ Item { return Math.min(panelMaxWidth, Math.max(panelMinWidth, width)); } - readonly property bool visiblePanel: panelEnabled && panelWidgets.length > 0 + readonly property bool visiblePanel: panelEnabled && panelEntries.length > 0 property bool revealed: false @@ -71,7 +72,6 @@ Item { readonly property real barMarginH: barFloating ? Math.floor(Settings.data.bar.marginHorizontal || 0) : 0 readonly property real barMarginV: barFloating ? Math.floor(Settings.data.bar.marginVertical || 0) : 0 - // Keep side panel attached to screen/bar layout so it doesn't overlap the bar readonly property real insetTop: (barShouldShow && barPosition === "top") ? (barHeight + barMarginV) : 0 readonly property real insetBottom: (barShouldShow && barPosition === "bottom") ? (barHeight + barMarginV) : 0 readonly property real insetLeft: (barShouldShow && barPosition === "left") ? (barHeight + barMarginH) : 0 @@ -83,6 +83,46 @@ Item { readonly property real shownX: isLeft ? insetLeft : (parent ? parent.width - insetRight - panelBody.width : 0) readonly property real hiddenX: isLeft ? (insetLeft - panelBody.width) : (parent ? parent.width - insetRight : 0) + function panelName(panelId: string): string { + switch (panelId) { + case "audioPanel": + return I18n.tr("panels.audio.title"); + case "batteryPanel": + return I18n.tr("battery.battery"); + case "bluetoothPanel": + return I18n.tr("common.bluetooth"); + case "brightnessPanel": + return I18n.tr("panels.osd.types-brightness-label"); + case "clockPanel": + return I18n.tr("common.calendar"); + case "controlCenterPanel": + return I18n.tr("panels.control-center.title"); + case "launcherPanel": + return I18n.tr("panels.launcher.title"); + case "mediaPlayerPanel": + return I18n.tr("common.media"); + case "networkPanel": + return I18n.tr("common.network"); + case "notificationHistoryPanel": + return I18n.tr("panels.notifications.history-title"); + case "sessionMenuPanel": + return I18n.tr("session-menu.title"); + case "settingsPanel": + return I18n.tr("panels.general.title"); + case "wallpaperPanel": + return I18n.tr("common.wallpaper"); + default: + return panelId; + } + } + + function openPanel(panelId: string) { + var panel = PanelService.getPanel(panelId, screen, true); + if (panel && panel.toggle) { + panel.toggle(); + } + } + function reveal() { if (!visiblePanel) return; @@ -149,7 +189,6 @@ Item { border.width: 1 radius: Style.radiusL - // Keep screen-edge side flush; flatten corners where attached to top/bottom bar for seamless junction topLeftRadius: root.isLeft || root.attachedToTopBar ? 0 : radius bottomLeftRadius: root.isLeft || root.attachedToBottomBar ? 0 : radius topRightRadius: root.isRight || root.attachedToTopBar ? 0 : radius @@ -187,79 +226,19 @@ Item { spacing: root.panelSpacing Repeater { - model: root.panelWidgets + model: root.panelEntries - delegate: Loader { - id: widgetLoader + delegate: NButton { required property var modelData - required property int index - readonly property var entry: modelData || {} - readonly property string widgetId: entry.id || "" - - active: widgetId !== "" && BarWidgetRegistry.hasWidget(widgetId) - sourceComponent: active ? BarWidgetRegistry.getWidget(widgetId) : null - - onLoaded: { - if (!item) - return; - - item.x = 0; - item.y = 0; - - if (item.hasOwnProperty("screen")) { - item.screen = root.screen; - } - - if (item.hasOwnProperty("widgetId")) { - item.widgetId = widgetId; - } - - if (item.hasOwnProperty("section")) { - item.section = root.isLeft ? "left" : "right"; - } - - if (item.hasOwnProperty("sectionWidgetIndex")) { - // Side panels use dedicated widget arrays, so disable bar-index based lookup - item.sectionWidgetIndex = -1; - } - - if (item.hasOwnProperty("sectionWidgetsCount")) { - item.sectionWidgetsCount = root.panelWidgets.length; - } - - - if (item.hasOwnProperty("widgetSettings")) { - item.widgetSettings = entry; - } - - if (item.hasOwnProperty("widgetMetadata")) { - item.widgetMetadata = BarWidgetRegistry.widgetMetadata[widgetId] || {}; - } - for (var key in entry) { - if (key === "id") - continue; - if (!item.hasOwnProperty(key)) - continue; - - // Some widgets expose settings as readonly computed props (ex: displayMode), - // so direct assignment can throw. Keep loader resilient and let widgetSettings - // drive those values. - try { - item[key] = entry[key]; - } catch (e) { - Logger.d("SideWidgetPanel", "Skipping read-only setting", key, "for", widgetId); - } - } - - if (BarWidgetRegistry.isPluginWidget(widgetId)) { - var pluginId = widgetId.replace("plugin:", ""); - var api = PluginService.getPluginAPI(pluginId); - if (api && item.hasOwnProperty("pluginApi")) { - item.pluginApi = api; - } - } - } + readonly property string panelId: entry.id || "" + + Layout.fillWidth: true + enabled: panelId !== "" + text: root.panelName(panelId) + icon: "chevron-right" + fontSize: Style.fontSizeM + onClicked: root.openPanel(panelId) } } } diff --git a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml index 5a0ebf7f7f..3f9e72c824 100644 --- a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml @@ -12,11 +12,11 @@ ColumnLayout { Layout.fillWidth: true property var availableWidgets - property var addWidgetToSection - property var removeWidgetFromSection - property var reorderWidgetInSection - property var updateWidgetSettingsInSection - property var moveWidgetBetweenSections + property var addPanelToSection + property var removePanelFromSection + property var reorderPanelInSection + property var updatePanelInSection + property var movePanelBetweenSections signal openPluginSettings(var manifest) @@ -30,7 +30,7 @@ ColumnLayout { } NText { - text: "Configure side panels and choose widgets shown on each side." + text: "Configure side panels and choose which panels are opened from each side." wrapMode: Text.WordWrap Layout.fillWidth: true color: Color.mOnSurfaceVariant @@ -52,7 +52,7 @@ ColumnLayout { NComboBox { label: "Panel width mode" - description: "Auto fits to widget content or use a fixed width." + description: "Auto fits to panel content or use a fixed width." model: [ {"key": "auto", "name": "Auto"}, {"key": "fixed", "name": "Fixed"} @@ -153,32 +153,34 @@ ColumnLayout { NSectionEditor { sectionName: I18n.tr("positions.left") sectionId: "left" - settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") - widgetRegistry: BarWidgetRegistry - widgetModel: sidePanels.leftWidgets + settingsDialogComponent: "" + widgetRegistry: null + widgetModel: sidePanels.leftPanels + availableSections: ["left", "right"] sectionIcons: root.getSectionIcons() availableWidgets: root.availableWidgets - onAddWidget: (widgetId, section) => root.addWidgetToSection(widgetId, section) - onRemoveWidget: (section, index) => root.removeWidgetFromSection(section, index) - onReorderWidget: (section, fromIndex, toIndex) => root.reorderWidgetInSection(section, fromIndex, toIndex) - onUpdateWidgetSettings: (section, index, settings) => root.updateWidgetSettingsInSection(section, index, settings) - onMoveWidget: (fromSection, index, toSection) => root.moveWidgetBetweenSections(fromSection, index, toSection) + onAddWidget: (panelId, section) => root.addPanelToSection(panelId, section) + onRemoveWidget: (section, index) => root.removePanelFromSection(section, index) + onReorderWidget: (section, fromIndex, toIndex) => root.reorderPanelInSection(section, fromIndex, toIndex) + onUpdateWidgetSettings: (section, index, settings) => root.updatePanelInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => root.movePanelBetweenSections(fromSection, index, toSection) onOpenPluginSettingsRequested: manifest => root.openPluginSettings(manifest) } NSectionEditor { sectionName: I18n.tr("positions.right") sectionId: "right" - settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml") - widgetRegistry: BarWidgetRegistry - widgetModel: sidePanels.rightWidgets + settingsDialogComponent: "" + widgetRegistry: null + widgetModel: sidePanels.rightPanels + availableSections: ["left", "right"] sectionIcons: root.getSectionIcons() availableWidgets: root.availableWidgets - onAddWidget: (widgetId, section) => root.addWidgetToSection(widgetId, section) - onRemoveWidget: (section, index) => root.removeWidgetFromSection(section, index) - onReorderWidget: (section, fromIndex, toIndex) => root.reorderWidgetInSection(section, fromIndex, toIndex) - onUpdateWidgetSettings: (section, index, settings) => root.updateWidgetSettingsInSection(section, index, settings) - onMoveWidget: (fromSection, index, toSection) => root.moveWidgetBetweenSections(fromSection, index, toSection) + onAddWidget: (panelId, section) => root.addPanelToSection(panelId, section) + onRemoveWidget: (section, index) => root.removePanelFromSection(section, index) + onReorderWidget: (section, fromIndex, toIndex) => root.reorderPanelInSection(section, fromIndex, toIndex) + onUpdateWidgetSettings: (section, index, settings) => root.updatePanelInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => root.movePanelBetweenSections(fromSection, index, toSection) onOpenPluginSettingsRequested: manifest => root.openPluginSettings(manifest) } } diff --git a/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml index 4f271d7d89..97948c68ae 100644 --- a/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml +++ b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml @@ -3,7 +3,6 @@ import QtQuick.Controls import QtQuick.Layouts import qs.Commons import qs.Modules.Panels.Settings.Tabs.Bar -import qs.Services.Noctalia import qs.Services.UI import qs.Widgets @@ -11,58 +10,50 @@ ColumnLayout { id: root spacing: 0 - function _ensureSidePanelWidgets() { + function _ensureSidePanelLists() { if (!Settings.data.bar.sidePanels) { return; } - if (!Settings.data.bar.sidePanels.leftWidgets) { - Settings.data.bar.sidePanels.leftWidgets = []; + if (!Settings.data.bar.sidePanels.leftPanels) { + Settings.data.bar.sidePanels.leftPanels = []; } - if (!Settings.data.bar.sidePanels.rightWidgets) { - Settings.data.bar.sidePanels.rightWidgets = []; + if (!Settings.data.bar.sidePanels.rightPanels) { + Settings.data.bar.sidePanels.rightPanels = []; } } - function _addSidePanelWidgetToSection(widgetId, section) { - _ensureSidePanelWidgets(); + function _addSidePanelToSection(panelId, section) { + _ensureSidePanelLists(); - var newWidget = { - "id": widgetId + var panelEntry = { + "id": panelId }; - if (BarWidgetRegistry.widgetHasUserSettings(widgetId)) { - var metadata = BarWidgetRegistry.widgetMetadata[widgetId]; - if (metadata) { - Object.keys(metadata).forEach(function (key) { - newWidget[key] = metadata[key]; - }); - } - } - var key = section + "Widgets"; - Settings.data.bar.sidePanels[key].push(newWidget); + var key = section + "Panels"; + Settings.data.bar.sidePanels[key].push(panelEntry); BarService.widgetsRevision++; } - function _removeSidePanelWidgetFromSection(section, index) { - _ensureSidePanelWidgets(); + function _removeSidePanelFromSection(section, index) { + _ensureSidePanelLists(); - var key = section + "Widgets"; - var widgets = Settings.data.bar.sidePanels[key] || []; - if (index >= 0 && index < widgets.length) { - var newArray = widgets.slice(); + var key = section + "Panels"; + var panels = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < panels.length) { + var newArray = panels.slice(); newArray.splice(index, 1); Settings.data.bar.sidePanels[key] = newArray; BarService.widgetsRevision++; } } - function _reorderSidePanelWidgetInSection(section, fromIndex, toIndex) { - _ensureSidePanelWidgets(); + function _reorderSidePanelInSection(section, fromIndex, toIndex) { + _ensureSidePanelLists(); - var key = section + "Widgets"; - var widgets = Settings.data.bar.sidePanels[key] || []; - if (fromIndex >= 0 && fromIndex < widgets.length && toIndex >= 0 && toIndex < widgets.length) { - var newArray = widgets.slice(); + var key = section + "Panels"; + var panels = Settings.data.bar.sidePanels[key] || []; + if (fromIndex >= 0 && fromIndex < panels.length && toIndex >= 0 && toIndex < panels.length) { + var newArray = panels.slice(); var item = newArray[fromIndex]; newArray.splice(fromIndex, 1); newArray.splice(toIndex, 0, item); @@ -71,87 +62,81 @@ ColumnLayout { } } - function _updateSidePanelWidgetSettingsInSection(section, index, settings) { - _ensureSidePanelWidgets(); + function _updateSidePanelInSection(section, index, panelEntry) { + _ensureSidePanelLists(); - var key = section + "Widgets"; - var widgets = Settings.data.bar.sidePanels[key] || []; - if (index >= 0 && index < widgets.length) { - widgets[index] = settings; - Settings.data.bar.sidePanels[key] = widgets.slice(); + var key = section + "Panels"; + var panels = Settings.data.bar.sidePanels[key] || []; + if (index >= 0 && index < panels.length) { + panels[index] = panelEntry; + Settings.data.bar.sidePanels[key] = panels.slice(); } } - function _moveSidePanelWidgetBetweenSections(fromSection, index, toSection) { - _ensureSidePanelWidgets(); + function _moveSidePanelBetweenSections(fromSection, index, toSection) { + _ensureSidePanelLists(); - var fromKey = fromSection + "Widgets"; - var toKey = toSection + "Widgets"; - var fromWidgets = Settings.data.bar.sidePanels[fromKey] || []; - var toWidgets = Settings.data.bar.sidePanels[toKey] || []; + var fromKey = fromSection + "Panels"; + var toKey = toSection + "Panels"; + var fromPanels = Settings.data.bar.sidePanels[fromKey] || []; + var toPanels = Settings.data.bar.sidePanels[toKey] || []; - if (index >= 0 && index < fromWidgets.length) { - var widget = fromWidgets[index]; - var sourceArray = fromWidgets.slice(); + if (index >= 0 && index < fromPanels.length) { + var panelEntry = fromPanels[index]; + var sourceArray = fromPanels.slice(); sourceArray.splice(index, 1); - var targetArray = toWidgets.slice(); - targetArray.push(widget); + var targetArray = toPanels.slice(); + targetArray.push(panelEntry); Settings.data.bar.sidePanels[fromKey] = sourceArray; Settings.data.bar.sidePanels[toKey] = targetArray; BarService.widgetsRevision++; } } - function updateAvailableWidgetsModel() { - availableWidgets.clear(); - const widgets = BarWidgetRegistry.getAvailableWidgets(); - widgets.forEach(entry => { - const isPlugin = BarWidgetRegistry.isPluginWidget(entry); - let displayName = entry; - if (isPlugin) { - const pluginId = entry.replace("plugin:", ""); - const manifest = PluginRegistry.getPluginManifest(pluginId); - if (manifest && manifest.name) { - displayName = manifest.name; - } else { - displayName = pluginId; - } - } - availableWidgets.append({ - "key": entry, - "name": displayName, - "badges": isPlugin ? [{"icon": "plugin", "color": Color.mSecondary}] : [] - }); - }); + function updateAvailablePanelsModel() { + availablePanels.clear(); + + var panels = [ + {"key": "audioPanel", "name": I18n.tr("panels.audio.title")}, + {"key": "batteryPanel", "name": I18n.tr("battery.battery")}, + {"key": "bluetoothPanel", "name": I18n.tr("common.bluetooth")}, + {"key": "brightnessPanel", "name": I18n.tr("panels.osd.types-brightness-label")}, + {"key": "clockPanel", "name": I18n.tr("common.calendar")}, + {"key": "controlCenterPanel", "name": I18n.tr("panels.control-center.title")}, + {"key": "launcherPanel", "name": I18n.tr("panels.launcher.title")}, + {"key": "mediaPlayerPanel", "name": I18n.tr("common.media")}, + {"key": "networkPanel", "name": I18n.tr("common.network")}, + {"key": "notificationHistoryPanel", "name": I18n.tr("panels.notifications.history-title")}, + {"key": "sessionMenuPanel", "name": I18n.tr("session-menu.title")}, + {"key": "settingsPanel", "name": I18n.tr("panels.general.title")}, + {"key": "wallpaperPanel", "name": I18n.tr("common.wallpaper")}, + ]; + + for (var i = 0; i < panels.length; i++) { + availablePanels.append(panels[i]); + } } ListModel { - id: availableWidgets + id: availablePanels } - Component.onCompleted: updateAvailableWidgetsModel() - - Connections { - target: BarWidgetRegistry - function onPluginWidgetRegistryUpdated() { - updateAvailableWidgetsModel(); - } - } + Component.onCompleted: updateAvailablePanelsModel() Connections { target: BarService function onActiveWidgetsChanged() { - updateAvailableWidgetsModel(); + updateAvailablePanelsModel(); } } SidePanelsSubTab { - availableWidgets: availableWidgets - addWidgetToSection: root._addSidePanelWidgetToSection - removeWidgetFromSection: root._removeSidePanelWidgetFromSection - reorderWidgetInSection: root._reorderSidePanelWidgetInSection - updateWidgetSettingsInSection: root._updateSidePanelWidgetSettingsInSection - moveWidgetBetweenSections: root._moveSidePanelWidgetBetweenSections + availableWidgets: availablePanels + addPanelToSection: root._addSidePanelToSection + removePanelFromSection: root._removeSidePanelFromSection + reorderPanelInSection: root._reorderSidePanelInSection + updatePanelInSection: root._updateSidePanelInSection + movePanelBetweenSections: root._moveSidePanelBetweenSections onOpenPluginSettings: manifest => pluginSettingsDialog.openPluginSettings(manifest) } From f05509132105ae6b8b1c7fe09bc8955bcf860e7c Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:57:53 -0600 Subject: [PATCH 08/12] Improve side panel selection with panel catalog and layout controls --- Assets/settings-default.json | 3 + Commons/Settings.qml | 3 + Modules/MainScreen/SideWidgetPanel.qml | 95 +++++++++++++++---- .../Settings/Tabs/Bar/SidePanelsSubTab.qml | 52 +++++++++- .../Tabs/SidePanels/SidePanelsTab.qml | 68 ++++++++++--- 5 files changed, 188 insertions(+), 33 deletions(-) diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 51caecc159..76dc7c164f 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -77,6 +77,9 @@ "hideDelay": 250, "padding": 12, "spacing": 8, + "layoutMode": "list", + "gridColumns": 2, + "itemStyle": "filled", "leftPanels": [ { "id": "controlCenterPanel" diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 67ebb6671b..2ee2edab55 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -267,6 +267,9 @@ Singleton { property int hideDelay: 250 property int padding: 12 property int spacing: 8 + property string layoutMode: "list" + property int gridColumns: 2 + property string itemStyle: "filled" property list leftPanels: [ { "id": "controlCenterPanel" diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index bf454f0e43..a214f068a4 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -21,21 +21,69 @@ Item { return isLeft ? (settings?.leftEnabled ?? true) : (settings?.rightEnabled ?? true); } + readonly property string layoutMode: settings?.layoutMode ?? "list" // "list" | "grid" + readonly property int gridColumns: Math.max(1, Math.min(4, settings?.gridColumns ?? 2)) + readonly property string itemStyle: settings?.itemStyle ?? "filled" // "filled" | "outline" | "minimal" + + function normalizePanelId(panelId: string): string { + switch (panelId) { + case "Audio": + return "audioPanel"; + case "Battery": + return "batteryPanel"; + case "Bluetooth": + return "bluetoothPanel"; + case "Brightness": + return "brightnessPanel"; + case "Clock": + return "clockPanel"; + case "ControlCenter": + return "controlCenterPanel"; + case "Launcher": + return "launcherPanel"; + case "MediaMini": + return "mediaPlayerPanel"; + case "Network": + return "networkPanel"; + case "NotificationHistory": + return "notificationHistoryPanel"; + case "SessionMenu": + return "sessionMenuPanel"; + case "Settings": + return "settingsPanel"; + case "WallpaperSelector": + return "wallpaperPanel"; + default: + return panelId; + } + } + readonly property var panelEntries: { var _rev = BarService.widgetsRevision; var fromSidePanels = isLeft ? settings?.leftPanels : settings?.rightPanels; + var sourceEntries = []; + if (fromSidePanels && fromSidePanels.length !== undefined) { - return fromSidePanels; + sourceEntries = fromSidePanels; + } else { + // Backward compatibility with older settings keys + var fromLegacy = isLeft ? settings?.leftWidgets : settings?.rightWidgets; + if (fromLegacy && fromLegacy.length !== undefined) + sourceEntries = fromLegacy; } - // Backward compatibility with older settings keys - var fromLegacy = isLeft ? settings?.leftWidgets : settings?.rightWidgets; - if (fromLegacy && fromLegacy.length !== undefined) { - return fromLegacy; + var normalized = []; + for (var i = 0; i < sourceEntries.length; i++) { + var entry = sourceEntries[i] || {}; + var normalizedId = normalizePanelId(entry.id || ""); + if (normalizedId === "") + continue; + normalized.push({ + "id": normalizedId + }); } - - return []; + return normalized; } readonly property real panelPadding: settings?.padding ?? Style.marginM @@ -48,7 +96,7 @@ Item { readonly property int configuredWidth: Math.max(panelMinWidth, settings?.width ?? 320) readonly property real computedPanelWidth: { - var width = useAutoWidth ? (contentColumn.implicitWidth + panelPadding * 2) : configuredWidth; + var width = useAutoWidth ? (contentLayout.implicitWidth + panelPadding * 2) : configuredWidth; return Math.min(panelMaxWidth, Math.max(panelMinWidth, width)); } @@ -93,6 +141,8 @@ Item { return I18n.tr("common.bluetooth"); case "brightnessPanel": return I18n.tr("panels.osd.types-brightness-label"); + case "changelogPanel": + return I18n.tr("panels.changelog.title"); case "clockPanel": return I18n.tr("common.calendar"); case "controlCenterPanel": @@ -109,6 +159,12 @@ Item { return I18n.tr("session-menu.title"); case "settingsPanel": return I18n.tr("panels.general.title"); + case "setupWizardPanel": + return I18n.tr("setup-wizard.title"); + case "systemStatsPanel": + return I18n.tr("panels.system-monitor.title"); + case "trayDrawerPanel": + return I18n.tr("common.tray"); case "wallpaperPanel": return I18n.tr("common.wallpaper"); default: @@ -142,9 +198,8 @@ Item { } onVisiblePanelChanged: { - if (!visiblePanel) { + if (!visiblePanel) concealNow(); - } } Timer { @@ -152,9 +207,8 @@ Item { interval: hideDelay repeat: false onTriggered: { - if (!triggerZone.containsMouse && !panelMouseArea.containsMouse) { + if (!triggerZone.containsMouse && !panelMouseArea.containsMouse) root.revealed = false; - } } } @@ -216,14 +270,16 @@ Item { anchors.fill: parent anchors.margins: root.panelPadding contentWidth: width - contentHeight: contentColumn.implicitHeight + contentHeight: contentLayout.implicitHeight clip: true interactive: contentHeight > height - ColumnLayout { - id: contentColumn + GridLayout { + id: contentLayout width: flick.width - spacing: root.panelSpacing + columns: root.layoutMode === "grid" ? root.gridColumns : 1 + columnSpacing: root.panelSpacing + rowSpacing: root.panelSpacing Repeater { model: root.panelEntries @@ -232,12 +288,19 @@ Item { required property var modelData readonly property var entry: modelData || {} readonly property string panelId: entry.id || "" + readonly property bool minimal: root.itemStyle === "minimal" + readonly property bool outlined: root.itemStyle === "outline" Layout.fillWidth: true + Layout.columnSpan: root.layoutMode === "list" ? contentLayout.columns : 1 enabled: panelId !== "" text: root.panelName(panelId) icon: "chevron-right" fontSize: Style.fontSizeM + colorBg: minimal ? "transparent" : Qt.alpha(Color.mSurfaceContainerHighest, 0.7) + colorBorder: outlined ? Color.mOutline : (minimal ? "transparent" : Qt.alpha(Color.mOutline, 0.35)) + colorFg: Color.mOnSurface + colorBgHover: minimal ? Qt.alpha(Color.mSurfaceContainerHighest, 0.35) : Qt.alpha(Color.mSurfaceContainerHighest, 0.95) onClicked: root.openPanel(panelId) } } diff --git a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml index 3f9e72c824..c05399ba00 100644 --- a/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml @@ -53,10 +53,7 @@ ColumnLayout { NComboBox { label: "Panel width mode" description: "Auto fits to panel content or use a fixed width." - model: [ - {"key": "auto", "name": "Auto"}, - {"key": "fixed", "name": "Fixed"} - ] + model: [{"key": "auto", "name": "Auto"}, {"key": "fixed", "name": "Fixed"}] currentKey: sidePanels.widthMode onSelected: key => sidePanels.widthMode = key } @@ -92,6 +89,53 @@ ColumnLayout { } } + NComboBox { + label: "Panel items layout" + description: "Choose how panel launchers are arranged inside each side panel." + model: [{"key": "list", "name": "List"}, {"key": "grid", "name": "Grid"}] + currentKey: sidePanels.layoutMode ?? "list" + onSelected: key => sidePanels.layoutMode = key + } + + NLabel { + label: "Grid columns" + description: "Used when layout is set to grid." + visible: (sidePanels.layoutMode ?? "list") === "grid" + } + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginM + visible: (sidePanels.layoutMode ?? "list") === "grid" + + NSlider { + id: gridColumnsSlider + Layout.fillWidth: true + from: 1 + to: 4 + stepSize: 1 + value: sidePanels.gridColumns ?? 2 + onPressedChanged: { + if (!pressed) + sidePanels.gridColumns = Math.round(value); + } + } + + NText { + text: Math.round(gridColumnsSlider.value) + " cols" + pointSize: Style.fontSizeM + color: Color.mOnSurfaceVariant + } + } + + NComboBox { + label: "Panel item style" + description: "Visual style for each panel launcher item." + model: [{"key": "filled", "name": "Filled"}, {"key": "outline", "name": "Outline"}, {"key": "minimal", "name": "Minimal"}] + currentKey: sidePanels.itemStyle ?? "filled" + onSelected: key => sidePanels.itemStyle = key + } + NLabel { label: "Edge trigger size" description: "How wide the hover activation strip is on each side." diff --git a/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml index 97948c68ae..04e2e02968 100644 --- a/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml +++ b/Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml @@ -10,15 +10,55 @@ ColumnLayout { id: root spacing: 0 + readonly property var legacyWidgetToPanelMap: ({ + "Audio": "audioPanel", + "Battery": "batteryPanel", + "Bluetooth": "bluetoothPanel", + "Brightness": "brightnessPanel", + "Clock": "clockPanel", + "ControlCenter": "controlCenterPanel", + "Launcher": "launcherPanel", + "MediaMini": "mediaPlayerPanel", + "Network": "networkPanel", + "NotificationHistory": "notificationHistoryPanel", + "SessionMenu": "sessionMenuPanel", + "Settings": "settingsPanel", + "WallpaperSelector": "wallpaperPanel" + }) + + function normalizePanelId(id) { + return legacyWidgetToPanelMap[id] || id; + } + + function normalizePanelEntries(list) { + var source = list || []; + var normalized = []; + for (var i = 0; i < source.length; i++) { + var entry = source[i] || {}; + var id = normalizePanelId(entry.id || ""); + if (id === "") + continue; + normalized.push({ + "id": id + }); + } + return normalized; + } + function _ensureSidePanelLists() { - if (!Settings.data.bar.sidePanels) { + if (!Settings.data.bar.sidePanels) return; - } + if (!Settings.data.bar.sidePanels.leftPanels) { - Settings.data.bar.sidePanels.leftPanels = []; + Settings.data.bar.sidePanels.leftPanels = normalizePanelEntries(Settings.data.bar.sidePanels.leftWidgets || []); + } else { + Settings.data.bar.sidePanels.leftPanels = normalizePanelEntries(Settings.data.bar.sidePanels.leftPanels); } + if (!Settings.data.bar.sidePanels.rightPanels) { - Settings.data.bar.sidePanels.rightPanels = []; + Settings.data.bar.sidePanels.rightPanels = normalizePanelEntries(Settings.data.bar.sidePanels.rightWidgets || []); + } else { + Settings.data.bar.sidePanels.rightPanels = normalizePanelEntries(Settings.data.bar.sidePanels.rightPanels); } } @@ -68,7 +108,9 @@ ColumnLayout { var key = section + "Panels"; var panels = Settings.data.bar.sidePanels[key] || []; if (index >= 0 && index < panels.length) { - panels[index] = panelEntry; + panels[index] = { + "id": normalizePanelId((panelEntry || {}).id || "") + }; Settings.data.bar.sidePanels[key] = panels.slice(); } } @@ -101,6 +143,7 @@ ColumnLayout { {"key": "batteryPanel", "name": I18n.tr("battery.battery")}, {"key": "bluetoothPanel", "name": I18n.tr("common.bluetooth")}, {"key": "brightnessPanel", "name": I18n.tr("panels.osd.types-brightness-label")}, + {"key": "changelogPanel", "name": I18n.tr("panels.changelog.title")}, {"key": "clockPanel", "name": I18n.tr("common.calendar")}, {"key": "controlCenterPanel", "name": I18n.tr("panels.control-center.title")}, {"key": "launcherPanel", "name": I18n.tr("panels.launcher.title")}, @@ -109,7 +152,10 @@ ColumnLayout { {"key": "notificationHistoryPanel", "name": I18n.tr("panels.notifications.history-title")}, {"key": "sessionMenuPanel", "name": I18n.tr("session-menu.title")}, {"key": "settingsPanel", "name": I18n.tr("panels.general.title")}, - {"key": "wallpaperPanel", "name": I18n.tr("common.wallpaper")}, + {"key": "setupWizardPanel", "name": I18n.tr("setup-wizard.title")}, + {"key": "systemStatsPanel", "name": I18n.tr("panels.system-monitor.title")}, + {"key": "trayDrawerPanel", "name": I18n.tr("common.tray")}, + {"key": "wallpaperPanel", "name": I18n.tr("common.wallpaper")} ]; for (var i = 0; i < panels.length; i++) { @@ -121,13 +167,9 @@ ColumnLayout { id: availablePanels } - Component.onCompleted: updateAvailablePanelsModel() - - Connections { - target: BarService - function onActiveWidgetsChanged() { - updateAvailablePanelsModel(); - } + Component.onCompleted: { + _ensureSidePanelLists(); + updateAvailablePanelsModel(); } SidePanelsSubTab { From 2d7ea5e77eda89285023ae29764cd8868237cd70 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:05:59 -0600 Subject: [PATCH 09/12] Fix side panel button styling crash and add deploy helper --- Modules/MainScreen/SideWidgetPanel.qml | 12 ++-- Scripts/dev/deploy-sidepanels.sh | 98 ++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100755 Scripts/dev/deploy-sidepanels.sh diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index a214f068a4..22e619d81d 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -289,7 +289,8 @@ Item { readonly property var entry: modelData || {} readonly property string panelId: entry.id || "" readonly property bool minimal: root.itemStyle === "minimal" - readonly property bool outlined: root.itemStyle === "outline" + readonly property bool outlinedStyle: root.itemStyle === "outline" + readonly property color launcherBaseColor: minimal ? "transparent" : Qt.alpha(Color.mSurfaceContainerHighest, 0.7) Layout.fillWidth: true Layout.columnSpan: root.layoutMode === "list" ? contentLayout.columns : 1 @@ -297,10 +298,11 @@ Item { text: root.panelName(panelId) icon: "chevron-right" fontSize: Style.fontSizeM - colorBg: minimal ? "transparent" : Qt.alpha(Color.mSurfaceContainerHighest, 0.7) - colorBorder: outlined ? Color.mOutline : (minimal ? "transparent" : Qt.alpha(Color.mOutline, 0.35)) - colorFg: Color.mOnSurface - colorBgHover: minimal ? Qt.alpha(Color.mSurfaceContainerHighest, 0.35) : Qt.alpha(Color.mSurfaceContainerHighest, 0.95) + outlined: outlinedStyle + backgroundColor: outlinedStyle ? Color.mOutline : launcherBaseColor + textColor: Color.mOnSurface + hoverColor: minimal ? Qt.alpha(Color.mSurfaceContainerHighest, 0.35) : Qt.alpha(Color.mSurfaceContainerHighest, 0.95) + textHoverColor: Color.mOnSurface onClicked: root.openPanel(panelId) } } diff --git a/Scripts/dev/deploy-sidepanels.sh b/Scripts/dev/deploy-sidepanels.sh new file mode 100755 index 0000000000..a8f0080250 --- /dev/null +++ b/Scripts/dev/deploy-sidepanels.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Deploy side-panels related files from a downloaded Noctalia zip. +# Usage: +# ./Scripts/dev/deploy-sidepanels.sh /path/to/noctalia.zip [/etc/xdg/quickshell/noctalia-shell] + +ZIP_PATH="${1:-}" +TARGET_ROOT="${2:-/etc/xdg/quickshell/noctalia-shell}" + +if [[ -z "$ZIP_PATH" ]]; then + echo "Usage: $0 /path/to/noctalia.zip [target_root]" + exit 1 +fi + +if [[ ! -f "$ZIP_PATH" ]]; then + echo "ERROR: Zip file not found: $ZIP_PATH" + exit 1 +fi + +if [[ ! -d "$TARGET_ROOT" ]]; then + echo "ERROR: Target root not found: $TARGET_ROOT" + exit 1 +fi + +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_DIR"' EXIT + +UNZIP_DIR="$TMP_DIR/unzipped" +mkdir -p "$UNZIP_DIR" + +echo "==> Unzipping: $ZIP_PATH" +unzip -q "$ZIP_PATH" -d "$UNZIP_DIR" + +# Detect repo root by locating shell.qml (safe with spaces) +SOURCE_SHELL_QML="$(find "$UNZIP_DIR" -type f -name shell.qml -print -quit || true)" +if [[ -z "$SOURCE_SHELL_QML" ]]; then + echo "ERROR: Could not find shell.qml inside zip (cannot detect source root)." + exit 1 +fi +SOURCE_ROOT="$(dirname "$SOURCE_SHELL_QML")" + +echo "==> Source root: $SOURCE_ROOT" +echo "==> Target root: $TARGET_ROOT" + +STAMP="$(date +%Y%m%d-%H%M%S)" +BACKUP_ROOT="$TARGET_ROOT/.backup-sidepanels-$STAMP" +mkdir -p "$BACKUP_ROOT" + +# Side-panel feature files (new + changed) +FILES=( + "Assets/settings-default.json" + "Assets/settings-search-index.json" + "Commons/Settings.qml" + "Modules/MainScreen/MainScreen.qml" + "Modules/MainScreen/SideWidgetPanel.qml" + "Modules/Panels/Settings/SettingsContent.qml" + "Modules/Panels/Settings/SettingsPanel.qml" + "Modules/Panels/Settings/Tabs/Bar/BarTab.qml" + "Modules/Panels/Settings/Tabs/Bar/SidePanelsSubTab.qml" + "Modules/Panels/Settings/Tabs/SidePanels/SidePanelsTab.qml" +) + +copied=0 +missing=0 + +for rel in "${FILES[@]}"; do + src="$SOURCE_ROOT/$rel" + dst="$TARGET_ROOT/$rel" + + if [[ ! -f "$src" ]]; then + echo "WARN: Missing in zip, skipped: $rel" + ((missing+=1)) + continue + fi + + mkdir -p "$(dirname "$dst")" + mkdir -p "$(dirname "$BACKUP_ROOT/$rel")" + + if [[ -f "$dst" ]]; then + cp -a "$dst" "$BACKUP_ROOT/$rel" + fi + + cp -a "$src" "$dst" + echo "OK: $rel" + ((copied+=1)) +done + +echo +echo "==> Done" +echo "Copied: $copied" +echo "Missing: $missing" +echo "Backup: $BACKUP_ROOT" + +echo +echo "Now restart quickshell/noctalia (example):" +echo " pkill -f quickshell || true" +echo " qs -c noctalia-shell &" From d219a9a0ed6be457730e3fb31f88c9447a8890c6 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:54:30 -0600 Subject: [PATCH 10/12] Embed selected panel content inside side panels --- Modules/MainScreen/SideWidgetPanel.qml | 62 ++++++++++++++++++++------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 22e619d81d..8859481ff1 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -172,6 +172,18 @@ Item { } } + + function getPanelObject(panelId: string) { + return PanelService.getPanel(panelId, screen, true); + } + + function getPanelContentComponent(panelId: string) { + var panelObj = getPanelObject(panelId); + if (panelObj && panelObj.panelContent) + return panelObj.panelContent; + return null; + } + function openPanel(panelId: string) { var panel = PanelService.getPanel(panelId, screen, true); if (panel && panel.toggle) { @@ -284,26 +296,48 @@ Item { Repeater { model: root.panelEntries - delegate: NButton { + delegate: Item { required property var modelData readonly property var entry: modelData || {} readonly property string panelId: entry.id || "" - readonly property bool minimal: root.itemStyle === "minimal" - readonly property bool outlinedStyle: root.itemStyle === "outline" - readonly property color launcherBaseColor: minimal ? "transparent" : Qt.alpha(Color.mSurfaceContainerHighest, 0.7) + readonly property var panelObject: root.getPanelObject(panelId) Layout.fillWidth: true Layout.columnSpan: root.layoutMode === "list" ? contentLayout.columns : 1 - enabled: panelId !== "" - text: root.panelName(panelId) - icon: "chevron-right" - fontSize: Style.fontSizeM - outlined: outlinedStyle - backgroundColor: outlinedStyle ? Color.mOutline : launcherBaseColor - textColor: Color.mOnSurface - hoverColor: minimal ? Qt.alpha(Color.mSurfaceContainerHighest, 0.35) : Qt.alpha(Color.mSurfaceContainerHighest, 0.95) - textHoverColor: Color.mOnSurface - onClicked: root.openPanel(panelId) + implicitHeight: embeddedLoader.active && embeddedLoader.item ? embeddedLoader.item.implicitHeight : fallbackButton.implicitHeight + + Loader { + id: embeddedLoader + anchors.left: parent.left + anchors.right: parent.right + active: panelId !== "" + sourceComponent: root.getPanelContentComponent(panelId) + + onLoaded: { + if (!item) + return; + if (item.hasOwnProperty("screen")) + item.screen = root.screen; + if (item.hasOwnProperty("panelID") && panelObject && panelObject.panelID !== undefined) + item.panelID = panelObject.panelID; + } + } + + NButton { + id: fallbackButton + visible: !embeddedLoader.item + enabled: panelId !== "" + anchors.left: parent.left + anchors.right: parent.right + text: root.panelName(panelId) + icon: "chevron-right" + fontSize: Style.fontSizeM + backgroundColor: Qt.alpha(Color.mSurfaceContainerHighest, 0.7) + hoverColor: Qt.alpha(Color.mSurfaceContainerHighest, 0.95) + textColor: Color.mOnSurface + textHoverColor: Color.mOnSurface + onClicked: root.openPanel(panelId) + } } } } From 011d01ab3eec655b0702550eedbffce7da68d853 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Sat, 14 Feb 2026 18:11:20 -0600 Subject: [PATCH 11/12] Improve embedded side-panel content sizing and binding --- Modules/MainScreen/SideWidgetPanel.qml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index 8859481ff1..ab741c36b5 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -304,7 +304,7 @@ Item { Layout.fillWidth: true Layout.columnSpan: root.layoutMode === "list" ? contentLayout.columns : 1 - implicitHeight: embeddedLoader.active && embeddedLoader.item ? embeddedLoader.item.implicitHeight : fallbackButton.implicitHeight + implicitHeight: embeddedLoader.active && embeddedLoader.item ? ((embeddedLoader.item.contentPreferredHeight !== undefined && embeddedLoader.item.contentPreferredHeight > 0) ? embeddedLoader.item.contentPreferredHeight : Math.max(embeddedLoader.item.implicitHeight || 0, 120 * Style.uiScaleRatio)) : fallbackButton.implicitHeight Loader { id: embeddedLoader @@ -316,6 +316,26 @@ Item { onLoaded: { if (!item) return; + + if (item.anchors && item.anchors.fill !== undefined) + item.anchors.fill = embeddedLoader; + + if (item.hasOwnProperty("width")) { + item.width = Qt.binding(function () { + return embeddedLoader.width; + }); + } + + if (item.hasOwnProperty("height")) { + item.height = Qt.binding(function () { + if (item.contentPreferredHeight !== undefined && item.contentPreferredHeight > 0) + return item.contentPreferredHeight; + if (item.implicitHeight !== undefined && item.implicitHeight > 0) + return item.implicitHeight; + return 120 * Style.uiScaleRatio; + }); + } + if (item.hasOwnProperty("screen")) item.screen = root.screen; if (item.hasOwnProperty("panelID") && panelObject && panelObject.panelID !== undefined) From 775a02718a6d025e86c7027529c3617851ec0575 Mon Sep 17 00:00:00 2001 From: xdonu2x <79326585+xdonu2x@users.noreply.github.com> Date: Sat, 14 Feb 2026 18:21:36 -0600 Subject: [PATCH 12/12] Resolve side panel embedded content after panel registration --- Modules/MainScreen/SideWidgetPanel.qml | 44 ++++++++++++++++++-------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/Modules/MainScreen/SideWidgetPanel.qml b/Modules/MainScreen/SideWidgetPanel.qml index ab741c36b5..67174b3df0 100644 --- a/Modules/MainScreen/SideWidgetPanel.qml +++ b/Modules/MainScreen/SideWidgetPanel.qml @@ -103,6 +103,7 @@ Item { readonly property bool visiblePanel: panelEnabled && panelEntries.length > 0 property bool revealed: false + property int panelLookupRevision: 0 property alias panelBody: panelBody property alias triggerZone: triggerZone @@ -173,17 +174,6 @@ Item { } - function getPanelObject(panelId: string) { - return PanelService.getPanel(panelId, screen, true); - } - - function getPanelContentComponent(panelId: string) { - var panelObj = getPanelObject(panelId); - if (panelObj && panelObj.panelContent) - return panelObj.panelContent; - return null; - } - function openPanel(panelId: string) { var panel = PanelService.getPanel(panelId, screen, true); if (panel && panel.toggle) { @@ -214,6 +204,31 @@ Item { concealNow(); } + + Timer { + id: panelResolveTimer + interval: 250 + repeat: true + running: root.visiblePanel + + onTriggered: { + root.panelLookupRevision++; + + var unresolved = 0; + for (var i = 0; i < root.panelEntries.length; i++) { + var entry = root.panelEntries[i] || {}; + var panelId = entry.id || ""; + if (!panelId) + continue; + if (!PanelService.getPanel(panelId, root.screen, true)) + unresolved++; + } + + if (unresolved === 0) + stop(); + } + } + Timer { id: hideTimer interval: hideDelay @@ -300,7 +315,10 @@ Item { required property var modelData readonly property var entry: modelData || {} readonly property string panelId: entry.id || "" - readonly property var panelObject: root.getPanelObject(panelId) + readonly property var panelObject: { + var _rev = root.panelLookupRevision; + return PanelService.getPanel(panelId, root.screen, true); + } Layout.fillWidth: true Layout.columnSpan: root.layoutMode === "list" ? contentLayout.columns : 1 @@ -311,7 +329,7 @@ Item { anchors.left: parent.left anchors.right: parent.right active: panelId !== "" - sourceComponent: root.getPanelContentComponent(panelId) + sourceComponent: panelObject && panelObject.panelContent ? panelObject.panelContent : null onLoaded: { if (!item)