diff --git a/Components/ThemedSlider.qml b/Components/ThemedSlider.qml index 1e737d6..e782019 100644 --- a/Components/ThemedSlider.qml +++ b/Components/ThemedSlider.qml @@ -1,45 +1,99 @@ import QtQuick import QtQuick.Controls +import QtQuick.Effects import qs.Settings // Reusable themed slider styled like the sliders in Wallpaper.qml Slider { id: slider - // Optional monitor screen for scaling context property var screen - // Convenience flag mirroring Wallpaper sliders property bool snapAlways: true + readonly property real trackHeight: 12 * Theme.scale(screen) + readonly property real knobDiameter: 28 * Theme.scale(screen) + // Optional color to cut the track beneath the knob (should match surrounding background) + // If not provided, falls back to Theme.backgroundPrimary + property var cutoutColor + // Extra radius for the cutout so it shows around the knob edges + readonly property real cutoutExtra: 8 * Theme.scale(screen) + snapMode: snapAlways ? Slider.SnapAlways : Slider.SnapOnRelease + implicitHeight: Math.max(trackHeight, knobDiameter) + background: Rectangle { x: slider.leftPadding y: slider.topPadding + slider.availableHeight / 2 - height / 2 implicitWidth: 200 - implicitHeight: 4 * Theme.scale(screen) + implicitHeight: trackHeight width: slider.availableWidth height: implicitHeight radius: height / 2 color: Theme.surfaceVariant Rectangle { + id: activeTrack width: slider.visualPosition * parent.width height: parent.height color: Theme.accentPrimary radius: parent.radius + + Behavior on width { + NumberAnimation { duration: 120; easing.type: Easing.OutQuad } + } + } + + // Circular cutout centered under the knob to create the "notch" on both sides + Rectangle { + id: knobCutout + width: knobDiameter + cutoutExtra + height: knobDiameter + cutoutExtra + radius: width / 2 + color: slider.cutoutColor !== undefined ? slider.cutoutColor : Theme.backgroundPrimary + x: Math.max(0, Math.min(parent.width - width, slider.visualPosition * (parent.width - slider.knobDiameter) - cutoutExtra / 2)) + y: (parent.height - height) / 2 } } - handle: Rectangle { + handle: Item { + id: handleRoot + width: knob.implicitWidth + height: knob.implicitHeight x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width) y: slider.topPadding + slider.availableHeight / 2 - height / 2 - implicitWidth: 20 * Theme.scale(screen) - implicitHeight: 20 * Theme.scale(screen) - radius: width / 2 - color: slider.pressed ? Theme.surfaceVariant : Theme.surface - border.color: Theme.accentPrimary - border.width: 2 * Theme.scale(screen) + + // Subtle shadow for a more polished look (keeps theme colors) + MultiEffect { + anchors.fill: knob + source: knob + shadowEnabled: true + shadowColor: Theme.shadow + shadowOpacity: 0.25 + shadowHorizontalOffset: 0 + shadowVerticalOffset: 1 + shadowBlur: 8 + } + + Rectangle { + id: knob + implicitWidth: knobDiameter + implicitHeight: knobDiameter + radius: width / 2 + color: slider.pressed ? Theme.surfaceVariant : Theme.surface + border.color: Theme.accentPrimary + border.width: 2 * Theme.scale(screen) + + // Press feedback halo (using accent color, low opacity) + Rectangle { + anchors.centerIn: parent + width: parent.width + 10 * Theme.scale(screen) + height: parent.height + 10 * Theme.scale(screen) + radius: width / 2 + color: Theme.accentPrimary + opacity: slider.pressed ? 0.16 : 0.0 + } + } } } diff --git a/Widgets/SettingsWindow/Tabs/Display.qml b/Widgets/SettingsWindow/Tabs/Display.qml index 870a6b5..166b51f 100644 --- a/Widgets/SettingsWindow/Tabs/Display.qml +++ b/Widgets/SettingsWindow/Tabs/Display.qml @@ -434,6 +434,7 @@ ColumnLayout { id: scaleSlider Layout.fillWidth: true screen: modelData + cutoutColor: Theme.surface from: 0.8 to: 2.0 stepSize: 0.05 diff --git a/Widgets/SettingsWindow/Tabs/Wallpaper.qml b/Widgets/SettingsWindow/Tabs/Wallpaper.qml index c08331b..f4c132b 100644 --- a/Widgets/SettingsWindow/Tabs/Wallpaper.qml +++ b/Widgets/SettingsWindow/Tabs/Wallpaper.qml @@ -200,6 +200,7 @@ ColumnLayout { ThemedSlider { id: intervalSlider Layout.fillWidth: true + cutoutColor: Theme.backgroundPrimary from: 10 to: 900 stepSize: 10 @@ -500,6 +501,7 @@ ColumnLayout { ThemedSlider { id: fpsSlider Layout.fillWidth: true + cutoutColor: Theme.backgroundPrimary from: 30 to: 500 stepSize: 5 @@ -551,6 +553,7 @@ ColumnLayout { ThemedSlider { id: durationSlider Layout.fillWidth: true + cutoutColor: Theme.backgroundPrimary from: 0.25 to: 10 stepSize: 0.05