diff --git a/Commons/Settings.qml b/Commons/Settings.qml index feebe5d..c01c5fe 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -100,6 +100,31 @@ Singleton { Logger.log("Settings", "Settings loaded successfully") isLoaded = true + for (var i = 0; i < adapter.bar.widgets.left.length; i++) { + var obj = adapter.bar.widgets.left[i] + if (typeof obj === "string") { + adapter.bar.widgets.left[i] = { + "id": obj + } + } + } + for (var i = 0; i < adapter.bar.widgets.center.length; i++) { + var obj = adapter.bar.widgets.center[i] + if (typeof obj === "string") { + adapter.bar.widgets.center[i] = { + "id": obj + } + } + } + for (var i = 0; i < adapter.bar.widgets.right.length; i++) { + var obj = adapter.bar.widgets.right[i] + if (typeof obj === "string") { + adapter.bar.widgets.right[i] = { + "id": obj + } + } + } + // Emit the signal root.settingsLoaded() @@ -126,6 +151,8 @@ Singleton { JsonAdapter { id: adapter + property int settingsVersion: 1 + // bar property JsonObject bar: JsonObject { property string position: "top" // Possible values: "top", "bottom" @@ -140,9 +167,39 @@ Singleton { // Widget configuration for modular bar system property JsonObject widgets widgets: JsonObject { - property list left: ["SystemMonitor", "ActiveWindow", "MediaMini"] - property list center: ["Workspace"] - property list right: ["ScreenRecorderIndicator", "Tray", "NotificationHistory", "WiFi", "Bluetooth", "Battery", "Volume", "Brightness", "NightLight", "Clock", "SidePanelToggle"] + property list left: [{ + "id": "SystemMonitor" + }, { + "id": "ActiveWindow" + }, { + "id": "MediaMini" + }] + property list center: [{ + "id": "Workspace" + }] + property list right: [{ + "id": "ScreenRecorderIndicator" + }, { + "id": "Tray" + }, { + "id": "NotificationHistory" + }, { + "id": "WiFi" + }, { + "id": "Bluetooth" + }, { + "id": "Battery" + }, { + "id": "Volume" + }, { + "id": "Brightness" + }, { + "id": "NightLight" + }, { + "id": "Clock" + }, { + "id": "SidePanelToggle" + }] } } diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 59e6655..2c8e6f7 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -73,7 +73,7 @@ Variants { Repeater { model: Settings.data.bar.widgets.left delegate: NWidgetLoader { - widgetName: modelData + widgetId: modelData.id widgetProps: { "screen": root.modelData || null, "scaling": ScalingService.getScreenScale(screen), @@ -100,8 +100,7 @@ Variants { Repeater { model: Settings.data.bar.widgets.center delegate: NWidgetLoader { - - widgetName: modelData + widgetId: modelData.id widgetProps: { "screen": root.modelData || null, "scaling": ScalingService.getScreenScale(screen), @@ -129,7 +128,7 @@ Variants { Repeater { model: Settings.data.bar.widgets.right delegate: NWidgetLoader { - widgetName: modelData + widgetId: modelData.id widgetProps: { "screen": root.modelData || null, "scaling": ScalingService.getScreenScale(screen), diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml new file mode 100644 index 0000000..0467f73 --- /dev/null +++ b/Modules/Bar/Widgets/CustomButton.qml @@ -0,0 +1,26 @@ +import Quickshell +import qs.Commons +import qs.Widgets +import qs.Services + +NIconButton { + id: root + + property ShellScreen screen + property real scaling: 1.0 + property bool allowUserSettings: true + + icon: "favorite" + tooltipText: "Hello world" + sizeRatio: 0.8 + + colorBg: Color.mSurfaceVariant + colorFg: Color.mOnSurface + colorBorder: Color.transparent + colorBorderHover: Color.transparent + + anchors.verticalCenter: parent.verticalCenter + onClicked: { + + } +} diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index e927456..697a0b7 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -162,7 +162,7 @@ ColumnLayout { sectionId: "left" widgetModel: Settings.data.bar.widgets.left availableWidgets: availableWidgets - onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) + onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) } @@ -173,7 +173,7 @@ ColumnLayout { sectionId: "center" widgetModel: Settings.data.bar.widgets.center availableWidgets: availableWidgets - onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) + onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) } @@ -184,7 +184,7 @@ ColumnLayout { sectionId: "right" widgetModel: Settings.data.bar.widgets.right availableWidgets: availableWidgets - onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) + onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) } @@ -198,14 +198,16 @@ ColumnLayout { } // Helper functions - function addWidgetToSection(widgetName, section) { - //Logger.log("BarTab", "Adding widget", widgetName, "to section", section) + function addWidgetToSection(widgetId, section) { + //Logger.log("BarTab", "Adding widget", widgetId, "to section", section) var sectionArray = Settings.data.bar.widgets[section] if (sectionArray) { // Create a new array to avoid modifying the original var newArray = sectionArray.slice() - newArray.push(widgetName) + newArray.push({ + "id": widgetId + }) //Logger.log("BarTab", "Widget added. New array:", JSON.stringify(newArray)) // Assign the new array diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index fc7016a..f99ebe6 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -16,6 +16,7 @@ Singleton { "Bluetooth": bluetoothComponent, "Brightness": brightnessComponent, "Clock": clockComponent, + "CustomButton": customButtonComponent, "DarkModeToggle": darkModeToggle, "KeyboardLayout": keyboardLayoutComponent, "MediaMini": mediaMiniComponent, @@ -33,6 +34,15 @@ Singleton { "Workspace": workspaceComponent }) + property var widgetMetadata: ({ + "CustomButton": { + allowUserSettings: true, + icon: "favorite", + execute: "" + }, + }) + + // Component definitions - these are loaded once at startup property Component activeWindowComponent: Component { ActiveWindow {} @@ -52,6 +62,9 @@ Singleton { property Component clockComponent: Component { Clock {} } + property Component customButtonComponent: Component { + CustomButton {} + } property Component darkModeToggle: Component { DarkModeToggle {} } @@ -100,20 +113,25 @@ Singleton { // ------------------------------ // Helper function to get widget component by name - function getWidget(name) { - return widgets[name] || null + function getWidget(id) { + return widgets[id] || null } // Helper function to check if widget exists - function hasWidget(name) { - return name in widgets + function hasWidget(id) { + return id in widgets } - // Get list of available widget names + // Get list of available widget id function getAvailableWidgets() { return Object.keys(widgets) } + // Helper function to check if widget has user settings + function widgetHasUserSettings(id) { + return (widgetMetadata[id] !== undefined) && (widgetMetadata[id].allowUserSettings === true) + } + function getNPillDirection(widget) { try { if (widget.barSection === "leftSection") { diff --git a/Widgets/NSectionEditor.qml b/Widgets/NSectionEditor.qml index a0a38a9..6813b28 100644 --- a/Widgets/NSectionEditor.qml +++ b/Widgets/NSectionEditor.qml @@ -3,6 +3,7 @@ import QtQuick.Controls import QtQuick.Layouts import qs.Commons import qs.Widgets +import qs.Services NBox { id: root @@ -12,7 +13,7 @@ NBox { property var widgetModel: [] property var availableWidgets: [] - signal addWidget(string widgetName, string section) + signal addWidget(string widgetId, string section) signal removeWidget(string section, int index) signal reorderWidget(string section, int fromIndex, int toIndex) @@ -32,8 +33,8 @@ NBox { } // Generate widget color from name checksum - function getWidgetColor(name) { - const totalSum = name.split('').reduce((acc, character) => { + function getWidgetColor(widgetId) { + const totalSum = widgetId.split('').reduce((acc, character) => { return acc + character.charCodeAt(0) }, 0) switch (totalSum % 5) { @@ -110,17 +111,18 @@ NBox { spacing: Style.marginS * scaling flow: Flow.LeftToRight + Repeater { model: widgetModel delegate: Rectangle { id: widgetItem required property int index - required property string modelData + required property var modelData width: widgetContent.implicitWidth + Style.marginL * scaling height: 40 * scaling radius: Style.radiusL * scaling - color: root.getWidgetColor(modelData) + color: root.getWidgetColor(modelData.id) border.color: Color.mOutline border.width: Math.max(1, Style.borderS * scaling) @@ -151,7 +153,7 @@ NBox { spacing: Style.marginXS * scaling NText { - text: modelData + text: modelData.id font.pointSize: Style.fontSizeS * scaling color: Color.mOnPrimary horizontalAlignment: Text.AlignHCenter @@ -159,6 +161,23 @@ NBox { Layout.preferredWidth: 80 * scaling } + Loader { + active: BarWidgetRegistry.widgetHasUserSettings(modelData.id) + sourceComponent: NIconButton { + icon: "settings" + sizeRatio: 0.6 + colorBorder: Color.applyOpacity(Color.mOutline, "40") + colorBg: Color.mOnSurface + colorFg: Color.mOnPrimary + colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40") + colorFgHover: Color.mOnPrimary + onClicked: { + // TODO open settings + } + } + } + + NIconButton { icon: "close" sizeRatio: 0.6 @@ -193,13 +212,13 @@ NBox { return } - //Logger.log("NSectionEditor", `Started dragging widget: ${modelData} at index ${index}`) + //Logger.log("NSectionEditor", `Started dragging widget: ${modelData.id} at index ${index}`) // Bring to front when starting drag widgetItem.z = 1000 } onReleased: { - //Logger.log("NSectionEditor", `Released widget: ${modelData} at index ${index}`) + //Logger.log("NSectionEditor", `Released widget: ${modelData.id} at index ${index}`) // Reset z-index when drag ends widgetItem.z = 0 diff --git a/Widgets/NWidgetLoader.qml b/Widgets/NWidgetLoader.qml index 1f4046c..17bf887 100644 --- a/Widgets/NWidgetLoader.qml +++ b/Widgets/NWidgetLoader.qml @@ -6,7 +6,7 @@ import qs.Commons Item { id: root - property string widgetName: "" + property string widgetId: "" property var widgetProps: ({}) property bool enabled: true @@ -27,12 +27,12 @@ Item { id: loader anchors.fill: parent - active: Settings.isLoaded && enabled && widgetName !== "" + active: Settings.isLoaded && enabled && widgetId !== "" sourceComponent: { if (!active) { return null } - return BarWidgetRegistry.getWidget(widgetName) + return BarWidgetRegistry.getWidget(widgetId) } onLoaded: { @@ -49,14 +49,14 @@ Item { item.onLoaded() } - //Logger.log("NWidgetLoader", "Loaded", widgetName, "on screen", item.screen.name) + //Logger.log("NWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name) } } // Error handling - onWidgetNameChanged: { - if (widgetName && !BarWidgetRegistry.hasWidget(widgetName)) { - Logger.warn("WidgetLoader", "Widget not found in registry:", widgetName) + onWidgetIdChanged: { + if (widgetId && !BarWidgetRegistry.hasWidget(widgetId)) { + Logger.warn("WidgetLoader", "Widget not found in registry:", widgetId) } } }