diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 76b87f64..8a08982e 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -833,7 +833,26 @@ "description": "Configure and manage the shortcuts widgets." }, "sectionLeft": "Left", - "sectionRight": "Right" + "sectionRight": "Right", + "custom-button": { + "icon": { + "label": "Icon", + "description": "Select an icon from the library." + }, + "browse": "Browse", + "command": { + "label": "Command", + "description": "The command to execute when the button is clicked." + }, + "tooltip": { + "label": "Tooltip", + "description": "The tooltip to show when hovering over the button." + } + }, + "dialog": { + "cancel": "Cancel", + "apply": "Apply" + } } }, "user-interface": { @@ -1450,15 +1469,16 @@ "search": "Search...", "select": "Select", "cancel": "Cancel", - "test": "Test" + "test": "Test", + "enter-tooltip": "Enter tooltip" }, "options": { "colors": { "primary": "Primary", "secondary": "Secondary", - "tertiary": "Tertiary", - "error": "Error", - "onSurface": "On Surface" + "tertiary": "Tertiary", + "error": "Error", + "onSurface": "On Surface" }, "bar": { "position": { diff --git a/Modules/ControlCenter/Cards/ShortcutsCard.qml b/Modules/ControlCenter/Cards/ShortcutsCard.qml index 2100a76b..3d478861 100644 --- a/Modules/ControlCenter/Cards/ShortcutsCard.qml +++ b/Modules/ControlCenter/Cards/ShortcutsCard.qml @@ -35,7 +35,8 @@ RowLayout { "widgetId": modelData.id, "section": "quickSettings", "sectionWidgetIndex": index, - "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.left.length + "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.left.length, + "widgetSettings": modelData } Layout.alignment: Qt.AlignVCenter } @@ -70,7 +71,8 @@ RowLayout { "widgetId": modelData.id, "section": "quickSettings", "sectionWidgetIndex": index, - "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.right.length + "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.right.length, + "widgetSettings": modelData } Layout.alignment: Qt.AlignVCenter } diff --git a/Modules/ControlCenter/Widgets/CustomButton.qml b/Modules/ControlCenter/Widgets/CustomButton.qml new file mode 100644 index 00000000..12b35343 --- /dev/null +++ b/Modules/ControlCenter/Widgets/CustomButton.qml @@ -0,0 +1,34 @@ +import QtQuick +import Quickshell +import qs.Commons +import qs.Services +import qs.Widgets + +// Dummy comment to force re-evaluation +Item { + id: root + + // Widget properties + property string widgetId: "CustomButton" + property var widgetSettings: {} // This will be populated from settings + + // Use settings or provide defaults + readonly property string customIcon: widgetSettings.icon || "heart" + readonly property string exec: widgetSettings.exec || "" + readonly property string tooltipText: widgetSettings.tooltipText || "Custom Button" + + implicitWidth: button.implicitWidth + implicitHeight: button.implicitHeight + + NIconButton { + id: button + icon: customIcon + tooltipText: tooltipText + onClicked: { + if (exec) { + Quickshell.execDetached(["sh", "-c", exec]) + Logger.i("CC:CustomButton", `Executing command: ${exec}`) + } + } + } +} diff --git a/Modules/Settings/ControlCenter/ControlCenterWidgetSettingsDialog.qml b/Modules/Settings/ControlCenter/ControlCenterWidgetSettingsDialog.qml new file mode 100644 index 00000000..a0aaaa01 --- /dev/null +++ b/Modules/Settings/ControlCenter/ControlCenterWidgetSettingsDialog.qml @@ -0,0 +1,120 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Widgets +import qs.Services + +// Widget Settings Dialog Component +Popup { + id: root + + property int widgetIndex: -1 + property var widgetData: null + property string widgetId: "" + property string sectionId: "" + + signal updateWidgetSettings(string section, int index, var settings) + + width: Math.max(content.implicitWidth + padding * 2, 500) + height: content.implicitHeight + padding * 2 + padding: Style.marginXL + modal: true + anchors.centerIn: parent + + onOpened: { + PanelService.willOpenPopup(root) + if (widgetData && widgetId) { + loadWidgetSettings() + } + } + + onClosed: { + PanelService.willClosePopup(root) + } + + background: Rectangle { + color: Color.mSurface + radius: Style.radiusL + border.color: Color.mPrimary + border.width: Style.borderM + } + + contentItem: ColumnLayout { + id: content + width: parent.width + spacing: Style.marginM + + // Title + RowLayout { + Layout.fillWidth: true + + NText { + text: I18n.tr("system.widget-settings-title", { "widget": root.widgetId }) + pointSize: Style.fontSizeL + font.weight: Style.fontWeightBold + color: Color.mPrimary + Layout.fillWidth: true + } + + NIconButton { + icon: "close" + tooltipText: I18n.tr("tooltips.close") + onClicked: root.close() + } + } + + // Separator + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: Color.mOutline + } + + Loader { + id: settingsLoader + Layout.fillWidth: true + } + + // Action buttons + RowLayout { + Layout.fillWidth: true + Layout.topMargin: Style.marginM + spacing: Style.marginM + + Item { Layout.fillWidth: true } + + NButton { + text: I18n.tr("settings.control-center.shortcuts.dialog.cancel", "Cancel") + outlined: true + onClicked: root.close() + } + + NButton { + text: I18n.tr("settings.control-center.shortcuts.dialog.apply", "Apply") + icon: "check" + onClicked: { + if (settingsLoader.item && settingsLoader.item.saveSettings) { + var newSettings = settingsLoader.item.saveSettings() + root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings) + root.close() + } + } + } + } + } + + function loadWidgetSettings() { + const widgetSettingsMap = { + "CustomButton": "WidgetSettings/CustomButtonSettings.qml" + } + + const source = widgetSettingsMap[widgetId] + if (source) { + settingsLoader.setSource(source, { + "widgetData": widgetData, + "widgetMetadata": ControlCenterWidgetRegistry.widgetMetadata[widgetId] + }) + } + } +} diff --git a/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml b/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml new file mode 100644 index 00000000..516db036 --- /dev/null +++ b/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml @@ -0,0 +1,70 @@ +import QtQuick +import QtQuick.Layouts +import qs.Commons +import qs.Widgets + +ColumnLayout { + id: root + spacing: Style.marginM + + property var widgetData: null + property var widgetMetadata: null + + property string valueIcon: widgetData.icon !== undefined ? widgetData.icon : widgetMetadata.icon + property string valueTooltip: widgetData.tooltipText !== undefined ? widgetData.tooltipText : widgetMetadata.tooltipText + + function saveSettings() { + var settings = Object.assign({}, widgetData || {}) + settings.icon = valueIcon + settings.exec = execInput.text + settings.tooltipText = tooltipInput.text + return settings + } + + RowLayout { + spacing: Style.marginM + + NLabel { + label: I18n.tr("settings.control-center.shortcuts.custom-button.icon.label", "Icon") + description: I18n.tr("settings.control-center.shortcuts.custom-button.icon.description", "The icon for the button.") + } + + NIcon { + Layout.alignment: Qt.AlignVCenter + icon: valueIcon + pointSize: Style.fontSizeXL + visible: valueIcon !== "" + } + + NButton { + text: I18n.tr("settings.control-center.shortcuts.custom-button.browse", "Browse") + onClicked: iconPicker.open() + } + } + + NIconPicker { + id: iconPicker + initialIcon: valueIcon + onIconSelected: function (iconName) { + valueIcon = iconName + } + } + + NTextInput { + id: execInput + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.command.label", "Command") + description: I18n.tr("settings.control-center.shortcuts.custom-button.command.description", "The command to execute when the button is clicked.") + placeholderText: I18n.tr("placeholders.enter-command") + text: widgetData?.exec || widgetMetadata.exec + } + + NTextInput { + id: tooltipInput + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.tooltip.label", "Tooltip") + description: I18n.tr("settings.control-center.shortcuts.custom-button.tooltip.description", "The tooltip to show when hovering over the button.") + placeholderText: I18n.tr("placeholders.enter-tooltip") + text: widgetData?.tooltipText || widgetMetadata.tooltipText + } +} diff --git a/Modules/Settings/Tabs/ControlCenterTab.qml b/Modules/Settings/Tabs/ControlCenterTab.qml index 372add57..69110393 100644 --- a/Modules/Settings/Tabs/ControlCenterTab.qml +++ b/Modules/Settings/Tabs/ControlCenterTab.qml @@ -226,7 +226,7 @@ ColumnLayout { NSectionEditor { sectionName: I18n.tr("settings.control-center.shortcuts.sectionLeft") sectionId: "left" - settingsDialogComponent: "" + settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/ControlCenter/ControlCenterWidgetSettingsDialog.qml") maxWidgets: 5 widgetRegistry: ControlCenterWidgetRegistry widgetModel: Settings.data.controlCenter.shortcuts["left"] @@ -245,7 +245,7 @@ ColumnLayout { NSectionEditor { sectionName: I18n.tr("settings.control-center.shortcuts.sectionRight") sectionId: "right" - settingsDialogComponent: "" + settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/ControlCenter/ControlCenterWidgetSettingsDialog.qml") maxWidgets: 5 widgetRegistry: ControlCenterWidgetRegistry widgetModel: Settings.data.controlCenter.shortcuts["right"] diff --git a/Services/ControlCenterWidgetRegistry.qml b/Services/ControlCenterWidgetRegistry.qml index f00263ed..cd7cb6c1 100644 --- a/Services/ControlCenterWidgetRegistry.qml +++ b/Services/ControlCenterWidgetRegistry.qml @@ -17,10 +17,18 @@ Singleton { "PowerProfile": powerProfileComponent, "ScreenRecorder": screenRecorderComponent, "WiFi": wiFiComponent, - "WallpaperSelector": wallpaperSelectorComponent + "WallpaperSelector": wallpaperSelectorComponent, + "CustomButton": customButtonComponent }) - property var widgetMetadata: ({}) + property var widgetMetadata: ({ + "CustomButton": { + "allowUserSettings": true, + "icon": "heart", + "exec": "", + "tooltipText": "Custom Button" + } + }) // Component definitions - these are loaded once at startup property Component bluetoothComponent: Component { @@ -47,6 +55,9 @@ Singleton { property Component wallpaperSelectorComponent: Component { WallpaperSelector {} } + property Component customButtonComponent: Component { + CustomButton {} + } function init() { Logger.i("ControlCenterWidgetRegistry", "Service started")