import QtQuick import QtQuick.Controls import QtQuick.Effects import qs.Commons import qs.Services.UI Slider { id: root property color fillColor: "transparent" property var cutoutColor: Color.mSurface property bool snapAlways: true property real widthRatio: 0.7 property string tooltipText property string tooltipDirection: "auto" property bool hovering: false property color topColor: "white" property color bottomColor: "black" property bool rainbowMode: false readonly property real knobDiameter: Math.round((Style.baseWidgetSize * widthRatio * Style.uiScaleRatio) / 2) * 2 readonly property real trackWidth: Math.round((knobDiameter * 0.4 * Style.uiScaleRatio) / 2) * 2 readonly property real cutoutExtra: Math.round((Style.baseWidgetSize * 0.1 * Style.uiScaleRatio) / 2) * 2 //horizontal: false orientation: Qt.Vertical padding: cutoutExtra / 2 snapMode: snapAlways ? Slider.SnapAlways : Slider.SnapOnRelease implicitWidth: Math.max(trackWidth, knobDiameter) background: Rectangle { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter x: root.leftPadding + root.availableWidth / 2 - width / 2 height: root.availableHeight - root.knobDiameter width: root.trackWidth radius: Math.min(Style.iRadiusL, width / 2) color: Qt.alpha(Color.mSurface, 0.5) border.color: Qt.alpha(Color.mOutline, 0.5) border.width: Style.borderS // Gradients gradient: root.rainbowMode ? rainbowGradient : standardGradient Gradient { id: standardGradient orientation: Gradient.Vertical GradientStop { position: 0.0 color: root.topColor } GradientStop { position: 1.0 color: root.bottomColor } } Gradient { id: rainbowGradient orientation: Gradient.Vertical GradientStop { position: 0.000 color: "#FF0000" } GradientStop { position: 0.167 color: "#FF00FF" } GradientStop { position: 0.333 color: "#0000FF" } GradientStop { position: 0.500 color: "#00FFFF" } GradientStop { position: 0.667 color: "#00FF00" } GradientStop { position: 0.833 color: "#FFFF00" } GradientStop { position: 1.000 color: "#FF0000" } } // Circular cutout Rectangle { id: knobCutout implicitWidth: root.knobDiameter + root.cutoutExtra implicitHeight: root.knobDiameter + root.cutoutExtra radius: Math.min(Style.iRadiusL, width / 2) color: root.cutoutColor !== undefined ? root.cutoutColor : Color.mSurface y: root.visualPosition * (root.availableHeight - root.knobDiameter) - ((root.knobDiameter + root.cutoutExtra) / 2) anchors.horizontalCenter: parent.horizontalCenter } } handle: Item { implicitWidth: root.knobDiameter implicitHeight: root.knobDiameter y: root.topPadding + root.visualPosition * (root.availableHeight - height) anchors.horizontalCenter: parent.horizontalCenter Rectangle { id: knob implicitWidth: root.knobDiameter implicitHeight: root.knobDiameter radius: Math.min(Style.iRadiusL, width / 2) color: { if (root.rainbowMode) { // Hue Logic: Map position (0.0 to 1.0) directly to Hue return Qt.hsva(1 - root.visualPosition, 1, 1, 1); } else { // Linear Interpolation for Standard Gradients // visualPosition 0.0 = Top, 1.0 = Bottom var t = root.visualPosition; var r = root.topColor.r * (1 - t) + root.bottomColor.r * t; var g = root.topColor.g * (1 - t) + root.bottomColor.g * t; var b = root.topColor.b * (1 - t) + root.bottomColor.b * t; return Qt.rgba(r, g, b, 1); } } border.color: root.pressed ? Color.mHover : Color.mPrimary border.width: Style.borderL anchors.centerIn: parent Behavior on color { ColorAnimation { duration: Style.animationFast } } } MouseArea { enabled: true anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true acceptedButtons: Qt.NoButton // Don't accept any mouse buttons - only hover propagateComposedEvents: true onEntered: { root.hovering = true; if (root.tooltipText) { TooltipService.show(knob, root.tooltipText, root.tooltipDirection); } } onExited: { root.hovering = false; if (root.tooltipText) { TooltipService.hide(); } } } // Hide tooltip when slider is pressed (anywhere on the slider) Connections { target: root function onPressedChanged() { if (root.pressed && root.tooltipText) { TooltipService.hide(); } } } } layer.enabled: true }