diff options
| author | ATMDA <atdma2600@gmail.com> | 2025-11-20 21:58:55 -0500 |
|---|---|---|
| committer | ATMDA <atdma2600@gmail.com> | 2025-11-20 21:58:55 -0500 |
| commit | 7779de55bbcc87ad4af7bcc4b0f4da6e0fe65847 (patch) | |
| tree | cf283a5b0d39380d0a0e97deb7dfe5949a38bb66 | |
| parent | controlcenter: corrected taskbar panel container margins/padding (diff) | |
| download | caelestia-shell-7779de55bbcc87ad4af7bcc4b0f4da6e0fe65847.tar.gz caelestia-shell-7779de55bbcc87ad4af7bcc4b0f4da6e0fe65847.tar.bz2 caelestia-shell-7779de55bbcc87ad4af7bcc4b0f4da6e0fe65847.zip | |
controlcenter: refactor SliderInput and StyledInputFields to use qt components and consolidated SliderInputs to single component
| -rw-r--r-- | components/controls/StyledInputField.qml | 80 | ||||
| -rw-r--r-- | modules/controlcenter/audio/AudioPane.qml | 158 | ||||
| -rw-r--r-- | modules/controlcenter/components/SliderInput.qml | 106 | ||||
| -rw-r--r-- | modules/controlcenter/components/controls/SliderInput.qml | 179 |
4 files changed, 172 insertions, 351 deletions
diff --git a/components/controls/StyledInputField.qml b/components/controls/StyledInputField.qml new file mode 100644 index 0000000..fcd0a33 --- /dev/null +++ b/components/controls/StyledInputField.qml @@ -0,0 +1,80 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.services +import qs.config +import QtQuick + +Item { + id: root + + property string text: "" + property var validator: null + property bool readOnly: false + property int horizontalAlignment: TextInput.AlignHCenter + property int implicitWidth: 70 + property bool enabled: true + + // Expose activeFocus through alias to avoid FINAL property override + readonly property alias hasFocus: inputField.activeFocus + + signal textEdited(string text) + signal editingFinished() + + implicitHeight: inputField.implicitHeight + Appearance.padding.small * 2 + + StyledRect { + id: container + + anchors.fill: parent + color: inputHover.containsMouse || inputField.activeFocus + ? Colours.layer(Colours.palette.m3surfaceContainer, 3) + : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: inputField.activeFocus + ? Colours.palette.m3primary + : Qt.alpha(Colours.palette.m3outline, 0.3) + opacity: root.enabled ? 1 : 0.5 + + Behavior on color { CAnim {} } + Behavior on border.color { CAnim {} } + + MouseArea { + id: inputHover + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + enabled: root.enabled + } + + StyledTextField { + id: inputField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: root.horizontalAlignment + validator: root.validator + readOnly: root.readOnly + enabled: root.enabled + + Binding { + target: inputField + property: "text" + value: root.text + when: !inputField.activeFocus + } + + onTextChanged: { + root.text = text; + root.textEdited(text); + } + + onEditingFinished: { + root.editingFinished(); + } + } + } +} + diff --git a/modules/controlcenter/audio/AudioPane.qml b/modules/controlcenter/audio/AudioPane.qml index 694e178..76122f9 100644 --- a/modules/controlcenter/audio/AudioPane.qml +++ b/modules/controlcenter/audio/AudioPane.qml @@ -263,67 +263,40 @@ Item { Layout.fillWidth: true } - StyledRect { + StyledInputField { + id: outputVolumeInput Layout.preferredWidth: 70 - implicitHeight: outputVolumeInput.implicitHeight + Appearance.padding.small * 2 - color: outputVolumeInputHover.containsMouse || outputVolumeInput.activeFocus - ? Colours.layer(Colours.palette.m3surfaceContainer, 3) - : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: outputVolumeInput.activeFocus - ? Colours.palette.m3primary - : Qt.alpha(Colours.palette.m3outline, 0.3) + validator: IntValidator { bottom: 0; top: 100 } enabled: !Audio.muted - opacity: enabled ? 1 : 0.5 - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - MouseArea { - id: outputVolumeInputHover - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton + + Component.onCompleted: { + text = Math.round(Audio.volume * 100).toString(); } - - StyledTextField { - id: outputVolumeInput - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignHCenter - validator: IntValidator { bottom: 0; top: 100 } - enabled: !Audio.muted - - Component.onCompleted: { - text = Math.round(Audio.volume * 100).toString(); - } - - Connections { - target: Audio - function onVolumeChanged() { - if (!outputVolumeInput.activeFocus) { - outputVolumeInput.text = Math.round(Audio.volume * 100).toString(); - } + + Connections { + target: Audio + function onVolumeChanged() { + if (!outputVolumeInput.hasFocus) { + outputVolumeInput.text = Math.round(Audio.volume * 100).toString(); } } - - onTextChanged: { - if (activeFocus) { - const val = parseInt(text); - if (!isNaN(val) && val >= 0 && val <= 100) { - Audio.setVolume(val / 100); - } - } - } - onEditingFinished: { + } + + onTextEdited: (text) => { + if (hasFocus) { const val = parseInt(text); - if (isNaN(val) || val < 0 || val > 100) { - text = Math.round(Audio.volume * 100).toString(); + if (!isNaN(val) && val >= 0 && val <= 100) { + Audio.setVolume(val / 100); } } } + + onEditingFinished: { + const val = parseInt(text); + if (isNaN(val) || val < 0 || val > 100) { + text = Math.round(Audio.volume * 100).toString(); + } + } } StyledText { @@ -368,7 +341,7 @@ Item { opacity: enabled ? 1 : 0.5 onMoved: { Audio.setVolume(value); - if (!outputVolumeInput.activeFocus) { + if (!outputVolumeInput.hasFocus) { outputVolumeInput.text = Math.round(value * 100).toString(); } } @@ -402,67 +375,40 @@ Item { Layout.fillWidth: true } - StyledRect { + StyledInputField { + id: inputVolumeInput Layout.preferredWidth: 70 - implicitHeight: inputVolumeInput.implicitHeight + Appearance.padding.small * 2 - color: inputVolumeInputHover.containsMouse || inputVolumeInput.activeFocus - ? Colours.layer(Colours.palette.m3surfaceContainer, 3) - : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: inputVolumeInput.activeFocus - ? Colours.palette.m3primary - : Qt.alpha(Colours.palette.m3outline, 0.3) + validator: IntValidator { bottom: 0; top: 100 } enabled: !Audio.sourceMuted - opacity: enabled ? 1 : 0.5 - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - MouseArea { - id: inputVolumeInputHover - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton + + Component.onCompleted: { + text = Math.round(Audio.sourceVolume * 100).toString(); } - - StyledTextField { - id: inputVolumeInput - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignHCenter - validator: IntValidator { bottom: 0; top: 100 } - enabled: !Audio.sourceMuted - - Component.onCompleted: { - text = Math.round(Audio.sourceVolume * 100).toString(); - } - - Connections { - target: Audio - function onSourceVolumeChanged() { - if (!inputVolumeInput.activeFocus) { - inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString(); - } + + Connections { + target: Audio + function onSourceVolumeChanged() { + if (!inputVolumeInput.hasFocus) { + inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString(); } } - - onTextChanged: { - if (activeFocus) { - const val = parseInt(text); - if (!isNaN(val) && val >= 0 && val <= 100) { - Audio.setSourceVolume(val / 100); - } - } - } - onEditingFinished: { + } + + onTextEdited: (text) => { + if (hasFocus) { const val = parseInt(text); - if (isNaN(val) || val < 0 || val > 100) { - text = Math.round(Audio.sourceVolume * 100).toString(); + if (!isNaN(val) && val >= 0 && val <= 100) { + Audio.setSourceVolume(val / 100); } } } + + onEditingFinished: { + const val = parseInt(text); + if (isNaN(val) || val < 0 || val > 100) { + text = Math.round(Audio.sourceVolume * 100).toString(); + } + } } StyledText { @@ -507,7 +453,7 @@ Item { opacity: enabled ? 1 : 0.5 onMoved: { Audio.setSourceVolume(value); - if (!inputVolumeInput.activeFocus) { + if (!inputVolumeInput.hasFocus) { inputVolumeInput.text = Math.round(value * 100).toString(); } } diff --git a/modules/controlcenter/components/SliderInput.qml b/modules/controlcenter/components/SliderInput.qml index 3d7cd4d..7348368 100644 --- a/modules/controlcenter/components/SliderInput.qml +++ b/modules/controlcenter/components/SliderInput.qml @@ -76,79 +76,53 @@ ColumnLayout { Layout.fillWidth: true } - StyledRect { + StyledInputField { + id: inputField Layout.preferredWidth: 70 - implicitHeight: inputField.implicitHeight + Appearance.padding.small * 2 - color: inputHover.containsMouse || inputField.activeFocus - ? Colours.layer(Colours.palette.m3surfaceContainer, 3) - : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: inputField.activeFocus - ? Colours.palette.m3primary - : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - MouseArea { - id: inputHover - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton + validator: root.validator + + Component.onCompleted: { + // Initialize text without triggering valueModified signal + text = root.formatValue(root.value); } - - StyledTextField { - id: inputField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignHCenter - validator: root.validator - - Component.onCompleted: { - // Initialize text without triggering valueModified signal - text = root.formatValue(root.value); - } - - onTextChanged: { - if (activeFocus) { - const val = root.parseValue(text); - if (!isNaN(val)) { - // Validate against validator bounds if available - let isValid = true; - if (root.validator) { - if (root.validator.bottom !== undefined && val < root.validator.bottom) { - isValid = false; - } - if (root.validator.top !== undefined && val > root.validator.top) { - isValid = false; - } + + onTextEdited: (text) => { + if (hasFocus) { + const val = root.parseValue(text); + if (!isNaN(val)) { + // Validate against validator bounds if available + let isValid = true; + if (root.validator) { + if (root.validator.bottom !== undefined && val < root.validator.bottom) { + isValid = false; } - - if (isValid) { - root.valueModified(val); + if (root.validator.top !== undefined && val > root.validator.top) { + isValid = false; } } + + if (isValid) { + root.valueModified(val); + } } } - - onEditingFinished: { - const val = root.parseValue(text); - let isValid = true; - if (root.validator) { - if (root.validator.bottom !== undefined && val < root.validator.bottom) { - isValid = false; - } - if (root.validator.top !== undefined && val > root.validator.top) { - isValid = false; - } + } + + onEditingFinished: { + const val = root.parseValue(text); + let isValid = true; + if (root.validator) { + if (root.validator.bottom !== undefined && val < root.validator.bottom) { + isValid = false; } - - if (isNaN(val) || !isValid) { - text = root.formatValue(root.value); + if (root.validator.top !== undefined && val > root.validator.top) { + isValid = false; } } + + if (isNaN(val) || !isValid) { + text = root.formatValue(root.value); + } } } @@ -181,7 +155,7 @@ ColumnLayout { onValueChanged: { // Update input field text in real-time as slider moves during dragging // Always update when slider value changes (during dragging or external updates) - if (!inputField.activeFocus) { + if (!inputField.hasFocus) { const newValue = root.stepSize > 0 ? Math.round(value / root.stepSize) * root.stepSize : value; inputField.text = root.formatValue(newValue); } @@ -190,7 +164,7 @@ ColumnLayout { onMoved: { const newValue = root.stepSize > 0 ? Math.round(value / root.stepSize) * root.stepSize : value; root.valueModified(newValue); - if (!inputField.activeFocus) { + if (!inputField.hasFocus) { inputField.text = root.formatValue(newValue); } } @@ -199,7 +173,7 @@ ColumnLayout { // Update input field when value changes externally (slider is already bound) onValueChanged: { // Only update if component is initialized to avoid issues during creation - if (root._initialized && !inputField.activeFocus) { + if (root._initialized && !inputField.hasFocus) { inputField.text = root.formatValue(root.value); } } diff --git a/modules/controlcenter/components/controls/SliderInput.qml b/modules/controlcenter/components/controls/SliderInput.qml deleted file mode 100644 index a114f7f..0000000 --- a/modules/controlcenter/components/controls/SliderInput.qml +++ /dev/null @@ -1,179 +0,0 @@ -pragma ComponentBehavior: Bound - -import ".." -import qs.components -import qs.components.controls -import qs.components.effects -import QtQuick -import QtQuick.Layouts - -ColumnLayout { - id: root - - property string label: "" - property real value: 0 - property real from: 0 - property real to: 100 - property real stepSize: 0 - property var validator: null - property string suffix: "" // Optional suffix text (e.g., "×", "px") - property var formatValueFunction: null // Optional custom format function - property var parseValueFunction: null // Optional custom parse function - - function formatValue(val: real): string { - if (formatValueFunction) { - return formatValueFunction(val); - } - // Default format function - if (validator && validator.bottom !== undefined) { - // Check if it's an integer validator - if (validator.top !== undefined && validator.top === Math.floor(validator.top)) { - return Math.round(val).toString(); - } - } - return val.toFixed(1); - } - - function parseValue(text: string): real { - if (parseValueFunction) { - return parseValueFunction(text); - } - // Default parse function - if (validator && validator.bottom !== undefined) { - // Check if it's an integer validator - if (validator.top !== undefined && validator.top === Math.floor(validator.top)) { - return parseInt(text); - } - } - return parseFloat(text); - } - - signal valueChanged(real newValue) - - spacing: Appearance.spacing.small - - RowLayout { - Layout.fillWidth: true - spacing: Appearance.spacing.normal - - StyledText { - visible: root.label !== "" - text: root.label - font.pointSize: Appearance.font.size.normal - } - - Item { - Layout.fillWidth: true - } - - StyledRect { - Layout.preferredWidth: 70 - implicitHeight: inputField.implicitHeight + Appearance.padding.small * 2 - color: inputHover.containsMouse || inputField.activeFocus - ? Colours.layer(Colours.palette.m3surfaceContainer, 3) - : Colours.layer(Colours.palette.m3surfaceContainer, 2) - radius: Appearance.rounding.small - border.width: 1 - border.color: inputField.activeFocus - ? Colours.palette.m3primary - : Qt.alpha(Colours.palette.m3outline, 0.3) - - Behavior on color { CAnim {} } - Behavior on border.color { CAnim {} } - - MouseArea { - id: inputHover - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton - } - - StyledTextField { - id: inputField - anchors.centerIn: parent - width: parent.width - Appearance.padding.normal - horizontalAlignment: TextInput.AlignHCenter - validator: root.validator - - Component.onCompleted: { - text = root.formatValue(root.value); - } - - onTextChanged: { - if (activeFocus) { - const val = root.parseValue(text); - if (!isNaN(val)) { - // Validate against validator bounds if available - let isValid = true; - if (root.validator) { - if (root.validator.bottom !== undefined && val < root.validator.bottom) { - isValid = false; - } - if (root.validator.top !== undefined && val > root.validator.top) { - isValid = false; - } - } - - if (isValid) { - root.valueChanged(val); - } - } - } - } - - onEditingFinished: { - const val = root.parseValue(text); - let isValid = true; - if (root.validator) { - if (root.validator.bottom !== undefined && val < root.validator.bottom) { - isValid = false; - } - if (root.validator.top !== undefined && val > root.validator.top) { - isValid = false; - } - } - - if (isNaN(val) || !isValid) { - text = root.formatValue(root.value); - } - } - } - } - - StyledText { - visible: root.suffix !== "" - text: root.suffix - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.normal - } - } - - StyledSlider { - id: slider - - Layout.fillWidth: true - implicitHeight: Appearance.padding.normal * 3 - - from: root.from - to: root.to - stepSize: root.stepSize - value: root.value - - onMoved: { - const newValue = root.stepSize > 0 ? Math.round(value / root.stepSize) * root.stepSize : value; - root.valueChanged(newValue); - if (!inputField.activeFocus) { - inputField.text = root.formatValue(newValue); - } - } - } - - // Update input field when value changes externally (slider is already bound) - onValueChanged: { - if (!inputField.activeFocus) { - inputField.text = root.formatValue(root.value); - } - } -} - |