import qs.services import qs.config import QtQuick import QtQuick.Controls Slider { id: root required property string icon required property color color property real oldValue property bool initializing: true Timer { id: initDelay running: true interval: 100 onTriggered: root.initializing = false } orientation: Qt.Vertical background: CustomRect { color: Config.colors.container radius: 1000 CustomRect { implicitWidth: root.orientation === Qt.Horizontal ? root.handle.x + root.handle.width : root.handle.width y: root.orientation === Qt.Vertical ? root.handle.y : 0 implicitHeight: root.orientation === Qt.Vertical ? parent.height - y : root.handle.height color: root.color opacity: 0.8 radius: parent.radius } } handle: Item { id: handle property bool moving: false x: root.orientation === Qt.Horizontal ? root.visualPosition * (root.availableWidth - width) : 0 y: root.orientation === Qt.Vertical ? root.visualPosition * (root.availableHeight - height) : 0 implicitWidth: root.orientation === Qt.Horizontal ? root.height : root.width implicitHeight: implicitWidth Elevation { anchors.fill: parent radius: rect.radius level: handleInteraction.containsMouse ? 2 : 1 } CustomRect { id: rect anchors.fill: parent color: root.color radius: 1000 MouseArea { id: handleInteraction anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.NoButton } MaterialIcon { id: icon property bool moving: handle.moving property bool stoppingMove: false function update(): void { text = moving ? Qt.binding(() => Math.round(root.value * 100)) : Qt.binding(() => root.icon); font.family = moving ? Config.font.family.sans : Config.font.family.material; font.pointSize = moving ? Config.font.size.smaller : Config.font.size.larger; } animate: !moving && !stoppingMove animateDuration: Config.anim.durations.small text: root.icon font.pointSize: Config.font.size.larger color: Config.colors.primaryDark anchors.centerIn: parent Behavior on moving { enabled: icon.moving !== targetValue SequentialAnimation { PropertyAction { target: icon property: "stoppingMove" value: true } Anim { target: icon property: "scale" from: 1 to: 0 duration: Config.anim.durations.small / 2 easing.bezierCurve: Config.anim.curves.standardAccel } ScriptAction { script: icon.update() } Anim { target: icon property: "scale" from: 0 to: 1 duration: Config.anim.durations.small / 2 easing.bezierCurve: Config.anim.curves.standardDecel } PropertyAction { target: icon property: "stoppingMove" value: false } } } } } } onPressedChanged: handle.moving = pressed onValueChanged: { if (Math.abs(value - oldValue) < 0.01) return; if (!initializing) { oldValue = value; handle.moving = true; stateChangeDelay.restart(); } } Timer { id: stateChangeDelay interval: 600 onTriggered: { if (!root.pressed) handle.moving = false; } } Behavior on value { enabled: !root.initializing Anim { duration: Config.anim.durations.normal } } }