7#include "private/qflickgesture_p.h"
8#include "private/qscroller_p.h"
10#include "private/qscrollerproperties_p.h"
15#include <QElapsedTimer>
17#include <QApplication>
18#include <QAbstractScrollArea>
19#if QT_CONFIG(graphicsview)
20#include <QGraphicsObject>
21#include <QGraphicsScene>
22#include <QGraphicsView>
25#include <QtCore/qmath.h>
26#include <QtGui/qevent.h>
30#include <QtCore/qloggingcategory.h>
42 dbg <<
"\n Time: start:" <<
s.startTime <<
" duration:" <<
s.deltaTime <<
" stop progress:" <<
s.stopProgress;
43 dbg <<
"\n Pos: start:" <<
s.startPos <<
" delta:" <<
s.deltaPos <<
" stop:" <<
s.stopPos;
44 dbg <<
"\n Curve: type:" <<
s.curve.type() <<
"\n";
105 return (
r < 0) ? -1 : ((
r > 0) ? 1 : 0);
113 const qreal dx = 0.01;
118 qCDebug(lcScroller) <<
"differentialForProgress(type: " << curve.
type()
119 <<
", pos: " <<
pos <<
") = " <<
d;
131 qWarning(
"progressForValue(): QEasingCurves of type %d do not have an "
132 "inverse, since they are not injective.", curve.
type());
139 for (
int iterations = 6; iterations; --iterations) {
153#if QT_CONFIG(animation)
172 ignoreUpdate =
false;
180 if (++skip >=
d->frameRateSkip()) {
258 qWarning(
"QScroller::scroller() was called with a null target.");
263 return qt_allScrollers()->value(
target);
266 qt_allScrollers()->insert(
target,
s);
286 return *qt_activeScrollers();
316 return d->properties;
322 if (
d->properties !=
sp) {
328 d->recalcScrollingSegments(
true);
332#ifndef QT_NO_GESTURES
367 switch (scrollGestureType) {
378 if (
target->isWidgetType()) {
383#if QT_CONFIG(graphicsview)
386 go->setAcceptTouchEvents(
true);
387 go->grabGesture(
sp->recognizerType);
390 return sp->recognizerType;
403 return s->d_ptr->recognizerType;
424 if (
target->isWidgetType()) {
427#if QT_CONFIG(graphicsview)
429 go->ungrabGesture(
sp->recognizerType);
435 sp->recognizer =
nullptr;
458#ifndef QT_NO_GESTURES
461 d->recognizer =
nullptr;
463 qt_allScrollers()->remove(
d->target);
464 qt_activeScrollers()->removeOne(
this);
505 d->contentPosition = snap;
506 d->overshootPosition =
QPointF(0, 0);
526#if QT_CONFIG(graphicsview)
530 if (
const auto *
scene = go->scene()) {
532 if (!views.isEmpty())
533 viewtr = views.first()->viewportTransform();
536 if (
tr.isScaling()) {
563 return d->releaseVelocity;
568 if (!
d->xSegments.isEmpty()) {
572 *
sp->decelerationFactor *
qreal(0.5)
577 if (!
d->ySegments.isEmpty()) {
581 *
sp->decelerationFactor *
qreal(0.5)
651 qCDebug(lcScroller) <<
"QScroller::scrollTo(req:" <<
pos <<
" [pix] / snap:"
652 << newpos <<
", " << scrollTime <<
" [ms])";
654 if (newpos ==
d->contentPosition +
d->overshootPosition)
667 d->setContentPositionHelperScrolling();
711 rect.width() + 2 * xmargin,
rect.height() + 2 * ymargin);
713 QSizeF visible =
d->viewportSize;
714 QRectF visibleRect(startPos, visible);
716 qCDebug(lcScroller) <<
"QScroller::ensureVisible(" <<
rect <<
" [pix], " << xmargin
717 <<
" [pix], " << ymargin <<
" [pix], " << scrollTime <<
"[ms])";
718 qCDebug(lcScroller) <<
" --> content position:" <<
d->contentPosition;
720 if (visibleRect.
contains(marginRect))
725 if (visibleRect.
width() <
rect.width()) {
727 if (
rect.left() > visibleRect.
left())
729 else if (
rect.right() < visibleRect.
right())
732 }
else if (visibleRect.
width() < marginRect.
width()) {
734 }
else if (marginRect.
left() > visibleRect.
left()) {
736 }
else if (marginRect.
right() < visibleRect.
right()) {
742 if (
rect.top() > visibleRect.
top())
744 else if (
rect.bottom() < visibleRect.
bottom())
747 }
else if (visibleRect.
height() < marginRect.
height()) {
749 }
else if (marginRect.
top() > visibleRect.
top()) {
751 }
else if (marginRect.
bottom() < visibleRect.
bottom()) {
757 if (newPos == startPos)
773 d->prepareScrolling(
d->pressPosition);
785 d->snapIntervalX = 0.0;
787 d->recalcScrollingSegments();
801 d->snapIntervalX = interval;
802 d->snapPositionsX.clear();
804 d->recalcScrollingSegments();
816 d->snapIntervalY = 0.0;
818 d->recalcScrollingSegments();
831 d->snapIntervalY = interval;
832 d->snapPositionsY.clear();
834 d->recalcScrollingSegments();
843#ifndef QT_NO_GESTURES
845 , recognizerType(
Qt::CustomGesture)
856 , scrollTimer(new QScrollTimer(
this))
881 default:
return "(invalid)";
891 default:
return "(invalid)";
897#if QT_CONFIG(animation)
908 timerhandler_t handler;
911 timerevent timerevents[] = {
916 for (
int i = 0;
i < int(
sizeof(timerevents) /
sizeof(*timerevents)); ++
i) {
917 timerevent *te = timerevents +
i;
919 if (
state == te->state) {
920 (this->*te->handler)();
925#if QT_CONFIG(animation)
946 qCDebug(lcScroller) <<
"QScroller::handleInput(" <<
input <<
", " <<
d->stateName(
d->state)
947 <<
", " <<
position <<
", " << timestamp <<
')';
952 inputhandler_t handler;
955 statechange statechanges[] = {
964 for (
int i = 0;
i < int(
sizeof(statechanges) /
sizeof(*statechanges)); ++
i) {
965 statechange *sc = statechanges +
i;
967 if (
d->state == sc->state &&
input == sc->input)
968 return (
d->*sc->handler)(
position -
d->overshootPosition, timestamp);
1014 QPointF deltaPixel = deltaPixelRaw;
1016 qCDebug(lcScroller) <<
"QScroller::updateVelocity(" << deltaPixelRaw
1017 <<
" [delta pix], " << deltaTime <<
" [delta ms])";
1020 if (((deltaPixelRaw /
qreal(deltaTime)).manhattanLength() / ((ppm.
x() + ppm.
y()) / 2) * 1000) >
qreal(2.5))
1021 deltaPixel = deltaPixelRaw *
qreal(2.5) * ppm / 1000 / (deltaPixelRaw /
qreal(deltaTime)).manhattanLength();
1032 qCDebug(lcScroller) <<
"SMOOTHED from " << newv <<
" to "
1041 qCDebug(lcScroller) <<
"NO SMOOTHING to " << newv;
1053 if (startPos == stopPos || deltaPos == 0)
1058 const auto &lastX =
xSegments.constLast();
1059 s.startTime = lastX.startTime + lastX.deltaTime * lastX.stopProgress;
1061 const auto &lastY =
ySegments.constLast();
1062 s.startTime = lastY.startTime + lastY.deltaTime * lastY.stopProgress;
1067 s.startPos = startPos;
1068 s.deltaPos = deltaPos;
1069 s.stopPos = stopPos;
1070 s.deltaTime = deltaTime * 1000;
1071 s.stopProgress = stopProgress;
1072 s.curve.setType(curve);
1080 qCDebug(lcScroller) <<
"+++ Added a new ScrollSegment: " <<
s;
1147 (stopPos != minPos && stopPos != maxPos))
1150 if (stopPos < minPos || stopPos > maxPos)
1153 if (stopPos == minPos || stopPos == maxPos)
1157 if (!
qIsNaN(nextSnap) && stopPos != nextSnap)
1176 qCDebug(lcScroller) <<
"+++ createScrollToSegments: t:" << deltaTime <<
"ep:"
1177 << endPos <<
"o:" << int(orientation);
1183 qreal deltaPos = (endPos - startPos) / 2;
1188 sp->scrollingCurve.type(), orientation);
1220 bool canOvershoot = !noOvershoot && (alwaysOvershoot || maxPos);
1222 qCDebug(lcScroller) <<
"+++ createScrollingSegments: s:" << startPos <<
"maxPos:" << maxPos
1223 <<
"o:" << int(orientation);
1225 qCDebug(lcScroller) <<
"v = " <<
v <<
", decelerationFactor = " <<
sp->decelerationFactor
1226 <<
", curveType = " <<
sp->scrollingCurve.type();
1228 qreal endPos = startPos + deltaPos;
1230 qCDebug(lcScroller) <<
" Real Delta:" << deltaPos;
1233 if ((startPos < minPos && endPos < minPos) ||
1234 (startPos > maxPos && endPos > maxPos)) {
1235 qreal stopPos = endPos < minPos ? minPos : maxPos;
1236 qreal oDeltaTime =
sp->overshootScrollTime;
1239 stopPos - startPos, stopPos,
sp->scrollingCurve.type(), orientation);
1248 qCDebug(lcScroller) <<
" Real Delta:" << lowerSnapPos <<
'-' << nextSnap <<
'-' <<higherSnapPos;
1251 if (nextSnap > higherSnapPos ||
qIsNaN(higherSnapPos))
1252 higherSnapPos = nextSnap;
1253 if (nextSnap < lowerSnapPos ||
qIsNaN(lowerSnapPos))
1254 lowerSnapPos = nextSnap;
1256 if (
qAbs(
v) <
sp->minimumVelocity) {
1258 qCDebug(lcScroller) <<
"### below minimum Vel" << orientation;
1261 if (
qIsNaN(nextSnap) || nextSnap == startPos)
1266 qreal snapDistance = higherSnapPos - lowerSnapPos;
1273 if (
sp->snapPositionRatio == 0.0 ||
qAbs(pressDistance /
sp->snapPositionRatio) > snapDistance)
1275 else if (pressDistance < 0.0)
1276 endPos = lowerSnapPos;
1278 endPos = higherSnapPos;
1280 deltaPos = endPos - startPos;
1281 qreal midPos = startPos + deltaPos *
qreal(0.3);
1285 endPos - midPos, endPos,
sp->scrollingCurve.type(), orientation);
1290 if (
v > 0 && !
qIsNaN(higherSnapPos)) {
1292 if (endPos - startPos)
1293 deltaTime *=
qAbs((higherSnapPos - startPos) / (endPos - startPos));
1294 if (deltaTime >
sp->snapTime)
1295 deltaTime =
sp->snapTime;
1296 endPos = higherSnapPos;
1298 }
else if (
v < 0 && !
qIsNaN(lowerSnapPos)) {
1300 if (endPos - startPos)
1301 deltaTime *=
qAbs((lowerSnapPos - startPos) / (endPos - startPos));
1302 if (deltaTime >
sp->snapTime)
1303 deltaTime =
sp->snapTime;
1304 endPos = lowerSnapPos;
1307 }
else if (endPos < minPos || endPos > maxPos) {
1308 qreal stopPos = endPos < minPos ? minPos : maxPos;
1310 qCDebug(lcScroller) <<
"Overshoot: delta:" << (stopPos - startPos);
1314 if (!canOvershoot) {
1315 qCDebug(lcScroller) <<
"Overshoot stopp:" << stopProgress;
1318 sp->scrollingCurve.type(), orientation);
1320 qreal oDeltaTime =
sp->overshootScrollTime;
1322 qreal oDistance = startPos + deltaPos *
sp->scrollingCurve.valueForProgress(oStopProgress) - stopPos;
1323 qreal oMaxDistance =
qSign(oDistance) * (viewSize *
sp->overshootScrollDistanceFactor);
1325 qCDebug(lcScroller) <<
"1 oDistance:" << oDistance <<
"Max:" << oMaxDistance
1326 <<
"stopP/oStopP" << stopProgress << oStopProgress;
1328 if (
qAbs(oDistance) >
qAbs(oMaxDistance)) {
1330 qAbs((stopPos + oMaxDistance - startPos) / deltaPos));
1331 oDistance = oMaxDistance;
1332 qCDebug(lcScroller) <<
"2 oDistance:" << oDistance <<
"Max:" << oMaxDistance
1333 <<
"stopP/oStopP" << stopProgress << oStopProgress;
1337 stopPos + oDistance,
sp->scrollingCurve.type(), orientation);
1339 stopPos + oDistance, -oDistance, stopPos,
sp->scrollingCurve.type(),
1346 sp->scrollingCurve.type(), orientation);
1374 * deltaTime * deltaTime *
qreal(0.5) *
sp->decelerationFactor;
1408 if (contentDelta !=
QPointF(0, 0)) {
1419#if QT_CONFIG(graphicsview)
1422 if (
const auto *
scene = go->scene()) {
1424 if (!views.isEmpty())
1446 if (
sp->axisLockThreshold) {
1447 int dx =
qAbs(deltaPixel.
x());
1448 int dy =
qAbs(deltaPixel.
y());
1450 bool vertical = (dy > dx);
1452 qCDebug(lcScroller) <<
"QScroller::handleDrag() -- axis lock:" <<
alpha <<
" / " <<
sp->axisLockThreshold
1453 <<
"- isvertical:" << vertical <<
"- dx:" << dx <<
"- dy:" << dy;
1454 if (alpha <= sp->axisLockThreshold) {
1521 bool moveAborted =
false;
1522 bool moveStarted = (((deltaPixel / ppm).manhattanLength()) >
sp->dragStartDistance);
1527 bool canScrollX = (max.
width() > 0);
1528 bool canScrollY = (max.
height() > 0);
1535 if (
qAbs(deltaPixel.
x() / ppm.
x()) <
qAbs(deltaPixel.
y() / ppm.
y())) {
1546 moveStarted =
false;
1548 }
else if (moveStarted) {
1552 deltaPixel = deltaPixel - deltaPixel * (
sp->dragStartDistance / deltaPixel.
manhattanLength());
1554 if (deltaPixel !=
QPointF(0, 0)) {
1572 qCDebug(lcScroller) <<
"QScroller::timerEventWhileDragging() -- dragDistance:" <<
dragDistance;
1590 if (((deltaPixel /
q->pixelPerMeter()).manhattanLength()) >
sp->dragStartDistance) {
1597 int signX = 0, signY = 0;
1606 sp->maximumVelocity));
1610 sp->maximumVelocity));
1630 qCDebug(lcScroller) <<
"QScroller::timerEventWhileScrolling()";
1660 bool sendLastScroll =
false;
1662 if (
state == newstate)
1665 qCDebug(lcScroller) <<
q <<
"QScroller::setState(" <<
stateName(newstate) <<
')';
1669#if QT_CONFIG(animation)
1670 scrollTimer->stop();
1675 sendLastScroll =
true;
1681#if QT_CONFIG(animation)
1682 scrollTimer->stop();
1691#if QT_CONFIG(animation)
1693 scrollTimer->start();
1698#if QT_CONFIG(animation)
1699 scrollTimer->start();
1706 if (sendLastScroll) {
1713 qt_activeScrollers()->push_back(
q);
1715 qt_activeScrollers()->removeOne(
q);
1737 if (
sp->overshootDragResistanceFactor)
1741 QPointF newPos = oldPos + deltaPos;
1743 qCDebug(lcScroller) <<
"QScroller::setContentPositionHelperDragging(" << deltaPos <<
" [pix])";
1753 !
sp->overshootDragDistanceFactor;
1756 !
sp->overshootDragDistanceFactor;
1760 qreal newOvershootX = (canOvershootX) ? newPos.
x() - newClampedPos.
x() : 0;
1761 qreal newOvershootY = (canOvershootY) ? newPos.
y() - newClampedPos.
y() : 0;
1766 qCDebug(lcScroller) <<
" --> noOs:" << noOvershootX <<
"drf:" <<
sp->overshootDragResistanceFactor
1767 <<
"mdf:" <<
sp->overshootScrollDistanceFactor <<
"ossP:"<<
sp->hOvershootPolicy;
1768 qCDebug(lcScroller) <<
" --> canOS:" << canOvershootX <<
"newOS:" << newOvershootX <<
"maxOS:" << maxOvershootX;
1770 if (
sp->overshootDragResistanceFactor) {
1771 newOvershootX *=
sp->overshootDragResistanceFactor;
1772 newOvershootY *=
sp->overshootDragResistanceFactor;
1777 newOvershootX =
qBound(-maxOvershootX, newOvershootX, maxOvershootX);
1778 newOvershootY =
qBound(-maxOvershootY, newOvershootY, maxOvershootY);
1788 qCDebug(lcScroller) <<
" --> new position:" << newClampedPos <<
"- new overshoot:"
1801 if ((
s.startTime +
s.deltaTime *
s.stopProgress) <=
now) {
1804 }
else if (
s.startTime <=
now) {
1806 pos =
s.startPos +
s.deltaPos *
s.curve.valueForProgress(progress);
1807 if (
s.deltaPos > 0 ?
pos >
s.stopPos :
pos <
s.stopPos) {
1829 qCDebug(lcScroller) <<
"QScroller::setContentPositionHelperScrolling()\n"
1872 qreal snapPosDist = snapPos -
p;
1873 if ((
dir > 0 && snapPosDist < 0) ||
1874 (dir < 0 && snapPosDist > 0))
1876 if (snapPos < minPos || snapPos > maxPos )
1879 if (
qIsNaN(bestSnapPos) ||
1880 qAbs(snapPosDist) < bestSnapPosDist ) {
1881 bestSnapPos = snapPos;
1882 bestSnapPosDist =
qAbs(snapPosDist);
1905 if (snapPos >=
first && snapPos <= maxPos ) {
1906 qreal snapPosDist = snapPos -
p;
1908 if (
qIsNaN(bestSnapPos) ||
1909 qAbs(snapPosDist) < bestSnapPosDist ) {
1910 bestSnapPos = snapPos;
1911 bestSnapPosDist =
qAbs(snapPosDist);
1919 qreal snapPosDist = snapPos -
p;
1920 if ((
dir > 0 && snapPosDist < 0) ||
1921 (dir < 0 && snapPosDist > 0))
1923 if (snapPos < minPos || snapPos > maxPos )
1926 if (
qIsNaN(bestSnapPos) ||
1927 qAbs(snapPosDist) < bestSnapPosDist) {
1928 bestSnapPos = snapPos;
1929 bestSnapPosDist =
qAbs(snapPosDist);
1952 if (snapPos >=
first && snapPos <= maxPos ) {
1953 qreal snapPosDist = snapPos -
p;
1955 if (
qIsNaN(bestSnapPos) ||
1956 qAbs(snapPosDist) < bestSnapPosDist) {
1957 bestSnapPos = snapPos;
1958 bestSnapPosDist =
qAbs(snapPosDist);
2010#include "moc_qscroller.cpp"
2011#include "moc_qscroller_p.cpp"
virtual void updateCurrentTime(int currentTime)=0
This pure virtual function is called every time the animation's currentTime changes.
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
Starts the animation.
int duration
the duration of the animation.
Type type() const
Returns the type of the easing curve.
Type
The type of easing curve.
qreal valueForProgress(qreal progress) const
Return the effective progress for the easing curve at progress.
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
void start() noexcept
Starts this timer.
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
static void unregisterRecognizer(Qt::GestureType type)
Unregisters all gesture recognizers of the specified type.
static Qt::GestureType registerRecognizer(QGestureRecognizer *recognizer)
Registers the given recognizer in the gesture framework and returns a gesture ID for it.
The QGraphicsObject class provides a base class for all graphics items that require signals,...
QList< QGraphicsView * > views() const
Returns a list of all the views that display this scene.
QScreen * primaryScreen
the primary (or default) screen of the application.
qreal length() const
Returns the length of the line.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void setParent(QObject *parent)
Makes the object a child of parent.
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\inmodule QtCore\reentrant
constexpr qreal & ry() noexcept
Returns a reference to the y coordinate of this point.
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal manhattanLength() const
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
constexpr qreal & rx() noexcept
Returns a reference to the x coordinate of this point.
constexpr void setY(qreal y) noexcept
Sets the y coordinate of this point to the given finite y coordinate.
constexpr void setX(qreal x) noexcept
Sets the x coordinate of this point to the given finite x coordinate.
\inmodule QtCore\reentrant
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr qreal height() const noexcept
Returns the height of the rectangle.
constexpr qreal width() const noexcept
Returns the width of the rectangle.
bool contains(const QRectF &r) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr void setWidth(qreal w) noexcept
Sets the width of the rectangle to the given finite width.
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr void setHeight(qreal h) noexcept
Sets the height of the rectangle to the given finite height.
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
The QScreen class is used to query screen properties. \inmodule QtGui.
qreal physicalDotsPerInchY
the number of physical dots or pixels per inch in the vertical direction
qreal physicalDotsPerInchX
the number of physical dots or pixels per inch in the horizontal direction
constexpr qreal width() const noexcept
Returns the width.
constexpr qreal height() const noexcept
Returns the height.
The QVector2D class represents a vector or vertex in 2D space.
float length() const noexcept
Returns the length of the vector from the origin.
QVector2D normalized() const noexcept
Returns the normalized unit vector form of this vector.
Combined button and popup list for selecting options.
static const QCssKnownValue positions[NumKnownPositionModes - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qIsNaN(qfloat16 f) noexcept
int qRound(qfloat16 d) noexcept
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr T qAbs(const T &t)
static bool contains(const QJsonArray &haystack, unsigned needle)
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLdouble GLdouble GLdouble GLdouble q
GLfloat GLfloat GLfloat alpha
GLenum GLenum GLenum input
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define QT_CONFIG(feature)
if(qFloatDistance(a, b)<(1<< 7))
[0]