From ad6f11179398cccccc9fbfc62a68d75264bd9774 Mon Sep 17 00:00:00 2001 From: miruka Date: Tue, 10 Dec 2019 11:49:46 -0400 Subject: [PATCH] Fix & improve keyboard and mousewheel flicking --- TODO.md | 3 +-- src/qml/Base/HListView.qml | 37 +++++++++++++++++++++++------ src/qml/Chat/Timeline/EventList.qml | 17 +------------ src/qml/Shortcuts.qml | 15 ++++-------- src/qml/utils.js | 34 +++++++++++++++++++------- 5 files changed, 61 insertions(+), 45 deletions(-) diff --git a/TODO.md b/TODO.md index 2106d617..b3d87bff 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,4 @@ -- make pageup/down not slippery again - better cancel for all boxes -- get rid of all currentSpacing stuff - Media - Handle set avatar upload errors @@ -24,6 +22,7 @@ - Refactoring - Use a singleton for utils.js - Use HBox for Profile + - Get rid of all `currentSpacing` stuff - Banners - Composer - Try gel for the models and stop being lazy in python diff --git a/src/qml/Base/HListView.qml b/src/qml/Base/HListView.qml index b2b02146..cba9dab0 100644 --- a/src/qml/Base/HListView.qml +++ b/src/qml/Base/HListView.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 2.12 ListView { id: listView - interactive: enableFlicking + interactive: allowDragging currentIndex: -1 keyNavigationWraps: true highlightMoveDuration: theme.animationDuration @@ -15,18 +15,13 @@ ListView { maximumFlickVelocity: 4000 - property bool enableFlicking: true - - readonly property int currentItemHeight: - currentItem ? currentItem.height : 0 - highlight: Rectangle { color: theme.controls.listView.highlight } ScrollBar.vertical: ScrollBar { - visible: listView.interactive || ! listView.enableFlicking + visible: listView.interactive || ! listView.allowDragging } add: Transition { @@ -52,4 +47,32 @@ ListView { } displaced: move + + + property bool allowDragging: true + + property alias cursorShape: mouseArea.cursorShape + + readonly property int currentItemHeight: + currentItem ? currentItem.height : 0 + + + Connections { + target: listView + enabled: ! listView.allowDragging + // interactive gets temporarily set to true below to allow wheel scroll + onDraggingChanged: listView.interactive = false + } + + MouseArea { + 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/qml/Chat/Timeline/EventList.qml b/src/qml/Chat/Timeline/EventList.qml index a8d90543..6a7686ee 100644 --- a/src/qml/Chat/Timeline/EventList.qml +++ b/src/qml/Chat/Timeline/EventList.qml @@ -61,7 +61,7 @@ Rectangle { HListView { id: eventList clip: true - enableFlicking: false + allowDragging: false anchors.fill: parent anchors.leftMargin: theme.spacing @@ -92,8 +92,6 @@ Rectangle { property bool ownEventsOnRight: width < theme.chat.eventList.ownEventsOnRightUnderWidth - property alias cursorShape: mouseArea.cursorShape - function canCombine(item, itemAfter) { if (! item || ! itemAfter) return false @@ -160,19 +158,6 @@ Rectangle { } delegate: EventDelegate {} - - MouseArea { - id: mouseArea - anchors.fill: parent - acceptedButtons: Qt.NoButton - - onWheel: Utils.smartVerticalFlick( - eventList, - 200 * Qt.styleHints.wheelScrollLines * - (wheel.angleDelta.y < 0 ? 1 : -1), - 2, - ) - } } } diff --git a/src/qml/Shortcuts.qml b/src/qml/Shortcuts.qml index 20ee1a74..133e473d 100644 --- a/src/qml/Shortcuts.qml +++ b/src/qml/Shortcuts.qml @@ -72,32 +72,25 @@ Item { HShortcut { enabled: toFlick sequences: settings.keys.scrollUp - onActivated: Utils.smartVerticalFlick(toFlick, -335) + onActivated: Utils.flickPages(toFlick, -1 / 10) } HShortcut { enabled: toFlick sequences: settings.keys.scrollDown - onActivated: Utils.smartVerticalFlick(toFlick, 335) + onActivated: Utils.flickPages(toFlick, 1 / 10) } HShortcut { enabled: toFlick sequences: settings.keys.scrollPageUp - onActivated: Utils.smartVerticalFlick( - toFlick, -2.3 * toFlick.height, 8, - ) - // Ensure only a slight slip after releasing the key - // onReleased: Utils.smartVerticalFlick(toFlick, -335) + onActivated: Utils.flickPages(toFlick, -1) } HShortcut { enabled: toFlick sequences: settings.keys.scrollPageDown - onActivated: Utils.smartVerticalFlick( - toFlick, 2.3 * toFlick.height, 8, - ) - // onReleased: Utils.smartVerticalFlick(toFlick, 335) + onActivated: Utils.flickPages(toFlick, 1) } HShortcut { diff --git a/src/qml/utils.js b/src/qml/utils.js index 73c544c5..7bfefea7 100644 --- a/src/qml/utils.js +++ b/src/qml/utils.js @@ -229,20 +229,36 @@ function getItem(array, mainKey, value) { } -function smartVerticalFlick(flickable, baseVelocity, fastMultiply=4) { - if (! flickable.interactive && flickable.enableFlicking) return +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 - baseVelocity = -baseVelocity - let vel = -flickable.verticalVelocity - let fast = (baseVelocity < 0 && vel < baseVelocity / 2) || - (baseVelocity > 0 && vel > baseVelocity / 2) + const futureVelocity = -flickable.height * pages + const currentVelocity = -flickable.verticalVelocity + const goFaster = + (futureVelocity < 0 && currentVelocity < futureVelocity / 2) || + (futureVelocity > 0 && currentVelocity > futureVelocity / 2) - flickable.flick(0, baseVelocity * (fast ? fastMultiply : 1)) + const normalDecel = flickable.flickDeceleration + const fastMultiply = pages && 8 / (1 - Math.log10(Math.abs(pages))) + const magicNumber = 2.5 + + flickable.flickDeceleration = Math.max( + goFaster ? normalDecel : -Infinity, + Math.abs(normalDecel * magicNumber * pages), + ) + + flickable.flick( + 0, futureVelocity * magicNumber * (goFaster ? fastMultiply : 1), + ) + + flickable.flickDeceleration = normalDecel } function flickToTop(flickable) { - if (! flickable.interactive && flickable.enableFlicking) return + if (! flickable.interactive && flickable.allowDragging) return if (flickable.visibleArea.yPosition < 0) return flickable.contentY -= flickable.contentHeight @@ -252,7 +268,7 @@ function flickToTop(flickable) { function flickToBottom(flickable) { - if (! flickable.interactive && flickable.enableFlicking) return + if (! flickable.interactive && flickable.allowDragging) return if (flickable.visibleArea.yPosition < 0) return flickable.contentY = flickTarget.contentHeight - flickTarget.height