From 5aa7ff7e9178c07089ac96c26a7b9a41e821b1c7 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Sun, 14 Sep 2025 20:52:32 -0400 Subject: [PATCH] NValueSlider: new component + pimped NSlider with a small gradient and removed rounded corners due to issues. --- Modules/Bar/Widgets/KeyboardLayout.qml | 1 + Modules/SettingsPanel/Tabs/AudioTab.qml | 80 ++++++-------- Modules/SettingsPanel/Tabs/BarTab.qml | 79 +++++--------- Modules/SettingsPanel/Tabs/DisplayTab.qml | 28 ++--- Modules/SettingsPanel/Tabs/DockTab.qml | 51 +++------ Modules/SettingsPanel/Tabs/GeneralTab.qml | 75 +++++-------- Modules/SettingsPanel/Tabs/LauncherTab.qml | 27 ++--- .../SettingsPanel/Tabs/NotificationTab.qml | 75 +++++-------- Modules/SettingsPanel/Tabs/WallpaperTab.qml | 44 +++----- Modules/SidePanel/Cards/MediaCard.qml | 1 - Widgets/NColorPickerDialog.qml | 100 +++++++----------- Widgets/NSlider.qml | 37 +++++-- Widgets/NSliderWithLabel.qml | 61 ----------- Widgets/NValueSlider.qml | 48 +++++++++ 14 files changed, 266 insertions(+), 441 deletions(-) delete mode 100644 Widgets/NSliderWithLabel.qml create mode 100644 Widgets/NValueSlider.qml diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml index 814d7f3..87aef27 100644 --- a/Modules/Bar/Widgets/KeyboardLayout.qml +++ b/Modules/Bar/Widgets/KeyboardLayout.qml @@ -50,6 +50,7 @@ Item { forceOpen: root.displayMode === "forceOpen" forceClose: root.displayMode === "alwaysHide" onClicked: { + // You could open keyboard settings here if needed // For now, just show the current layout } diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml index c7755d0..07a9762 100644 --- a/Modules/SettingsPanel/Tabs/AudioTab.qml +++ b/Modules/SettingsPanel/Tabs/AudioTab.qml @@ -2,9 +2,9 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Quickshell.Services.Pipewire -import qs.Widgets import qs.Commons import qs.Services +import qs.Widgets ColumnLayout { id: root @@ -34,37 +34,29 @@ ColumnLayout { description: "System-wide volume level." } - RowLayout { - // Pipewire seems a bit finicky, if we spam too many volume changes it breaks easily - // Probably because they have some quick fades in and out to avoid clipping - // We use a timer to space out the updates, to avoid lock up - Timer { - interval: Style.animationFast - running: true - repeat: true - onTriggered: { - if (Math.abs(localVolume - AudioService.volume) >= 0.01) { - AudioService.setVolume(localVolume) - } + // Pipewire seems a bit finicky, if we spam too many volume changes it breaks easily + // Probably because they have some quick fades in and out to avoid clipping + // We use a timer to space out the updates, to avoid lock up + Timer { + interval: Style.animationFast + running: true + repeat: true + onTriggered: { + if (Math.abs(localVolume - AudioService.volume) >= 0.01) { + AudioService.setVolume(localVolume) } } + } - NSlider { - Layout.fillWidth: true - from: 0 - to: Settings.data.audio.volumeOverdrive ? 2.0 : 1.0 - value: localVolume - stepSize: 0.01 - onMoved: { - localVolume = value - } - } - - NText { - text: Math.floor(AudioService.volume * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface + NValueSlider { + Layout.fillWidth: true + from: 0 + to: Settings.data.audio.volumeOverdrive ? 2.0 : 1.0 + value: localVolume + stepSize: 0.01 + text: Math.floor(AudioService.volume * 100) + "%" + onMoved: { + localVolume = value } } } @@ -96,24 +88,14 @@ ColumnLayout { description: "Microphone input volume level." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1.0 - value: AudioService.inputVolume - stepSize: 0.01 - onMoved: { - AudioService.setInputVolume(value) - } - } - - NText { - text: Math.floor(AudioService.inputVolume * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1.0 + value: AudioService.inputVolume + stepSize: 0.01 + text: Math.floor(AudioService.inputVolume * 100) + "%" + onMoved: value => AudioService.setInputVolume(value) } } @@ -144,9 +126,7 @@ ColumnLayout { value: Settings.data.audio.volumeStep stepSize: 1 suffix: "%" - onValueChanged: { - Settings.data.audio.volumeStep = value - } + onValueChanged: value => Settings.data.audio.volumeStep = value } } diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index ca5ce47..6837861 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -82,23 +82,14 @@ ColumnLayout { description: "Adjust the background opacity of the bar." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.bar.backgroundOpacity - onMoved: Settings.data.bar.backgroundOpacity = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.bar.backgroundOpacity + onMoved: value => Settings.data.bar.backgroundOpacity = value + text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%" } } NToggle { @@ -133,25 +124,14 @@ ColumnLayout { color: Color.mOnSurfaceVariant } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.bar.marginVertical - onMoved: Settings.data.bar.marginVertical = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.round(Settings.data.bar.marginVertical * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginXS * scaling - Layout.preferredWidth: 50 - horizontalAlignment: Text.AlignRight - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.bar.marginVertical + onMoved: value => Settings.data.bar.marginVertical = value + text: Math.round(Settings.data.bar.marginVertical * 100) + "%" } } @@ -164,25 +144,14 @@ ColumnLayout { color: Color.mOnSurfaceVariant } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.bar.marginHorizontal - onMoved: Settings.data.bar.marginHorizontal = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.round(Settings.data.bar.marginHorizontal * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginXS * scaling - Layout.preferredWidth: 50 - horizontalAlignment: Text.AlignRight - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.bar.marginHorizontal + onMoved: value => Settings.data.bar.marginHorizontal = value + text: Math.round(Settings.data.bar.marginHorizontal * 100) + "%" } } } diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index b43fc72..eef69cb 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -116,21 +116,15 @@ ColumnLayout { Layout.preferredWidth: 80 * scaling } - NSlider { + NValueSlider { id: scaleSlider from: 0.7 to: 1.8 stepSize: 0.01 value: localScaling - onPressedChanged: ScalingService.setScreenScale(modelData, value) - Layout.fillWidth: true - Layout.minimumWidth: 200 * scaling - } - - NText { + onPressedChanged: (pressed, value) => ScalingService.setScreenScale(modelData, value) text: `${Math.round(localScaling * 100)}%` - Layout.preferredWidth: 50 * scaling - horizontalAlignment: Text.AlignRight + Layout.fillWidth: true } // Reset button container @@ -165,24 +159,14 @@ ColumnLayout { Layout.preferredWidth: 80 * scaling } - NSlider { + NValueSlider { Layout.fillWidth: true - Layout.minimumWidth: 200 * scaling from: 0 to: 1 value: brightnessMonitor ? brightnessMonitor.brightness : 0.5 - stepSize: 0.05 - onPressedChanged: { - if (!pressed && brightnessMonitor) { - brightnessMonitor.setBrightness(value) - } - } - } - - NText { + stepSize: 0.01 + onPressedChanged: (pressed, value) => brightnessMonitor.setBrightness(value) text: brightnessMonitor ? Math.round(brightnessMonitor.brightness * 100) + "%" : "N/A" - Layout.preferredWidth: 50 * scaling - horizontalAlignment: Text.AlignRight } // Empty container to match scale row layout diff --git a/Modules/SettingsPanel/Tabs/DockTab.qml b/Modules/SettingsPanel/Tabs/DockTab.qml index d3b7c64..293378c 100644 --- a/Modules/SettingsPanel/Tabs/DockTab.qml +++ b/Modules/SettingsPanel/Tabs/DockTab.qml @@ -49,24 +49,14 @@ ColumnLayout { label: "Background Opacity" description: "Adjust the background opacity." } - - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.dock.backgroundOpacity - onMoved: Settings.data.dock.backgroundOpacity = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.dock.backgroundOpacity * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.dock.backgroundOpacity + onMoved: value => Settings.data.dock.backgroundOpacity = value + text: Math.floor(Settings.data.dock.backgroundOpacity * 100) + "%" } } @@ -79,23 +69,14 @@ ColumnLayout { description: "Adjust the floating distance from the screen edge." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 4 - stepSize: 0.01 - value: Settings.data.dock.floatingRatio - onMoved: Settings.data.dock.floatingRatio = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.dock.floatingRatio * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 4 + stepSize: 0.01 + value: Settings.data.dock.floatingRatio + onMoved: value => Settings.data.dock.floatingRatio = value + text: Math.floor(Settings.data.dock.floatingRatio * 100) + "%" } } diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml index a6141f3..4deed7a 100644 --- a/Modules/SettingsPanel/Tabs/GeneralTab.qml +++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml @@ -74,23 +74,14 @@ ColumnLayout { description: "Adjust the rounded border of all UI elements." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.general.radiusRatio - onMoved: Settings.data.general.radiusRatio = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.general.radiusRatio * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.general.radiusRatio + onMoved: value => Settings.data.general.radiusRatio = value + text: Math.floor(Settings.data.general.radiusRatio * 100) + "%" } } @@ -104,23 +95,14 @@ ColumnLayout { description: "Adjust global animation speed." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0.1 - to: 2.0 - stepSize: 0.01 - value: Settings.data.general.animationSpeed - onMoved: Settings.data.general.animationSpeed = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.round(Settings.data.general.animationSpeed * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0.1 + to: 2.0 + stepSize: 0.01 + value: Settings.data.general.animationSpeed + onMoved: value => Settings.data.general.animationSpeed = value + text: Math.round(Settings.data.general.animationSpeed * 100) + "%" } } } @@ -156,23 +138,14 @@ ColumnLayout { description: "Adjust the rounded corners of the screen." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 0 - to: 2 - stepSize: 0.01 - value: Settings.data.general.screenRadiusRatio - onMoved: Settings.data.general.screenRadiusRatio = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.general.screenRadiusRatio * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 2 + stepSize: 0.01 + value: Settings.data.general.screenRadiusRatio + onMoved: value => Settings.data.general.screenRadiusRatio = value + text: Math.floor(Settings.data.general.screenRadiusRatio * 100) + "%" } } } diff --git a/Modules/SettingsPanel/Tabs/LauncherTab.qml b/Modules/SettingsPanel/Tabs/LauncherTab.qml index 00165b4..616583d 100644 --- a/Modules/SettingsPanel/Tabs/LauncherTab.qml +++ b/Modules/SettingsPanel/Tabs/LauncherTab.qml @@ -74,24 +74,15 @@ ColumnLayout { Layout.fillWidth: true } - RowLayout { - NSlider { - id: launcherBgOpacity - Layout.fillWidth: true - from: 0.0 - to: 1.0 - stepSize: 0.01 - value: Settings.data.appLauncher.backgroundOpacity - onMoved: Settings.data.appLauncher.backgroundOpacity = value - cutoutColor: Color.mSurface - } - - NText { - text: Math.floor(Settings.data.appLauncher.backgroundOpacity * 100) + "%" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + id: launcherBgOpacity + Layout.fillWidth: true + from: 0.0 + to: 1.0 + stepSize: 0.01 + value: Settings.data.appLauncher.backgroundOpacity + onMoved: value => Settings.data.appLauncher.backgroundOpacity = value + text: Math.floor(Settings.data.appLauncher.backgroundOpacity * 100) + "%" } } diff --git a/Modules/SettingsPanel/Tabs/NotificationTab.qml b/Modules/SettingsPanel/Tabs/NotificationTab.qml index 3900555..fa6d268 100644 --- a/Modules/SettingsPanel/Tabs/NotificationTab.qml +++ b/Modules/SettingsPanel/Tabs/NotificationTab.qml @@ -100,23 +100,14 @@ ColumnLayout { description: "How long low priority notifications stay visible." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 1 - to: 30 - stepSize: 1 - value: Settings.data.notifications.lowUrgencyDuration - onMoved: Settings.data.notifications.lowUrgencyDuration = value - cutoutColor: Color.mSurface - } - - NText { - text: Settings.data.notifications.lowUrgencyDuration + "s" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 1 + to: 30 + stepSize: 1 + value: Settings.data.notifications.lowUrgencyDuration + onMoved: value => Settings.data.notifications.lowUrgencyDuration = value + text: Settings.data.notifications.lowUrgencyDuration + "s" } } @@ -130,23 +121,14 @@ ColumnLayout { description: "How long normal priority notifications stay visible." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 1 - to: 30 - stepSize: 1 - value: Settings.data.notifications.normalUrgencyDuration - onMoved: Settings.data.notifications.normalUrgencyDuration = value - cutoutColor: Color.mSurface - } - - NText { - text: Settings.data.notifications.normalUrgencyDuration + "s" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 1 + to: 30 + stepSize: 1 + value: Settings.data.notifications.normalUrgencyDuration + onMoved: value => Settings.data.notifications.normalUrgencyDuration = value + text: Settings.data.notifications.normalUrgencyDuration + "s" } } @@ -160,23 +142,14 @@ ColumnLayout { description: "How long critical priority notifications stay visible." } - RowLayout { - NSlider { - Layout.fillWidth: true - from: 1 - to: 30 - stepSize: 1 - value: Settings.data.notifications.criticalUrgencyDuration - onMoved: Settings.data.notifications.criticalUrgencyDuration = value - cutoutColor: Color.mSurface - } - - NText { - text: Settings.data.notifications.criticalUrgencyDuration + "s" - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - color: Color.mOnSurface - } + NValueSlider { + Layout.fillWidth: true + from: 1 + to: 30 + stepSize: 1 + value: Settings.data.notifications.criticalUrgencyDuration + onMoved: value => Settings.data.notifications.criticalUrgencyDuration = value + text: Settings.data.notifications.criticalUrgencyDuration + "s" } } } diff --git a/Modules/SettingsPanel/Tabs/WallpaperTab.qml b/Modules/SettingsPanel/Tabs/WallpaperTab.qml index e0f8a2b..ea4ddc3 100644 --- a/Modules/SettingsPanel/Tabs/WallpaperTab.qml +++ b/Modules/SettingsPanel/Tabs/WallpaperTab.qml @@ -138,21 +138,14 @@ ColumnLayout { description: "Duration of transition animations in seconds." } - RowLayout { - spacing: Style.marginL * scaling - NSlider { - Layout.fillWidth: true - from: 500 - to: 10000 - stepSize: 100 - value: Settings.data.wallpaper.transitionDuration - onMoved: Settings.data.wallpaper.transitionDuration = value - cutoutColor: Color.mSurface - } - NText { - text: (Settings.data.wallpaper.transitionDuration / 1000).toFixed(2) + "s" - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - } + NValueSlider { + Layout.fillWidth: true + from: 500 + to: 10000 + stepSize: 100 + value: Settings.data.wallpaper.transitionDuration + onMoved: value => Settings.data.wallpaper.transitionDuration = value + text: (Settings.data.wallpaper.transitionDuration / 1000).toFixed(1) + "s" } } @@ -163,20 +156,13 @@ ColumnLayout { description: "Duration of transition animations in seconds." } - RowLayout { - spacing: Style.marginL * scaling - NSlider { - Layout.fillWidth: true - from: 0.0 - to: 1.0 - value: Settings.data.wallpaper.transitionEdgeSmoothness - onMoved: Settings.data.wallpaper.transitionEdgeSmoothness = value - cutoutColor: Color.mSurface - } - NText { - text: Math.round(Settings.data.wallpaper.transitionEdgeSmoothness * 100) + "%" - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - } + NValueSlider { + Layout.fillWidth: true + from: 0.0 + to: 1.0 + value: Settings.data.wallpaper.transitionEdgeSmoothness + onMoved: value => Settings.data.wallpaper.transitionEdgeSmoothness = value + text: Math.round(Settings.data.wallpaper.transitionEdgeSmoothness * 100) + "%" } } } diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml index 9879256..66db286 100644 --- a/Modules/SidePanel/Cards/MediaCard.qml +++ b/Modules/SidePanel/Cards/MediaCard.qml @@ -258,7 +258,6 @@ NBox { stepSize: 0 snapAlways: false enabled: MediaService.trackLength > 0 && MediaService.canSeek - cutoutColor: Color.mSurface heightRatio: 0.65 onMoved: { diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml index 40e0f1c..b20b59f 100644 --- a/Widgets/NColorPickerDialog.qml +++ b/Widgets/NColorPickerDialog.qml @@ -243,24 +243,19 @@ Popup { Layout.preferredWidth: 20 * scaling } - NSlider { + NValueSlider { id: redSlider Layout.fillWidth: true from: 0 to: 255 value: Math.round(root.selectedColor.r * 255) - onMoved: { - root.selectedColor = Qt.rgba(value / 255, root.selectedColor.g, root.selectedColor.b, 1) - var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) - root.currentHue = hsv[0] - root.currentSaturation = hsv[1] - } - } - - NText { - text: Math.round(redSlider.value) - font.family: Settings.data.ui.fontFixed - Layout.preferredWidth: 30 * scaling + onMoved: value => { + root.selectedColor = Qt.rgba(value / 255, root.selectedColor.g, root.selectedColor.b, 1) + var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) + root.currentHue = hsv[0] + root.currentSaturation = hsv[1] + } + text: Math.round(value) } } @@ -274,25 +269,20 @@ Popup { Layout.preferredWidth: 20 * scaling } - NSlider { + NValueSlider { id: greenSlider Layout.fillWidth: true from: 0 to: 255 value: Math.round(root.selectedColor.g * 255) - onMoved: { - root.selectedColor = Qt.rgba(root.selectedColor.r, value / 255, root.selectedColor.b, 1) - // Update stored hue and saturation when RGB changes - var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) - root.currentHue = hsv[0] - root.currentSaturation = hsv[1] - } - } - - NText { - text: Math.round(greenSlider.value) - font.family: Settings.data.ui.fontFixed - Layout.preferredWidth: 30 * scaling + onMoved: value => { + root.selectedColor = Qt.rgba(root.selectedColor.r, value / 255, root.selectedColor.b, 1) + // Update stored hue and saturation when RGB changes + var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) + root.currentHue = hsv[0] + root.currentSaturation = hsv[1] + } + text: Math.round(value) } } @@ -306,25 +296,20 @@ Popup { Layout.preferredWidth: 20 * scaling } - NSlider { + NValueSlider { id: blueSlider Layout.fillWidth: true from: 0 to: 255 value: Math.round(root.selectedColor.b * 255) - onMoved: { - root.selectedColor = Qt.rgba(root.selectedColor.r, root.selectedColor.g, value / 255, 1) - // Update stored hue and saturation when RGB changes - var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) - root.currentHue = hsv[0] - root.currentSaturation = hsv[1] - } - } - - NText { - text: Math.round(blueSlider.value) - font.family: Settings.data.ui.fontFixed - Layout.preferredWidth: 30 * scaling + onMoved: value => { + root.selectedColor = Qt.rgba(root.selectedColor.r, root.selectedColor.g, value / 255, 1) + // Update stored hue and saturation when RGB changes + var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) + root.currentHue = hsv[0] + root.currentSaturation = hsv[1] + } + text: Math.round(value) } } @@ -338,7 +323,7 @@ Popup { Layout.preferredWidth: 80 * scaling } - NSlider { + NValueSlider { id: brightnessSlider Layout.fillWidth: true from: 0 @@ -347,27 +332,22 @@ Popup { var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) return hsv[2] } - onMoved: { - var hue = root.currentHue - var saturation = root.currentSaturation + onMoved: value => { + var hue = root.currentHue + var saturation = root.currentSaturation - if (hue === 0 && saturation === 0) { - var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) - hue = hsv[0] - saturation = hsv[1] - root.currentHue = hue - root.currentSaturation = saturation - } + if (hue === 0 && saturation === 0) { + var hsv = root.rgbToHsv(root.selectedColor.r * 255, root.selectedColor.g * 255, root.selectedColor.b * 255) + hue = hsv[0] + saturation = hsv[1] + root.currentHue = hue + root.currentSaturation = saturation + } - var rgb = root.hsvToRgb(hue, saturation, value) - root.selectedColor = Qt.rgba(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255, 1) - } - } - - NText { + var rgb = root.hsvToRgb(hue, saturation, value) + root.selectedColor = Qt.rgba(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255, 1) + } text: Math.round(brightnessSlider.value) + "%" - font.family: Settings.data.ui.fontFixed - Layout.preferredWidth: 40 * scaling } } } diff --git a/Widgets/NSlider.qml b/Widgets/NSlider.qml index a1c50d0..462beca 100644 --- a/Widgets/NSlider.qml +++ b/Widgets/NSlider.qml @@ -7,13 +7,12 @@ import qs.Services Slider { id: root - // Optional color to cut the track beneath the knob (should match surrounding background) - property var cutoutColor + property var cutoutColor: Color.mSurface property bool snapAlways: true property real heightRatio: 0.75 readonly property real knobDiameter: Math.round(Style.baseWidgetSize * heightRatio * scaling) - readonly property real trackHeight: knobDiameter * 0.5 + readonly property real trackHeight: knobDiameter * 0.4 readonly property real cutoutExtra: Math.round(Style.baseWidgetSize * 0.1 * scaling) snapMode: snapAlways ? Slider.SnapAlways : Slider.SnapOnRelease @@ -26,15 +25,38 @@ Slider { implicitHeight: trackHeight width: root.availableWidth height: implicitHeight - radius: height / 2 + radius: 0 color: Color.mSurface + // Animated gradient active track Rectangle { id: activeTrack width: root.visualPosition * parent.width height: parent.height - color: Color.mPrimary radius: parent.radius + + // Animated gradient fill + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { + position: 0.0 + color: Qt.darker(Color.mPrimary, 1.2) + Behavior on color { ColorAnimation { duration: 300 } } + } + GradientStop { + position: 0.5 + color: Color.mPrimary + SequentialAnimation on position { + loops: Animation.Infinite + NumberAnimation { from: 0.3; to: 0.7; duration: 2000; easing.type: Easing.InOutSine } + NumberAnimation { from: 0.7; to: 0.3; duration: 2000; easing.type: Easing.InOutSine } + } + } + GradientStop { + position: 1.0 + color: Qt.lighter(Color.mPrimary, 1.2) + } + } } // Circular cutout @@ -44,8 +66,7 @@ Slider { height: knobDiameter + cutoutExtra radius: width / 2 color: root.cutoutColor !== undefined ? root.cutoutColor : Color.mSurface - x: Math.max(0, Math.min(parent.width - width, Math.round(root.visualPosition * (parent.width - root.knobDiameter) - cutoutExtra / 2))) - y: (parent.height - height) / 2 + x: root.leftPadding + root.visualPosition * (root.availableWidth - root.knobDiameter) - cutoutExtra / 2 anchors.verticalCenter: parent.verticalCenter } } @@ -73,4 +94,4 @@ Slider { } } } -} +} \ No newline at end of file diff --git a/Widgets/NSliderWithLabel.qml b/Widgets/NSliderWithLabel.qml deleted file mode 100644 index eaa9dc1..0000000 --- a/Widgets/NSliderWithLabel.qml +++ /dev/null @@ -1,61 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import qs.Commons -import qs.Services -import qs.Widgets - -RowLayout { - id: root - - // Properties that mirror NSlider - property real from: 0 - property real to: 1 - property real value: 0 - property real stepSize: 0.01 - property var cutoutColor - property bool snapAlways: true - property real heightRatio: 0.75 - property bool showPercentage: true - property string suffix: "%" - property int decimalPlaces: 0 // 0 for integers, 1 for one decimal place, etc. - - // Signals - signal moved(real value) - signal pressedChanged(bool pressed) - - spacing: Style.marginS * scaling - - NSlider { - id: slider - Layout.fillWidth: true - from: root.from - to: root.to - value: root.value - stepSize: root.stepSize - cutoutColor: root.cutoutColor - snapAlways: root.snapAlways - heightRatio: root.heightRatio - stableWidth: true - minWidth: 200 * scaling - - onMoved: root.moved(value) - onPressedChanged: root.pressedChanged(pressed) - } - - NText { - id: percentageLabel - visible: root.showPercentage - text: { - if (root.decimalPlaces === 0) { - return Math.round(slider.value * 100) + root.suffix - } else { - return (slider.value * 100).toFixed(root.decimalPlaces) + root.suffix - } - } - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling - Layout.preferredWidth: 50 * scaling - horizontalAlignment: Text.AlignRight - } -} diff --git a/Widgets/NValueSlider.qml b/Widgets/NValueSlider.qml new file mode 100644 index 0000000..4f06954 --- /dev/null +++ b/Widgets/NValueSlider.qml @@ -0,0 +1,48 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons +import qs.Services +import qs.Widgets + +RowLayout { + id: root + + property real from: 0 + property real to: 1 + property real value: 0 + property real stepSize: 0.01 + property var cutoutColor: Color.mSurface + property bool snapAlways: true + property real heightRatio: 0.75 + property string text: "" + + // Signals + signal moved(real value) + signal pressedChanged(bool pressed, real value) + + spacing: Style.marginL * scaling + + NSlider { + id: slider + Layout.fillWidth: true + from: root.from + to: root.to + value: root.value + stepSize: root.stepSize + cutoutColor: root.cutoutColor + snapAlways: root.snapAlways + heightRatio: root.heightRatio + onMoved: root.moved(value) + onPressedChanged: root.pressedChanged(pressed, value) + } + + NText { + visible: root.text !== "" + text: root.text + font.family: Settings.data.ui.fontFixed + Layout.alignment: Qt.AlignVCenter + Layout.preferredWidth: 40 * scaling + horizontalAlignment: Text.AlignRight + } +}