1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QQUICKFLICKABLE_P_P_H |
41 | #define QQUICKFLICKABLE_P_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists purely as an |
48 | // implementation detail. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include "qquickflickable_p.h" |
55 | #include "qquickitem_p.h" |
56 | #include "qquickitemchangelistener_p.h" |
57 | |
58 | #include <QtQml/qqml.h> |
59 | #include <QtCore/qdatetime.h> |
60 | #include "qplatformdefs.h" |
61 | |
62 | #include <private/qquicktimeline_p_p.h> |
63 | #include <private/qquickanimation_p_p.h> |
64 | #include <private/qquicktransitionmanager_p_p.h> |
65 | #include <private/qpodvector_p.h> |
66 | |
67 | QT_BEGIN_NAMESPACE |
68 | |
69 | // Really slow flicks can be annoying. |
70 | const qreal MinimumFlickVelocity = 75.0; |
71 | |
72 | class QQuickFlickableVisibleArea; |
73 | class QQuickTransition; |
74 | class QQuickFlickableReboundTransition; |
75 | |
76 | class Q_QUICK_PRIVATE_EXPORT QQuickFlickablePrivate : public QQuickItemPrivate, public QQuickItemChangeListener |
77 | { |
78 | Q_DECLARE_PUBLIC(QQuickFlickable) |
79 | |
80 | public: |
81 | static inline QQuickFlickablePrivate *get(QQuickFlickable *o) { return o->d_func(); } |
82 | |
83 | QQuickFlickablePrivate(); |
84 | void init(); |
85 | |
86 | struct Velocity : public QQuickTimeLineValue |
87 | { |
88 | Velocity(QQuickFlickablePrivate *p) |
89 | : parent(p) {} |
90 | void setValue(qreal v) override { |
91 | if (v != value()) { |
92 | QQuickTimeLineValue::setValue(v); |
93 | parent->updateVelocity(); |
94 | } |
95 | } |
96 | QQuickFlickablePrivate *parent; |
97 | }; |
98 | |
99 | struct AxisData { |
100 | AxisData(QQuickFlickablePrivate *fp, void (QQuickFlickablePrivate::*func)(qreal)) |
101 | : move(fp, func) |
102 | , transitionToBounds(nullptr) |
103 | , viewSize(-1), lastPos(0), previousDragDelta(0), velocity(0), startMargin(0), endMargin(0) |
104 | , origin(0), overshoot(0) |
105 | , transitionTo(0) |
106 | , continuousFlickVelocity(0), velocityTime(), vTime(0) |
107 | , smoothVelocity(fp), atEnd(false), atBeginning(true) |
108 | , transitionToSet(false) |
109 | , fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false) |
110 | , dragging(false), extentsChanged(false) |
111 | , explicitValue(false), minExtentDirty(true), maxExtentDirty(true) |
112 | , unused(0) |
113 | {} |
114 | |
115 | ~AxisData(); |
116 | |
117 | void reset() { |
118 | velocityBuffer.clear(); |
119 | dragStartOffset = 0; |
120 | fixingUp = false; |
121 | inOvershoot = false; |
122 | } |
123 | |
124 | void markExtentsDirty() { |
125 | minExtentDirty = true; |
126 | maxExtentDirty = true; |
127 | extentsChanged = true; |
128 | } |
129 | |
130 | void resetTransitionTo() { |
131 | transitionTo = 0; |
132 | transitionToSet = false; |
133 | } |
134 | |
135 | void addVelocitySample(qreal v, qreal maxVelocity); |
136 | void updateVelocity(); |
137 | |
138 | QQuickTimeLineValueProxy<QQuickFlickablePrivate> move; |
139 | QQuickFlickableReboundTransition *transitionToBounds; |
140 | qreal viewSize; |
141 | qreal pressPos; |
142 | qreal lastPos; |
143 | qreal dragStartOffset; |
144 | qreal dragMinBound; |
145 | qreal dragMaxBound; |
146 | qreal previousDragDelta; |
147 | qreal velocity; |
148 | qreal flickTarget; |
149 | qreal startMargin; |
150 | qreal endMargin; |
151 | qreal origin; |
152 | qreal overshoot; |
153 | qreal transitionTo; |
154 | qreal continuousFlickVelocity; |
155 | QElapsedTimer velocityTime; |
156 | int vTime; |
157 | QQuickFlickablePrivate::Velocity smoothVelocity; |
158 | QPODVector<qreal,10> velocityBuffer; |
159 | bool atEnd : 1; |
160 | bool atBeginning : 1; |
161 | bool transitionToSet : 1; |
162 | bool fixingUp : 1; |
163 | bool inOvershoot : 1; |
164 | bool inRebound : 1; |
165 | bool moving : 1; |
166 | bool flicking : 1; |
167 | bool dragging : 1; |
168 | bool extentsChanged : 1; |
169 | bool explicitValue : 1; |
170 | mutable bool minExtentDirty : 1; |
171 | mutable bool maxExtentDirty : 1; |
172 | uint unused : 19; |
173 | }; |
174 | |
175 | bool flickX(qreal velocity); |
176 | bool flickY(qreal velocity); |
177 | virtual bool flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, |
178 | QQuickTimeLineCallback::Callback fixupCallback, qreal velocity); |
179 | void flickingStarted(bool flickingH, bool flickingV); |
180 | |
181 | void fixupX(); |
182 | void fixupY(); |
183 | virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent); |
184 | void adjustContentPos(AxisData &data, qreal toPos); |
185 | void resetTimeline(AxisData &data); |
186 | void clearTimeline(); |
187 | |
188 | void updateBeginningEnd(); |
189 | |
190 | bool isInnermostPressDelay(QQuickItem *item) const; |
191 | void captureDelayedPress(QQuickItem *item, QMouseEvent *event); |
192 | void clearDelayedPress(); |
193 | void replayDelayedPress(); |
194 | |
195 | void setViewportX(qreal x); |
196 | void setViewportY(qreal y); |
197 | |
198 | qreal overShootDistance(qreal size) const; |
199 | |
200 | void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override; |
201 | |
202 | void draggingStarting(); |
203 | void draggingEnding(); |
204 | |
205 | bool isViewMoving() const; |
206 | |
207 | void cancelInteraction(); |
208 | |
209 | void addPointerHandler(QQuickPointerHandler *h) override; |
210 | |
211 | // TODO Qt 6: QPointerEvent |
212 | virtual bool wantsPointerEvent(const QEvent *) { return true; } |
213 | |
214 | public: |
215 | QQuickItem *contentItem; |
216 | |
217 | AxisData hData; |
218 | AxisData vData; |
219 | |
220 | QQuickTimeLine timeline; |
221 | bool hMoved : 1; |
222 | bool vMoved : 1; |
223 | bool stealMouse : 1; |
224 | bool pressed : 1; |
225 | bool scrollingPhase : 1; |
226 | bool interactive : 1; |
227 | bool calcVelocity : 1; |
228 | bool pixelAligned : 1; |
229 | bool syncDrag : 1; |
230 | QElapsedTimer timer; |
231 | qint64 lastPosTime; |
232 | qint64 lastPressTime; |
233 | QPointF lastPos; |
234 | QPointF pressPos; |
235 | QVector2D accumulatedWheelPixelDelta; |
236 | qreal deceleration; |
237 | qreal maxVelocity; |
238 | qreal reportedVelocitySmoothing; |
239 | QMouseEvent *delayedPressEvent; |
240 | QBasicTimer delayedPressTimer; |
241 | int pressDelay; |
242 | int fixupDuration; |
243 | qreal flickBoost; |
244 | qreal initialWheelFlickDistance; |
245 | |
246 | enum FixupMode { Normal, Immediate, ExtentChanged }; |
247 | FixupMode fixupMode; |
248 | |
249 | static void fixupY_callback(void *); |
250 | static void fixupX_callback(void *); |
251 | |
252 | void updateVelocity(); |
253 | int vTime; |
254 | QQuickTimeLine velocityTimeline; |
255 | QQuickFlickableVisibleArea *visibleArea; |
256 | QQuickFlickable::FlickableDirection flickableDirection; |
257 | QQuickFlickable::BoundsBehavior boundsBehavior; |
258 | QQuickFlickable::BoundsMovement boundsMovement; |
259 | QQuickTransition *rebound; |
260 | |
261 | void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, |
262 | QQuickTimeLineCallback::Callback fixupCallback); |
263 | |
264 | void handleMousePressEvent(QMouseEvent *); |
265 | void handleMouseMoveEvent(QMouseEvent *); |
266 | void handleMouseReleaseEvent(QMouseEvent *); |
267 | |
268 | void maybeBeginDrag(qint64 currentTimestamp, const QPointF &pressPosn); |
269 | void drag(qint64 currentTimestamp, QEvent::Type eventType, const QPointF &localPos, |
270 | const QVector2D &deltas, bool overThreshold, bool momentum, |
271 | bool velocitySensitiveOverBounds, const QVector2D &velocity); |
272 | |
273 | qint64 computeCurrentTime(QInputEvent *event) const; |
274 | qreal devicePixelRatio() const; |
275 | |
276 | // flickableData property |
277 | static void data_append(QQmlListProperty<QObject> *, QObject *); |
278 | static int data_count(QQmlListProperty<QObject> *); |
279 | static QObject *data_at(QQmlListProperty<QObject> *, int); |
280 | static void data_clear(QQmlListProperty<QObject> *); |
281 | }; |
282 | |
283 | class QQuickFlickableVisibleArea : public QObject |
284 | { |
285 | Q_OBJECT |
286 | |
287 | Q_PROPERTY(qreal xPosition READ xPosition NOTIFY xPositionChanged) |
288 | Q_PROPERTY(qreal yPosition READ yPosition NOTIFY yPositionChanged) |
289 | Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY widthRatioChanged) |
290 | Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged) |
291 | QML_ANONYMOUS |
292 | |
293 | public: |
294 | QQuickFlickableVisibleArea(QQuickFlickable *parent=nullptr); |
295 | |
296 | qreal xPosition() const; |
297 | qreal widthRatio() const; |
298 | qreal yPosition() const; |
299 | qreal heightRatio() const; |
300 | |
301 | void updateVisible(); |
302 | |
303 | Q_SIGNALS: |
304 | void xPositionChanged(qreal xPosition); |
305 | void yPositionChanged(qreal yPosition); |
306 | void widthRatioChanged(qreal widthRatio); |
307 | void heightRatioChanged(qreal heightRatio); |
308 | |
309 | private: |
310 | QQuickFlickable *flickable; |
311 | qreal m_xPosition; |
312 | qreal m_widthRatio; |
313 | qreal m_yPosition; |
314 | qreal m_heightRatio; |
315 | }; |
316 | |
317 | QT_END_NAMESPACE |
318 | |
319 | QML_DECLARE_TYPE(QQuickFlickableVisibleArea) |
320 | |
321 | #endif // QQUICKFLICKABLE_P_P_H |
322 | |