diff --git a/.config/quickshell/ii/modules/common/widgets/StyledFlickable.qml b/.config/quickshell/ii/modules/common/widgets/StyledFlickable.qml index 715d09a62..c765a3fce 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledFlickable.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledFlickable.qml @@ -9,6 +9,8 @@ Flickable { property real touchpadScrollFactor: Config?.options.interactions.scrolling.touchpadScrollFactor ?? 100 property real mouseScrollFactor: Config?.options.interactions.scrolling.mouseScrollFactor ?? 50 property real mouseScrollDeltaThreshold: Config?.options.interactions.scrolling.mouseScrollDeltaThreshold ?? 120 + // Accumulated scroll destination so wheel deltas stack while animating + property real scrollTargetY: 0 MouseArea { visible: Config?.options.interactions.scrolling.fasterTouchpadScroll @@ -16,12 +18,17 @@ Flickable { acceptedButtons: Qt.NoButton onWheel: function(wheelEvent) { const delta = wheelEvent.angleDelta.y / root.mouseScrollDeltaThreshold; - // The angleDelta.y of a touchpad is usually small and continuous, + // The angleDelta.y of a touchpad is usually small and continuous, // while that of a mouse wheel is typically in multiples of ±120. var scrollFactor = Math.abs(wheelEvent.angleDelta.y) >= root.mouseScrollDeltaThreshold ? root.mouseScrollFactor : root.touchpadScrollFactor; - var targetY = root.contentY - delta * scrollFactor; - targetY = Math.max(0, Math.min(targetY, root.contentHeight - root.height)); + + const maxY = Math.max(0, root.contentHeight - root.height); + const base = scrollAnim.running ? root.scrollTargetY : root.contentY; + var targetY = Math.max(0, Math.min(base - delta * scrollFactor, maxY)); + + root.scrollTargetY = targetY; root.contentY = targetY; + wheelEvent.accepted = true; } } @@ -33,4 +40,11 @@ Flickable { easing.bezierCurve: Appearance.animation.scroll.bezierCurve } } + + // Keep target synced when not animating (e.g., drag/flick or programmatic changes) + onContentYChanged: { + if (!scrollAnim.running) { + root.scrollTargetY = root.contentY; + } + } } diff --git a/.config/quickshell/ii/modules/common/widgets/StyledListView.qml b/.config/quickshell/ii/modules/common/widgets/StyledListView.qml index 7783d6fc0..aebf35d77 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledListView.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledListView.qml @@ -14,6 +14,8 @@ ListView { property int dragIndex: -1 property real dragDistance: 0 property bool popin: true + // Accumulated scroll destination so wheel deltas stack while animating + property real scrollTargetY: 0 property real touchpadScrollFactor: Config?.options.interactions.scrolling.touchpadScrollFactor ?? 100 property real mouseScrollFactor: Config?.options.interactions.scrolling.mouseScrollFactor ?? 50 @@ -33,12 +35,17 @@ ListView { acceptedButtons: Qt.NoButton onWheel: function(wheelEvent) { const delta = wheelEvent.angleDelta.y / root.mouseScrollDeltaThreshold; - // The angleDelta.y of a touchpad is usually small and continuous, + // The angleDelta.y of a touchpad is usually small and continuous, // while that of a mouse wheel is typically in multiples of ±120. var scrollFactor = Math.abs(wheelEvent.angleDelta.y) >= root.mouseScrollDeltaThreshold ? root.mouseScrollFactor : root.touchpadScrollFactor; - var targetY = root.contentY - delta * scrollFactor; - targetY = Math.max(0, Math.min(targetY, root.contentHeight - root.height)); + + const maxY = Math.max(0, root.contentHeight - root.height); + const base = scrollAnim.running ? root.scrollTargetY : root.contentY; + var targetY = Math.max(0, Math.min(base - delta * scrollFactor, maxY)); + + root.scrollTargetY = targetY; root.contentY = targetY; + wheelEvent.accepted = true; } } @@ -51,6 +58,13 @@ ListView { } } + // Keep target synced when not animating (e.g., drag/flick or programmatic changes) + onContentYChanged: { + if (!scrollAnim.running) { + root.scrollTargetY = root.contentY; + } + } + add: Transition { animations: [ Appearance?.animation.elementMove.numberAnimation.createObject(this, {