fix(volume): kill the slider rubberband on release

The live-drag thumb reverted to the round-tripped bound value on release; because that value echoes back asynchronously the thumb snapped to the stale position then to the fresh one (a rubberband bounce). The thumb now tracks drag-fraction, which stays put on release and re-syncs to the external value only when it changes on its own (MPRIS / keyboard) while not dragging.

cc
This commit is contained in:
vicrodh committed 2026-07-13 00:19:51 -06:00
1 parent a0cca35810
commit 256b0d36a0
2 files changed
+27 -11

No files matched your search

+14 -6
View File
@@ -28,11 +28,19 @@ export component QbzSlider inherits Rectangle {
// Travel range for the thumb centre.
property <length> travel: root.width - root.thumb-size;
// Live drag: while held, the thumb tracks the POINTER (continuous, no round-
// trip through the bound value) so it never visibly steps between levels.
// Live drag: the thumb tracks `drag-fraction`, which follows the POINTER
// while held and STAYS PUT on release — it never snaps back to the async
// round-tripped bound value (that snap-back was the rubberband). It re-syncs
// to the external value only when the value changes on its own (MPRIS /
// keyboard) while not dragging.
property <bool> dragging: false;
property <float> live-fraction: 0.0;
property <float> shown-fraction: root.dragging ? root.live-fraction : root.fraction;
property <float> drag-fraction: root.fraction;
property <float> shown-fraction: root.drag-fraction;
changed fraction => {
if (!root.dragging) {
root.drag-fraction = root.fraction;
}
}
// Track. HC-only outline so the rail stays visible when accent flattens.
Rectangle {
@@ -82,7 +90,7 @@ export component QbzSlider inherits Rectangle {
pointer-event(e) => {
if (e.kind == PointerEventKind.down) {
root.dragging = true;
root.live-fraction = root.fraction-from-x(self.mouse-x);
root.drag-fraction = root.fraction-from-x(self.mouse-x);
if (root.value-from-x(self.mouse-x) != root.value) {
root.changed(root.value-from-x(self.mouse-x));
}
@@ -95,7 +103,7 @@ export component QbzSlider inherits Rectangle {
// Continuous drag while held — thumb follows the pointer every frame.
moved => {
if (root.dragging) {
root.live-fraction = root.fraction-from-x(self.mouse-x);
root.drag-fraction = root.fraction-from-x(self.mouse-x);
if (root.value-from-x(self.mouse-x) != root.value) {
root.changed(root.value-from-x(self.mouse-x));
}
@@ -25,10 +25,18 @@ export component QbzVerticalSlider inherits Rectangle {
// Travel range for the thumb centre (top..bottom of the column).
property <length> travel: root.height - root.thumb-size;
// Live drag: while held, the thumb tracks the POINTER directly.
// Live drag: the thumb tracks `drag-fraction`, which follows the POINTER
// while held and STAYS PUT on release (no snap-back to the async round-
// tripped value = the rubberband); it re-syncs to the external value only
// when that value changes on its own while not dragging.
property <bool> dragging: false;
property <float> live-fraction: 0.0;
property <float> shown-fraction: root.dragging ? root.live-fraction : root.fraction;
property <float> drag-fraction: root.fraction;
property <float> shown-fraction: root.drag-fraction;
changed fraction => {
if (!root.dragging) {
root.drag-fraction = root.fraction;
}
}
// Track (the full vertical rail). HC-only outline keeps the rail visible
// when accent flattens.
@@ -81,7 +89,7 @@ export component QbzVerticalSlider inherits Rectangle {
pointer-event(e) => {
if (e.kind == PointerEventKind.down) {
root.dragging = true;
root.live-fraction = root.fraction-from-y(self.mouse-y);
root.drag-fraction = root.fraction-from-y(self.mouse-y);
if (root.value-from-y(self.mouse-y) != root.value) {
root.changed(root.value-from-y(self.mouse-y));
}
@@ -93,7 +101,7 @@ export component QbzVerticalSlider inherits Rectangle {
// Continuous drag while held — thumb follows the pointer every frame.
moved => {
if (root.dragging) {
root.live-fraction = root.fraction-from-y(self.mouse-y);
root.drag-fraction = root.fraction-from-y(self.mouse-y);
if (root.value-from-y(self.mouse-y) != root.value) {
root.changed(root.value-from-y(self.mouse-y));
}