feat(controlcenter): implement multi-state support for custom button

This commit is contained in:
loner
2025-11-03 16:17:55 +08:00
parent ba7282daa6
commit 5a9470d64e
4 changed files with 181 additions and 117 deletions
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Layouts
import QtQml.Models // Import ListModel
import qs.Commons
import qs.Widgets
@@ -13,35 +14,58 @@ ColumnLayout {
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 ListModel _stateChecksListModel: ListModel {}
property string stateChecksJson: "[]"
property string generalTooltipText: (widgetData && widgetData.generalTooltipText !== undefined) ? widgetData.generalTooltipText : widgetMetadata.generalTooltipText
property bool enableOnStateLogic: (widgetData && widgetData.enableOnStateLogic !== undefined) ? widgetData.enableOnStateLogic : widgetMetadata.enableOnStateLogic
Component.onCompleted: {
stateChecksJson = (widgetData && widgetData.stateChecksJson !== undefined) ? widgetData.stateChecksJson : widgetMetadata.stateChecksJson || "[]"
try {
var initialChecks = JSON.parse(stateChecksJson)
if (initialChecks && Array.isArray(initialChecks)) {
for (var i = 0; i < initialChecks.length; i++) {
var item = initialChecks[i]
if (item && typeof item === "object") {
_settings._stateChecksListModel.append({
command: item.command || "",
icon: item.icon || ""
})
} else {
console.warn("⚠️ Invalid stateChecks entry at index " + i + ":", item)
}
}
}
} catch (e) {
console.error("CustomButtonSettings: Failed to parse stateChecksJson:", e.message)
}
}
}
function saveSettings() {
var saved = {
var savedStateChecksArray = []
for (var i = 0; i < _settings._stateChecksListModel.count; i++) {
savedStateChecksArray.push(_settings._stateChecksListModel.get(i))
}
_settings.stateChecksJson = JSON.stringify(savedStateChecksArray)
return {
id: widgetData.id,
icon: _settings.icon,
onStateIcon: _settings.onStateIcon,
onClicked: _settings.onClicked,
onRightClicked: _settings.onRightClicked,
onMiddleClicked: _settings.onMiddleClicked,
onStateCommand: _settings.onStateCommand,
stateChecksJson: _settings.stateChecksJson,
generalTooltipText: _settings.generalTooltipText,
enableOnStateLogic: _settings.enableOnStateLogic
}
return saved
}
RowLayout {
spacing: Style.marginM
spacing: Style?.marginM ?? 8
NLabel {
label: I18n.tr("settings.control-center.shortcuts.custom-button.icon.label")
@@ -51,7 +75,7 @@ ColumnLayout {
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: _settings.icon || widgetMetadata.icon
pointSize: Style.fontSizeXL
pointSize: Style?.fontSizeXL ?? 24
visible: (_settings.icon || widgetMetadata.icon) !== ""
}
@@ -70,7 +94,6 @@ ColumnLayout {
}
NTextInput {
id: generalTooltipTextInput
Layout.fillWidth: true
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")
@@ -80,7 +103,6 @@ ColumnLayout {
}
NTextInput {
id: onClickedCommandInput
Layout.fillWidth: true
label: I18n.tr("settings.control-center.shortcuts.custom-button.on-clicked.label")
description: I18n.tr("settings.control-center.shortcuts.custom-button.on-clicked.description")
@@ -90,7 +112,6 @@ ColumnLayout {
}
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")
@@ -100,7 +121,6 @@ ColumnLayout {
}
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")
@@ -120,48 +140,69 @@ ColumnLayout {
onToggled: checked => _settings.enableOnStateLogic = checked
}
// On-State Icon
RowLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
visible: _settings.enableOnStateLogic
spacing: (Style?.marginM ?? 8) * 2
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")
label: "State Checks"
}
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: _settings.onStateIcon || widgetMetadata.onStateIcon
pointSize: Style.fontSizeXL
visible: (_settings.onStateIcon || widgetMetadata.onStateIcon) !== ""
Repeater {
model: _settings._stateChecksListModel
delegate: ColumnLayout {
Layout.fillWidth: true
spacing: Style?.marginM ?? 8
property int currentIndex: index
RowLayout {
Layout.fillWidth: true
spacing: Style?.marginS ?? 4
NTextInput {
Layout.fillWidth: true
label: "Command"
text: model.command
onEditingFinished: _settings._stateChecksListModel.set(currentIndex, { "command": text, "icon": model.icon })
}
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: model.icon
visible: model.icon !== undefined && model.icon !== ""
}
NButton {
text: "Browse Icon"
Layout.preferredWidth: Style?.buttonWidthM ?? 100
onClicked: iconPickerDelegate.open()
}
NIconPicker {
id: iconPickerDelegate
initialIcon: model.icon
onIconSelected: function (iconName) {
_settings._stateChecksListModel.set(currentIndex, { "command": model.command, "icon": iconName })
}
}
NButton {
text: "Remove"
Layout.preferredWidth: Style?.buttonWidthM ?? 100
onClicked: _settings._stateChecksListModel.remove(currentIndex)
}
}
NDivider {}
}
}
NButton {
Layout.fillWidth: true
text: I18n.tr("settings.control-center.shortcuts.custom-button.browse")
onClicked: onStateIconPicker.open()
text: "Add State Check"
onClicked: _settings._stateChecksListModel.append({ command: "", icon: "" })
}
}
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
}
}
NDivider {}
}
+6 -2
View File
@@ -329,8 +329,12 @@ ColumnLayout {
}
function _updateWidgetSettingsInSection(section, index, settings) {
// Update the widget settings in the Settings data
Settings.data.controlCenter.shortcuts[section][index] = settings
// Create a new array to trigger QML's change detection for persistence.
// This is crucial for Settings.data to detect the change and persist it.
var newSectionArray = Settings.data.controlCenter.shortcuts[section].slice()
newSectionArray[index] = settings
Settings.data.controlCenter.shortcuts[section] = newSectionArray
Settings.saveImmediate()
}
// Base list model for all combo boxes