diff --git a/src/backend/user_files.py b/src/backend/user_files.py index 68f23fbf..20425f32 100644 --- a/src/backend/user_files.py +++ b/src/backend/user_files.py @@ -235,6 +235,7 @@ class UISettings(JSONDataFile): "clearRoomFilterOnEscape": True, "clearMemberFilterOnEscape": True, "collapseSidePanesUnderWindowWidth": 400, + "enableKineticScrolling": True, "hideProfileChangeEvents": True, "hideMembershipEvents": False, "hideUnknownEvents": False, diff --git a/src/gui/Base/HFlickable.qml b/src/gui/Base/HFlickable.qml index 92d024d7..83c07352 100644 --- a/src/gui/Base/HFlickable.qml +++ b/src/gui/Base/HFlickable.qml @@ -5,5 +5,7 @@ import QtQuick.Controls 2.12 Flickable { interactive: contentWidth > width || contentHeight > height - ScrollBar.vertical: ScrollBar {} + ScrollBar.vertical: ScrollBar { + visible: parent.interactive + } } diff --git a/src/gui/Base/HFlickableColumnPage.qml b/src/gui/Base/HFlickableColumnPage.qml index 8ce563ff..027281d7 100644 --- a/src/gui/Base/HFlickableColumnPage.qml +++ b/src/gui/Base/HFlickableColumnPage.qml @@ -26,4 +26,9 @@ HPage { height: flickable.height } } + + HKineticScrollingDisabler { + flickable: flickable + anchors.fill: flickable + } } diff --git a/src/gui/Base/HGridView.qml b/src/gui/Base/HGridView.qml index 2bb2f5ad..79bdc3d0 100644 --- a/src/gui/Base/HGridView.qml +++ b/src/gui/Base/HGridView.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 GridView { id: gridView - interactive: allowDragging currentIndex: -1 keyNavigationWraps: true highlightMoveDuration: theme.animationDuration @@ -23,7 +22,7 @@ GridView { } ScrollBar.vertical: ScrollBar { - visible: gridView.interactive || ! gridView.allowDragging + visible: gridView.interactive } // property bool debug: false @@ -59,7 +58,6 @@ GridView { onSelectedCountChanged: if (! selectedCount) lastCheckedDelegateIndex = 0 - property bool allowDragging: true property alias cursorShape: mouseArea.cursorShape property int currentItemHeight: currentItem ? currentItem.height : 0 @@ -119,22 +117,8 @@ GridView { } - Connections { - target: gridView - enabled: ! gridView.allowDragging - // interactive gets temporarily set to true below to allow wheel scroll - onDraggingChanged: gridView.interactive = false - } - - MouseArea { + HKineticScrollingDisabler { id: mouseArea anchors.fill: parent - enabled: ! parent.allowDragging || cursorShape !== Qt.ArrowCursor - acceptedButtons: Qt.NoButton - onWheel: { - // Allow wheel usage, will be back to false on any drag attempt - parent.interactive = true - wheel.accepted = false - } } } diff --git a/src/gui/Base/HKineticScrollingDisabler.qml b/src/gui/Base/HKineticScrollingDisabler.qml new file mode 100644 index 00000000..b0a49ea0 --- /dev/null +++ b/src/gui/Base/HKineticScrollingDisabler.qml @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.12 + +// MouseArea component to disable kinetic scrolling +MouseArea { + id: mouseArea + enabled: ! window.settings.enableKineticScrolling + propagateComposedEvents: true + acceptedButtons: Qt.NoButton + + + onWheel: { + // Make components below the stack notice the wheel event + wheel.accepted = false + + const pos = getNewPosition(flickable, wheel) + flickable.flick(0, 0) + flickable.contentY = pos + } + + + property Flickable flickable: parent + + // Used to get default flickDeceleration value + readonly property Flickable dummy: Flickable {} + + + function getNewPosition(flickable, wheel) { + // wheel.pixelDelta will be available on high resolution trackpads. + // Otherwise use wheel.angleDelta, which is available from mouses and + // low resolution trackpads. + // When higher pixelDelta, more scroll will be applied + const pixelDelta = + wheel.pixelDelta.y || + wheel.angleDelta.y / 8 * Qt.styleHints.wheelScrollLines + + // Return current position if there was not any movement + if (flickable.contentHeight < flickable.height || !pixelDelta) + return flickable.contentY + + const maxScroll = + flickable.contentHeight + + flickable.originY + + flickable.bottomMargin - + flickable.height + const minScroll = flickable.topMargin + flickable.originY + + // Avoid overscrolling + return Math.max( + minScroll, + Math.min(maxScroll, flickable.contentY - pixelDelta) + ) + } + + + Binding { + target: flickable + property: "maximumFlickVelocity" + value: mouseArea.enabled ? 0 : 4000.0 + } + + Binding { + target: flickable + property: "flickDeceleration" + value: mouseArea.enabled ? 0 : dummy.flickDeceleration + } +} diff --git a/src/gui/Base/HListView.qml b/src/gui/Base/HListView.qml index 4e938c6e..82391d64 100644 --- a/src/gui/Base/HListView.qml +++ b/src/gui/Base/HListView.qml @@ -5,7 +5,6 @@ import QtQuick.Controls 2.12 ListView { id: listView - interactive: allowDragging currentIndex: -1 keyNavigationWraps: true highlightMoveDuration: theme.animationDuration @@ -24,7 +23,7 @@ ListView { } ScrollBar.vertical: ScrollBar { - visible: listView.interactive || ! listView.allowDragging + visible: listView.interactive } // property bool debug: false @@ -60,7 +59,6 @@ ListView { onSelectedCountChanged: if (! selectedCount) lastCheckedDelegateIndex = 0 - property bool allowDragging: true property alias cursorShape: mouseArea.cursorShape property int currentItemHeight: currentItem ? currentItem.height : 0 @@ -120,22 +118,8 @@ ListView { } - Connections { - target: listView - enabled: ! listView.allowDragging - // interactive gets temporarily set to true below to allow wheel scroll - onDraggingChanged: listView.interactive = false - } - - MouseArea { + HKineticScrollingDisabler { id: mouseArea anchors.fill: parent - enabled: ! parent.allowDragging || cursorShape !== Qt.ArrowCursor - acceptedButtons: Qt.NoButton - onWheel: { - // Allow wheel usage, will be back to false on any drag attempt - parent.interactive = true - wheel.accepted = false - } } } diff --git a/src/gui/Utils.qml b/src/gui/Utils.qml index 3add6868..ad7b550d 100644 --- a/src/gui/Utils.qml +++ b/src/gui/Utils.qml @@ -325,7 +325,7 @@ QtObject { function flickPages(flickable, pages) { // Adapt velocity and deceleration for the number of pages to flick. // If this is a repeated flicking, flick faster than a single flick. - if (! flickable.interactive && flickable.allowDragging) return + if (! flickable.interactive) return const futureVelocity = -flickable.height * pages const currentVelocity = -flickable.verticalVelocity @@ -351,7 +351,7 @@ QtObject { function flickToTop(flickable) { - if (! flickable.interactive && flickable.allowDragging) return + if (! flickable.interactive) return if (flickable.visibleArea.yPosition < 0) return flickable.contentY -= flickable.contentHeight @@ -361,7 +361,7 @@ QtObject { function flickToBottom(flickable) { - if (! flickable.interactive && flickable.allowDragging) return + if (! flickable.interactive) return if (flickable.visibleArea.yPosition < 0) return flickable.contentY = flickable.contentHeight - flickable.height