diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 3b9466a..a7693ff 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -217,6 +217,7 @@ Singleton { audio: JsonObject { property string visualizerType: "linear" + property int volumeStep: 5 } // ui diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml index 98fba12..ffc225e 100644 --- a/Modules/SettingsPanel/Tabs/AudioTab.qml +++ b/Modules/SettingsPanel/Tabs/AudioTab.qml @@ -120,6 +120,27 @@ ColumnLayout { } } } + + // Volume Step Size + ColumnLayout { + spacing: Style.marginS * scaling + Layout.fillWidth: true + Layout.topMargin: Style.marginM * scaling + + NSpinBox { + Layout.fillWidth: true + label: "Volume Step Size" + description: "Adjust the step size for volume changes (scroll wheel, keyboard shortcuts)." + minimum: 1 + maximum: 25 + value: Settings.data.audio.volumeStep + stepSize: 1 + suffix: "%" + onValueChanged: { + Settings.data.audio.volumeStep = value + } + } + } } NDivider { diff --git a/Modules/SettingsPanel/Tabs/BrightnessTab.qml b/Modules/SettingsPanel/Tabs/BrightnessTab.qml index f5c8270..3b61e7b 100644 --- a/Modules/SettingsPanel/Tabs/BrightnessTab.qml +++ b/Modules/SettingsPanel/Tabs/BrightnessTab.qml @@ -49,34 +49,17 @@ Item { spacing: Style.marginS * scaling Layout.fillWidth: true - NLabel { + NSpinBox { + Layout.fillWidth: true label: "Brightness Step Size" description: "Adjust the step size for brightness changes (scroll wheel, keyboard shortcuts)." - } - - RowLayout { - Layout.fillWidth: true - spacing: Style.marginM * scaling - - NSlider { - Layout.fillWidth: true - from: 1 - to: 50 - value: Settings.data.brightness.brightnessStep - stepSize: 1 - onPressedChanged: { - if (!pressed) { - Settings.data.brightness.brightnessStep = value - } - } - } - - NText { - text: Settings.data.brightness.brightnessStep + "%" - Layout.alignment: Qt.AlignVCenter - color: Color.mOnSurface - font.pointSize: Style.fontSizeM * scaling - font.weight: Style.fontWeightBold + minimum: 1 + maximum: 50 + value: Settings.data.brightness.brightnessStep + stepSize: 1 + suffix: "%" + onValueChanged: { + Settings.data.brightness.brightnessStep = value } } } diff --git a/README.md b/README.md index fbf418c..6bde91f 100644 --- a/README.md +++ b/README.md @@ -250,4 +250,4 @@ Thank you to everyone who supports me and this project 💜! ## License -This project is licensed under the terms of the [MIT License](./LICENSE). +This project is licensed under the terms of the [MIT License](./LICENSE). \ No newline at end of file diff --git a/Services/AudioService.qml b/Services/AudioService.qml index f11813d..0dd6fc9 100644 --- a/Services/AudioService.qml +++ b/Services/AudioService.qml @@ -4,6 +4,7 @@ import QtQuick import Quickshell import Quickshell.Io import Quickshell.Services.Pipewire +import qs.Commons Singleton { id: root @@ -34,7 +35,7 @@ Singleton { readonly property alias muted: root._muted property bool _muted: !!sink?.audio?.muted - readonly property real stepVolume: 0.05 + readonly property real stepVolume: Settings.data.audio.volumeStep / 100.0 PwObjectTracker { objects: [...root.sinks, ...root.sources] diff --git a/Widgets/NImageCached.qml b/Widgets/NImageCached.qml index 61de0a8..88e448e 100644 --- a/Widgets/NImageCached.qml +++ b/Widgets/NImageCached.qml @@ -47,4 +47,4 @@ Image { }) } } -} +} \ No newline at end of file diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml new file mode 100644 index 0000000..493bc15 --- /dev/null +++ b/Widgets/NSpinBox.qml @@ -0,0 +1,203 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Services +import qs.Widgets + +RowLayout { + id: root + + // Public properties + property alias value: spinBox.value + property alias from: spinBox.from + property alias to: spinBox.to + property alias stepSize: spinBox.stepSize + property string suffix: "" + property string prefix: "" + property string label: "" + property string description: "" + property bool enabled: true + property bool hovering: false + property int baseSize: Style.baseWidgetSize + + // Convenience properties for common naming + property alias minimum: spinBox.from + property alias maximum: spinBox.to + + signal entered + signal exited + + Layout.fillWidth: true + + ColumnLayout { + spacing: Style.marginXXS * scaling + Layout.fillWidth: true + + NText { + text: label + font.pointSize: Style.fontSizeM * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + visible: label !== "" + } + + NText { + text: description + font.pointSize: Style.fontSizeS * scaling + color: Color.mOnSurfaceVariant + wrapMode: Text.WordWrap + Layout.fillWidth: true + visible: description !== "" + } + } + + // Simple value display with subtle controls + Rectangle { + id: spinBoxContainer + + implicitWidth: 100 * scaling // Wider for better proportions + implicitHeight: (root.baseSize - 4) * scaling // Slightly shorter than toggle + radius: height * 0.5 // Fully rounded like toggle + color: Color.mSurfaceVariant + border.color: root.hovering ? Color.mPrimary : Color.mOutline + border.width: 1 + + Behavior on border.color { + ColorAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + + // Mouse area for scroll wheel and hover + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + hoverEnabled: true + onEntered: { + root.hovering = true + root.entered() + } + onExited: { + root.hovering = false + root.exited() + } + onWheel: function(wheel) { + if (wheel.angleDelta.y > 0 && spinBox.value < spinBox.to) { + spinBox.increase() + } else if (wheel.angleDelta.y < 0 && spinBox.value > spinBox.from) { + spinBox.decrease() + } + } + } + + // Decrease button (left) + Rectangle { + id: decreaseButton + width: parent.height * 0.8 // Make it circular + height: parent.height * 0.8 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: parent.height * 0.1 + radius: width * 0.5 // Perfect circle + color: decreaseArea.containsMouse ? Color.mPrimary : "transparent" + opacity: root.enabled && spinBox.value > spinBox.from ? 1.0 : 0.3 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + + NIcon { + anchors.centerIn: parent + text: "remove" + font.pointSize: Style.fontSizeS * scaling + color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary + } + + MouseArea { + id: decreaseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + enabled: root.enabled && spinBox.value > spinBox.from + onClicked: spinBox.decrease() + } + } + + // Increase button (right) + Rectangle { + id: increaseButton + width: parent.height * 0.8 // Make it circular + height: parent.height * 0.8 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: parent.height * 0.1 + radius: width * 0.5 // Perfect circle + color: increaseArea.containsMouse ? Color.mPrimary : "transparent" + opacity: root.enabled && spinBox.value < spinBox.to ? 1.0 : 0.3 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + easing.type: Easing.InOutCubic + } + } + + NIcon { + anchors.centerIn: parent + text: "add" + font.pointSize: Style.fontSizeS * scaling + color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary + } + + MouseArea { + id: increaseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + enabled: root.enabled && spinBox.value < spinBox.to + onClicked: spinBox.increase() + } + } + + // Center value display + SpinBox { + id: spinBox + anchors.left: decreaseButton.right + anchors.right: increaseButton.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 4 * scaling + height: parent.height + + background: Item {} + up.indicator: Item {} + down.indicator: Item {} + + font.pointSize: Style.fontSizeM * scaling + font.family: Settings.data.ui.fontDefault + + from: 0 + to: 100 + stepSize: 1 + editable: false // Only use buttons/scroll + enabled: root.enabled + + contentItem: Item { + anchors.fill: parent + + NText { + anchors.centerIn: parent + text: root.prefix + spinBox.value + root.suffix + font.pointSize: Style.fontSizeM * scaling + font.weight: Style.fontWeightMedium + color: Color.mOnSurface + horizontalAlignment: Text.AlignHCenter + } + } + } + } +}