aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2/qquickrangeslider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates2/qquickrangeslider.cpp')
-rw-r--r--src/quicktemplates2/qquickrangeslider.cpp352
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()