QtBase  v6.3.1
qscroller.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets 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 #include "qevent.h"
41 #include "qwidget.h"
42 #include "qscroller.h"
43 #include "private/qflickgesture_p.h"
44 #include "private/qscroller_p.h"
45 #include "qscrollerproperties.h"
46 #include "private/qscrollerproperties_p.h"
47 #include "qnumeric.h"
48 #include "math.h"
49 
50 #include <QTime>
51 #include <QElapsedTimer>
52 #include <QMap>
53 #include <QApplication>
54 #include <QAbstractScrollArea>
55 #if QT_CONFIG(graphicsview)
56 #include <QGraphicsObject>
57 #include <QGraphicsScene>
58 #include <QGraphicsView>
59 #endif
60 #include <QVector2D>
61 #include <QtCore/qmath.h>
62 #include <QtGui/qevent.h>
63 #include <qnumeric.h>
64 
65 #include <QtDebug>
66 
67 
68 
70 
72 
73 //#define QSCROLLER_DEBUG
74 
75 #ifdef QSCROLLER_DEBUG
76 # define qScrollerDebug qDebug
77 #else
78 # define qScrollerDebug while (false) qDebug
79 #endif
80 
82 {
83  dbg << "\n Time: start:" << s.startTime << " duration:" << s.deltaTime << " stop progress:" << s.stopProgress;
84  dbg << "\n Pos: start:" << s.startPos << " delta:" << s.deltaPos << " stop:" << s.stopPos;
85  dbg << "\n Curve: type:" << s.curve.type() << "\n";
86  return dbg;
87 }
88 
89 
90 // a few helper operators to make the code below a lot more readable:
91 // otherwise a lot of ifs would have to be multi-line to check both the x
92 // and y coordinate separately.
93 
94 // returns true only if the abs. value of BOTH x and y are <= f
95 inline bool operator<=(const QPointF &p, qreal f)
96 {
97  return (qAbs(p.x()) <= f) && (qAbs(p.y()) <= f);
98 }
99 
100 // returns true only if the abs. value of BOTH x and y are < f
101 inline bool operator<(const QPointF &p, qreal f)
102 {
103  return (qAbs(p.x()) < f) && (qAbs(p.y()) < f);
104 }
105 
106 // returns true if the abs. value of EITHER x or y are >= f
107 inline bool operator>=(const QPointF &p, qreal f)
108 {
109  return (qAbs(p.x()) >= f) || (qAbs(p.y()) >= f);
110 }
111 
112 // returns true if the abs. value of EITHER x or y are > f
113 inline bool operator>(const QPointF &p, qreal f)
114 {
115  return (qAbs(p.x()) > f) || (qAbs(p.y()) > f);
116 }
117 
118 // returns a new point with both coordinates having the abs. value of the original one
119 inline QPointF qAbs(const QPointF &p)
120 {
121  return QPointF(qAbs(p.x()), qAbs(p.y()));
122 }
123 
124 // returns a new point with all components of p1 multiplied by the corresponding components of p2
125 inline QPointF operator*(const QPointF &p1, const QPointF &p2)
126 {
127  return QPointF(p1.x() * p2.x(), p1.y() * p2.y());
128 }
129 
130 // returns a new point with all components of p1 divided by the corresponding components of p2
131 inline QPointF operator/(const QPointF &p1, const QPointF &p2)
132 {
133  return QPointF(p1.x() / p2.x(), p1.y() / p2.y());
134 }
135 
136 inline QPointF clampToRect(const QPointF &p, const QRectF &rect)
137 {
138  qreal x = qBound(rect.left(), p.x(), rect.right());
139  qreal y = qBound(rect.top(), p.y(), rect.bottom());
140  return QPointF(x, y);
141 }
142 
143 // returns -1, 0 or +1 according to r being <0, ==0 or >0
144 inline int qSign(qreal r)
145 {
146  return (r < 0) ? -1 : ((r > 0) ? 1 : 0);
147 }
148 
149 // this version is not mathematically exact, but it just works for every
150 // easing curve type (even custom ones)
151 
152 static qreal differentialForProgress(const QEasingCurve &curve, qreal pos)
153 {
154  const qreal dx = 0.01;
155  qreal left = (pos < qreal(0.5)) ? pos : pos - qreal(dx);
156  qreal right = (pos >= qreal(0.5)) ? pos : pos + qreal(dx);
157  qreal d = (curve.valueForProgress(right) - curve.valueForProgress(left)) / qreal(dx);
158 
159  //qScrollerDebug() << "differentialForProgress(type: " << curve.type() << ", pos: " << pos << ") = " << d;
160 
161  return d;
162 }
163 
164 // this version is not mathematically exact, but it just works for every
165 // easing curve type (even custom ones)
166 
167 static qreal progressForValue(const QEasingCurve &curve, qreal value)
168 {
169  if (Q_UNLIKELY(curve.type() >= QEasingCurve::InElastic &&
170  curve.type() < QEasingCurve::Custom)) {
171  qWarning("progressForValue(): QEasingCurves of type %d do not have an inverse, since they are not injective.", curve.type());
172  return value;
173  }
174  if (value < qreal(0) || value > qreal(1))
175  return value;
176 
177  qreal progress = value, left(0), right(1);
178  for (int iterations = 6; iterations; --iterations) {
179  qreal v = curve.valueForProgress(progress);
180  if (v < value)
181  left = progress;
182  else if (v > value)
183  right = progress;
184  else
185  break;
186  progress = (left + right) / qreal(2);
187  }
188  return progress;
189 }
190 
191 
192 #if QT_CONFIG(animation)
193 class QScrollTimer : public QAbstractAnimation
194 {
195 public:
196  QScrollTimer(QScrollerPrivate *_d)
197  : QAbstractAnimation(_d), d(_d), ignoreUpdate(false), skip(0)
198  { }
199 
200  int duration() const override
201  {
202  return -1;
203  }
204 
205  void start()
206  {
207  // QAbstractAnimation::start() will immediately call
208  // updateCurrentTime(), but our state is not set correctly yet
209  ignoreUpdate = true;
211  ignoreUpdate = false;
212  skip = 0;
213  }
214 
215 protected:
216  void updateCurrentTime(int /*currentTime*/) override
217  {
218  if (!ignoreUpdate) {
219  if (++skip >= d->frameRateSkip()) {
220  skip = 0;
221  d->timerTick();
222  }
223  }
224  }
225 
226 private:
228  bool ignoreUpdate;
229  int skip;
230 };
231 #endif // animation
232 
275 
276 Q_GLOBAL_STATIC(ScrollerHash, qt_allScrollers)
277 Q_GLOBAL_STATIC(QList<QScroller *>, qt_activeScrollers)
278 
279 
284 bool QScroller::hasScroller(QObject *target)
285 {
286  return (qt_allScrollers()->value(target));
287 }
288 
298 {
299  if (!target) {
300  qWarning("QScroller::scroller() was called with a null target.");
301  return nullptr;
302  }
303 
304  if (qt_allScrollers()->contains(target))
305  return qt_allScrollers()->value(target);
306 
307  QScroller *s = new QScroller(target);
308  qt_allScrollers()->insert(target, s);
309  return s;
310 }
311 
317 {
318  return scroller(const_cast<QObject*>(target));
319 }
320 
327 {
328  return *qt_activeScrollers();
329 }
330 
336 {
337  Q_D(const QScroller);
338  return d->target;
339 }
340 
356 {
357  Q_D(const QScroller);
358  return d->properties;
359 }
360 
362 {
363  Q_D(QScroller);
364  if (d->properties != sp) {
365  d->properties = sp;
367 
368  // we need to force the recalculation here, since the overshootPolicy may have changed and
369  // existing segments may include an overshoot animation.
370  d->recalcScrollingSegments(true);
371  }
372 }
373 
374 #ifndef QT_NO_GESTURES
375 
398 {
399  // ensure that a scroller for target is created
401  if (!s)
402  return Qt::GestureType(0);
403 
404  QScrollerPrivate *sp = s->d_ptr;
405  if (sp->recognizer)
406  ungrabGesture(target); // ungrab the old gesture
407 
409  switch (scrollGestureType) {
413  default :
414  case TouchGesture : button = Qt::NoButton; break; // NoButton == Touch
415  }
416 
417  sp->recognizer = new QFlickGestureRecognizer(button);
418  sp->recognizerType = QGestureRecognizer::registerRecognizer(sp->recognizer);
419 
420  if (target->isWidgetType()) {
421  QWidget *widget = static_cast<QWidget *>(target);
422  widget->grabGesture(sp->recognizerType);
423  if (scrollGestureType == TouchGesture)
425 #if QT_CONFIG(graphicsview)
426  } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target)) {
427  if (scrollGestureType == TouchGesture)
428  go->setAcceptTouchEvents(true);
429  go->grabGesture(sp->recognizerType);
430 #endif // QT_CONFIG(graphicsview)
431  }
432  return sp->recognizerType;
433 }
434 
442 {
444  if (s && s->d_ptr)
445  return s->d_ptr->recognizerType;
446  else
447  return Qt::GestureType(0);
448 }
449 
457 {
459  if (!s)
460  return;
461 
462  QScrollerPrivate *sp = s->d_ptr;
463  if (!sp->recognizer)
464  return; // nothing to do
465 
466  if (target->isWidgetType()) {
467  QWidget *widget = static_cast<QWidget *>(target);
468  widget->ungrabGesture(sp->recognizerType);
469 #if QT_CONFIG(graphicsview)
470  } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target)) {
471  go->ungrabGesture(sp->recognizerType);
472 #endif
473  }
474 
476  // do not delete the recognizer. The QGestureManager is doing this.
477  sp->recognizer = nullptr;
478 }
479 
480 #endif // QT_NO_GESTURES
481 
485 QScroller::QScroller(QObject *target)
486  : d_ptr(new QScrollerPrivate(this, target))
487 {
488  Q_ASSERT(target); // you can't create a scroller without a target in any normal way
489  setParent(target);
490  Q_D(QScroller);
491  d->init();
492 }
493 
497 QScroller::~QScroller()
498 {
499  Q_D(QScroller);
500 #ifndef QT_NO_GESTURES
502  // do not delete the recognizer. The QGestureManager is doing this.
503  d->recognizer = nullptr;
504 #endif
505  qt_allScrollers()->remove(d->target);
506  qt_activeScrollers()->removeOne(this);
507 
508  delete d_ptr;
509 }
510 
511 
527 {
528  Q_D(const QScroller);
529  return d->state;
530 }
531 
536 {
537  Q_D(QScroller);
538  if (d->state != Inactive) {
539  QPointF here = clampToRect(d->contentPosition, d->contentPosRange);
540  qreal snapX = d->nextSnapPos(here.x(), 0, Qt::Horizontal);
541  qreal snapY = d->nextSnapPos(here.y(), 0, Qt::Vertical);
542  QPointF snap = here;
543  if (!qIsNaN(snapX))
544  snap.setX(snapX);
545  if (!qIsNaN(snapY))
546  snap.setY(snapY);
547  d->contentPosition = snap;
548  d->overshootPosition = QPointF(0, 0);
549 
550  d->setState(Inactive);
551  }
552 }
553 
564 {
565  Q_D(const QScroller);
566  QPointF ppm = d->pixelPerMeter;
567 
568 #if QT_CONFIG(graphicsview)
569  if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(d->target)) {
570  QTransform viewtr;
571  //TODO: the first view isn't really correct - maybe use an additional field in the prepare event?
572  if (const auto *scene = go->scene()) {
573  const auto views = scene->views();
574  if (!views.isEmpty())
575  viewtr = views.first()->viewportTransform();
576  }
577  QTransform tr = go->deviceTransform(viewtr);
578  if (tr.isScaling()) {
579  QPointF p0 = tr.map(QPointF(0, 0));
580  QPointF px = tr.map(QPointF(1, 0));
581  QPointF py = tr.map(QPointF(0, 1));
582  ppm.rx() /= QLineF(p0, px).length();
583  ppm.ry() /= QLineF(p0, py).length();
584  }
585  }
586 #endif // QT_CONFIG(graphicsview)
587  return ppm;
588 }
589 
599 {
600  Q_D(const QScroller);
601  const QScrollerPropertiesPrivate *sp = d->properties.d.data();
602 
603  switch (state()) {
604  case Dragging:
605  return d->releaseVelocity;
606  case Scrolling: {
607  QPointF vel;
608  qint64 now = d->monotonicTimer.elapsed();
609 
610  if (!d->xSegments.isEmpty()) {
611  const QScrollerPrivate::ScrollSegment &s = d->xSegments.head();
612  qreal progress = qreal(now - s.startTime) / qreal(s.deltaTime);
613  qreal v = qSign(s.deltaPos) * qreal(s.deltaTime) / qreal(1000) * sp->decelerationFactor * qreal(0.5) * differentialForProgress(s.curve, progress);
614  vel.setX(v);
615  }
616 
617  if (!d->ySegments.isEmpty()) {
618  const QScrollerPrivate::ScrollSegment &s = d->ySegments.head();
619  qreal progress = qreal(now - s.startTime) / qreal(s.deltaTime);
620  qreal v = qSign(s.deltaPos) * qreal(s.deltaTime) / qreal(1000) * sp->decelerationFactor * qreal(0.5) * differentialForProgress(s.curve, progress);
621  vel.setY(v);
622  }
623  return vel;
624  }
625  default:
626  return QPointF(0, 0);
627  }
628 }
629 
640 {
641  Q_D(const QScroller);
642  return QPointF(d->scrollingSegmentsEndPos(Qt::Horizontal),
643  d->scrollingSegmentsEndPos(Qt::Vertical));
644 }
645 
661 {
662  // we could make this adjustable via QScrollerProperties
663  scrollTo(pos, 300);
664 }
665 
670 void QScroller::scrollTo(const QPointF &pos, int scrollTime)
671 {
672  Q_D(QScroller);
673 
674  if (d->state == Pressed || d->state == Dragging )
675  return;
676 
677  // no need to resend a prepare event if we are already scrolling
678  if (d->state == Inactive && !d->prepareScrolling(QPointF()))
679  return;
680 
681  QPointF newpos = clampToRect(pos, d->contentPosRange);
682  qreal snapX = d->nextSnapPos(newpos.x(), 0, Qt::Horizontal);
683  qreal snapY = d->nextSnapPos(newpos.y(), 0, Qt::Vertical);
684  if (!qIsNaN(snapX))
685  newpos.setX(snapX);
686  if (!qIsNaN(snapY))
687  newpos.setY(snapY);
688 
689  qScrollerDebug() << "QScroller::scrollTo(req:" << pos << " [pix] / snap:" << newpos << ", " << scrollTime << " [ms])";
690 
691  if (newpos == d->contentPosition + d->overshootPosition)
692  return;
693 
694  QPointF vel = velocity();
695 
696  if (scrollTime < 0)
697  scrollTime = 0;
698  qreal time = qreal(scrollTime) / 1000;
699 
700  d->createScrollToSegments(vel.x(), time, newpos.x(), Qt::Horizontal, QScrollerPrivate::ScrollTypeScrollTo);
701  d->createScrollToSegments(vel.y(), time, newpos.y(), Qt::Vertical, QScrollerPrivate::ScrollTypeScrollTo);
702 
703  if (!scrollTime)
704  d->setContentPositionHelperScrolling();
705  d->setState(scrollTime ? Scrolling : Inactive);
706 }
707 
723 void QScroller::ensureVisible(const QRectF &rect, qreal xmargin, qreal ymargin)
724 {
725  // we could make this adjustable via QScrollerProperties
726  ensureVisible(rect, xmargin, ymargin, 1000);
727 }
728 
733 void QScroller::ensureVisible(const QRectF &rect, qreal xmargin, qreal ymargin, int scrollTime)
734 {
735  Q_D(QScroller);
736 
737  if (d->state == Pressed || d->state == Dragging )
738  return;
739 
740  if (d->state == Inactive && !d->prepareScrolling(QPointF()))
741  return;
742 
743  // -- calculate the current pos (or the position after the current scroll)
744  QPointF startPos(d->scrollingSegmentsEndPos(Qt::Horizontal),
745  d->scrollingSegmentsEndPos(Qt::Vertical));
746 
747  QRectF marginRect(rect.x() - xmargin, rect.y() - ymargin,
748  rect.width() + 2 * xmargin, rect.height() + 2 * ymargin);
749 
750  QSizeF visible = d->viewportSize;
751  QRectF visibleRect(startPos, visible);
752 
753  qScrollerDebug() << "QScroller::ensureVisible(" << rect << " [pix], " << xmargin << " [pix], " << ymargin << " [pix], " << scrollTime << "[ms])";
754  qScrollerDebug() << " --> content position:" << d->contentPosition;
755 
756  if (visibleRect.contains(marginRect))
757  return;
758 
759  QPointF newPos = startPos;
760 
761  if (visibleRect.width() < rect.width()) {
762  // at least try to move the rect into view
763  if (rect.left() > visibleRect.left())
764  newPos.setX(rect.left());
765  else if (rect.right() < visibleRect.right())
766  newPos.setX(rect.right() - visible.width());
767 
768  } else if (visibleRect.width() < marginRect.width()) {
769  newPos.setX(rect.center().x() - visibleRect.width() / 2);
770  } else if (marginRect.left() > visibleRect.left()) {
771  newPos.setX(marginRect.left());
772  } else if (marginRect.right() < visibleRect.right()) {
773  newPos.setX(marginRect.right() - visible.width());
774  }
775 
776  if (visibleRect.height() < rect.height()) {
777  // at least try to move the rect into view
778  if (rect.top() > visibleRect.top())
779  newPos.setX(rect.top());
780  else if (rect.bottom() < visibleRect.bottom())
781  newPos.setX(rect.bottom() - visible.height());
782 
783  } else if (visibleRect.height() < marginRect.height()) {
784  newPos.setY(rect.center().y() - visibleRect.height() / 2);
785  } else if (marginRect.top() > visibleRect.top()) {
786  newPos.setY(marginRect.top());
787  } else if (marginRect.bottom() < visibleRect.bottom()) {
788  newPos.setY(marginRect.bottom() - visible.height());
789  }
790 
791  // clamp to maximum content position
792  newPos = clampToRect(newPos, d->contentPosRange);
793  if (newPos == startPos)
794  return;
795 
796  scrollTo(newPos, scrollTime);
797 }
798 
807 {
808  Q_D(QScroller);
809  d->prepareScrolling(d->pressPosition);
810 }
811 
818 {
819  Q_D(QScroller);
820  d->snapPositionsX = positions;
821  d->snapIntervalX = 0.0;
822 
823  d->recalcScrollingSegments();
824 }
825 
834 {
835  Q_D(QScroller);
836  d->snapFirstX = first;
837  d->snapIntervalX = interval;
838  d->snapPositionsX.clear();
839 
840  d->recalcScrollingSegments();
841 }
842 
849 {
850  Q_D(QScroller);
851  d->snapPositionsY = positions;
852  d->snapIntervalY = 0.0;
853 
854  d->recalcScrollingSegments();
855 }
856 
864 {
865  Q_D(QScroller);
866  d->snapFirstY = first;
867  d->snapIntervalY = interval;
868  d->snapPositionsY.clear();
869 
870  d->recalcScrollingSegments();
871 }
872 
873 
874 
875 // -------------- private ------------
876 
878  : target(_target)
879 #ifndef QT_NO_GESTURES
880  , recognizer(nullptr)
881  , recognizerType(Qt::CustomGesture)
882 #endif
883  , state(QScroller::Inactive)
884  , firstScroll(true)
885  , pressTimestamp(0)
886  , lastTimestamp(0)
887  , snapFirstX(-1.0)
888  , snapIntervalX(0.0)
889  , snapFirstY(-1.0)
890  , snapIntervalY(0.0)
892  , scrollTimer(new QScrollTimer(this))
893 #endif
894  , q_ptr(q)
895 {
897 }
898 
900 {
901  setDpiFromWidget(nullptr);
903 }
904 
906 {
908 }
909 
911 {
912  switch (state) {
913  case QScroller::Inactive: return "inactive";
914  case QScroller::Pressed: return "pressed";
915  case QScroller::Dragging: return "dragging";
916  case QScroller::Scrolling: return "scrolling";
917  default: return "(invalid)";
918  }
919 }
920 
922 {
923  switch (input) {
924  case QScroller::InputPress: return "press";
925  case QScroller::InputMove: return "move";
926  case QScroller::InputRelease: return "release";
927  default: return "(invalid)";
928  }
929 }
930 
932 {
933 #if QT_CONFIG(animation)
934  scrollTimer->stop();
935 #endif
936  delete q_ptr;
937 }
938 
940 {
941  struct timerevent {
943  typedef void (QScrollerPrivate::*timerhandler_t)();
944  timerhandler_t handler;
945  };
946 
947  timerevent timerevents[] = {
950  };
951 
952  for (int i = 0; i < int(sizeof(timerevents) / sizeof(*timerevents)); ++i) {
953  timerevent *te = timerevents + i;
954 
955  if (state == te->state) {
956  (this->*te->handler)();
957  return;
958  }
959  }
960 
961 #if QT_CONFIG(animation)
962  scrollTimer->stop();
963 #endif
964 }
965 
979 {
980  Q_D(QScroller);
981 
982  qScrollerDebug() << "QScroller::handleInput(" << input << ", " << d->stateName(d->state) << ", " << position << ", " << timestamp << ')';
983  struct statechange {
984  State state;
985  Input input;
986  typedef bool (QScrollerPrivate::*inputhandler_t)(const QPointF &position, qint64 timestamp);
987  inputhandler_t handler;
988  };
989 
990  statechange statechanges[] = {
997  };
998 
999  for (int i = 0; i < int(sizeof(statechanges) / sizeof(*statechanges)); ++i) {
1000  statechange *sc = statechanges + i;
1001 
1002  if (d->state == sc->state && input == sc->input)
1003  return (d->*sc->handler)(position - d->overshootPosition, timestamp);
1004  }
1005  return false;
1006 }
1007 
1012 {
1013  return pixelPerMeter * qreal(0.0254);
1014 }
1015 
1023 {
1024  pixelPerMeter = dpi / qreal(0.0254);
1025 }
1026 
1031 {
1033  Q_ASSERT(screen);
1035 }
1036 
1041 void QScrollerPrivate::updateVelocity(const QPointF &deltaPixelRaw, qint64 deltaTime)
1042 {
1043  if (deltaTime <= 0)
1044  return;
1045 
1046  Q_Q(QScroller);
1047  QPointF ppm = q->pixelPerMeter();
1049  QPointF deltaPixel = deltaPixelRaw;
1050 
1051  qScrollerDebug() << "QScroller::updateVelocity(" << deltaPixelRaw << " [delta pix], " << deltaTime << " [delta ms])";
1052 
1053  // faster than 2.5mm/ms seems bogus (that would be a screen height in ~20 ms)
1054  if (((deltaPixelRaw / qreal(deltaTime)).manhattanLength() / ((ppm.x() + ppm.y()) / 2) * 1000) > qreal(2.5))
1055  deltaPixel = deltaPixelRaw * qreal(2.5) * ppm / 1000 / (deltaPixelRaw / qreal(deltaTime)).manhattanLength();
1056 
1057  QPointF newv = -deltaPixel / qreal(deltaTime) * qreal(1000) / ppm;
1058  // around 95% of all updates are in the [1..50] ms range, so make sure
1059  // to scale the smoothing factor over that range: this way a 50ms update
1060  // will have full impact, while 5ms update will only have a 10% impact.
1061  qreal smoothing = sp->dragVelocitySmoothingFactor * qMin(qreal(deltaTime), qreal(50)) / qreal(50);
1062 
1063  // only smooth if we already have a release velocity and only if the
1064  // user hasn't stopped to move his finger for more than 100ms
1065  if ((releaseVelocity != QPointF(0, 0)) && (deltaTime < 100)) {
1066  qScrollerDebug() << "SMOOTHED from " << newv << " to " << newv * smoothing + releaseVelocity * (qreal(1) - smoothing);
1067  // smooth x or y only if the new velocity is either 0 or at least in
1068  // the same direction of the release velocity
1069  if (!newv.x() || (qSign(releaseVelocity.x()) == qSign(newv.x())))
1070  newv.setX(newv.x() * smoothing + releaseVelocity.x() * (qreal(1) - smoothing));
1071  if (!newv.y() || (qSign(releaseVelocity.y()) == qSign(newv.y())))
1072  newv.setY(newv.y() * smoothing + releaseVelocity.y() * (qreal(1) - smoothing));
1073  } else
1074  qScrollerDebug() << "NO SMOOTHING to " << newv;
1075 
1076  releaseVelocity.setX(qBound(-sp->maximumVelocity, newv.x(), sp->maximumVelocity));
1077  releaseVelocity.setY(qBound(-sp->maximumVelocity, newv.y(), sp->maximumVelocity));
1078 
1079  qScrollerDebug() << " --> new velocity:" << releaseVelocity;
1080 }
1081 
1082 void QScrollerPrivate::pushSegment(ScrollType type, qreal deltaTime, qreal stopProgress, qreal startPos, qreal deltaPos, qreal stopPos, QEasingCurve::Type curve, Qt::Orientation orientation)
1083 {
1084  if (startPos == stopPos || deltaPos == 0)
1085  return;
1086 
1087  ScrollSegment s;
1088  if (orientation == Qt::Horizontal && !xSegments.isEmpty()) {
1089  const auto &lastX = xSegments.constLast();
1090  s.startTime = lastX.startTime + lastX.deltaTime * lastX.stopProgress;
1091  } else if (orientation == Qt::Vertical && !ySegments.isEmpty()) {
1092  const auto &lastY = ySegments.constLast();
1093  s.startTime = lastY.startTime + lastY.deltaTime * lastY.stopProgress;
1094  } else {
1095  s.startTime = monotonicTimer.elapsed();
1096  }
1097 
1098  s.startPos = startPos;
1099  s.deltaPos = deltaPos;
1100  s.stopPos = stopPos;
1101  s.deltaTime = deltaTime * 1000;
1102  s.stopProgress = stopProgress;
1103  s.curve.setType(curve);
1104  s.type = type;
1105 
1106  if (orientation == Qt::Horizontal)
1107  xSegments.enqueue(s);
1108  else
1109  ySegments.enqueue(s);
1110 
1111  qScrollerDebug() << "+++ Added a new ScrollSegment: " << s;
1112 }
1113 
1114 
1119 {
1120  Q_Q(QScroller);
1121  QPointF ppm = q->pixelPerMeter();
1122 
1123  releaseVelocity = q->velocity();
1124 
1125  if (forceRecalc ||
1129 }
1130 
1135 {
1136  if (orientation == Qt::Horizontal) {
1137  if (xSegments.isEmpty())
1138  return contentPosition.x() + overshootPosition.x();
1139  else
1140  return xSegments.last().stopPos;
1141  } else {
1142  if (ySegments.isEmpty())
1143  return contentPosition.y() + overshootPosition.y();
1144  else
1145  return ySegments.last().stopPos;
1146  }
1147 }
1148 
1153 {
1155  qreal minPos;
1156  qreal maxPos;
1157 
1158  if (orientation == Qt::Horizontal) {
1159  segments = &xSegments;
1160  minPos = contentPosRange.left();
1161  maxPos = contentPosRange.right();
1162  } else {
1163  segments = &ySegments;
1164  minPos = contentPosRange.top();
1165  maxPos = contentPosRange.bottom();
1166  }
1167 
1168  if (segments->isEmpty())
1169  return true;
1170 
1171  const ScrollSegment &last = segments->last();
1172  qreal stopPos = last.stopPos;
1173 
1174  if (last.type == ScrollTypeScrollTo)
1175  return true; // scrollTo is always valid
1176 
1177  if (last.type == ScrollTypeOvershoot &&
1178  (stopPos != minPos && stopPos != maxPos))
1179  return false;
1180 
1181  if (stopPos < minPos || stopPos > maxPos)
1182  return false;
1183 
1184  if (stopPos == minPos || stopPos == maxPos) // the begin and the end of the list are always ok
1185  return true;
1186 
1187  qreal nextSnap = nextSnapPos(stopPos, 0, orientation);
1188  if (!qIsNaN(nextSnap) && stopPos != nextSnap)
1189  return false;
1190 
1191  return true;
1192 }
1193 
1198 {
1199  Q_UNUSED(v);
1200 
1201  if (orientation == Qt::Horizontal)
1202  xSegments.clear();
1203  else
1204  ySegments.clear();
1205 
1206  qScrollerDebug() << "+++ createScrollToSegments: t:" << deltaTime << "ep:" << endPos << "o:" << int(orientation);
1207 
1209 
1210  qreal startPos = (orientation == Qt::Horizontal) ? contentPosition.x() + overshootPosition.x()
1212  qreal deltaPos = (endPos - startPos) / 2;
1213 
1214  pushSegment(type, deltaTime * qreal(0.3), qreal(1.0), startPos, deltaPos, startPos + deltaPos, QEasingCurve::InQuad, orientation);
1215  pushSegment(type, deltaTime * qreal(0.7), qreal(1.0), startPos + deltaPos, deltaPos, endPos, sp->scrollingCurve.type(), orientation);
1216 }
1217 
1221  qreal deltaTime, qreal deltaPos,
1222  Qt::Orientation orientation)
1223 {
1225 
1227  qreal minPos;
1228  qreal maxPos;
1229  qreal viewSize;
1230 
1231  if (orientation == Qt::Horizontal) {
1232  xSegments.clear();
1233  policy = sp->hOvershootPolicy;
1234  minPos = contentPosRange.left();
1235  maxPos = contentPosRange.right();
1236  viewSize = viewportSize.width();
1237  } else {
1238  ySegments.clear();
1239  policy = sp->vOvershootPolicy;
1240  minPos = contentPosRange.top();
1241  maxPos = contentPosRange.bottom();
1242  viewSize = viewportSize.height();
1243  }
1244 
1245  bool alwaysOvershoot = (policy == QScrollerProperties::OvershootAlwaysOn);
1246  bool noOvershoot = (policy == QScrollerProperties::OvershootAlwaysOff) || !sp->overshootScrollDistanceFactor;
1247  bool canOvershoot = !noOvershoot && (alwaysOvershoot || maxPos);
1248 
1249  qScrollerDebug() << "+++ createScrollingSegments: s:" << startPos << "maxPos:" << maxPos << "o:" << int(orientation);
1250 
1251  qScrollerDebug() << "v = " << v << ", decelerationFactor = " << sp->decelerationFactor << ", curveType = " << sp->scrollingCurve.type();
1252 
1253  qreal endPos = startPos + deltaPos;
1254 
1255  qScrollerDebug() << " Real Delta:" << deltaPos;
1256 
1257  // -- check if are in overshoot and end in overshoot
1258  if ((startPos < minPos && endPos < minPos) ||
1259  (startPos > maxPos && endPos > maxPos)) {
1260  qreal stopPos = endPos < minPos ? minPos : maxPos;
1261  qreal oDeltaTime = sp->overshootScrollTime;
1262 
1263  pushSegment(ScrollTypeOvershoot, oDeltaTime * qreal(0.7), qreal(1.0), startPos, stopPos - startPos, stopPos, sp->scrollingCurve.type(), orientation);
1264  return;
1265  }
1266 
1267  // -- determine snap points
1268  qreal nextSnap = nextSnapPos(endPos, 0, orientation);
1269  qreal lowerSnapPos = nextSnapPos(startPos, -1, orientation);
1270  qreal higherSnapPos = nextSnapPos(startPos, 1, orientation);
1271 
1272  qScrollerDebug() << " Real Delta:" << lowerSnapPos << '-' << nextSnap << '-' <<higherSnapPos;
1273 
1274  // - check if we can reach another snap point
1275  if (nextSnap > higherSnapPos || qIsNaN(higherSnapPos))
1276  higherSnapPos = nextSnap;
1277  if (nextSnap < lowerSnapPos || qIsNaN(lowerSnapPos))
1278  lowerSnapPos = nextSnap;
1279 
1280  if (qAbs(v) < sp->minimumVelocity) {
1281 
1282  qScrollerDebug() << "### below minimum Vel" << orientation;
1283 
1284  // - no snap points or already at one
1285  if (qIsNaN(nextSnap) || nextSnap == startPos)
1286  return; // nothing to do, no scrolling needed.
1287 
1288  // - decide which point to use
1289 
1290  qreal snapDistance = higherSnapPos - lowerSnapPos;
1291 
1292  qreal pressDistance = (orientation == Qt::Horizontal) ?
1293  lastPosition.x() - pressPosition.x() :
1294  lastPosition.y() - pressPosition.y();
1295 
1296  // if not dragged far enough, pick the next snap point.
1297  if (sp->snapPositionRatio == 0.0 || qAbs(pressDistance / sp->snapPositionRatio) > snapDistance)
1298  endPos = nextSnap;
1299  else if (pressDistance < 0.0)
1300  endPos = lowerSnapPos;
1301  else
1302  endPos = higherSnapPos;
1303 
1304  deltaPos = endPos - startPos;
1305  qreal midPos = startPos + deltaPos * qreal(0.3);
1306  pushSegment(ScrollTypeFlick, sp->snapTime * qreal(0.3), qreal(1.0), startPos, midPos - startPos, midPos, QEasingCurve::InQuad, orientation);
1307  pushSegment(ScrollTypeFlick, sp->snapTime * qreal(0.7), qreal(1.0), midPos, endPos - midPos, endPos, sp->scrollingCurve.type(), orientation);
1308  return;
1309  }
1310 
1311  // - go to the next snappoint if there is one
1312  if (v > 0 && !qIsNaN(higherSnapPos)) {
1313  // change the time in relation to the changed end position
1314  if (endPos - startPos)
1315  deltaTime *= qAbs((higherSnapPos - startPos) / (endPos - startPos));
1316  if (deltaTime > sp->snapTime)
1317  deltaTime = sp->snapTime;
1318  endPos = higherSnapPos;
1319 
1320  } else if (v < 0 && !qIsNaN(lowerSnapPos)) {
1321  // change the time in relation to the changed end position
1322  if (endPos - startPos)
1323  deltaTime *= qAbs((lowerSnapPos - startPos) / (endPos - startPos));
1324  if (deltaTime > sp->snapTime)
1325  deltaTime = sp->snapTime;
1326  endPos = lowerSnapPos;
1327 
1328  // -- check if we are overshooting
1329  } else if (endPos < minPos || endPos > maxPos) {
1330  qreal stopPos = endPos < minPos ? minPos : maxPos;
1331 
1332  qScrollerDebug() << "Overshoot: delta:" << (stopPos - startPos);
1333 
1334  qreal stopProgress = progressForValue(sp->scrollingCurve, qAbs((stopPos - startPos) / deltaPos));
1335 
1336  if (!canOvershoot) {
1337  qScrollerDebug() << "Overshoot stopp:" << stopProgress;
1338 
1339  pushSegment(ScrollTypeFlick, deltaTime, stopProgress, startPos, endPos, stopPos, sp->scrollingCurve.type(), orientation);
1340  } else {
1341  qreal oDeltaTime = sp->overshootScrollTime;
1342  qreal oStopProgress = qMin(stopProgress + oDeltaTime * qreal(0.3) / deltaTime, qreal(1));
1343  qreal oDistance = startPos + deltaPos * sp->scrollingCurve.valueForProgress(oStopProgress) - stopPos;
1344  qreal oMaxDistance = qSign(oDistance) * (viewSize * sp->overshootScrollDistanceFactor);
1345 
1346  qScrollerDebug() << "1 oDistance:" << oDistance << "Max:" << oMaxDistance << "stopP/oStopP" << stopProgress << oStopProgress;
1347 
1348  if (qAbs(oDistance) > qAbs(oMaxDistance)) {
1349  oStopProgress = progressForValue(sp->scrollingCurve, qAbs((stopPos + oMaxDistance - startPos) / deltaPos));
1350  oDistance = oMaxDistance;
1351  qScrollerDebug() << "2 oDistance:" << oDistance << "Max:" << oMaxDistance << "stopP/oStopP" << stopProgress << oStopProgress;
1352  }
1353 
1354  pushSegment(ScrollTypeFlick, deltaTime, oStopProgress, startPos, deltaPos, stopPos + oDistance, sp->scrollingCurve.type(), orientation);
1355  pushSegment(ScrollTypeOvershoot, oDeltaTime * qreal(0.7), qreal(1.0), stopPos + oDistance, -oDistance, stopPos, sp->scrollingCurve.type(), orientation);
1356  }
1357  return;
1358  }
1359 
1360  pushSegment(ScrollTypeFlick, deltaTime, qreal(1.0), startPos, deltaPos, endPos, sp->scrollingCurve.type(), orientation);
1361 }
1362 
1363 
1365  const QPointF &startPos,
1366  const QPointF &ppm)
1367 {
1369 
1370  // This is only correct for QEasingCurve::OutQuad (linear velocity,
1371  // constant deceleration), but the results look and feel ok for OutExpo
1372  // and OutSine as well
1373 
1374  // v(t) = deltaTime * a * 0.5 * differentialForProgress(t / deltaTime)
1375  // v(0) = vrelease
1376  // v(deltaTime) = 0
1377  // deltaTime = (2 * vrelease) / (a * differential(0))
1378 
1379  // pos(t) = integrate(v(t)dt)
1380  // pos(t) = vrelease * t - 0.5 * a * t * t
1381  // pos(t) = deltaTime * a * 0.5 * progress(t / deltaTime) * deltaTime
1382  // deltaPos = pos(deltaTime)
1383 
1384  QVector2D vel(v);
1385  qreal deltaTime = (qreal(2) * vel.length()) / (sp->decelerationFactor * differentialForProgress(sp->scrollingCurve, 0));
1386  QPointF deltaPos = (vel.normalized() * QVector2D(ppm)).toPointF() * deltaTime * deltaTime * qreal(0.5) * sp->decelerationFactor;
1387 
1388  createScrollingSegments(v.x(), startPos.x(), deltaTime, deltaPos.x(),
1389  Qt::Horizontal);
1390  createScrollingSegments(v.y(), startPos.y(), deltaTime, deltaPos.y(),
1391  Qt::Vertical);
1392 }
1393 
1399 {
1401  spe.ignore();
1402  sendEvent(target, &spe);
1403 
1404  qScrollerDebug() << "QScrollPrepareEvent returned from" << target << "with" << spe.isAccepted() << "mcp:" << spe.contentPosRange() << "cp:" << spe.contentPos();
1405  if (spe.isAccepted()) {
1406  QPointF oldContentPos = contentPosition + overshootPosition;
1407  QPointF contentDelta = spe.contentPos() - oldContentPos;
1408 
1409  viewportSize = spe.viewportSize();
1411  if (contentPosRange.width() < 0)
1413  if (contentPosRange.height() < 0)
1417 
1418  // - check if the content position was moved
1419  if (contentDelta != QPointF(0, 0)) {
1420  // need to correct all segments
1421  for (int i = 0; i < xSegments.count(); i++)
1422  xSegments[i].startPos -= contentDelta.x();
1423 
1424  for (int i = 0; i < ySegments.count(); i++)
1425  ySegments[i].startPos -= contentDelta.y();
1426  }
1427 
1430 #if QT_CONFIG(graphicsview)
1431  if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(target)) {
1432  //TODO: the first view isn't really correct - maybe use an additional field in the prepare event?
1433  if (const auto *scene = go->scene()) {
1434  const auto views = scene->views();
1435  if (!views.isEmpty())
1436  setDpiFromWidget(views.first());
1437  }
1438  }
1439 #endif
1440 
1441  if (state == QScroller::Scrolling) {
1443  }
1444  return true;
1445  }
1446 
1447  return false;
1448 }
1449 
1451 {
1453 
1454  QPointF deltaPixel = position - lastPosition;
1455  qint64 deltaTime = timestamp - lastTimestamp;
1456 
1457  if (sp->axisLockThreshold) {
1458  int dx = qAbs(deltaPixel.x());
1459  int dy = qAbs(deltaPixel.y());
1460  if (dx || dy) {
1461  bool vertical = (dy > dx);
1462  qreal alpha = qreal(vertical ? dx : dy) / qreal(vertical ? dy : dx);
1463  //qScrollerDebug() << "QScroller::handleDrag() -- axis lock:" << alpha << " / " << axisLockThreshold << "- isvertical:" << vertical << "- dx:" << dx << "- dy:" << dy;
1464  if (alpha <= sp->axisLockThreshold) {
1465  if (vertical)
1466  deltaPixel.setX(0);
1467  else
1468  deltaPixel.setY(0);
1469  }
1470  }
1471  }
1472 
1473  // calculate velocity (if the user would release the mouse NOW)
1474  updateVelocity(deltaPixel, deltaTime);
1475 
1476  // restrict velocity, if content is not scrollable
1477  QRectF max = contentPosRange;
1478  bool canScrollX = (max.width() > 0) || (sp->hOvershootPolicy == QScrollerProperties::OvershootAlwaysOn);
1479  bool canScrollY = (max.height() > 0) || (sp->vOvershootPolicy == QScrollerProperties::OvershootAlwaysOn);
1480 
1481  if (!canScrollX) {
1482  deltaPixel.setX(0);
1483  releaseVelocity.setX(0);
1484  }
1485  if (!canScrollY) {
1486  deltaPixel.setY(0);
1487  releaseVelocity.setY(0);
1488  }
1489 
1490 // if (firstDrag) {
1491 // // Do not delay the first drag
1492 // setContentPositionHelper(q->contentPosition() - overshootDistance - deltaPixel);
1493 // dragDistance = QPointF(0, 0);
1494 // } else {
1495  dragDistance += deltaPixel;
1496 // }
1497 //qScrollerDebug() << "######################" << deltaPixel << position.y() << lastPosition.y();
1498 
1500  lastTimestamp = timestamp;
1501 }
1502 
1504 {
1505  if (prepareScrolling(position)) {
1507 
1508  if (!contentPosRange.isNull() ||
1509  (sp->hOvershootPolicy == QScrollerProperties::OvershootAlwaysOn) ||
1510  (sp->vOvershootPolicy == QScrollerProperties::OvershootAlwaysOn)) {
1511 
1513  lastTimestamp = pressTimestamp = timestamp;
1515  }
1516  }
1517  return false;
1518 }
1519 
1521 {
1522  if (overshootPosition != QPointF(0.0, 0.0)) {
1524  return true;
1525  } else {
1527  return false;
1528  }
1529 }
1530 
1532 {
1533  Q_Q(QScroller);
1535  QPointF ppm = q->pixelPerMeter();
1536 
1537  QPointF deltaPixel = position - pressPosition;
1538 
1539  bool moveAborted = false;
1540  bool moveStarted = (((deltaPixel / ppm).manhattanLength()) > sp->dragStartDistance);
1541 
1542  // check the direction of the mouse drag and abort if it's too much in the wrong direction.
1543  if (moveStarted) {
1544  QRectF max = contentPosRange;
1545  bool canScrollX = (max.width() > 0);
1546  bool canScrollY = (max.height() > 0);
1547 
1548  if (sp->hOvershootPolicy == QScrollerProperties::OvershootAlwaysOn)
1549  canScrollX = true;
1550  if (sp->vOvershootPolicy == QScrollerProperties::OvershootAlwaysOn)
1551  canScrollY = true;
1552 
1553  if (qAbs(deltaPixel.x() / ppm.x()) < qAbs(deltaPixel.y() / ppm.y())) {
1554  if (!canScrollY)
1555  moveAborted = true;
1556  } else {
1557  if (!canScrollX)
1558  moveAborted = true;
1559  }
1560  }
1561 
1562  if (moveAborted) {
1564  moveStarted = false;
1565 
1566  } else if (moveStarted) {
1568 
1569  // subtract the dragStartDistance
1570  deltaPixel = deltaPixel - deltaPixel * (sp->dragStartDistance / deltaPixel.manhattanLength());
1571 
1572  if (deltaPixel != QPointF(0, 0)) {
1573  // handleDrag updates lastPosition, lastTimestamp and velocity
1574  handleDrag(pressPosition + deltaPixel, timestamp);
1575  }
1576  }
1577  return moveStarted;
1578 }
1579 
1581 {
1582  // handleDrag updates lastPosition, lastTimestamp and velocity
1583  handleDrag(position, timestamp);
1584  return true;
1585 }
1586 
1588 {
1589  if (dragDistance != QPointF(0, 0)) {
1590  qScrollerDebug() << "QScroller::timerEventWhileDragging() -- dragDistance:" << dragDistance;
1591 
1593  dragDistance = QPointF(0, 0);
1594  }
1595 }
1596 
1598 {
1599  Q_Q(QScroller);
1601 
1602  // handleDrag updates lastPosition, lastTimestamp and velocity
1603  handleDrag(position, timestamp);
1604 
1605  // check if we moved at all - this can happen if you stop a running
1606  // scroller with a press and release shortly afterwards
1607  QPointF deltaPixel = position - pressPosition;
1608  if (((deltaPixel / q->pixelPerMeter()).manhattanLength()) > sp->dragStartDistance) {
1609 
1610  // handle accelerating flicks
1611  if ((oldVelocity != QPointF(0, 0)) && sp->acceleratingFlickMaximumTime &&
1612  ((timestamp - pressTimestamp) < qint64(sp->acceleratingFlickMaximumTime * 1000))) {
1613 
1614  // - determine if the direction was changed
1615  int signX = 0, signY = 0;
1616  if (releaseVelocity.x())
1617  signX = (releaseVelocity.x() > 0) == (oldVelocity.x() > 0) ? 1 : -1;
1618  if (releaseVelocity.y())
1619  signY = (releaseVelocity.y() > 0) == (oldVelocity.y() > 0) ? 1 : -1;
1620 
1621  if (signX > 0)
1622  releaseVelocity.setX(qBound(-sp->maximumVelocity,
1623  oldVelocity.x() * sp->acceleratingFlickSpeedupFactor,
1624  sp->maximumVelocity));
1625  if (signY > 0)
1626  releaseVelocity.setY(qBound(-sp->maximumVelocity,
1627  oldVelocity.y() * sp->acceleratingFlickSpeedupFactor,
1628  sp->maximumVelocity));
1629  }
1630  }
1631 
1632  QPointF ppm = q->pixelPerMeter();
1634 
1635  qScrollerDebug() << "QScroller::releaseWhileDragging() -- velocity:" << releaseVelocity << "-- minimum velocity:" << sp->minimumVelocity << "overshoot" << overshootPosition;
1636 
1637  if (xSegments.isEmpty() && ySegments.isEmpty())
1639  else
1641 
1642  return true;
1643 }
1644 
1646 {
1647  qScrollerDebug("QScroller::timerEventWhileScrolling()");
1648 
1650  if (xSegments.isEmpty() && ySegments.isEmpty())
1652 }
1653 
1655 {
1656  Q_Q(QScroller);
1657 
1658  if ((q->velocity() <= properties.d->maximumClickThroughVelocity) &&
1659  (overshootPosition == QPointF(0.0, 0.0))) {
1661  return false;
1662  } else {
1664  lastTimestamp = pressTimestamp = timestamp;
1667  return true;
1668  }
1669 }
1670 
1675 {
1676  Q_Q(QScroller);
1677  bool sendLastScroll = false;
1678 
1679  if (state == newstate)
1680  return;
1681 
1682  qScrollerDebug() << q << "QScroller::setState(" << stateName(newstate) << ')';
1683 
1684  switch (newstate) {
1685  case QScroller::Inactive:
1686 #if QT_CONFIG(animation)
1687  scrollTimer->stop();
1688 #endif
1689 
1690  // send the last scroll event (but only after the current state change was finished)
1691  if (!firstScroll)
1692  sendLastScroll = true;
1693 
1694  releaseVelocity = QPointF(0, 0);
1695  break;
1696 
1697  case QScroller::Pressed:
1698 #if QT_CONFIG(animation)
1699  scrollTimer->stop();
1700 #endif
1701 
1703  releaseVelocity = QPointF(0, 0);
1704  break;
1705 
1706  case QScroller::Dragging:
1707  dragDistance = QPointF(0, 0);
1708 #if QT_CONFIG(animation)
1709  if (state == QScroller::Pressed)
1710  scrollTimer->start();
1711 #endif
1712  break;
1713 
1714  case QScroller::Scrolling:
1715 #if QT_CONFIG(animation)
1716  scrollTimer->start();
1717 #endif
1718  break;
1719  }
1720 
1721  qSwap(state, newstate);
1722 
1723  if (sendLastScroll) {
1725  sendEvent(target, &se);
1726  firstScroll = true;
1727  }
1729  if (!qt_activeScrollers()->contains(q))
1730  qt_activeScrollers()->push_back(q);
1731  } else {
1732  qt_activeScrollers()->removeOne(q);
1733  }
1734  emit q->stateChanged(state);
1735 }
1736 
1737 
1751 {
1753 
1754  if (sp->overshootDragResistanceFactor)
1755  overshootPosition /= sp->overshootDragResistanceFactor;
1756 
1758  QPointF newPos = oldPos + deltaPos;
1759 
1760  qScrollerDebug() << "QScroller::setContentPositionHelperDragging(" << deltaPos << " [pix])";
1761  qScrollerDebug() << " --> overshoot:" << overshootPosition << "- old pos:" << oldPos << "- new pos:" << newPos;
1762 
1763  QPointF newClampedPos = clampToRect(newPos, contentPosRange);
1764 
1765  // --- handle overshooting and stop if the coordinate is going back inside the normal area
1766  bool alwaysOvershootX = (sp->hOvershootPolicy == QScrollerProperties::OvershootAlwaysOn);
1767  bool alwaysOvershootY = (sp->vOvershootPolicy == QScrollerProperties::OvershootAlwaysOn);
1768  bool noOvershootX = (sp->hOvershootPolicy == QScrollerProperties::OvershootAlwaysOff) ||
1769  ((state == QScroller::Dragging) && !sp->overshootDragResistanceFactor) ||
1770  !sp->overshootDragDistanceFactor;
1771  bool noOvershootY = (sp->vOvershootPolicy == QScrollerProperties::OvershootAlwaysOff) ||
1772  ((state == QScroller::Dragging) && !sp->overshootDragResistanceFactor) ||
1773  !sp->overshootDragDistanceFactor;
1774  bool canOvershootX = !noOvershootX && (alwaysOvershootX || contentPosRange.width());
1775  bool canOvershootY = !noOvershootY && (alwaysOvershootY || contentPosRange.height());
1776 
1777  qreal newOvershootX = (canOvershootX) ? newPos.x() - newClampedPos.x() : 0;
1778  qreal newOvershootY = (canOvershootY) ? newPos.y() - newClampedPos.y() : 0;
1779 
1780  qreal maxOvershootX = viewportSize.width() * sp->overshootDragDistanceFactor;
1781  qreal maxOvershootY = viewportSize.height() * sp->overshootDragDistanceFactor;
1782 
1783  qScrollerDebug() << " --> noOs:" << noOvershootX << "drf:" << sp->overshootDragResistanceFactor << "mdf:" << sp->overshootScrollDistanceFactor << "ossP:"<<sp->hOvershootPolicy;
1784  qScrollerDebug() << " --> canOS:" << canOvershootX << "newOS:" << newOvershootX << "maxOS:" << maxOvershootX;
1785 
1786  if (sp->overshootDragResistanceFactor) {
1787  newOvershootX *= sp->overshootDragResistanceFactor;
1788  newOvershootY *= sp->overshootDragResistanceFactor;
1789  }
1790 
1791  // -- stop at the maximum overshoot distance
1792 
1793  newOvershootX = qBound(-maxOvershootX, newOvershootX, maxOvershootX);
1794  newOvershootY = qBound(-maxOvershootY, newOvershootY, maxOvershootY);
1795 
1796  overshootPosition.setX(newOvershootX);
1797  overshootPosition.setY(newOvershootY);
1798  contentPosition = newClampedPos;
1799 
1801  sendEvent(target, &se);
1802  firstScroll = false;
1803 
1804  qScrollerDebug() << " --> new position:" << newClampedPos << "- new overshoot:" << overshootPosition <<
1805  "- overshoot x/y?:" << overshootPosition;
1806 }
1807 
1808 
1810 {
1811  qreal pos = oldPos;
1812 
1813  // check the X segments for new positions
1814  while (!segments.isEmpty()) {
1815  const ScrollSegment s = segments.head();
1816 
1817  if ((s.startTime + s.deltaTime * s.stopProgress) <= now) {
1818  segments.dequeue();
1819  pos = s.stopPos;
1820  } else if (s.startTime <= now) {
1821  qreal progress = qreal(now - s.startTime) / qreal(s.deltaTime);
1822  pos = s.startPos + s.deltaPos * s.curve.valueForProgress(progress);
1823  if (s.deltaPos > 0 ? pos > s.stopPos : pos < s.stopPos) {
1824  segments.dequeue();
1825  pos = s.stopPos;
1826  } else {
1827  break;
1828  }
1829  } else {
1830  break;
1831  }
1832  }
1833  return pos;
1834 }
1835 
1837 {
1840 
1841  newPos.setX(nextSegmentPosition(xSegments, now, newPos.x()));
1842  newPos.setY(nextSegmentPosition(ySegments, now, newPos.y()));
1843 
1844  // -- set the position and handle overshoot
1845  qScrollerDebug() << "QScroller::setContentPositionHelperScrolling()\n"
1846  " --> overshoot:" << overshootPosition << "- new pos:" << newPos;
1847 
1848  QPointF newClampedPos = clampToRect(newPos, contentPosRange);
1849 
1850  overshootPosition = newPos - newClampedPos;
1851  contentPosition = newClampedPos;
1852 
1854  sendEvent(target, &se);
1855  firstScroll = false;
1856 
1857  qScrollerDebug() << " --> new position:" << newClampedPos << "- new overshoot:" << overshootPosition;
1858 }
1859 
1869 {
1870  qreal bestSnapPos = Q_QNAN;
1871  qreal bestSnapPosDist = Q_INFINITY;
1872 
1873  qreal minPos;
1874  qreal maxPos;
1875 
1876  if (orientation == Qt::Horizontal) {
1877  minPos = contentPosRange.left();
1878  maxPos = contentPosRange.right();
1879  } else {
1880  minPos = contentPosRange.top();
1881  maxPos = contentPosRange.bottom();
1882  }
1883 
1884  if (orientation == Qt::Horizontal) {
1885  // the snap points in the list
1886  for (qreal snapPos : snapPositionsX) {
1887  qreal snapPosDist = snapPos - p;
1888  if ((dir > 0 && snapPosDist < 0) ||
1889  (dir < 0 && snapPosDist > 0))
1890  continue; // wrong direction
1891  if (snapPos < minPos || snapPos > maxPos )
1892  continue; // invalid
1893 
1894  if (qIsNaN(bestSnapPos) ||
1895  qAbs(snapPosDist) < bestSnapPosDist ) {
1896  bestSnapPos = snapPos;
1897  bestSnapPosDist = qAbs(snapPosDist);
1898  }
1899  }
1900 
1901  // the snap point interval
1902  if (snapIntervalX > 0.0) {
1903  qreal first = minPos + snapFirstX;
1904  qreal snapPos;
1905  if (dir > 0)
1906  snapPos = qCeil((p - first) / snapIntervalX) * snapIntervalX + first;
1907  else if (dir < 0)
1908  snapPos = qFloor((p - first) / snapIntervalX) * snapIntervalX + first;
1909  else if (p <= first)
1910  snapPos = first;
1911  else
1912  {
1913  qreal last = qFloor((maxPos - first) / snapIntervalX) * snapIntervalX + first;
1914  if (p >= last)
1915  snapPos = last;
1916  else
1917  snapPos = qRound((p - first) / snapIntervalX) * snapIntervalX + first;
1918  }
1919 
1920  if (snapPos >= first && snapPos <= maxPos ) {
1921  qreal snapPosDist = snapPos - p;
1922 
1923  if (qIsNaN(bestSnapPos) ||
1924  qAbs(snapPosDist) < bestSnapPosDist ) {
1925  bestSnapPos = snapPos;
1926  bestSnapPosDist = qAbs(snapPosDist);
1927  }
1928  }
1929  }
1930 
1931  } else { // (orientation == Qt::Vertical)
1932  // the snap points in the list
1933  for (qreal snapPos : snapPositionsY) {
1934  qreal snapPosDist = snapPos - p;
1935  if ((dir > 0 && snapPosDist < 0) ||
1936  (dir < 0 && snapPosDist > 0))
1937  continue; // wrong direction
1938  if (snapPos < minPos || snapPos > maxPos )
1939  continue; // invalid
1940 
1941  if (qIsNaN(bestSnapPos) ||
1942  qAbs(snapPosDist) < bestSnapPosDist) {
1943  bestSnapPos = snapPos;
1944  bestSnapPosDist = qAbs(snapPosDist);
1945  }
1946  }
1947 
1948  // the snap point interval
1949  if (snapIntervalY > 0.0) {
1950  qreal first = minPos + snapFirstY;
1951  qreal snapPos;
1952  if (dir > 0)
1953  snapPos = qCeil((p - first) / snapIntervalY) * snapIntervalY + first;
1954  else if (dir < 0)
1955  snapPos = qFloor((p - first) / snapIntervalY) * snapIntervalY + first;
1956  else if (p <= first)
1957  snapPos = first;
1958  else
1959  {
1960  qreal last = qFloor((maxPos - first) / snapIntervalY) * snapIntervalY + first;
1961  if (p >= last)
1962  snapPos = last;
1963  else
1964  snapPos = qRound((p - first) / snapIntervalY) * snapIntervalY + first;
1965  }
1966 
1967  if (snapPos >= first && snapPos <= maxPos ) {
1968  qreal snapPosDist = snapPos - p;
1969 
1970  if (qIsNaN(bestSnapPos) ||
1971  qAbs(snapPosDist) < bestSnapPosDist) {
1972  bestSnapPos = snapPos;
1973  bestSnapPosDist = qAbs(snapPosDist);
1974  }
1975  }
1976  }
1977  }
1978 
1979  return bestSnapPos;
1980 }
1981 
2023 
2024 #include "moc_qscroller.cpp"
2025 #include "moc_qscroller_p.cpp"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
#define value
[5]
The QAbstractAnimation class is the base of all animations.
virtual void updateCurrentTime(int currentTime)=0
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
int duration
the duration of the animation.
bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
operator<<(QDataStream &ds, qfloat16 f)
Definition: qfloat16.cpp:327
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
The QEasingCurve class provides easing curves for controlling animation.
Definition: qeasingcurve.h:55
Type type() const
qreal valueForProgress(qreal progress) const
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
qint64 elapsed() const noexcept
void start() noexcept
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
void ignore()
Definition: qcoreevent.h:314
bool isAccepted() const
Definition: qcoreevent.h:311
static void unregisterRecognizer(Qt::GestureType type)
static Qt::GestureType registerRecognizer(QGestureRecognizer *recognizer)
The QGraphicsObject class provides a base class for all graphics items that require signals,...
QList< QGraphicsView * > views() const
QScreen * primaryScreen
the primary (or default) screen of the application.
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:215
qreal length() const
Definition: qline.cpp:569
Definition: qlist.h:108
Definition: qmap.h:222
QMargins operator*(const QMargins &margins, int factor)
Definition: qmargins.h:192
QMargins operator/(const QMargins &margins, int divisor)
Definition: qmargins.h:216
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
void setParent(QObject *parent)
Definition: qobject.cpp:2108
void destroyed(QObject *=nullptr)
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr qreal & ry() noexcept
Definition: qpoint.h:386
constexpr qreal x() const noexcept
Definition: qpoint.h:361
constexpr qreal manhattanLength() const
Definition: qpoint.h:351
constexpr qreal y() const noexcept
Definition: qpoint.h:366
constexpr qreal & rx() noexcept
Definition: qpoint.h:381
constexpr void setY(qreal y) noexcept
Definition: qpoint.h:376
constexpr void setX(qreal x) noexcept
Definition: qpoint.h:371
The QQueue class is a generic container that provides a queue.
Definition: qqueue.h:50
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
constexpr qreal bottom() const noexcept
Definition: qrect.h:527
constexpr qreal height() const noexcept
Definition: qrect.h:741
constexpr qreal width() const noexcept
Definition: qrect.h:738
bool contains(const QRectF &r) const noexcept
Definition: qrect.cpp:2006
constexpr qreal left() const noexcept
Definition: qrect.h:524
constexpr void setWidth(qreal w) noexcept
Definition: qrect.h:827
constexpr bool isNull() const noexcept
Definition: qrect.h:667
constexpr qreal top() const noexcept
Definition: qrect.h:525
constexpr void setHeight(qreal h) noexcept
Definition: qrect.h:830
constexpr qreal right() const noexcept
Definition: qrect.h:526
T * data() const noexcept
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition: qscreen.h:68
qreal physicalDotsPerInchY
the number of physical dots or pixels per inch in the vertical direction
Definition: qscreen.h:90
qreal physicalDotsPerInchX
the number of physical dots or pixels per inch in the horizontal direction
Definition: qscreen.h:88
The QScrollEvent class is sent when scrolling.
Definition: qevent.h:1085
@ ScrollFinished
Definition: qevent.h:1092
@ ScrollStarted
Definition: qevent.h:1090
@ ScrollUpdated
Definition: qevent.h:1091
The QScrollPrepareEvent class is sent in preparation of scrolling.
Definition: qevent.h:1058
QPointF contentPos() const
Definition: qevent.h:1070
QRectF contentPosRange() const
Definition: qevent.h:1069
QSizeF viewportSize() const
Definition: qevent.h:1068
The QScroller class enables kinetic scrolling for any scrolling widget or graphics item.
Definition: qscroller.h:62
void setSnapPositionsY(const QList< qreal > &positions)
Definition: qscroller.cpp:848
static QScroller * scroller(QObject *target)
Definition: qscroller.cpp:297
QPointF velocity() const
Definition: qscroller.cpp:598
static void ungrabGesture(QObject *target)
Definition: qscroller.cpp:456
static Qt::GestureType grabbedGesture(QObject *target)
Definition: qscroller.cpp:441
void setSnapPositionsX(const QList< qreal > &positions)
Definition: qscroller.cpp:817
@ InputRelease
Definition: qscroller.h:90
@ InputMove
Definition: qscroller.h:89
@ InputPress
Definition: qscroller.h:88
QPointF pixelPerMeter() const
Definition: qscroller.cpp:563
QPointF finalPosition() const
Definition: qscroller.cpp:639
friend class QFlickGestureRecognizer
Definition: qscroller.h:146
static QList< QScroller * > activeScrollers()
Definition: qscroller.cpp:326
static Qt::GestureType grabGesture(QObject *target, ScrollerGestureType gestureType=TouchGesture)
Definition: qscroller.cpp:397
bool handleInput(Input input, const QPointF &position, qint64 timestamp=0)
Definition: qscroller.cpp:978
void resendPrepareEvent()
Definition: qscroller.cpp:806
void scrollTo(const QPointF &pos)
Definition: qscroller.cpp:660
QScrollerProperties scrollerProperties
The scroller properties of this scroller. The properties are used by the QScroller to determine its s...
Definition: qscroller.h:66
State state
the state of the scroller
Definition: qscroller.h:64
void stop()
Definition: qscroller.cpp:535
QObject * target() const
Definition: qscroller.cpp:335
void ensureVisible(const QRectF &rect, qreal xmargin, qreal ymargin)
Definition: qscroller.cpp:723
void scrollerPropertiesChanged(const QScrollerProperties &)
@ Inactive
Definition: qscroller.h:71
@ Dragging
Definition: qscroller.h:73
@ Scrolling
Definition: qscroller.h:74
void setScrollerProperties(const QScrollerProperties &prop)
Definition: qscroller.cpp:361
ScrollerGestureType
Definition: qscroller.h:79
@ LeftMouseButtonGesture
Definition: qscroller.h:81
@ MiddleMouseButtonGesture
Definition: qscroller.h:83
@ RightMouseButtonGesture
Definition: qscroller.h:82
@ TouchGesture
Definition: qscroller.h:80
QPointF pixelPerMeter
Definition: qscroller_p.h:196
QRectF contentPosRange
Definition: qscroller_p.h:166
qreal scrollingSegmentsEndPos(Qt::Orientation orientation) const
Definition: qscroller.cpp:1134
QQueue< ScrollSegment > ySegments
Definition: qscroller_p.h:186
QScrollerProperties properties
Definition: qscroller_p.h:156
QPointF pressPosition
Definition: qscroller_p.h:178
bool moveWhilePressed(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1531
void setContentPositionHelperScrolling()
Definition: qscroller.cpp:1836
QList< qreal > snapPositionsY
Definition: qscroller_p.h:192
bool pressWhileInactive(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1503
void setState(QScroller::State s)
Definition: qscroller.cpp:1674
qreal nextSnapPos(qreal p, int dir, Qt::Orientation orientation) const
Definition: qscroller.cpp:1868
QScroller::State state
Definition: qscroller_p.h:173
bool pressWhileScrolling(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1654
QPointF contentPosition
Definition: qscroller_p.h:167
QPointF lastPosition
Definition: qscroller_p.h:179
void setDpi(const QPointF &dpi)
Definition: qscroller.cpp:1022
void recalcScrollingSegments(bool forceRecalc=false)
Definition: qscroller.cpp:1118
void setDpiFromWidget(QWidget *widget)
Definition: qscroller.cpp:1030
QPointF dragDistance
Definition: qscroller_p.h:183
bool scrollingSegmentsValid(Qt::Orientation orientation) const
Definition: qscroller.cpp:1152
QElapsedTimer monotonicTimer
Definition: qscroller_p.h:198
static const char * inputName(QScroller::Input input)
Definition: qscroller.cpp:921
qint64 lastTimestamp
Definition: qscroller_p.h:181
void createScrollingSegments(qreal v, qreal startPos, qreal deltaTime, qreal deltaPos, Qt::Orientation orientation)
Definition: qscroller.cpp:1220
void setContentPositionHelperDragging(const QPointF &deltaPos)
Definition: qscroller.cpp:1750
void targetDestroyed()
Definition: qscroller.cpp:931
void pushSegment(ScrollType type, qreal deltaTime, qreal stopProgress, qreal startPos, qreal deltaPos, qreal stopPos, QEasingCurve::Type curve, Qt::Orientation orientation)
Definition: qscroller.cpp:1082
QPointF dpi() const
Definition: qscroller.cpp:1011
QList< qreal > snapPositionsX
Definition: qscroller_p.h:189
QScroller * q_ptr
Definition: qscroller_p.h:205
bool moveWhileDragging(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1580
QQueue< ScrollSegment > xSegments
Definition: qscroller_p.h:185
void createScrollToSegments(qreal v, qreal deltaTime, qreal endPos, Qt::Orientation orientation, ScrollType type)
Definition: qscroller.cpp:1197
QPointF oldVelocity
Definition: qscroller_p.h:176
bool prepareScrolling(const QPointF &position)
Definition: qscroller.cpp:1398
QPointF releaseVelocity
Definition: qscroller_p.h:200
QPointF overshootPosition
Definition: qscroller_p.h:168
void handleDrag(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1450
void sendEvent(QObject *o, QEvent *e)
Definition: qscroller.cpp:905
bool releaseWhilePressed(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1520
void timerEventWhileScrolling()
Definition: qscroller.cpp:1645
void timerEventWhileDragging()
Definition: qscroller.cpp:1587
static qreal nextSegmentPosition(QQueue< ScrollSegment > &segments, qint64 now, qreal oldPos)
Definition: qscroller.cpp:1809
bool releaseWhileDragging(const QPointF &position, qint64 timestamp)
Definition: qscroller.cpp:1597
qint64 pressTimestamp
Definition: qscroller_p.h:180
void updateVelocity(const QPointF &deltaPixelRaw, qint64 deltaTime)
Definition: qscroller.cpp:1041
static const char * stateName(QScroller::State state)
Definition: qscroller.cpp:910
QScrollerPrivate(QScroller *q, QObject *target)
Definition: qscroller.cpp:877
The QScrollerProperties class stores the settings for a QScroller.
QScopedPointer< QScrollerPropertiesPrivate > d
The QSizeF class defines the size of a two-dimensional object using floating point precision.
Definition: qsize.h:235
constexpr qreal width() const noexcept
Definition: qsize.h:349
constexpr qreal height() const noexcept
Definition: qsize.h:352
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
bool operator<=(const QUuid &lhs, const QUuid &rhs)
Definition: quuid.h:216
bool operator>=(const QUuid &lhs, const QUuid &rhs)
Definition: quuid.h:218
The QVector2D class represents a vector or vertex in 2D space.
Definition: qvectornd.h:62
float length() const noexcept
Definition: qvectornd.h:565
QVector2D normalized() const noexcept
Definition: qvectornd.h:575
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:133
void setAttribute(Qt::WidgetAttribute, bool on=true)
Definition: qwidget.cpp:11088
void grabGesture(Qt::GestureType type, Qt::GestureFlags flags=Qt::GestureFlags())
Definition: qwidget.cpp:12249
void ungrabGesture(Qt::GestureType type)
Definition: qwidget.cpp:12262
QScreen * screen() const
Definition: qwidget.cpp:2508
#define this
Definition: dialogs.cpp:56
QOpenGLWidget * widget
[1]
QPixmap p2
QPixmap p1
[0]
QPushButton * button
[2]
qSwap(pi, e)
double e
set contains("Julia")
rect
[4]
else opt state
[0]
#define true
Definition: ftrandom.c:51
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option)
Definition: qnamespace.h:55
MouseButton
Definition: qnamespace.h:81
@ LeftButton
Definition: qnamespace.h:83
@ RightButton
Definition: qnamespace.h:84
@ MiddleButton
Definition: qnamespace.h:85
@ NoButton
Definition: qnamespace.h:82
@ WA_AcceptTouchEvents
Definition: qnamespace.h:429
Orientation
Definition: qnamespace.h:123
@ Horizontal
Definition: qnamespace.h:124
@ Vertical
Definition: qnamespace.h:125
GestureType
Definition: qnamespace.h:1641
default
Definition: devices.py:76
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
[3]
void
Definition: png.h:1080
#define Q_UNLIKELY(x)
EGLOutputLayerEXT EGLint EGLAttrib value
bool qIsNaN(qfloat16 f) noexcept
Definition: qfloat16.h:221
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
long long qint64
Definition: qglobal.h:298
#define QT_CONFIG(feature)
Definition: qglobal.h:107
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition: qlogging.h:179
int qFloor(T v)
Definition: qmath.h:78
int qCeil(T v)
Definition: qmath.h:72
#define Q_INFINITY
Definition: qnumeric.h:106
#define Q_QNAN
Definition: qnumeric.h:110
#define SLOT(a)
Definition: qobjectdefs.h:87
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLenum type
Definition: qopengl.h:270
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLdouble GLdouble right
GLfloat GLfloat f
GLint left
GLenum target
GLint first
GLint y
struct _cl_event * event
Definition: qopenglext.h:2998
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
GLuint segments
Definition: qopenglext.h:9598
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLfloat GLfloat GLfloat alpha
Definition: qopenglext.h:418
GLenum GLenum GLenum input
Definition: qopenglext.h:10816
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define qScrollerDebug
Definition: qscroller.cpp:78
QPointF clampToRect(const QPointF &p, const QRectF &rect)
Definition: qscroller.cpp:136
int qSign(qreal r)
Definition: qscroller.cpp:144
bool operator>(const QPointF &p, qreal f)
Definition: qscroller.cpp:113
QMap< QObject *, QScroller * > ScrollerHash
Definition: qscroller.cpp:274
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
QT_BEGIN_NAMESPACE bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
#define sp
#define tr(X)
#define emit
Definition: qtmetamacros.h:85
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition: qwidget.h:819
Q_UNUSED(salary)
[21]
QScreen * screen
[1]
Definition: main.cpp:76
QPropertyAnimation * animation
[0]
QObject::connect nullptr
QTime time
[5]
QString dir
[11]
QGraphicsScene scene
[0]
QSizePolicy policy
QAtomicInt iterations