diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 8a08982e..6b972cc6 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -847,6 +847,34 @@ "tooltip": { "label": "Tooltip", "description": "The tooltip to show when hovering over the button." + }, + "on-state-icon": { + "label": "On State Icon", + "description": "The icon for the button when it's in the 'on' state." + }, + "on-clicked": { + "label": "Left Click Command", + "description": "Command to execute when the button is left-clicked." + }, + "on-right-clicked": { + "label": "Right Click Command", + "description": "Command to execute when the button is right-clicked." + }, + "on-middle-clicked": { + "label": "Middle Click Command", + "description": "Command to execute when the button is middle-clicked." + }, + "on-state-command": { + "label": "On State Check Command", + "description": "Command to execute to check if the button should be in the 'on' state. Returns 0 for on, non-zero for off." + }, + "general-tooltip-text": { + "label": "General Tooltip Text", + "description": "General description for the button's tooltip." + }, + "enable-on-state-logic": { + "label": "Enable On-State Logic", + "description": "Enable a second icon and 'hot' state based on a check command." } }, "dialog": { diff --git a/Modules/ControlCenter/Widgets/CustomButton.qml b/Modules/ControlCenter/Widgets/CustomButton.qml index 12b35343..cab9df16 100644 --- a/Modules/ControlCenter/Widgets/CustomButton.qml +++ b/Modules/ControlCenter/Widgets/CustomButton.qml @@ -1,5 +1,6 @@ import QtQuick import Quickshell +import Quickshell.Io import qs.Commons import qs.Services import qs.Widgets @@ -10,24 +11,103 @@ Item { // Widget properties property string widgetId: "CustomButton" - property var widgetSettings: {} // This will be populated from settings + property var widgetSettings // 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" + property string onClickedCommand: "" + property string onRightClickedCommand: "" + property string onMiddleClickedCommand: "" + property string initialIcon: "heart" + property string onStateIcon: "heart" + property string onStateCommand: "" + property string generalTooltipText: "Custom Button" + property bool enableOnStateLogic: false + + // Internal state + property string _currentIcon: initialIcon + property bool _isHot: false + + Connections { + target: root + function _updatePropertiesFromSettings() { + onClickedCommand = widgetSettings.onClicked || "" + onRightClickedCommand = widgetSettings.onRightClicked || "" + onMiddleClickedCommand = widgetSettings.onMiddleClicked || "" + initialIcon = (widgetSettings.icon && widgetSettings.icon !== "") ? widgetSettings.icon : "heart" + onStateIcon = (widgetSettings.onStateIcon && widgetSettings.onStateIcon !== "") ? widgetSettings.onStateIcon : "heart" + onStateCommand = widgetSettings.onStateCommand || "" + generalTooltipText = widgetSettings.generalTooltipText || "Custom Button" + enableOnStateLogic = widgetSettings.enableOnStateLogic || false + + updateState() + } + function onWidgetSettingsChanged() { _updatePropertiesFromSettings() } + } + + Process { + id: onStateCheckProcess + running: false + command: ["sh", "-c", onStateCommand] + onExited: function(exitCode, stdout, stderr) { + if (exitCode === 0) { + _isHot = true + _currentIcon = onStateIcon || initialIcon + } else { + _isHot = false + _currentIcon = initialIcon + } + + } + } + + function updateState() { + if (enableOnStateLogic && onStateCommand) { + onStateCheckProcess.running = true // Start the process + } else { + _isHot = false + _currentIcon = initialIcon + } + } + + function _buildTooltipText() { + let tooltip = generalTooltipText + if (onClickedCommand) { + tooltip += `\nLeft click: ${onClickedCommand}` + } + if (onRightClickedCommand) { + tooltip += `\nRight click: ${onRightClickedCommand}` + } + if (onMiddleClickedCommand) { + tooltip += `\nMiddle click: ${onMiddleClickedCommand}` + } + + return tooltip + } implicitWidth: button.implicitWidth implicitHeight: button.implicitHeight - NIconButton { + NIconButtonHot { id: button - icon: customIcon - tooltipText: tooltipText + icon: _currentIcon + hot: _isHot + tooltipText: _buildTooltipText() onClicked: { - if (exec) { - Quickshell.execDetached(["sh", "-c", exec]) - Logger.i("CC:CustomButton", `Executing command: ${exec}`) + if (onClickedCommand) { + Quickshell.execDetached(["sh", "-c", onClickedCommand]) + updateState() + } + } + onRightClicked: { + if (onRightClickedCommand) { + Quickshell.execDetached(["sh", "-c", onRightClickedCommand]) + updateState() + } + } + onMiddleClicked: { + if (onMiddleClickedCommand) { + Quickshell.execDetached(["sh", "-c", onMiddleClickedCommand]) + updateState() } } } diff --git a/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml b/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml index 516db036..1631106c 100644 --- a/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml +++ b/Modules/Settings/ControlCenter/WidgetSettings/CustomButtonSettings.qml @@ -5,66 +5,163 @@ 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 + QtObject { + id: _settings + + property string icon: (widgetData && widgetData.icon !== undefined) ? widgetData.icon : widgetMetadata.icon + property string onStateIcon: (widgetData && widgetData.onStateIcon !== undefined) ? widgetData.onStateIcon : widgetMetadata.onStateIcon + property string onClicked: (widgetData && widgetData.onClicked !== undefined) ? widgetData.onClicked : widgetMetadata.onClicked + property string onRightClicked: (widgetData && widgetData.onRightClicked !== undefined) ? widgetData.onRightClicked : widgetMetadata.onRightClicked + property string onMiddleClicked: (widgetData && widgetData.onMiddleClicked !== undefined) ? widgetData.onMiddleClicked : widgetMetadata.onMiddleClicked + property string onStateCommand: (widgetData && widgetData.onStateCommand !== undefined) ? widgetData.onStateCommand : widgetMetadata.onStateCommand + property string generalTooltipText: (widgetData && widgetData.generalTooltipText !== undefined) ? widgetData.generalTooltipText : widgetMetadata.generalTooltipText + property bool enableOnStateLogic: (widgetData && widgetData.enableOnStateLogic !== undefined) ? widgetData.enableOnStateLogic : widgetMetadata.enableOnStateLogic + + + } function saveSettings() { - var settings = Object.assign({}, widgetData || {}) - settings.icon = valueIcon - settings.exec = execInput.text - settings.tooltipText = tooltipInput.text - return settings + var saved = { + id: widgetData.id, + icon: _settings.icon, + onStateIcon: _settings.onStateIcon, + onClicked: _settings.onClicked, + onRightClicked: _settings.onRightClicked, + onMiddleClicked: _settings.onMiddleClicked, + onStateCommand: _settings.onStateCommand, + generalTooltipText: _settings.generalTooltipText, + enableOnStateLogic: _settings.enableOnStateLogic + } + + return saved } 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.") + label: I18n.tr("settings.control-center.shortcuts.custom-button.icon.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.icon.description") } NIcon { Layout.alignment: Qt.AlignVCenter - icon: valueIcon + icon: _settings.icon || widgetMetadata.icon pointSize: Style.fontSizeXL - visible: valueIcon !== "" + visible: (_settings.icon || widgetMetadata.icon) !== "" } NButton { - text: I18n.tr("settings.control-center.shortcuts.custom-button.browse", "Browse") + text: I18n.tr("settings.control-center.shortcuts.custom-button.browse") onClicked: iconPicker.open() } } NIconPicker { id: iconPicker - initialIcon: valueIcon + initialIcon: _settings.icon onIconSelected: function (iconName) { - valueIcon = iconName + _settings.icon = iconName } } NTextInput { - id: execInput + id: generalTooltipTextInput 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 + label: I18n.tr("settings.control-center.shortcuts.custom-button.general-tooltip-text.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.general-tooltip-text.description") + placeholderText: I18n.tr("placeholders.enter-text") + text: _settings.generalTooltipText + onTextChanged: _settings.generalTooltipText = text } NTextInput { - id: tooltipInput + id: onClickedCommandInput 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 + label: I18n.tr("settings.control-center.shortcuts.custom-button.on-clicked.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.on-clicked.description") + placeholderText: I18n.tr("placeholders.enter-command") + text: _settings.onClicked + onTextChanged: _settings.onClicked = text + } + + NTextInput { + id: onRightClickedCommandInput + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.on-right-clicked.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.on-right-clicked.description") + placeholderText: I18n.tr("placeholders.enter-command") + text: _settings.onRightClicked + onTextChanged: _settings.onRightClicked = text + } + + NTextInput { + id: onMiddleClickedCommandInput + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.on-middle-clicked.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.on-middle-clicked.description") + placeholderText: I18n.tr("placeholders.enter-command") + text: _settings.onMiddleClicked + onTextChanged: _settings.onMiddleClicked = text + } + + NDivider {} + + NToggle { + id: enableOnStateLogicToggle + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.enable-on-state-logic.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.enable-on-state-logic.description") + checked: _settings.enableOnStateLogic + onToggled: checked => _settings.enableOnStateLogic = checked + } + + // On-State Icon + RowLayout { + Layout.fillWidth: true + spacing: Style.marginS + visible: _settings.enableOnStateLogic + + NLabel { + label: I18n.tr("settings.control-center.shortcuts.custom-button.on-state-icon.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.on-state-icon.description") + } + + NIcon { + Layout.alignment: Qt.AlignVCenter + icon: _settings.onStateIcon || widgetMetadata.onStateIcon + pointSize: Style.fontSizeXL + visible: (_settings.onStateIcon || widgetMetadata.onStateIcon) !== "" + } + + NButton { + Layout.fillWidth: true + text: I18n.tr("settings.control-center.shortcuts.custom-button.browse") + onClicked: onStateIconPicker.open() + } + } + + NIconPicker { + id: onStateIconPicker + initialIcon: _settings.onStateIcon + onIconSelected: function (iconName) { + _settings.onStateIcon = iconName + } + } + + NTextInput { + id: onStateCommandInput + Layout.fillWidth: true + label: I18n.tr("settings.control-center.shortcuts.custom-button.on-state-command.label") + description: I18n.tr("settings.control-center.shortcuts.custom-button.on-state-command.description") + placeholderText: I18n.tr("placeholders.enter-command") + text: _settings.onStateCommand + onTextChanged: _settings.onStateCommand = text + enabled: _settings.enableOnStateLogic + visible: _settings.enableOnStateLogic } } diff --git a/Services/ControlCenterWidgetRegistry.qml b/Services/ControlCenterWidgetRegistry.qml index cd7cb6c1..d460fdfa 100644 --- a/Services/ControlCenterWidgetRegistry.qml +++ b/Services/ControlCenterWidgetRegistry.qml @@ -25,8 +25,13 @@ Singleton { "CustomButton": { "allowUserSettings": true, "icon": "heart", - "exec": "", - "tooltipText": "Custom Button" + "onStateIcon": "heart", + "onClicked": "", + "onRightClicked": "", + "onMiddleClicked": "", + "onStateCommand": "", + "generalTooltipText": "Custom Button", + "enableOnStateLogic": false } })