feat(view): implement smooth wheel scrolling for NListView with global setting

This commit is contained in:
tibssy
2026-03-26 00:23:29 +00:00
parent df62bb3212
commit 3798118461
6 changed files with 75 additions and 3 deletions
+2
View File
@@ -1217,6 +1217,8 @@
"profile-tooltip": "Profile picture",
"reverse-scrolling-description": "Reverse the interpreted scroll direction",
"reverse-scrolling-label": "Reverse scrolling",
"smooth-scrolling-description": "Animate list scrolling for a smoother wheel experience.",
"smooth-scrolling-label": "Smooth scrolling",
"screen-corners-desc": "Customize screen corner rounding and visual effects.",
"screen-corners-radius-description": "Adjust the rounded corners of the screen.",
"screen-corners-radius-label": "Screen corners radius",
+2 -1
View File
@@ -141,7 +141,8 @@
"Del"
]
},
"reverseScroll": false
"reverseScroll": false,
"smoothScrollEnabled": true
},
"ui": {
"fontDefault": "",
+8
View File
@@ -1279,6 +1279,14 @@
"tabLabel": "common.general",
"subTab": null
},
{
"labelKey": "panels.general.smooth-scrolling-label",
"descriptionKey": "panels.general.smooth-scrolling-description",
"widget": "NToggle",
"tab": 0,
"tabLabel": "common.general",
"subTab": null
},
{
"labelKey": "panels.general.keybinds-title",
"descriptionKey": "panels.general.keybinds-description",
+1
View File
@@ -319,6 +319,7 @@ Singleton {
property list<string> keyRemove: ["Del"]
}
property bool reverseScroll: false
property bool smoothScrollEnabled: true
}
// ui
@@ -150,6 +150,15 @@ ColumnLayout {
onToggled: checked => Settings.data.general.reverseScroll = checked
}
NToggle {
Layout.fillWidth: true
label: I18n.tr("panels.general.smooth-scrolling-label")
description: I18n.tr("panels.general.smooth-scrolling-description")
checked: Settings.data.general.smoothScrollEnabled
defaultValue: Settings.getDefaultValue("general.smoothScrollEnabled")
onToggled: checked => Settings.data.general.smoothScrollEnabled = checked
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginM
+53 -2
View File
@@ -73,6 +73,32 @@ Item {
// Scroll speed multiplier for mouse wheel (1.0 = default, higher = faster)
property real wheelScrollMultiplier: 2.0
property int smoothWheelAnimationDuration: Style.animationNormal
property real _wheelTargetY: 0
function clampScrollY(value) {
return Math.max(0, Math.min(value, listView.contentHeight - listView.height));
}
function applyWheelScroll(delta) {
if (!root.contentOverflows)
return;
const step = delta * root.wheelScrollMultiplier;
if (!Settings.data.general.smoothScrollEnabled || Settings.data.general.animationDisabled) {
listView.contentY = root.clampScrollY(listView.contentY - step);
root._wheelTargetY = listView.contentY;
return;
}
if (!wheelScrollAnimation.running)
root._wheelTargetY = listView.contentY;
root._wheelTargetY = root.clampScrollY(root._wheelTargetY - step);
wheelScrollAnimation.to = root._wheelTargetY;
wheelScrollAnimation.restart();
}
// Forward ListView methods
function positionViewAtIndex(index, mode) {
@@ -124,6 +150,7 @@ Item {
implicitHeight: 200
Component.onCompleted: {
_wheelTargetY = listView.contentY;
createGradients();
}
@@ -191,6 +218,31 @@ Item {
clip: true
boundsBehavior: Flickable.StopAtBounds
NumberAnimation {
id: wheelScrollAnimation
target: listView
property: "contentY"
duration: root.smoothWheelAnimationDuration
easing.type: Easing.OutCubic
}
onDraggingChanged: {
if (dragging) {
wheelScrollAnimation.stop();
root._wheelTargetY = contentY;
}
}
onFlickingChanged: {
if (flicking) {
wheelScrollAnimation.stop();
root._wheelTargetY = contentY;
}
}
onContentHeightChanged: root._wheelTargetY = root.clampScrollY(root._wheelTargetY)
onHeightChanged: root._wheelTargetY = root.clampScrollY(root._wheelTargetY)
WheelHandler {
enabled: !root.contentOverflows
@@ -205,8 +257,7 @@ Item {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => {
const delta = event.pixelDelta.y !== 0 ? event.pixelDelta.y : event.angleDelta.y / 2;
const newY = listView.contentY - (delta * root.wheelScrollMultiplier);
listView.contentY = Math.max(0, Math.min(newY, listView.contentHeight - listView.height));
root.applyWheelScroll(delta);
event.accepted = true;
}
}