Files

78 lines
2.3 KiB
QML

import QtQuick
import "../../DCommon/Common/WheelInput.js" as WheelInput
import "../../DCommon/Widgets/ScrollConstants.js" as Scroll
WheelHandler {
id: handler
property real travel: 0
property real drift: 0
property bool engaged: false
property real lastTime: 0
property var samples: []
readonly property Timer settle: Timer {
interval: NotificationMetrics.swipeWheelSettleMs
onTriggered: handler.finish()
}
signal began
signal moved(real travel)
signal ended(real velocity)
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
orientation: Qt.Horizontal
blocking: false
target: null
function velocity() {
if (samples.length < 2)
return 0;
const span = samples[samples.length - 1].time - samples[0].time;
if (span <= 0)
return 0;
const total = samples.reduce((sum, s) => sum + s.delta, 0);
return Math.max(-Scroll.maxMomentumVelocity, Math.min(Scroll.maxMomentumVelocity, total / span * 1000));
}
function finish() {
settle.stop();
const lifted = Date.now() - lastTime < Scroll.velocitySampleWindowMs;
const fling = lifted ? velocity() : 0;
travel = 0;
drift = 0;
samples = [];
if (!engaged)
return;
engaged = false;
ended(fling);
}
onWheel: event => {
if (!WheelInput.isTouchpad(event))
return;
const now = Date.now();
// Qt Wayland negates finger deltas; natural scrolling flips them back and reports inverted
const delta = (event.inverted ? event.pixelDelta.x : -event.pixelDelta.x) * Scroll.touchpadSpeed;
travel += delta;
drift += event.pixelDelta.y * Scroll.touchpadSpeed;
samples = samples.filter(s => now - s.time < Scroll.velocitySampleWindowMs).concat({
"delta": delta,
"time": now
});
lastTime = now;
settle.restart();
if (!engaged) {
if (Math.abs(travel) < NotificationMetrics.swipeWheelEngageDistance || Math.abs(travel) <= Math.abs(drift))
return;
engaged = true;
began();
}
moved(travel);
}
onActiveChanged: {
if (!active)
finish();
}
}