diff options
Diffstat (limited to 'src/quicktemplates2/qquickrangeslider.cpp')
-rw-r--r-- | src/quicktemplates2/qquickrangeslider.cpp | 352 |
1 files changed, 249 insertions, 103 deletions
diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp index 4e350ef2..a5c1d747 100644 --- a/src/quicktemplates2/qquickrangeslider.cpp +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -92,7 +92,8 @@ public: handle(nullptr), slider(slider), pressed(false), - hovered(false) + hovered(false), + touchId(-1) { } @@ -103,9 +104,6 @@ public: static QQuickRangeSliderNodePrivate *get(QQuickRangeSliderNode *node); -private: - friend class QQuickRangeSlider; - qreal value; bool isPendingValue; qreal pendingValue; @@ -114,6 +112,7 @@ private: QQuickRangeSlider *slider; bool pressed; bool hovered; + int touchId; }; bool QQuickRangeSliderNodePrivate::isFirst() const @@ -316,6 +315,7 @@ class QQuickRangeSliderPrivate : public QQuickControlPrivate public: QQuickRangeSliderPrivate() : + live(false), from(defaultFrom), to(defaultTo), stepSize(0), @@ -326,27 +326,25 @@ public: { } + QQuickRangeSliderNode *pressedNode(int touchId = -1) const; + void handlePress(const QPointF &point, int touchId = -1); + void handleMove(const QPointF &point, int touchId = -1); + void handleRelease(const QPointF &point, int touchId = -1); + void handleUngrab(); + void updateHover(const QPointF &pos); + bool live; qreal from; qreal to; qreal stepSize; QQuickRangeSliderNode *first; QQuickRangeSliderNode *second; - QPoint pressPoint; + QPointF pressPoint; Qt::Orientation orientation; QQuickRangeSlider::SnapMode snapMode; }; -void QQuickRangeSliderPrivate::updateHover(const QPointF &pos) -{ - Q_Q(QQuickRangeSlider); - QQuickItem *firstHandle = first->handle(); - QQuickItem *secondHandle = second->handle(); - first->setHovered(firstHandle && firstHandle->isEnabled() && firstHandle->contains(q->mapToItem(firstHandle, pos))); - second->setHovered(secondHandle && secondHandle->isEnabled() && secondHandle->contains(q->mapToItem(secondHandle, pos))); -} - static qreal valueAt(const QQuickRangeSlider *slider, qreal position) { return slider->from() + (slider->to() - slider->from()) * position; @@ -365,7 +363,7 @@ static qreal snapPosition(const QQuickRangeSlider *slider, qreal position) return qRound(position / effectiveStep) * effectiveStep; } -static qreal positionAt(const QQuickRangeSlider *slider, QQuickItem *handle, const QPoint &point) +static qreal positionAt(const QQuickRangeSlider *slider, QQuickItem *handle, const QPointF &point) { if (slider->orientation() == Qt::Horizontal) { const qreal hw = handle ? handle->width() : 0; @@ -386,6 +384,135 @@ static qreal positionAt(const QQuickRangeSlider *slider, QQuickItem *handle, con return 0; } +QQuickRangeSliderNode *QQuickRangeSliderPrivate::pressedNode(int touchId) const +{ + if (touchId == -1) + return first->isPressed() ? first : (second->isPressed() ? second : nullptr); + if (QQuickRangeSliderNodePrivate::get(first)->touchId == touchId) + return first; + if (QQuickRangeSliderNodePrivate::get(second)->touchId == touchId) + return second; + return nullptr; +} + +void QQuickRangeSliderPrivate::handlePress(const QPointF &point, int touchId) +{ + Q_Q(QQuickRangeSlider); + pressPoint = point; + + QQuickItem *firstHandle = first->handle(); + QQuickItem *secondHandle = second->handle(); + const bool firstHit = firstHandle && !first->isPressed() && firstHandle->contains(q->mapToItem(firstHandle, point)); + const bool secondHit = secondHandle && !second->isPressed() && secondHandle->contains(q->mapToItem(secondHandle, point)); + QQuickRangeSliderNode *hitNode = nullptr; + QQuickRangeSliderNode *otherNode = nullptr; + + if (firstHit && secondHit) { + // choose highest + hitNode = firstHandle->z() > secondHandle->z() ? first : second; + otherNode = firstHandle->z() > secondHandle->z() ? second : first; + } else if (firstHit) { + hitNode = first; + otherNode = second; + } else if (secondHit) { + hitNode = second; + otherNode = first; + } else { + // find the nearest + const qreal firstDistance = QLineF(firstHandle->boundingRect().center(), + q->mapToItem(firstHandle, point)).length(); + const qreal secondDistance = QLineF(secondHandle->boundingRect().center(), + q->mapToItem(secondHandle, point)).length(); + + if (qFuzzyCompare(firstDistance, secondDistance)) { + // same distance => choose the one that can be moved towards the press position + const bool inverted = from > to; + const qreal pos = positionAt(q, firstHandle, point); + if ((!inverted && pos < first->position()) || (inverted && pos > first->position())) { + hitNode = first; + otherNode = second; + } else { + hitNode = second; + otherNode = first; + } + } else if (firstDistance < secondDistance) { + hitNode = first; + otherNode = second; + } else { + hitNode = second; + otherNode = first; + } + } + + if (hitNode) { + hitNode->setPressed(true); + hitNode->handle()->setZ(1); + QQuickRangeSliderNodePrivate::get(hitNode)->touchId = touchId; + } + if (otherNode) + otherNode->handle()->setZ(0); +} + +void QQuickRangeSliderPrivate::handleMove(const QPointF &point, int touchId) +{ + Q_Q(QQuickRangeSlider); + if (!q->keepMouseGrab()) + return; + QQuickRangeSliderNode *pressedNode = QQuickRangeSliderPrivate::pressedNode(touchId); + if (pressedNode) { + qreal pos = positionAt(q, pressedNode->handle(), point); + if (snapMode == QQuickRangeSlider::SnapAlways) + pos = snapPosition(q, pos); + if (live) + pressedNode->setValue(valueAt(q, pos)); + else + QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); + } +} + +void QQuickRangeSliderPrivate::handleRelease(const QPointF &point, int touchId) +{ + Q_Q(QQuickRangeSlider); + pressPoint = QPointF(); + + QQuickRangeSliderNode *pressedNode = QQuickRangeSliderPrivate::pressedNode(touchId); + if (!pressedNode) + return; + QQuickRangeSliderNodePrivate *pressedNodePrivate = QQuickRangeSliderNodePrivate::get(pressedNode); + + if (q->keepMouseGrab()) { + qreal pos = positionAt(q, pressedNode->handle(), point); + if (snapMode != QQuickRangeSlider::NoSnap) + pos = snapPosition(q, pos); + qreal val = valueAt(q, pos); + if (!qFuzzyCompare(val, pressedNode->value())) + pressedNode->setValue(val); + else if (snapMode != QQuickRangeSlider::NoSnap) + pressedNodePrivate->setPosition(pos); + q->setKeepMouseGrab(false); + } + pressedNode->setPressed(false); + pressedNodePrivate->touchId = -1; +} + +void QQuickRangeSliderPrivate::handleUngrab() +{ + pressPoint = QPointF(); + first->setPressed(false); + second->setPressed(false); + QQuickRangeSliderNodePrivate::get(first)->touchId = -1; + QQuickRangeSliderNodePrivate::get(second)->touchId = -1; +} + +void QQuickRangeSliderPrivate::updateHover(const QPointF &pos) +{ + Q_Q(QQuickRangeSlider); + QQuickItem *firstHandle = first->handle(); + QQuickItem *secondHandle = second->handle(); + first->setHovered(firstHandle && firstHandle->isEnabled() && firstHandle->contains(q->mapToItem(firstHandle, pos))); + second->setHovered(secondHandle && secondHandle->isEnabled() && secondHandle->contains(q->mapToItem(secondHandle, pos))); +} + QQuickRangeSlider::QQuickRangeSlider(QQuickItem *parent) : QQuickControl(*(new QQuickRangeSliderPrivate), parent) { @@ -474,8 +601,10 @@ void QQuickRangeSlider::setTo(qreal to) If \l to is greater than \l from, the value of the first handle must be greater than the second, and vice versa. - Unlike \l {first.position}{position}, value is not updated while the - handle is dragged, but rather when it has been released. + Unlike \l {first.position}{position}, value is not updated by default + while the handle is dragged, but rather when it has been released. The + \l live property can be used to make the slider provide live updates + for value. The default value is \c 0.0. \row @@ -536,8 +665,10 @@ QQuickRangeSliderNode *QQuickRangeSlider::first() const If \l to is greater than \l from, the value of the first handle must be greater than the second, and vice versa. - Unlike \l {second.position}{position}, value is not updated while the - handle is dragged, but rather when it has been released. + Unlike \l {second.position}{position}, value is not updated by default + while the handle is dragged, but rather when it has been released. The + \l live property can be used to make the slider provide live updates + for value. The default value is \c 0.0. \row @@ -657,6 +788,33 @@ void QQuickRangeSlider::setOrientation(Qt::Orientation orientation) } /*! + \since QtQuick.Controls 2.2 + \qmlproperty bool QtQuick.Controls::RangeSlider::live + + This property holds whether the slider provides live updates for the \l first.value + and \l second.value properties while the respective handles are dragged. + + The default value is \c false. + + \sa first.value, second.value +*/ +bool QQuickRangeSlider::live() const +{ + Q_D(const QQuickRangeSlider); + return d->live; +} + +void QQuickRangeSlider::setLive(bool live) +{ + Q_D(QQuickRangeSlider); + if (d->live == live) + return; + + d->live = live; + emit liveChanged(); +} + +/*! \qmlmethod void QtQuick.Controls::RangeSlider::setValues(real firstValue, real secondValue) Sets \l first.value and \l second.value with the given arguments. @@ -804,58 +962,7 @@ void QQuickRangeSlider::mousePressEvent(QMouseEvent *event) { Q_D(QQuickRangeSlider); QQuickControl::mousePressEvent(event); - d->pressPoint = event->pos(); - - QQuickItem *firstHandle = d->first->handle(); - QQuickItem *secondHandle = d->second->handle(); - const bool firstHit = firstHandle && firstHandle->contains(mapToItem(firstHandle, d->pressPoint)); - const bool secondHit = secondHandle && secondHandle->contains(mapToItem(secondHandle, d->pressPoint)); - QQuickRangeSliderNode *hitNode = nullptr; - QQuickRangeSliderNode *otherNode = nullptr; - - if (firstHit && secondHit) { - // choose highest - hitNode = firstHandle->z() > secondHandle->z() ? d->first : d->second; - otherNode = firstHandle->z() > secondHandle->z() ? d->second : d->first; - } else if (firstHit) { - hitNode = d->first; - otherNode = d->second; - } else if (secondHit) { - hitNode = d->second; - otherNode = d->first; - } else { - // find the nearest - const qreal firstDistance = QLineF(firstHandle->boundingRect().center(), - mapToItem(firstHandle, event->pos())).length(); - const qreal secondDistance = QLineF(secondHandle->boundingRect().center(), - mapToItem(secondHandle, event->pos())).length(); - - if (qFuzzyCompare(firstDistance, secondDistance)) { - // same distance => choose the one that can be moved towards the press position - const bool inverted = d->from > d->to; - const qreal pos = positionAt(this, firstHandle, event->pos()); - if ((!inverted && pos < d->first->position()) || (inverted && pos > d->first->position())) { - hitNode = d->first; - otherNode = d->second; - } else { - hitNode = d->second; - otherNode = d->first; - } - } else if (firstDistance < secondDistance) { - hitNode = d->first; - otherNode = d->second; - } else { - hitNode = d->second; - otherNode = d->first; - } - } - - if (hitNode) { - hitNode->setPressed(true); - hitNode->handle()->setZ(1); - } - if (otherNode) - otherNode->handle()->setZ(0); + d->handlePress(event->localPos()); } void QQuickRangeSlider::mouseMoveEvent(QMouseEvent *event) @@ -864,53 +971,92 @@ void QQuickRangeSlider::mouseMoveEvent(QMouseEvent *event) QQuickControl::mouseMoveEvent(event); if (!keepMouseGrab()) { if (d->orientation == Qt::Horizontal) - setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().x() - d->pressPoint.x(), Qt::XAxis, event)); + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->localPos().x() - d->pressPoint.x(), Qt::XAxis, event)); else - setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->pos().y() - d->pressPoint.y(), Qt::YAxis, event)); - } - if (keepMouseGrab()) { - QQuickRangeSliderNode *pressedNode = d->first->isPressed() ? d->first : (d->second->isPressed() ? d->second : nullptr); - if (pressedNode) { - qreal pos = positionAt(this, pressedNode->handle(), event->pos()); - if (d->snapMode == SnapAlways) - pos = snapPosition(this, pos); - QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); - } + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(event->localPos().y() - d->pressPoint.y(), Qt::YAxis, event)); } + d->handleMove(event->localPos()); } void QQuickRangeSlider::mouseReleaseEvent(QMouseEvent *event) { Q_D(QQuickRangeSlider); QQuickControl::mouseReleaseEvent(event); + d->handleRelease(event->localPos()); +} - d->pressPoint = QPoint(); - if (!keepMouseGrab()) - return; +void QQuickRangeSlider::mouseUngrabEvent() +{ + Q_D(QQuickRangeSlider); + QQuickControl::mouseUngrabEvent(); + d->handleUngrab(); +} - QQuickRangeSliderNode *pressedNode = d->first->isPressed() ? d->first : (d->second->isPressed() ? d->second : nullptr); - if (!pressedNode) - return; +void QQuickRangeSlider::touchEvent(QTouchEvent *event) +{ + Q_D(QQuickRangeSlider); + switch (event->type()) { + case QEvent::TouchBegin: + if (!d->first->isPressed() || !d->second->isPressed()) { + const QTouchEvent::TouchPoint point = event->touchPoints().first(); + d->handlePress(point.pos(), point.id()); + } else { + event->ignore(); + } + break; + + case QEvent::TouchUpdate: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + switch (point.state()) { + case Qt::TouchPointPressed: + if (!d->first->isPressed() || !d->second->isPressed()) + d->handlePress(point.pos(), point.id()); + break; + case Qt::TouchPointMoved: + if (!keepMouseGrab()) { + if (d->orientation == Qt::Horizontal) + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(point.pos().x() - point.startPos().x(), Qt::XAxis, &point)); + else + setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(point.pos().y() - point.startPos().y(), Qt::YAxis, &point)); + } + if (point.id() == QQuickRangeSliderNodePrivate::get(d->first)->touchId + || point.id() == QQuickRangeSliderNodePrivate::get(d->second)->touchId) + d->handleMove(point.pos(), point.id()); + break; + case Qt::TouchPointReleased: + if (point.id() == QQuickRangeSliderNodePrivate::get(d->first)->touchId + || point.id() == QQuickRangeSliderNodePrivate::get(d->second)->touchId) + d->handleRelease(point.pos(), point.id()); + break; + default: + break; + } + } + break; - qreal pos = positionAt(this, pressedNode->handle(), event->pos()); - if (d->snapMode != NoSnap) - pos = snapPosition(this, pos); - qreal val = valueAt(this, pos); - if (!qFuzzyCompare(val, pressedNode->value())) - pressedNode->setValue(val); - else if (d->snapMode != NoSnap) - QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); - setKeepMouseGrab(false); - pressedNode->setPressed(false); + case QEvent::TouchEnd: + for (const QTouchEvent::TouchPoint &point : event->touchPoints()) { + if (point.id() == QQuickRangeSliderNodePrivate::get(d->first)->touchId + || point.id() == QQuickRangeSliderNodePrivate::get(d->second)->touchId) + d->handleRelease(point.pos(), point.id()); + } + break; + + case QEvent::TouchCancel: + d->handleUngrab(); + break; + + default: + QQuickControl::touchEvent(event); + break; + } } -void QQuickRangeSlider::mouseUngrabEvent() +void QQuickRangeSlider::touchUngrabEvent() { Q_D(QQuickRangeSlider); - QQuickControl::mouseUngrabEvent(); - d->pressPoint = QPoint(); - d->first->setPressed(false); - d->second->setPressed(false); + QQuickControl::touchUngrabEvent(); + d->handleUngrab(); } void QQuickRangeSlider::mirrorChange() |