Krita Source Code Documentation
Loading...
Searching...
No Matches
KisKineticScroller.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2018 Emmet O 'Neill <emmetoneill.pdx@gmail.com>
3 * SPDX-FileCopyrightText: 2018 Eoin O 'Neill <eoinoneill1991@gmail.com>
4 * SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
10
11#include <QAbstractItemView>
12#include <QEvent>
13#include <QScrollBar>
14
15#include <ksharedconfig.h>
16#include <kconfiggroup.h>
17
18namespace {
25 class KisKineticScrollerEventFilter : public QObject
26 {
27 Q_OBJECT
28
29 QAbstractScrollArea *m_scrollArea;
30 QScroller::ScrollerGestureType m_gestureType;
31
32 public:
33 KisKineticScrollerEventFilter(QScroller::ScrollerGestureType gestureType, QAbstractScrollArea *parent)
34 : QObject(parent)
35 , m_scrollArea(parent)
36 , m_gestureType(gestureType)
37 {
38 }
39
40 protected:
41 bool eventFilter(QObject *watched, QEvent *event) override {
42 switch (event->type()) {
43 case QEvent::Enter:
44 QScroller::ungrabGesture(m_scrollArea);
45 break;
46 case QEvent::Leave:
47 QScroller::grabGesture(m_scrollArea, m_gestureType);
48 break;
49 default:
50 break;
51 }
52 return QObject::eventFilter(watched, event);
53 }
54 };
55} /* namespace */
56
57QScroller* KisKineticScroller::createPreconfiguredScroller(QAbstractScrollArea *scrollArea) {
58 KConfigGroup config = KSharedConfig::openConfig()->group("");
59 int sensitivity = config.readEntry("KineticScrollingSensitivity", 75);
60 bool enabled = config.readEntry("KineticScrollingEnabled", true);
61 bool hideScrollBars = config.readEntry("KineticScrollingHideScrollbar", false);
62 float resistanceCoefficient = config.readEntry("KineticScrollingResistanceCoefficient", 10.0f);
63 float dragVelocitySmoothFactor = config.readEntry("KineticScrollingDragVelocitySmoothingFactor", 1.0f);
64 float minimumVelocity = config.readEntry("KineticScrollingMinimumVelocity", 0.0f);
65 float axisLockThresh = config.readEntry("KineticScrollingAxisLockThreshold", 1.0f);
66 float maximumClickThroughVelocity = config.readEntry("KineticScrollingMaxClickThroughVelocity", 0.0f);
67 float flickAccelerationFactor = config.readEntry("KineticScrollingFlickAccelerationFactor", 1.5f);
68 float overshootDragResistanceFactor = config.readEntry("KineticScrollingOvershotDragResistanceFactor", 0.1f);
69 float overshootDragDistanceFactor = config.readEntry("KineticScrollingOvershootDragDistanceFactor", 0.3f);
70 float overshootScrollDistanceFactor = config.readEntry("KineticScrollingOvershootScrollDistanceFactor", 0.1f);
71 float overshootScrollTime = config.readEntry("KineticScrollingOvershootScrollTime", 0.4f);
72 QScroller::ScrollerGestureType gestureType = getConfiguredGestureType();
73
74 if (enabled && scrollArea) {
75 if (hideScrollBars) {
76 scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
77 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
78 } else if (gestureType != QScroller::TouchGesture) {
79 auto *filter = new KisKineticScrollerEventFilter(gestureType, scrollArea);
80 scrollArea->horizontalScrollBar()->installEventFilter(filter);
81 scrollArea->verticalScrollBar()->installEventFilter(filter);
82 }
83
84 QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(scrollArea);
85 if (itemView) {
86 itemView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
87 }
88
89 QScroller *scroller = QScroller::scroller(scrollArea);
90 QScroller::grabGesture(scrollArea, gestureType);
91
92 QScrollerProperties properties;
93
94 // DragStartDistance seems to be based on meter per second; though it's
95 // not explicitly documented, other QScroller values are in that metric.
96 // To start kinetic scrolling, with minimal sensitivity, we expect a drag
97 // of 10 mm, with minimum sensitivity any > 0 mm.
98 const float mm = 0.001f;
99 const float resistance = 1.0f - (sensitivity / 100.0f);
100 const float mousePressEventDelay = config.readEntry("KineticScrollingMousePressDelay", 1.0f - 0.75f * resistance);
101
102 properties.setScrollMetric(QScrollerProperties::DragStartDistance, resistance * resistanceCoefficient * mm);
103 properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor, dragVelocitySmoothFactor);
104 properties.setScrollMetric(QScrollerProperties::MinimumVelocity, minimumVelocity);
105 properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, axisLockThresh);
106 properties.setScrollMetric(QScrollerProperties::MaximumClickThroughVelocity, maximumClickThroughVelocity);
107 properties.setScrollMetric(QScrollerProperties::MousePressEventDelay, mousePressEventDelay);
108 properties.setScrollMetric(QScrollerProperties::AcceleratingFlickSpeedupFactor, flickAccelerationFactor);
109
110 properties.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOn);
111 properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, overshootDragResistanceFactor);
112 properties.setScrollMetric(QScrollerProperties::OvershootDragDistanceFactor, overshootDragDistanceFactor);
113 properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, overshootScrollDistanceFactor);
114 properties.setScrollMetric(QScrollerProperties::OvershootScrollTime, overshootScrollTime);
115
116 scroller->setScrollerProperties(properties);
117
118 return scroller;
119 }
120
121 return nullptr;
122}
123
124QScroller::ScrollerGestureType KisKineticScroller::getConfiguredGestureType() {
125 KConfigGroup config = KSharedConfig::openConfig()->group("");
126#ifdef Q_OS_ANDROID
127 // Use a different default. Shouldn't we use KisConfig::kineticScrollingGesture?
128 int gesture = config.readEntry("KineticScrollingGesture", 1);
129#else
130 int gesture = config.readEntry("KineticScrollingGesture", 0);
131#endif
132
133 switch (gesture) {
134 case 0: {
135 return QScroller::TouchGesture;
136 }
137 case 1: {
138 return QScroller::LeftMouseButtonGesture;
139 }
140 case 2: {
141 return QScroller::MiddleMouseButtonGesture;
142 }
143 case 3: {
144 return QScroller::RightMouseButtonGesture;
145 }
146 default:
147 return QScroller::MiddleMouseButtonGesture;
148 }
149}
150
151void KisKineticScroller::updateCursor(QWidget *source, QScroller::State state) {
152 if( state == QScroller::State::Pressed ) {
153 source->setCursor(Qt::OpenHandCursor);
154 } else if (state == QScroller::State::Dragging) {
155 source->setCursor(Qt::ClosedHandCursor);
156 } else {
157 source->setCursor(Qt::ArrowCursor);
158 }
159}
160
161#include "KisKineticScroller.moc"
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
KRITAWIDGETUTILS_EXPORT QScroller::ScrollerGestureType getConfiguredGestureType()
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)