From dbf102063604d362ac31a33043850e3f23f54d0a Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Mon, 15 Sep 2025 14:37:29 +0200 Subject: [PATCH] CustomButton: add script execution/polling support with text display --- Modules/Bar/Widgets/CustomButton.qml | 96 ++++++++++++++----- .../WidgetSettings/CustomButtonSettings.qml | 31 ++++++ Services/BarWidgetRegistry.qml | 4 +- 3 files changed, 106 insertions(+), 25 deletions(-) diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml index f80f8ba..9ab1b11 100644 --- a/Modules/Bar/Widgets/CustomButton.qml +++ b/Modules/Bar/Widgets/CustomButton.qml @@ -1,12 +1,13 @@ import QtQuick import QtQuick.Layouts import Quickshell +import Quickshell.Io import qs.Commons import qs.Services import qs.Widgets import qs.Modules.SettingsPanel -NIconButton { +Item { id: root // Widget properties passed from Bar.qml @@ -35,33 +36,80 @@ NIconButton { readonly property string leftClickExec: widgetSettings.leftClickExec || widgetMetadata.leftClickExec readonly property string rightClickExec: widgetSettings.rightClickExec || widgetMetadata.rightClickExec readonly property string middleClickExec: widgetSettings.middleClickExec || widgetMetadata.middleClickExec + readonly property string textCommand: widgetSettings.textCommand !== undefined ? widgetSettings.textCommand : (widgetMetadata.textCommand || "") + readonly property int textIntervalMs: widgetSettings.textIntervalMs !== undefined ? widgetSettings.textIntervalMs : (widgetMetadata.textIntervalMs || 3000) readonly property bool hasExec: (leftClickExec || rightClickExec || middleClickExec) - enabled: hasExec - allowClickWhenDisabled: true // we want to be able to open config with left click when its not setup properly - colorBorder: Color.transparent - colorBorderHover: Color.transparent - sizeRatio: 0.8 - icon: customIcon - tooltipText: { - if (!hasExec) { - return "Custom Button - Configure in settings" - } else { - var lines = [] - if (leftClickExec !== "") { - lines.push(`Left click: ${leftClickExec}.`) + implicitWidth: pill.width + implicitHeight: pill.height + + NPill { + id: pill + + rightOpen: BarWidgetRegistry.getNPillDirection(root) + icon: customIcon + text: _dynamicText + autoHide: false + forceOpen: _dynamicText !== "" + forceClose: false + disableOpen: true + tooltipText: { + if (!hasExec) { + return "Custom Button - Configure in settings" + } else { + var lines = [] + if (leftClickExec !== "") { + lines.push(`Left click: ${leftClickExec}.`) + } + if (rightClickExec !== "") { + lines.push(`Right click: ${rightClickExec}.`) + } + if (middleClickExec !== "") { + lines.push(`Middle click: ${middleClickExec}.`) + } + return lines.join("\n") } - if (rightClickExec !== "") { - lines.push(`Right click: ${rightClickExec}.`) - } - if (middleClickExec !== "") { - lines.push(`Middle click: ${middleClickExec}.`) - } - return lines.join("
") + } + + onClicked: root.onClicked() + onRightClicked: root.onRightClicked() + onMiddleClicked: root.onMiddleClicked() + } + + // Internal state for dynamic text + property string _dynamicText: "" + + // Periodically run the text command (if set) + Timer { + id: refreshTimer + interval: Math.max(250, textIntervalMs) + repeat: true + running: (textCommand && textCommand.length > 0) + triggeredOnStart: true + onTriggered: { + if (!textCommand || textCommand.length === 0) + return + if (textProc.running) + return + textProc.command = ["sh", "-lc", textCommand] + textProc.running = true } } - onClicked: { + Process { + id: textProc + stdout: StdioCollector {} + stderr: StdioCollector {} + onExited: (exitCode, exitStatus) => { + var out = String(stdout.text || "").trim() + if (out.indexOf("\n") !== -1) { + out = out.split("\n")[0] + } + _dynamicText = out + } + } + + function onClicked() { if (leftClickExec) { Quickshell.execDetached(["sh", "-c", leftClickExec]) Logger.log("CustomButton", `Executing command: ${leftClickExec}`) @@ -73,14 +121,14 @@ NIconButton { } } - onRightClicked: { + function onRightClicked() { if (rightClickExec) { Quickshell.execDetached(["sh", "-c", rightClickExec]) Logger.log("CustomButton", `Executing command: ${rightClickExec}`) } } - onMiddleClicked: { + function onMiddleClicked() { if (middleClickExec) { Quickshell.execDetached(["sh", "-c", middleClickExec]) Logger.log("CustomButton", `Executing command: ${middleClickExec}`) diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml index b6a5d32..371d845 100644 --- a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml +++ b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml @@ -19,6 +19,8 @@ ColumnLayout { settings.leftClickExec = leftClickExecInput.text settings.rightClickExec = rightClickExecInput.text settings.middleClickExec = middleClickExecInput.text + settings.textCommand = textCommandInput.text + settings.textIntervalMs = parseInt(textIntervalInput.text || textIntervalInput.placeholderText, 10) return settings } @@ -228,4 +230,33 @@ ColumnLayout { placeholderText: "Enter command to execute (app or custom script)" text: widgetData.middleClickExec || widgetMetadata.middleClickExec } + + NDivider { + Layout.fillWidth: true + } + + NText { + text: "Dynamic Text" + font.pointSize: Style.fontSizeM * scaling + font.weight: Style.fontWeightBold + color: Color.mPrimary + } + + NTextInput { + id: textCommandInput + Layout.fillWidth: true + label: "Text Command" + description: "Shell command to run periodically (first line becomes the text)." + placeholderText: "echo \"Hello World\"" + text: widgetData?.textCommand || widgetMetadata.textCommand + } + + NTextInput { + id: textIntervalInput + Layout.fillWidth: true + label: "Refresh Interval" + description: "Interval in milliseconds." + placeholderText: String(widgetMetadata.textIntervalMs || 3000) + text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : "" + } } diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index 4fbcd22..392b570 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -61,7 +61,9 @@ Singleton { "icon": "heart", "leftClickExec": "", "rightClickExec": "", - "middleClickExec": "" + "middleClickExec": "", + "textCommand": "", + "textIntervalMs": 3000 }, "Microphone": { "allowUserSettings": true,