Merge pull request #2411 from lonerOrz/cc-icon

add explicit iconPosition control for CustomButton widget
This commit is contained in:
Lysec
2026-04-07 22:13:59 +02:00
committed by GitHub
10 changed files with 605 additions and 439 deletions
+13 -3
View File
@@ -105,13 +105,13 @@
"collapse-condition-description": "If the output text matches this value, the button will collapse.",
"collapse-condition-label": "Collapse condition",
"color-selection-description": "Apply theme colors to icon and text.",
"icon-color-selection-description": "Apply theme colors to icons.",
"text-color-selection-description": "Apply theme colors to text.",
"default-tooltip": "Custom button, configure in settings",
"display-command-output-description": "Enter a command to run at a regular interval. The first line of its output will be displayed as text.",
"display-command-output-label": "Display command output",
"display-command-output-stream-description": "Enter a command to run continuously.",
"dynamic-text": "Dynamic text",
"enable-colorization-description": "Enable colorization for the custom button icon and text, applying theme colors.",
"enable-colorization-label": "Enable colorization",
"general-tooltip-text-description": "Custom text to display in the button's tooltip.",
"general-tooltip-text-label": "Custom tooltip text",
"hide-mode-always-expanded": "Always expanded",
@@ -120,6 +120,12 @@
"hide-mode-label": "Hide mode",
"hide-mode-max-transparent": "Max expanded but transparent",
"icon-description": "Select an icon from the library.",
"icon-position-description": "Select where the icon appears relative to the text.",
"icon-position-label": "Icon position",
"icon-position-left": "Left",
"icon-position-right": "Right",
"icon-position-top": "Top",
"icon-position-bottom": "Bottom",
"ipc-identifier-description": "Unique identifier for IPC commands. Use this identifier with 'qs -c noctalia-shell ipc call cb [action] [identifier]' to control this button via IPC.",
"ipc-identifier-label": "IPC Identifier",
"left-click-description": "Command to execute when the button is left-clicked.",
@@ -157,7 +163,10 @@
"wheel-up": "Scroll up",
"wheel-up-description": "Command to execute when the scroll wheel is scrolled up.",
"wheel-up-label": "Wheel up command",
"wheel-update-text": "Update displayed text on scroll"
"wheel-update-text": "Update displayed text on scroll",
"tab-actions": "Actions",
"tab-icon": "Icon",
"tab-text": "Text Command"
},
"keyboard-layout": {
"show-icon-description": "Display the keyboard layout icon."
@@ -517,6 +526,7 @@
"select-color": "Select color",
"select-color-description": "Apply theme colors for emphasis.",
"select-icon-color": "Select icon color",
"select-text-color": "Select text color",
"settings": "Settings",
"shortcuts": "Shortcuts",
"shutdown": "Shutdown",
+2 -1
View File
@@ -53,6 +53,7 @@
"CustomButton": {
"icon": "heart",
"showIcon": true,
"iconPosition": "left",
"showExecTooltip": true,
"showTextTooltip": true,
"generalTooltipText": "",
@@ -79,8 +80,8 @@
"horizontal": 10,
"vertical": 10
},
"enableColorization": false,
"colorizeSystemIcon": "none",
"colorizeSystemText": "none",
"ipcIdentifier": ""
},
"DarkMode": {
+3
View File
@@ -10,6 +10,7 @@ Item {
required property ShellScreen screen
property string icon: ""
property string iconPosition: ""
property string text: ""
property string suffix: ""
property var tooltipText
@@ -55,6 +56,7 @@ Item {
BarPillVertical {
screen: root.screen
icon: root.icon
iconPosition: root.iconPosition
text: root.text
suffix: root.suffix
tooltipText: root.tooltipText
@@ -84,6 +86,7 @@ Item {
BarPillHorizontal {
screen: root.screen
icon: root.icon
iconPosition: root.iconPosition
text: root.text
suffix: root.suffix
tooltipText: root.tooltipText
+22 -7
View File
@@ -18,6 +18,7 @@ Item {
property bool forceOpen: false
property bool forceClose: false
property bool oppositeDirection: false
property string iconPosition: ""
property bool hovered: false
property color customBackgroundColor: "transparent"
property color customTextIconColor: "transparent"
@@ -111,16 +112,22 @@ Item {
x: {
if (!hasIcon)
return 0;
// iconPosition takes precedence, fallback to oppositeDirection
if (iconPosition === "right")
return (iconCircle.x + iconCircle.width / 2) - width;
if (iconPosition === "left")
return (iconCircle.x + iconCircle.width / 2);
return oppositeDirection ? (iconCircle.x + iconCircle.width / 2) : (iconCircle.x + iconCircle.width / 2) - width;
}
opacity: revealed ? Style.opacityFull : Style.opacityNone
color: "transparent" // Make pill background transparent to avoid double opacity
topLeftRadius: oppositeDirection ? 0 : Style.radiusM
bottomLeftRadius: oppositeDirection ? 0 : Style.radiusM
topRightRadius: oppositeDirection ? Style.radiusM : 0
bottomRightRadius: oppositeDirection ? Style.radiusM : 0
// iconPosition takes precedence, fallback to oppositeDirection
topLeftRadius: iconPosition ? (iconPosition === "right" ? Style.radiusM : 0) : (oppositeDirection ? 0 : Style.radiusM)
bottomLeftRadius: iconPosition ? (iconPosition === "right" ? Style.radiusM : 0) : (oppositeDirection ? 0 : Style.radiusM)
topRightRadius: iconPosition ? (iconPosition === "right" ? 0 : Style.radiusM) : (oppositeDirection ? Style.radiusM : 0)
bottomRightRadius: iconPosition ? (iconPosition === "right" ? 0 : Style.radiusM) : (oppositeDirection ? Style.radiusM : 0)
anchors.verticalCenter: parent.verticalCenter
NText {
@@ -132,10 +139,17 @@ Item {
// Better text horizontal centering
var centerX = (parent.width - width) / 2;
var offset = oppositeDirection ? Style.marginXS : -Style.marginXS;
// iconPosition takes precedence, fallback to oppositeDirection
var offset;
if (iconPosition === "right")
offset = -Style.marginXS;
else if (iconPosition === "left")
offset = Style.marginXS;
else
offset = oppositeDirection ? Style.marginXS : -Style.marginXS;
if (forceOpen) {
// If its force open, the icon disc background is the same color as the bg pill move text slightly
offset += oppositeDirection ? -Style.marginXXS : Style.marginXXS;
offset += iconPosition === "right" ? Style.marginXXS : (iconPosition === "left" ? -Style.marginXXS : oppositeDirection ? -Style.marginXXS : Style.marginXXS);
}
return centerX + offset;
}
@@ -171,7 +185,8 @@ Item {
color: "transparent" // Make icon background transparent to avoid double opacity
anchors.verticalCenter: parent.verticalCenter
x: oppositeDirection ? 0 : (parent.width - width)
// iconPosition takes precedence, fallback to oppositeDirection
x: iconPosition ? (iconPosition === "right" ? (parent.width - width) : 0) : (oppositeDirection ? 0 : (parent.width - width))
NIcon {
icon: root.icon
+5 -3
View File
@@ -18,6 +18,7 @@ Item {
property bool forceOpen: false
property bool forceClose: false
property bool oppositeDirection: false
property string iconPosition: ""
property bool hovered: false
property bool rotateText: false
property color customBackgroundColor: "transparent"
@@ -48,9 +49,10 @@ Item {
readonly property int maxPillWidth: rotateText ? Math.max(buttonSize, Math.round(textItem.implicitHeight + Style.margin2M)) : buttonSize
readonly property int maxPillHeight: rotateText ? Math.max(1, Math.round(textItem.implicitWidth + Style.margin2M + Math.round(iconCircle.height / 4))) : Math.max(1, Math.round(textItem.implicitHeight + Style.margin2M))
// Determine pill direction based on section position
readonly property bool openDownward: oppositeDirection
readonly property bool openUpward: !oppositeDirection
// Determine pill direction based on icon position (fallback to oppositeDirection if not set)
// For vertical bar: iconPosition="left" (top) means icon at top, text expands downward
readonly property bool openDownward: (iconPosition === "left" || iconPosition === "right") ? (iconPosition === "left") : oppositeDirection
readonly property bool openUpward: (iconPosition === "left" || iconPosition === "right") ? (iconPosition === "right") : !oppositeDirection
// Effective shown state (true if animated open or forced, but not if force closed)
readonly property bool revealed: !forceClose && (forceOpen || showPill)
+66 -11
View File
@@ -12,6 +12,27 @@ import qs.Widgets
Item {
id: root
NPopupContextMenu {
id: contextMenu
model: [
{
"label": I18n.tr("actions.widget-settings"),
"action": "widget-settings",
"icon": "settings"
},
]
onTriggered: action => {
contextMenu.close();
PanelService.closeContextMenu(screen);
if (action === "widget-settings") {
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
}
}
}
property ShellScreen screen
// Widget properties passed from Bar.qml for per-instance settings
@@ -37,6 +58,7 @@ Item {
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
readonly property string customIcon: widgetSettings.icon || widgetMetadata.icon
readonly property string iconPosition: widgetSettings.iconPosition || widgetMetadata.iconPosition
readonly property string leftClickExec: widgetSettings.leftClickExec || widgetMetadata.leftClickExec
readonly property bool leftClickUpdateText: widgetSettings.leftClickUpdateText ?? widgetMetadata.leftClickUpdateText
readonly property string rightClickExec: widgetSettings.rightClickExec || widgetMetadata.rightClickExec
@@ -139,14 +161,19 @@ Item {
return " ".repeat(currentMaxTextLength);
}
readonly property bool enableColorization: widgetSettings.enableColorization || false
readonly property string colorizeSystemIcon: {
if (widgetSettings.colorizeSystemIcon !== undefined)
return widgetSettings.colorizeSystemIcon;
return widgetMetadata.colorizeSystemIcon !== undefined ? widgetMetadata.colorizeSystemIcon : "none";
}
readonly property string colorizeSystemText: {
if (widgetSettings.colorizeSystemText !== undefined)
return widgetSettings.colorizeSystemText;
return widgetMetadata.colorizeSystemText !== undefined ? widgetMetadata.colorizeSystemText : "none";
}
readonly property bool isColorizing: enableColorization && colorizeSystemIcon !== "none"
// Colorization is active if either icon or text has a color set
readonly property bool isColorizing: colorizeSystemIcon !== "none" || colorizeSystemText !== "none"
// Get color value from color name (returns null for invalid names)
function _getColorValue(colorName, forHover) {
@@ -187,8 +214,10 @@ Item {
return isHover ? Color.mOnHover : Color.mOnSurface;
}
readonly property color iconColor: _resolveIconColor(_dynamicColor, colorizeSystemIcon, false)
readonly property color iconHoverColor: _resolveIconColor(_dynamicColor, colorizeSystemIcon, true)
readonly property color iconColor: _resolveIconColor(_dynamicIconColor || _dynamicColor, colorizeSystemIcon, false)
readonly property color iconHoverColor: _resolveIconColor(_dynamicIconColor || _dynamicColor, colorizeSystemIcon, true)
readonly property color textColor: _resolveIconColor(_dynamicTextColor || _dynamicColor, colorizeSystemText, false)
readonly property color textHoverColor: _resolveIconColor(_dynamicTextColor || _dynamicColor, colorizeSystemText, true)
implicitWidth: pill.width
implicitHeight: pill.height
@@ -200,13 +229,15 @@ Item {
opacity: _pillOpacity
screen: root.screen
oppositeDirection: BarService.getPillDirection(root)
iconPosition: root.iconPosition
icon: _pillIcon
text: _pillText
rotateText: isVerticalBar && currentMaxTextLength > 0
autoHide: false
forceOpen: _pillForceOpen
forceClose: !_pillForceOpen
customTextIconColor: iconColor
customIconColor: iconColor
customTextColor: textColor
// Helper function to build tooltip content
function _buildTooltipContent() {
@@ -285,6 +316,8 @@ Item {
property string _dynamicIcon: ""
property string _dynamicTooltip: ""
property string _dynamicColor: ""
property string _dynamicIconColor: ""
property string _dynamicTextColor: ""
// Maximum length for text display before scrolling (different values for horizontal and vertical)
readonly property var maxTextLength: {
@@ -413,11 +446,25 @@ Item {
const text = parsed.text || "";
const icon = parsed.icon || "";
let tooltip = parsed.tooltip || "";
const color = parsed.color || "";
// Validate color value
// Support both "color" (legacy) and "iconColor"/"textColor" (new)
const legacyColor = parsed.color || "";
const iconColorKey = parsed.iconColor || "";
const textColorKey = parsed.textColor || "";
const validColors = ["primary", "secondary", "tertiary", "error", "none"];
const validColor = (color && validColors.includes(color)) ? color : "";
// Helper to resolve color: legacy > specific > none
function resolveColor(legacy, specific) {
if (legacy && validColors.includes(legacy))
return legacy;
if (specific && validColors.includes(specific))
return specific;
return "";
}
const resolvedIconColor = resolveColor(legacyColor, iconColorKey);
const resolvedTextColor = resolveColor(legacyColor, textColorKey);
if (checkCollapse(text)) {
_scrollState.originalText = "";
@@ -425,6 +472,8 @@ Item {
_dynamicIcon = "";
_dynamicTooltip = "";
_dynamicColor = "";
_dynamicIconColor = "";
_dynamicTextColor = "";
_scrollState.needsScrolling = false;
_scrollState.phase = 0;
_scrollState.phaseCounter = 0;
@@ -444,7 +493,9 @@ Item {
scrollTimer.stop();
}
_dynamicIcon = icon;
_dynamicColor = validColor;
_dynamicColor = legacyColor; // Keep legacy color for fallback
_dynamicIconColor = resolvedIconColor;
_dynamicTextColor = resolvedTextColor;
_dynamicTooltip = toHtml(tooltip);
_scrollState.offset = 0;
@@ -460,6 +511,8 @@ Item {
_dynamicIcon = "";
_dynamicTooltip = "";
_dynamicColor = "";
_dynamicIconColor = "";
_dynamicTextColor = "";
_scrollState.needsScrolling = false;
_scrollState.phase = 0;
_scrollState.phaseCounter = 0;
@@ -480,6 +533,8 @@ Item {
}
_dynamicIcon = "";
_dynamicColor = "";
_dynamicIconColor = "";
_dynamicTextColor = "";
_dynamicTooltip = toHtml(contentStr);
_scrollState.offset = 0;
}
@@ -521,8 +576,8 @@ Item {
if (rightClickExec) {
Quickshell.execDetached(["sh", "-lc", rightClickExec]);
Logger.i("CustomButton", `Executing command: ${rightClickExec}`);
} else if (!rightClickUpdateText) {
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
} else {
PanelService.showContextMenu(contextMenu, pill, screen);
}
if (!textStream && rightClickUpdateText) {
runTextCommand();
@@ -15,6 +15,7 @@ Popup {
property string widgetId: ""
property string sectionId: ""
property var screen: null
property bool barIsVertical: false
property var settingsCache: ({})
readonly property real maxHeight: (screen ? screen.height : (parent ? parent.height : 800)) * 0.8
@@ -17,7 +17,11 @@ ColumnLayout {
signal settingsChanged(var settings)
// Bar orientation (per-screen)
property bool barIsVertical: (Settings.getBarPositionForScreen(screen?.name) === "left" || Settings.getBarPositionForScreen(screen?.name) === "right")
property string valueIcon: widgetData.icon !== undefined ? widgetData.icon : widgetMetadata.icon
property string valueIconPosition: widgetData.iconPosition !== undefined ? widgetData.iconPosition : widgetMetadata.iconPosition
property bool valueTextStream: widgetData.textStream !== undefined ? widgetData.textStream : widgetMetadata.textStream
property bool valueParseJson: widgetData.parseJson !== undefined ? widgetData.parseJson : widgetMetadata.parseJson
property int valueMaxTextLengthHorizontal: widgetData?.maxTextLength?.horizontal ?? widgetMetadata?.maxTextLength?.horizontal
@@ -26,14 +30,15 @@ ColumnLayout {
property bool valueShowIcon: (widgetData.showIcon !== undefined) ? widgetData.showIcon : widgetMetadata.showIcon
property bool valueShowExecTooltip: widgetData.showExecTooltip !== undefined ? widgetData.showExecTooltip : widgetMetadata.showExecTooltip
property bool valueShowTextTooltip: widgetData.showTextTooltip !== undefined ? widgetData.showTextTooltip : widgetMetadata.showTextTooltip
property bool valueEnableColorization: widgetData.enableColorization !== undefined ? widgetData.enableColorization : widgetMetadata.enableColorization
property string valueColorizeSystemIcon: widgetData.colorizeSystemIcon !== undefined ? widgetData.colorizeSystemIcon : widgetMetadata.colorizeSystemIcon
property string valueColorizeSystemText: widgetData.colorizeSystemText !== undefined ? widgetData.colorizeSystemText : widgetMetadata.colorizeSystemText
property string valueIpcIdentifier: widgetData.ipcIdentifier !== undefined ? widgetData.ipcIdentifier : widgetMetadata.ipcIdentifier
property string valueGeneralTooltipText: widgetData.generalTooltipText !== undefined ? widgetData.generalTooltipText : widgetMetadata.generalTooltipText
function saveSettings() {
var settings = Object.assign({}, widgetData || {});
settings.icon = valueIcon;
settings.iconPosition = valueIconPosition;
settings.leftClickExec = leftClickExecInput.text;
settings.leftClickUpdateText = leftClickUpdateText.checked;
settings.rightClickExec = rightClickExecInput.text;
@@ -60,453 +65,523 @@ ColumnLayout {
"vertical": valueMaxTextLengthVertical
};
settings.textIntervalMs = parseInt(textIntervalInput.text || textIntervalInput.placeholderText, 10);
settings.enableColorization = valueEnableColorization;
settings.colorizeSystemIcon = valueColorizeSystemIcon;
settings.colorizeSystemText = valueColorizeSystemText;
settings.ipcIdentifier = valueIpcIdentifier;
settings.generalTooltipText = valueGeneralTooltipText;
settingsChanged(settings);
}
RowLayout {
spacing: Style.marginM
NLabel {
label: I18n.tr("common.icon")
description: I18n.tr("bar.custom-button.icon-description")
}
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: valueIcon
pointSize: Style.fontSizeXL
visible: valueIcon !== ""
}
NButton {
text: I18n.tr("common.browse")
onClicked: iconPicker.open()
}
}
NIconPicker {
id: iconPicker
initialIcon: valueIcon
onIconSelected: function (iconName) {
valueIcon = iconName;
saveSettings();
}
}
NToggle {
id: showIconToggle
label: I18n.tr("bar.custom-button.show-icon-label")
description: I18n.tr("bar.custom-button.show-icon-description")
checked: valueShowIcon
onToggled: checked => {
valueShowIcon = checked;
saveSettings();
}
visible: textCommandInput.text !== ""
defaultValue: widgetMetadata.showIcon
}
NToggle {
label: I18n.tr("bar.custom-button.enable-colorization-label")
description: I18n.tr("bar.custom-button.enable-colorization-description")
checked: valueEnableColorization
onToggled: checked => {
valueEnableColorization = checked;
saveSettings();
}
defaultValue: widgetMetadata.enableColorization
}
NColorChoice {
visible: valueEnableColorization
label: I18n.tr("common.select-icon-color")
description: I18n.tr("bar.custom-button.color-selection-description")
currentKey: valueColorizeSystemIcon
onSelected: key => {
valueColorizeSystemIcon = key;
saveSettings();
}
defaultValue: widgetMetadata.colorizeSystemIcon
}
NTextInput {
NTabBar {
id: subTabBar
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.general-tooltip-text-label")
description: I18n.tr("bar.custom-button.general-tooltip-text-description")
placeholderText: I18n.tr("placeholders.enter-tooltip")
text: valueGeneralTooltipText
onTextChanged: {
valueGeneralTooltipText = text;
saveSettings();
Layout.bottomMargin: Style.marginM
distributeEvenly: true
currentIndex: tabView.currentIndex
NTabButton {
text: I18n.tr("bar.custom-button.tab-actions")
tabIndex: 0
checked: tabView.currentIndex === 0
onClicked: tabView.currentIndex = 0
}
defaultValue: widgetMetadata.generalTooltipText
}
NToggle {
id: showExecTooltipToggle
label: I18n.tr("bar.custom-button.show-exec-tooltip-label")
description: I18n.tr("bar.custom-button.show-exec-tooltip-description")
checked: valueShowExecTooltip
onToggled: checked => {
valueShowExecTooltip = checked;
saveSettings();
}
defaultValue: widgetMetadata.showExecTooltip
}
NToggle {
id: showTextTooltipToggle
label: I18n.tr("bar.custom-button.show-text-tooltip-label")
description: I18n.tr("bar.custom-button.show-text-tooltip-description")
checked: valueShowTextTooltip
onToggled: checked => {
valueShowTextTooltip = checked;
saveSettings();
}
defaultValue: widgetMetadata.showTextTooltip
}
NTextInput {
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.ipc-identifier-label")
description: I18n.tr("bar.custom-button.ipc-identifier-description")
placeholderText: I18n.tr("placeholders.enter-ipc-identifier")
text: valueIpcIdentifier
onTextChanged: {
valueIpcIdentifier = text;
saveSettings();
NTabButton {
text: I18n.tr("bar.custom-button.tab-icon")
tabIndex: 1
checked: tabView.currentIndex === 1
onClicked: tabView.currentIndex = 1
}
defaultValue: widgetMetadata.ipcIdentifier
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: leftClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.left-click-label")
description: I18n.tr("bar.custom-button.left-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.leftClickExec || widgetMetadata.leftClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.leftClickExec
}
NToggle {
id: leftClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(leftClickUpdateText, I18n.tr("bar.custom-button.left-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.leftClickUpdateText ?? widgetMetadata.leftClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.leftClickUpdateText
NTabButton {
text: I18n.tr("bar.custom-button.tab-text")
tabIndex: 2
checked: tabView.currentIndex === 2
onClicked: tabView.currentIndex = 2
}
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: rightClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.right-click-label")
description: I18n.tr("bar.custom-button.right-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.rightClickExec || widgetMetadata.rightClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.rightClickExec
}
NToggle {
id: rightClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(rightClickUpdateText, I18n.tr("bar.custom-button.right-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.rightClickUpdateText ?? widgetMetadata.rightClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.rightClickUpdateText
}
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: middleClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.middle-click-label")
description: I18n.tr("bar.custom-button.middle-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData.middleClickExec || widgetMetadata.middleClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.middleClickExec
}
NToggle {
id: middleClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(middleClickUpdateText, I18n.tr("bar.custom-button.middle-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.middleClickUpdateText ?? widgetMetadata.middleClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.middleClickUpdateText
}
}
// Wheel command settings
NToggle {
id: separateWheelToggle
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-mode-separate-label")
description: I18n.tr("bar.custom-button.wheel-mode-separate-description")
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode) === "separate"
checked: internalChecked
onToggled: checked => {
internalChecked = checked;
saveSettings();
}
defaultValue: widgetMetadata.wheelMode === "separate"
}
ColumnLayout {
NTabView {
id: tabView
Layout.fillWidth: true
RowLayout {
id: unifiedWheelLayout
visible: !separateWheelToggle.checked
// ============ Actions Tab ============
ColumnLayout {
spacing: Style.marginM
NTextInput {
id: wheelExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-label")
description: I18n.tr("bar.custom-button.wheel-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelExec || widgetMetadata?.wheelExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelExec
RowLayout {
spacing: Style.marginM
NTextInput {
id: leftClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.left-click-label")
description: I18n.tr("bar.custom-button.left-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.leftClickExec || widgetMetadata.leftClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.leftClickExec
}
NToggle {
id: leftClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(leftClickUpdateText, I18n.tr("bar.custom-button.left-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.leftClickUpdateText ?? widgetMetadata.leftClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.leftClickUpdateText
}
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: rightClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.right-click-label")
description: I18n.tr("bar.custom-button.right-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.rightClickExec || widgetMetadata.rightClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.rightClickExec
}
NToggle {
id: rightClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(rightClickUpdateText, I18n.tr("bar.custom-button.right-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.rightClickUpdateText ?? widgetMetadata.rightClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.rightClickUpdateText
}
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: middleClickExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.middle-click-label")
description: I18n.tr("bar.custom-button.middle-click-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.middleClickExec || widgetMetadata.middleClickExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.middleClickExec
}
NToggle {
id: middleClickUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(middleClickUpdateText, I18n.tr("bar.custom-button.middle-click-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.middleClickUpdateText ?? widgetMetadata.middleClickUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.middleClickUpdateText
}
}
NToggle {
id: wheelUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.wheelUpdateText ?? widgetMetadata?.wheelUpdateText
onToggled: isChecked => {
checked = isChecked;
id: separateWheelToggle
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-mode-separate-label")
description: I18n.tr("bar.custom-button.wheel-mode-separate-description")
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode) === "separate"
checked: internalChecked
onToggled: checked => {
internalChecked = checked;
saveSettings();
}
defaultValue: widgetMetadata.wheelUpdateText
defaultValue: widgetMetadata.wheelMode === "separate"
}
ColumnLayout {
Layout.fillWidth: true
RowLayout {
id: unifiedWheelLayout
visible: !separateWheelToggle.checked
spacing: Style.marginM
NTextInput {
id: wheelExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-label")
description: I18n.tr("bar.custom-button.wheel-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelExec || widgetMetadata?.wheelExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelExec
}
NToggle {
id: wheelUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.wheelUpdateText ?? widgetMetadata?.wheelUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.wheelUpdateText
}
}
ColumnLayout {
id: separatedWheelLayout
Layout.fillWidth: true
visible: separateWheelToggle.checked
RowLayout {
spacing: Style.marginM
NTextInput {
id: wheelUpExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-up-label")
description: I18n.tr("bar.custom-button.wheel-up-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelUpExec
}
NToggle {
id: wheelUpUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelUpUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.wheelUpUpdateText ?? widgetMetadata?.wheelUpUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.wheelUpUpdateText
}
}
RowLayout {
spacing: Style.marginM
NTextInput {
id: wheelDownExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-down-label")
description: I18n.tr("bar.custom-button.wheel-down-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelDownExec
}
NToggle {
id: wheelDownUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelDownUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: widgetData?.wheelDownUpdateText ?? widgetMetadata?.wheelDownUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.wheelDownUpdateText
}
}
}
}
}
// ============ Icon Tab ============
ColumnLayout {
id: separatedWheelLayout
Layout.fillWidth: true
visible: separateWheelToggle.checked
spacing: Style.marginM
RowLayout {
spacing: Style.marginM
NTextInput {
id: wheelUpExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-up-label")
description: I18n.tr("bar.custom-button.wheel-up-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelUpExec
}
NToggle {
id: wheelUpUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelUpUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: (widgetData?.wheelUpUpdateText !== undefined) ? widgetData.wheelUpUpdateText : widgetMetadata?.wheelUpUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.wheelUpUpdateText
}
NToggle {
id: showIconToggle
label: I18n.tr("bar.custom-button.show-icon-label")
description: I18n.tr("bar.custom-button.show-icon-description")
checked: valueShowIcon
onToggled: checked => {
valueShowIcon = checked;
saveSettings();
}
visible: textCommandInput.text !== ""
defaultValue: widgetMetadata.showIcon
}
RowLayout {
spacing: Style.marginM
visible: valueShowIcon
NTextInput {
id: wheelDownExecInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.wheel-down-label")
description: I18n.tr("bar.custom-button.wheel-down-description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec
onTextChanged: saveSettings()
defaultValue: widgetMetadata.wheelDownExec
NLabel {
label: I18n.tr("common.icon")
description: I18n.tr("bar.custom-button.icon-description")
}
NToggle {
id: wheelDownUpdateText
enabled: !valueTextStream
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelDownUpdateText, I18n.tr("bar.custom-button.wheel-update-text"))
onExited: TooltipService.hide()
checked: (widgetData?.wheelDownUpdateText !== undefined) ? widgetData.wheelDownUpdateText : widgetMetadata?.wheelDownUpdateText
onToggled: isChecked => {
checked = isChecked;
saveSettings();
}
defaultValue: widgetMetadata.wheelDownUpdateText
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: valueIcon
pointSize: Style.fontSizeXL
visible: valueIcon !== ""
}
NButton {
text: I18n.tr("common.browse")
onClicked: iconPicker.open()
}
}
}
}
NDivider {
Layout.fillWidth: true
}
NHeader {
label: I18n.tr("bar.custom-button.dynamic-text")
}
NSpinBox {
label: I18n.tr("bar.custom-button.max-text-length-horizontal-label")
description: I18n.tr("bar.custom-button.max-text-length-horizontal-description")
from: 0
to: 100
value: valueMaxTextLengthHorizontal
onValueChanged: {
valueMaxTextLengthHorizontal = value;
saveSettings();
}
defaultValue: widgetMetadata.maxTextLength.horizontal
}
NSpinBox {
label: I18n.tr("bar.custom-button.max-text-length-vertical-label")
description: I18n.tr("bar.custom-button.max-text-length-vertical-description")
from: 0
to: 100
value: valueMaxTextLengthVertical
onValueChanged: {
valueMaxTextLengthVertical = value;
saveSettings();
}
defaultValue: widgetMetadata.maxTextLength.vertical
}
NToggle {
id: textStreamInput
label: I18n.tr("bar.custom-button.text-stream-label")
description: I18n.tr("bar.custom-button.text-stream-description")
checked: valueTextStream
onToggled: checked => {
valueTextStream = checked;
saveSettings();
}
defaultValue: widgetMetadata.textStream
}
NToggle {
id: parseJsonInput
label: I18n.tr("bar.custom-button.parse-json-label")
description: I18n.tr("bar.custom-button.parse-json-description")
checked: valueParseJson
onToggled: checked => {
valueParseJson = checked;
saveSettings();
}
defaultValue: widgetMetadata.parseJson
}
NTextInput {
id: textCommandInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.display-command-output-label")
description: valueTextStream ? I18n.tr("bar.custom-button.display-command-output-stream-description") : I18n.tr("bar.custom-button.display-command-output-description")
placeholderText: I18n.tr("placeholders.command-example")
text: widgetData?.textCommand || widgetMetadata.textCommand
onTextChanged: saveSettings()
defaultValue: widgetMetadata.textCommand
}
NTextInput {
id: textCollapseInput
Layout.fillWidth: true
visible: valueTextStream
label: I18n.tr("bar.custom-button.collapse-condition-label")
description: I18n.tr("bar.custom-button.collapse-condition-description")
placeholderText: I18n.tr("placeholders.enter-text-to-collapse")
text: widgetData?.textCollapse || widgetMetadata.textCollapse
onTextChanged: saveSettings()
defaultValue: widgetMetadata.textCollapse
}
NTextInput {
id: textIntervalInput
Layout.fillWidth: true
visible: !valueTextStream
label: I18n.tr("bar.custom-button.refresh-interval-label")
description: I18n.tr("bar.custom-button.refresh-interval-description")
placeholderText: String(widgetMetadata.textIntervalMs)
text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
onTextChanged: saveSettings()
defaultValue: String(widgetMetadata.textIntervalMs)
}
NComboBox {
id: hideModeComboBox
label: I18n.tr("bar.custom-button.hide-mode-label")
description: I18n.tr("bar.custom-button.hide-mode-description")
model: [
{
name: I18n.tr("bar.custom-button.hide-mode-always-expanded"),
key: "alwaysExpanded"
},
{
name: I18n.tr("bar.custom-button.hide-mode-expand-with-output"),
key: "expandWithOutput"
},
{
name: I18n.tr("bar.custom-button.hide-mode-max-transparent"),
key: "maxTransparent"
NIconPicker {
id: iconPicker
initialIcon: valueIcon
onIconSelected: function (iconName) {
valueIcon = iconName;
saveSettings();
}
}
]
currentKey: valueHideMode
onSelected: key => {
valueHideMode = key;
saveSettings();
}
visible: textCommandInput.text !== "" && valueTextStream == true
defaultValue: widgetMetadata.hideMode
NComboBox {
id: iconPositionComboBox
visible: valueShowIcon
label: I18n.tr("bar.custom-button.icon-position-label")
description: I18n.tr("bar.custom-button.icon-position-description")
model: barIsVertical ? [
{
name: I18n.tr("bar.custom-button.icon-position-top"),
key: "left"
},
{
name: I18n.tr("bar.custom-button.icon-position-bottom"),
key: "right"
}
] : [
{
name: I18n.tr("bar.custom-button.icon-position-left"),
key: "left"
},
{
name: I18n.tr("bar.custom-button.icon-position-right"),
key: "right"
}
]
currentKey: valueIconPosition
onSelected: key => {
valueIconPosition = key;
saveSettings();
}
defaultValue: widgetMetadata.iconPosition
}
NColorChoice {
label: I18n.tr("common.select-icon-color")
description: I18n.tr("bar.custom-button.icon-color-selection-description")
currentKey: valueColorizeSystemIcon
onSelected: key => {
valueColorizeSystemIcon = key;
saveSettings();
}
defaultValue: widgetMetadata.colorizeSystemIcon
}
NTextInput {
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.general-tooltip-text-label")
description: I18n.tr("bar.custom-button.general-tooltip-text-description")
placeholderText: I18n.tr("placeholders.enter-tooltip")
text: valueGeneralTooltipText
onTextChanged: {
valueGeneralTooltipText = text;
saveSettings();
}
defaultValue: widgetMetadata.generalTooltipText
}
NToggle {
id: showExecTooltipToggle
label: I18n.tr("bar.custom-button.show-exec-tooltip-label")
description: I18n.tr("bar.custom-button.show-exec-tooltip-description")
checked: valueShowExecTooltip
onToggled: checked => {
valueShowExecTooltip = checked;
saveSettings();
}
defaultValue: widgetMetadata.showExecTooltip
}
NToggle {
id: showTextTooltipToggle
label: I18n.tr("bar.custom-button.show-text-tooltip-label")
description: I18n.tr("bar.custom-button.show-text-tooltip-description")
checked: valueShowTextTooltip
onToggled: checked => {
valueShowTextTooltip = checked;
saveSettings();
}
defaultValue: widgetMetadata.showTextTooltip
}
NTextInput {
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.ipc-identifier-label")
description: I18n.tr("bar.custom-button.ipc-identifier-description")
placeholderText: I18n.tr("placeholders.enter-ipc-identifier")
text: valueIpcIdentifier
onTextChanged: {
valueIpcIdentifier = text;
saveSettings();
}
defaultValue: widgetMetadata.ipcIdentifier
}
}
// ============ Text Tab ============
ColumnLayout {
spacing: Style.marginM
NColorChoice {
label: I18n.tr("common.select-text-color")
description: I18n.tr("bar.custom-button.text-color-selection-description")
currentKey: valueColorizeSystemText
onSelected: key => {
valueColorizeSystemText = key;
saveSettings();
}
defaultValue: widgetMetadata.colorizeSystemText
}
NSpinBox {
label: I18n.tr("bar.custom-button.max-text-length-horizontal-label")
description: I18n.tr("bar.custom-button.max-text-length-horizontal-description")
from: 0
to: 100
value: valueMaxTextLengthHorizontal
onValueChanged: {
valueMaxTextLengthHorizontal = value;
saveSettings();
}
defaultValue: widgetMetadata.maxTextLength.horizontal
}
NSpinBox {
label: I18n.tr("bar.custom-button.max-text-length-vertical-label")
description: I18n.tr("bar.custom-button.max-text-length-vertical-description")
from: 0
to: 100
value: valueMaxTextLengthVertical
onValueChanged: {
valueMaxTextLengthVertical = value;
saveSettings();
}
defaultValue: widgetMetadata.maxTextLength.vertical
}
NToggle {
id: textStreamInput
label: I18n.tr("bar.custom-button.text-stream-label")
description: I18n.tr("bar.custom-button.text-stream-description")
checked: valueTextStream
onToggled: checked => {
valueTextStream = checked;
saveSettings();
}
defaultValue: widgetMetadata.textStream
}
NToggle {
id: parseJsonInput
label: I18n.tr("bar.custom-button.parse-json-label")
description: I18n.tr("bar.custom-button.parse-json-description")
checked: valueParseJson
onToggled: checked => {
valueParseJson = checked;
saveSettings();
}
defaultValue: widgetMetadata.parseJson
}
NTextInput {
id: textCommandInput
Layout.fillWidth: true
label: I18n.tr("bar.custom-button.display-command-output-label")
description: valueTextStream ? I18n.tr("bar.custom-button.display-command-output-stream-description") : I18n.tr("bar.custom-button.display-command-output-description")
placeholderText: I18n.tr("placeholders.command-example")
text: widgetData?.textCommand || widgetMetadata.textCommand
onTextChanged: saveSettings()
defaultValue: widgetMetadata.textCommand
}
NTextInput {
id: textCollapseInput
Layout.fillWidth: true
visible: valueTextStream
label: I18n.tr("bar.custom-button.collapse-condition-label")
description: I18n.tr("bar.custom-button.collapse-condition-description")
placeholderText: I18n.tr("placeholders.enter-text-to-collapse")
text: widgetData?.textCollapse || widgetMetadata.textCollapse
onTextChanged: saveSettings()
defaultValue: widgetMetadata.textCollapse
}
NTextInput {
id: textIntervalInput
Layout.fillWidth: true
visible: !valueTextStream
label: I18n.tr("bar.custom-button.refresh-interval-label")
description: I18n.tr("bar.custom-button.refresh-interval-description")
placeholderText: String(widgetMetadata.textIntervalMs)
text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
onTextChanged: saveSettings()
defaultValue: String(widgetMetadata.textIntervalMs)
}
NComboBox {
id: hideModeComboBox
label: I18n.tr("bar.custom-button.hide-mode-label")
description: I18n.tr("bar.custom-button.hide-mode-description")
model: [
{
name: I18n.tr("bar.custom-button.hide-mode-always-expanded"),
key: "alwaysExpanded"
},
{
name: I18n.tr("bar.custom-button.hide-mode-expand-with-output"),
key: "expandWithOutput"
},
{
name: I18n.tr("bar.custom-button.hide-mode-max-transparent"),
key: "maxTransparent"
}
]
currentKey: valueHideMode
onSelected: key => {
valueHideMode = key;
saveSettings();
}
visible: textCommandInput.text !== "" && valueTextStream == true
defaultValue: widgetMetadata.hideMode
}
}
}
}
+4 -1
View File
@@ -126,11 +126,13 @@ Singleton {
"customIconPath": "",
"colorizeDistroLogo": false,
"colorizeSystemIcon": "none",
"colorizeSystemText": "none",
"enableColorization": false
},
"CustomButton": {
"icon": "heart",
"showIcon": true,
"iconPosition": "left",
"showExecTooltip": true,
"showTextTooltip": true,
"generalTooltipText": "",
@@ -157,8 +159,8 @@ Singleton {
"horizontal": 10,
"vertical": 10
},
"enableColorization": false,
"colorizeSystemIcon": "none",
"colorizeSystemText": "none",
"ipcIdentifier": ""
},
"DarkMode": {
@@ -188,6 +190,7 @@ Singleton {
"icon": "rocket",
"customIconPath": "",
"colorizeSystemIcon": "none",
"colorizeSystemText": "none",
"enableColorization": false,
"iconColor": "none"
},
+2 -1
View File
@@ -267,7 +267,8 @@ NBox {
"widgetData": widgetData,
"widgetId": widgetData.id,
"sectionId": root.sectionId,
"screen": root.screen
"screen": root.screen,
"barIsVertical": root.barIsVertical
});
if (dialog) {