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