add volume and brightness control
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
// A themed 0-1 slider. Reports intent through `moved` rather than driving
|
||||
// `value` itself, the same way ToggleSwitch does, so the caller can keep it
|
||||
// bound to the real state — the volume pipewire ended up at, the brightness the
|
||||
// backlight accepted — and let the slider follow.
|
||||
//
|
||||
// While a drag is in flight the knob tracks the pointer instead, so a backend
|
||||
// that answers a moment late cannot make it stutter under the finger.
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real value: 0
|
||||
// One wheel notch, one arrow key.
|
||||
property real stepSize: 0.05
|
||||
property color fillColor: Theme.accent
|
||||
|
||||
signal moved(real value)
|
||||
|
||||
// Where the drag has got to, used in place of `value` until it ends.
|
||||
property real dragValue: 0
|
||||
|
||||
readonly property real position: mouse.pressed ? root.dragValue : Math.max(0, Math.min(1, root.value))
|
||||
|
||||
// The hit area is a good deal taller than the groove: this panel gets used
|
||||
// with a finger as often as a pointer.
|
||||
implicitWidth: 120
|
||||
implicitHeight: Theme.sliderKnob + Theme.padding * 2
|
||||
|
||||
readonly property real travel: root.width - Theme.sliderKnob
|
||||
|
||||
function setFromX(x: real): void {
|
||||
const position = root.travel > 0 ? (x - Theme.sliderKnob / 2) / root.travel : 0;
|
||||
const value = Math.max(0, Math.min(1, position));
|
||||
|
||||
root.dragValue = value;
|
||||
root.moved(value);
|
||||
}
|
||||
|
||||
function step(delta: real): void {
|
||||
root.moved(Math.max(0, Math.min(1, root.position + delta)));
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: groove
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
height: Theme.sliderTrack
|
||||
radius: height / 2
|
||||
color: Theme.background
|
||||
border.width: Theme.borderWidth
|
||||
border.color: Theme.border
|
||||
|
||||
Rectangle {
|
||||
// Stops under the middle of the knob, so the fill and the knob move
|
||||
// as one piece rather than the fill running out ahead of it.
|
||||
width: Math.min(groove.width, Theme.sliderKnob / 2 + root.travel * root.position)
|
||||
height: groove.height
|
||||
radius: groove.radius
|
||||
color: root.enabled ? root.fillColor : Theme.textDim
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: knob
|
||||
|
||||
x: root.travel * root.position
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Theme.sliderKnob
|
||||
height: width
|
||||
radius: width / 2
|
||||
color: root.enabled ? Theme.text : Theme.textDim
|
||||
border.width: Theme.borderWidth
|
||||
border.color: Theme.background
|
||||
scale: mouse.pressed ? 1.15 : 1
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.animDuration
|
||||
easing.type: Theme.animEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: true
|
||||
|
||||
// A press anywhere on the groove jumps there: on a touchscreen there is
|
||||
// no way to grab the knob first.
|
||||
onPressed: event => root.setFromX(event.x)
|
||||
onPositionChanged: event => {
|
||||
if (mouse.pressed)
|
||||
root.setFromX(event.x);
|
||||
}
|
||||
|
||||
onWheel: event => {
|
||||
const notches = event.angleDelta.y / 120;
|
||||
if (notches !== 0)
|
||||
root.step(notches * root.stepSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user