| 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 |  |