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_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 | , smoothVelocity(fp), atEnd(false), atBeginning(true) |
66 | , transitionToSet(false) |
67 | , fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false) |
68 | , flickingWhenDragBegan(false), dragging(false), extentsChanged(false) |
69 | , explicitValue(false), contentPositionChangedExternallyDuringDrag(false) |
70 | , minExtentDirty(true), maxExtentDirty(true) |
71 | {} |
72 | |
73 | ~AxisData(); |
74 | |
75 | void reset() { |
76 | velocityBuffer.clear(); |
77 | dragStartOffset = 0; |
78 | fixingUp = false; |
79 | inOvershoot = false; |
80 | contentPositionChangedExternallyDuringDrag = false; |
81 | } |
82 | |
83 | void markExtentsDirty() { |
84 | minExtentDirty = true; |
85 | maxExtentDirty = true; |
86 | extentsChanged = true; |
87 | } |
88 | |
89 | void resetTransitionTo() { |
90 | transitionTo = 0; |
91 | transitionToSet = false; |
92 | } |
93 | |
94 | void addVelocitySample(qreal v, qreal maxVelocity); |
95 | void updateVelocity(); |
96 | |
97 | QQuickTimeLineValueProxy<QQuickFlickablePrivate> move; |
98 | QQuickFlickableReboundTransition *transitionToBounds = nullptr; |
99 | qreal viewSize = -1; |
100 | qreal pressPos = 0; |
101 | qreal lastPos = 0; |
102 | qreal dragStartOffset = 0; |
103 | qreal dragMinBound = 0; |
104 | qreal dragMaxBound = 0; |
105 | qreal previousDragDelta = 0; |
106 | qreal velocity = 0; |
107 | qreal flickTarget = 0; |
108 | qreal startMargin = 0; |
109 | qreal endMargin = 0; |
110 | qreal origin = 0; |
111 | qreal overshoot = 0; |
112 | qreal transitionTo = 0; |
113 | qreal continuousFlickVelocity = 0; |
114 | QElapsedTimer velocityTime; |
115 | int vTime = 0; |
116 | QQuickFlickablePrivate::Velocity smoothVelocity; |
117 | QPODVector<qreal,10> velocityBuffer; |
118 | // bitfield |
119 | uint atEnd : 1; |
120 | uint atBeginning : 1; |
121 | uint transitionToSet : 1; |
122 | uint fixingUp : 1; |
123 | uint inOvershoot : 1; |
124 | uint inRebound : 1; |
125 | uint moving : 1; |
126 | uint flicking : 1; |
127 | uint flickingWhenDragBegan : 1; |
128 | uint dragging : 1; |
129 | uint extentsChanged : 1; |
130 | uint explicitValue : 1; |
131 | uint contentPositionChangedExternallyDuringDrag : 1; |
132 | // mutable portion of bitfield |
133 | mutable uint minExtentDirty : 1; |
134 | mutable uint maxExtentDirty : 1; |
135 | // end bitfield |
136 | }; |
137 | |
138 | bool flickX(QEvent::Type eventType, qreal velocity); |
139 | bool flickY(QEvent::Type eventType, qreal velocity); |
140 | virtual bool flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, |
141 | QQuickTimeLineCallback::Callback fixupCallback, |
142 | QEvent::Type eventType, qreal velocity); |
143 | void flickingStarted(bool flickingH, bool flickingV); |
144 | |
145 | void fixupX(); |
146 | void fixupY(); |
147 | virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent); |
148 | void adjustContentPos(AxisData &data, qreal toPos); |
149 | void resetTimeline(AxisData &data); |
150 | void clearTimeline(); |
151 | |
152 | void updateBeginningEnd(); |
153 | |
154 | bool isInnermostPressDelay(QQuickItem *item) const; |
155 | void captureDelayedPress(QQuickItem *item, QPointerEvent *event); |
156 | void clearDelayedPress(); |
157 | void replayDelayedPress(); |
158 | |
159 | void setViewportX(qreal x); |
160 | void setViewportY(qreal y); |
161 | |
162 | qreal overShootDistance(qreal velocity) const; |
163 | |
164 | void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override; |
165 | |
166 | void draggingStarting(); |
167 | void draggingEnding(); |
168 | |
169 | bool isViewMoving() const; |
170 | |
171 | void cancelInteraction(); |
172 | |
173 | void addPointerHandler(QQuickPointerHandler *h) override; |
174 | |
175 | virtual bool wantsPointerEvent(const QPointerEvent *) { return true; } |
176 | |
177 | public: |
178 | QQuickItem *contentItem; |
179 | |
180 | AxisData hData; |
181 | AxisData vData; |
182 | |
183 | MovementReason moveReason = Other; |
184 | |
185 | QQuickTimeLine timeline; |
186 | bool hMoved : 1; |
187 | bool vMoved : 1; |
188 | bool stealMouse : 1; |
189 | bool pressed : 1; |
190 | bool scrollingPhase : 1; |
191 | bool interactive : 1; |
192 | bool calcVelocity : 1; |
193 | bool pixelAligned : 1; |
194 | bool syncDrag : 1; |
195 | QElapsedTimer timer; |
196 | qint64 lastPosTime; |
197 | qint64 lastPressTime; |
198 | QPointF lastPos; |
199 | QPointF pressPos; |
200 | QVector2D accumulatedWheelPixelDelta; |
201 | qreal deceleration; |
202 | qreal wheelDeceleration; |
203 | qreal maxVelocity; |
204 | QPointerEvent *delayedPressEvent; |
205 | QBasicTimer delayedPressTimer; |
206 | int pressDelay; |
207 | int fixupDuration; |
208 | qreal flickBoost; |
209 | qreal initialWheelFlickDistance; |
210 | |
211 | enum FixupMode { Normal, Immediate, ExtentChanged }; |
212 | FixupMode fixupMode; |
213 | |
214 | static void fixupY_callback(void *); |
215 | static void fixupX_callback(void *); |
216 | |
217 | void updateVelocity(); |
218 | int vTime; |
219 | QQuickTimeLine velocityTimeline; |
220 | QQuickFlickableVisibleArea *visibleArea; |
221 | QQuickFlickable::FlickableDirection flickableDirection; |
222 | QQuickFlickable::BoundsBehavior boundsBehavior; |
223 | QQuickFlickable::BoundsMovement boundsMovement; |
224 | QQuickTransition *rebound; |
225 | |
226 | void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, |
227 | QQuickTimeLineCallback::Callback fixupCallback); |
228 | |
229 | void handlePressEvent(QPointerEvent *); |
230 | void handleMoveEvent(QPointerEvent *); |
231 | void handleReleaseEvent(QPointerEvent *); |
232 | |
233 | void maybeBeginDrag(qint64 currentTimestamp, const QPointF &pressPosn, |
234 | Qt::MouseButtons buttons = Qt::NoButton); |
235 | void drag(qint64 currentTimestamp, QEvent::Type eventType, const QPointF &localPos, |
236 | const QVector2D &deltas, bool overThreshold, bool momentum, |
237 | bool velocitySensitiveOverBounds, const QVector2D &velocity); |
238 | |
239 | QVector2D firstPointLocalVelocity(QPointerEvent *event); |
240 | qint64 computeCurrentTime(QInputEvent *event) const; |
241 | qreal devicePixelRatio() const; |
242 | |
243 | // flickableData property |
244 | static void data_append(QQmlListProperty<QObject> *, QObject *); |
245 | static qsizetype data_count(QQmlListProperty<QObject> *); |
246 | static QObject *data_at(QQmlListProperty<QObject> *, qsizetype); |
247 | static void data_clear(QQmlListProperty<QObject> *); |
248 | }; |
249 | |
250 | class Q_QUICK_EXPORT QQuickFlickableVisibleArea : public QObject |
251 | { |
252 | Q_OBJECT |
253 | |
254 | Q_PROPERTY(qreal xPosition READ xPosition NOTIFY xPositionChanged FINAL) |
255 | Q_PROPERTY(qreal yPosition READ yPosition NOTIFY yPositionChanged FINAL) |
256 | Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY widthRatioChanged FINAL) |
257 | Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged FINAL) |
258 | QML_ANONYMOUS |
259 | QML_ADDED_IN_VERSION(2, 0) |
260 | |
261 | public: |
262 | QQuickFlickableVisibleArea(QQuickFlickable *parent=nullptr); |
263 | |
264 | qreal xPosition() const; |
265 | qreal widthRatio() const; |
266 | qreal yPosition() const; |
267 | qreal heightRatio() const; |
268 | |
269 | void updateVisible(); |
270 | |
271 | Q_SIGNALS: |
272 | void xPositionChanged(qreal xPosition); |
273 | void yPositionChanged(qreal yPosition); |
274 | void widthRatioChanged(qreal widthRatio); |
275 | void heightRatioChanged(qreal heightRatio); |
276 | |
277 | private: |
278 | QQuickFlickable *flickable; |
279 | qreal m_xPosition; |
280 | qreal m_widthRatio; |
281 | qreal m_yPosition; |
282 | qreal m_heightRatio; |
283 | }; |
284 | |
285 | QT_END_NAMESPACE |
286 | |
287 | #endif // QQUICKFLICKABLE_P_P_H |
288 | |