200 lines
4.8 KiB
QML
200 lines
4.8 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import QtQuick.Templates
|
|
import ZShell.Components
|
|
import ZShell
|
|
import qs.Components
|
|
import qs.Config
|
|
|
|
Slider {
|
|
id: root
|
|
|
|
property bool animateWave
|
|
property color bgColor: enabled ? DynamicColors.palette.m3secondaryContainer : Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
|
|
property color fgColor: enabled ? DynamicColors.palette.m3primary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.38)
|
|
property real filledWidth
|
|
property alias inset: inset
|
|
property color insetColor: enabled ? (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary) : DynamicColors.palette.m3onSurface
|
|
property string insetIcon: ""
|
|
property real pos: visualPosition
|
|
property int radius: Appearance.rounding.small
|
|
property int waveDuration: 1000
|
|
property real waveFrequency: 6
|
|
property bool wavy
|
|
|
|
signal interaction(v: real)
|
|
|
|
implicitHeight: 12
|
|
implicitWidth: 200
|
|
|
|
contentItem: Item {
|
|
anchors.fill: parent
|
|
|
|
CustomRect {
|
|
id: remaining
|
|
|
|
anchors.left: handle.right
|
|
anchors.leftMargin: Appearance.spacing.extraSmall
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
bottomLeftRadius: Appearance.rounding.extraSmall / 2
|
|
color: root.bgColor
|
|
implicitHeight: parent.height * (parent.height <= 12 ? opacity : Math.min(opacity * 2, 1))
|
|
opacity: Math.min(width, 12) / 12
|
|
radius: root.radius
|
|
topLeftRadius: Appearance.rounding.extraSmall / 2
|
|
}
|
|
|
|
CustomRect {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 4 * remaining.opacity
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: root.fgColor
|
|
implicitHeight: 4 * remaining.opacity
|
|
implicitWidth: implicitHeight
|
|
opacity: remaining.opacity
|
|
radius: Appearance.rounding.full
|
|
}
|
|
|
|
CustomRect {
|
|
id: handle
|
|
|
|
anchors.left: filled.right
|
|
anchors.leftMargin: Appearance.spacing.extraSmall
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: root.fgColor
|
|
implicitHeight: {
|
|
const t = ZUtils.clamp((parent.height - 12) / 16, 0, 1);
|
|
const lerp = (a, b) => a + (b - a) * t;
|
|
return parent.height * (mouse.pressed ? lerp(3.5, 1.5) : lerp(3, 1.2));
|
|
}
|
|
implicitWidth: 4
|
|
radius: Appearance.rounding.full
|
|
|
|
Behavior on implicitHeight {
|
|
Anim {
|
|
type: Anim.FastSpatial
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: filled
|
|
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
asynchronous: true
|
|
sourceComponent: root.wavy ? waveComp : lineComp
|
|
}
|
|
|
|
MaterialIcon {
|
|
id: inset
|
|
|
|
readonly property bool attached: root.pos < 0.1
|
|
property real dockT: attached ? 1 : 0
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.top: parent.top
|
|
color: root.insetColor
|
|
font.pixelSize: Appearance.font.size.smaller * 2
|
|
text: root.insetIcon
|
|
verticalAlignment: Text.AlignVCenter
|
|
visible: !root.wavy && root.insetIcon !== ""
|
|
x: Appearance.spacing.extraSmall + dockT * (handle.x + Appearance.spacing.small)
|
|
|
|
Behavior on dockT {
|
|
Anim {
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: lineComp
|
|
|
|
CustomRect {
|
|
bottomRightRadius: Appearance.rounding.extraSmall / 2
|
|
color: root.fgColor
|
|
implicitHeight: root.height
|
|
implicitWidth: root.filledWidth
|
|
radius: root.radius
|
|
topRightRadius: Appearance.rounding.extraSmall / 2
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: waveComp
|
|
|
|
WavyLine {
|
|
color: root.fgColor
|
|
frequency: root.waveFrequency
|
|
fullLength: root.width - handle.implicitWidth - handle.anchors.leftMargin
|
|
implicitHeight: lineWidth * amplitudeMultiplier * 2 + lineWidth
|
|
implicitWidth: root.filledWidth
|
|
lineWidth: root.height * 0.7
|
|
startX: x
|
|
|
|
Behavior on color {
|
|
CAnim {
|
|
}
|
|
}
|
|
Anim on waveProgress {
|
|
duration: root.waveDuration
|
|
easing.type: Easing.Linear
|
|
from: 0
|
|
loops: Animation.Infinite
|
|
paused: !root.animateWave
|
|
running: true
|
|
to: 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Behavior on filledWidth {
|
|
id: widthBehavior
|
|
|
|
Anim {
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: filledWidth = Qt.binding(() => (width - handle.implicitWidth - handle.anchors.leftMargin) * pos)
|
|
|
|
Binding {
|
|
id: posBinding
|
|
|
|
property: "pos"
|
|
target: root
|
|
value: ZUtils.clamp(mouse.pressStartPos + mouse.dragMovement, 0, 1)
|
|
when: mouse.pressed
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouse
|
|
|
|
property real dragMovement
|
|
property real pressStartPos
|
|
property real pressStartX
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
implicitHeight: handle.implicitHeight
|
|
preventStealing: true
|
|
|
|
onPositionChanged: e => {
|
|
dragMovement = (e.x - pressStartX) / width;
|
|
root.interaction(posBinding.value);
|
|
}
|
|
onPressed: e => {
|
|
widthBehavior.enabled = false;
|
|
pressStartX = e.x;
|
|
pressStartPos = root.visualPosition;
|
|
}
|
|
onReleased: e => {
|
|
root.interaction(posBinding.value);
|
|
widthBehavior.enabled = true;
|
|
dragMovement = 0;
|
|
}
|
|
}
|
|
}
|