summary refs log tree commit diff
path: root/resources/qml/ScrollHelper.qml
blob: 2d315a6d4605cd65ace2d74f45a88e560ad4ff2d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net>
// Copyright (C) 2017 Christian Mollekopf, <mollekopf@kolabsystems.com>
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* Shamelessly stolen from:
* https://cgit.kde.org/kube.git/tree/framework/qml/ScrollHelper.qml
*
* The MouseArea + interactive: false + maximumFlickVelocity are required
* to fix scrolling for desktop systems where we don't want flicking behaviour.
*
* See also:
* ScrollView.qml in qtquickcontrols
* qquickwheelarea.cpp in qtquickcontrols
*/

import QtQuick 2.9
import QtQuick.Controls 2.3

MouseArea {
    // console.warn("Delta: ", wheel.pixelDelta.y);
    // console.warn("Old position: ", flickable.contentY);
    // console.warn("New position: ", newPos);

    id: root

    property Flickable flickable
    property alias enabled: root.enabled

    function calculateNewPosition(flickableItem, wheel) {
        //Nothing to scroll
        if (flickableItem.contentHeight < flickableItem.height)
            return flickableItem.contentY;

        //Ignore 0 events (happens at least with Christians trackpad)
        if (wheel.pixelDelta.y == 0 && wheel.angleDelta.y == 0)
            return flickableItem.contentY;

        //pixelDelta seems to be the same as angleDelta/8
        var pixelDelta = 0;
        //The pixelDelta is a smaller number if both are provided, so pixelDelta can be 0 while angleDelta is still something. So we check the angleDelta
        if (wheel.angleDelta.y) {
            var wheelScrollLines = 3; //Default value of QApplication wheelScrollLines property
            var pixelPerLine = 20; //Default value in Qt, originally comes from QTextEdit
            var ticks = (wheel.angleDelta.y / 8) / 15; //Divide by 8 gives us pixels typically come in 15pixel steps.
            pixelDelta = ticks * pixelPerLine * wheelScrollLines;
        } else {
            pixelDelta = wheel.pixelDelta.y;
        }
        pixelDelta = Math.round(pixelDelta);
        if (!pixelDelta)
            return flickableItem.contentY;

        var minYExtent = flickableItem.originY + flickableItem.topMargin;
        var maxYExtent = (flickableItem.contentHeight + flickableItem.bottomMargin + flickableItem.originY) - flickableItem.height;
        if (typeof (flickableItem.headerItem) !== "undefined" && flickableItem.headerItem)
            minYExtent += flickableItem.headerItem.height;

        //Avoid overscrolling
        return Math.max(minYExtent, Math.min(maxYExtent, flickableItem.contentY - pixelDelta));
    }

    propagateComposedEvents: true
    //Place the mouse area under the flickable
    z: -1
    onFlickableChanged: {
        if (enabled) {
            flickable.maximumFlickVelocity = 100000;
            flickable.boundsBehavior = Flickable.StopAtBounds;
            root.parent = flickable;
        }
    }
    acceptedButtons: Qt.NoButton
    onWheel: {
        var newPos = calculateNewPosition(flickable, wheel);
        // Show the scrollbars
        flickable.flick(0, 0);
        flickable.contentY = newPos;
        cancelFlickStateTimer.restart();
    }

    Timer {
        id: cancelFlickStateTimer

        //How long the scrollbar will remain visible
        interval: 500
        // Hide the scrollbars
        onTriggered: {
            flickable.cancelFlick();
            flickable.movementEnded();
        }
    }

}