Files
arthur-os/shell/Ui/PanelSlider.qml
T
David Heinemeier Hansson 8ed6e302b0 Small cleanups: reuse Util.clamp in OSD; PanelSlider hover via _hot
OSD reimplemented clamp() inline when Util already has one.

PanelSlider's knob-scale binding read `mouseArea.containsMouse` directly
instead of going through a `_hot` like the other interactive controls
(TextField, NumberField, Dropdown). Mirror them so future style work
has a single property to override.
2026-05-20 20:33:27 +02:00

121 lines
3.5 KiB
QML

import QtQuick
import qs.Commons
Item {
id: root
property QtObject bar: null
property real value: 0
property real minimum: 0
property real maximum: 1
property real step: 0.05
property bool integer: false
property color trackColor: bar ? Style.selectedFillFor(bar.foreground, Color.accent) : "#333"
property color fillColor: bar ? bar.foreground : Color.foreground
property color knobColor: bar ? bar.foreground : Color.foreground
property bool dragging: false
property real trackHeight: Math.max(4, Math.round(Style.spacing.controlHeight * 0.11))
property real knobSize: Math.max(14, Math.round(Style.spacing.controlHeight * 0.38))
property real liveValue: value
onValueChanged: if (!dragging) liveValue = value
signal moved(real value)
signal released(real value)
implicitWidth: Style.space(200)
implicitHeight: Math.max(Style.space(22), knobSize + Style.spacing.md)
readonly property real range: Math.max(0.0001, maximum - minimum)
readonly property real progress: Math.max(0, Math.min(1, (liveValue - minimum) / range))
readonly property bool _hot: mouseArea.containsMouse || root.dragging
Rectangle {
id: track
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
height: root.trackHeight
radius: height / 2
color: root.trackColor
}
Rectangle {
id: fill
anchors.verticalCenter: track.verticalCenter
anchors.left: track.left
height: track.height
radius: track.radius
color: root.fillColor
width: track.width * root.progress
Behavior on width {
enabled: !root.dragging
NumberAnimation { duration: 140; easing.type: Easing.OutCubic }
}
}
Rectangle {
id: knob
width: root.knobSize
height: root.knobSize
radius: root.knobSize / 2
color: root.knobColor
border.color: root.bar ? root.bar.background : "#101315"
border.width: Math.max(1, Style.space(2))
anchors.verticalCenter: track.verticalCenter
x: Math.max(0, Math.min(track.width - width, track.width * root.progress - width / 2))
scale: root._hot ? 1.15 : 1.0
Behavior on x {
enabled: !root.dragging
NumberAnimation { duration: 140; easing.type: Easing.OutCubic }
}
Behavior on scale {
NumberAnimation { duration: 110; easing.type: Easing.OutCubic }
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
function valueFromX(x) {
var clamped = Math.max(0, Math.min(track.width, x))
var raw = root.minimum + (clamped / track.width) * root.range
if (root.integer) raw = Math.round(raw)
return Math.max(root.minimum, Math.min(root.maximum, raw))
}
onPressed: function(mouse) {
root.dragging = true
var next = valueFromX(mouse.x)
root.liveValue = next
root.moved(next)
}
onPositionChanged: function(mouse) {
if (!root.dragging) return
var next = valueFromX(mouse.x)
root.liveValue = next
root.moved(next)
}
onReleased: function(mouse) {
root.dragging = false
root.released(root.liveValue)
root.liveValue = root.value
}
onWheel: function(wheel) {
var delta = wheel.angleDelta.y > 0 ? root.step : -root.step
var next = Math.max(root.minimum, Math.min(root.maximum, root.liveValue + delta))
if (root.integer) next = Math.round(next)
root.liveValue = next
root.moved(next)
root.released(next)
}
}
}