aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates/qquickselectionrectangle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates/qquickselectionrectangle.cpp')
-rw-r--r--src/quicktemplates/qquickselectionrectangle.cpp157
1 files changed, 123 insertions, 34 deletions
diff --git a/src/quicktemplates/qquickselectionrectangle.cpp b/src/quicktemplates/qquickselectionrectangle.cpp
index a2adc43dcd..1bf04b7094 100644
--- a/src/quicktemplates/qquickselectionrectangle.cpp
+++ b/src/quicktemplates/qquickselectionrectangle.cpp
@@ -81,7 +81,7 @@ QT_BEGIN_NAMESPACE
The handle is not hidden by default when a selection is removed.
Instead, this is the responsibility of the delegate, to open up for
custom fade-out animations. The easiest way to ensure that the handle
- ends up hidden, is to simply bind \l visible to the the \l active
+ ends up hidden, is to simply bind \l {Item::}{visible} to the \l active
state of the SelectionRectangle:
\qml
@@ -109,7 +109,7 @@ QT_BEGIN_NAMESPACE
The handle is not hidden by default when a selection is removed.
Instead, this is the responsibility of the delegate, to open up for
custom fade-out animations. The easiest way to ensure that the handle
- ends up hidden, is to simply bind \l visible to the the \l active
+ ends up hidden, is to simply bind \l {Item::}{visible} to the \l active
state of the SelectionRectangle:
\qml
@@ -144,14 +144,14 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlattachedproperty SelectionRectangle QtQuick::SelectionRectangle::control
+ \qmlattachedproperty SelectionRectangle QtQuick.Controls::SelectionRectangle::control
This attached property holds the SelectionRectangle that manages the delegate instance.
It is attached to each handle instance.
*/
/*!
- \qmlattachedproperty bool QtQuick::SelectionRectangle::dragging
+ \qmlattachedproperty bool QtQuick.Controls::SelectionRectangle::dragging
This attached property will be \c true if the user is dragging on the handle.
It is attached to each handle instance.
@@ -170,56 +170,118 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
else
m_selectable->setSelectionEndPos(m_scrollToPoint);
updateHandles();
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
m_scrollToPoint.rx() += dist.width() > 0 ? m_scrollSpeed.width() : -m_scrollSpeed.width();
m_scrollToPoint.ry() += dist.height() > 0 ? m_scrollSpeed.height() : -m_scrollSpeed.height();
m_scrollSpeed = QSizeF(qAbs(dist.width() * 0.007), qAbs(dist.height() * 0.007));
});
- QObject::connect(m_tapHandler, &QQuickTapHandler::tapped, [this] {
- updateActiveState(false);
- });
+ QObject::connect(m_tapHandler, &QQuickTapHandler::pressedChanged, [this]() {
+ if (!m_tapHandler->isPressed())
+ return;
+ if (m_effectiveSelectionMode != QQuickSelectionRectangle::Drag)
+ return;
- QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [this]() {
const QPointF pos = m_tapHandler->point().pressPosition();
const auto modifiers = m_tapHandler->point().modifiers();
+ if (modifiers & ~(Qt::ControlModifier | Qt::ShiftModifier))
+ return;
+
+ if (modifiers & Qt::ShiftModifier) {
+ // Extend the selection towards the pressed cell. If there is no
+ // existing selection, start a new selection from the current item
+ // to the pressed item.
+ if (!m_active) {
+ if (!m_selectable->startSelection(pos, modifiers))
+ return;
+ m_selectable->setSelectionStartPos(QPoint{-1, -1});
+ }
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ } else if (modifiers & Qt::ControlModifier) {
+ // Select a single cell, but keep the old selection (unless
+ // m_selectable->startSelection(pos. modifiers) returns false, which
+ // it will if selectionMode only allows a single selection).
+ if (handleUnderPos(pos) != nullptr) {
+ // Don't allow press'n'hold to start a new
+ // selection if it started on top of a handle.
+ return;
+ }
+
+ if (!m_selectable->startSelection(pos, modifiers))
+ return;
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ }
+ });
- if (!m_selectable->startSelection(pos))
+ QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [this]() {
+ if (m_effectiveSelectionMode != QQuickSelectionRectangle::PressAndHold)
return;
+
+ const QPointF pos = m_tapHandler->point().pressPosition();
+ const auto modifiers = m_tapHandler->point().modifiers();
if (handleUnderPos(pos) != nullptr) {
// Don't allow press'n'hold to start a new
// selection if it started on top of a handle.
return;
}
- if (!m_alwaysAcceptPressAndHold) {
- if (m_selectionMode == QQuickSelectionRectangle::Auto) {
- // In Auto mode, we only accept press and hold from touch
- if (m_tapHandler->point().device()->pointerType() != QPointingDevice::PointerType::Finger)
+
+ if (modifiers == Qt::ShiftModifier) {
+ // Extend the selection towards the pressed cell. If there is no
+ // existing selection, start a new selection from the current item
+ // to the pressed item.
+ if (!m_active) {
+ if (!m_selectable->startSelection(pos, modifiers))
return;
- } else if (m_selectionMode != QQuickSelectionRectangle::PressAndHold) {
- return;
+ m_selectable->setSelectionStartPos(QPoint{-1, -1});
}
- }
-
- if (!modifiers.testFlag(Qt::ShiftModifier))
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ } else if (modifiers == Qt::ControlModifier) {
+ // Select a single cell, but keep the old selection (unless
+ // m_selectable->startSelection(pos, modifiers) returns false, which
+ // it will if selectionMode only allows a single selection).
+ if (!m_selectable->startSelection(pos, modifiers))
+ return;
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ } else if (modifiers == Qt::NoModifier) {
+ // Select a single cell
m_selectable->clearSelection();
- m_selectable->setSelectionStartPos(pos);
- m_selectable->setSelectionEndPos(pos);
- updateHandles();
- updateActiveState(true);
+ if (!m_selectable->startSelection(pos, modifiers))
+ return;
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ }
});
QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [this]() {
+ Q_ASSERT(m_effectiveSelectionMode == QQuickSelectionRectangle::Drag);
const QPointF startPos = m_dragHandler->centroid().pressPosition();
const QPointF dragPos = m_dragHandler->centroid().position();
const auto modifiers = m_dragHandler->centroid().modifiers();
+ if (modifiers & ~(Qt::ControlModifier | Qt::ShiftModifier))
+ return;
if (m_dragHandler->active()) {
- if (!m_selectable->startSelection(startPos))
- return;
- if (!modifiers.testFlag(Qt::ShiftModifier))
- m_selectable->clearSelection();
- m_selectable->setSelectionStartPos(startPos);
+ // Start a new selection unless there is an active selection
+ // already, and one of the relevant modifiers are being held.
+ // In that case we continue to extend the active selection instead.
+ const bool modifiersHeld = modifiers & (Qt::ControlModifier | Qt::ShiftModifier);
+ if (!m_active || !modifiersHeld) {
+ if (!m_selectable->startSelection(startPos, modifiers))
+ return;
+ m_selectable->setSelectionStartPos(startPos);
+ }
m_selectable->setSelectionEndPos(dragPos);
m_draggedHandle = nullptr;
updateHandles();
@@ -248,7 +310,7 @@ void QQuickSelectionRectanglePrivate::scrollTowardsPos(const QPointF &pos)
if (m_scrollTimer.isActive())
return;
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
if (!dist.isNull())
m_scrollTimer.start(1);
}
@@ -409,6 +471,25 @@ void QQuickSelectionRectanglePrivate::connectToTarget()
if (const auto flickable = qobject_cast<QQuickFlickable *>(m_target)) {
connect(flickable, &QQuickFlickable::interactiveChanged, this, &QQuickSelectionRectanglePrivate::updateSelectionMode);
}
+
+ // Add a callback function that tells if the selection was
+ // modified outside of the actions taken by SelectionRectangle.
+ m_selectable->setCallback([this](QQuickSelectable::CallBackFlag flag){
+ switch (flag) {
+ case QQuickSelectable::CallBackFlag::CancelSelection:
+ // The selection is either cleared, or can no longer be
+ // represented as a rectangle with two selection handles.
+ updateActiveState(false);
+ break;
+ case QQuickSelectable::CallBackFlag::SelectionRectangleChanged:
+ // The selection has changed, but the selection is still
+ // rectangular and without holes.
+ updateHandles();
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ });
}
void QQuickSelectionRectanglePrivate::updateSelectionMode()
@@ -419,26 +500,33 @@ void QQuickSelectionRectanglePrivate::updateSelectionMode()
m_tapHandler->setEnabled(enabled);
if (m_selectionMode == QQuickSelectionRectangle::Auto) {
- if (qobject_cast<QQuickScrollView *>(m_target->parentItem())) {
+ if (m_target && qobject_cast<QQuickScrollView *>(m_target->parentItem())) {
// ScrollView allows flicking with touch, but not with mouse. So we do
// the same here: you can drag to select with a mouse, but not with touch.
+ m_effectiveSelectionMode = QQuickSelectionRectangle::Drag;
m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::Mouse);
m_dragHandler->setEnabled(enabled);
} else if (const auto flickable = qobject_cast<QQuickFlickable *>(m_target)) {
- m_dragHandler->setEnabled(enabled && !flickable->isInteractive());
+ if (enabled && !flickable->isInteractive()) {
+ m_effectiveSelectionMode = QQuickSelectionRectangle::Drag;
+ m_dragHandler->setEnabled(true);
+ } else {
+ m_effectiveSelectionMode = QQuickSelectionRectangle::PressAndHold;
+ m_dragHandler->setEnabled(false);
+ }
} else {
+ m_effectiveSelectionMode = QQuickSelectionRectangle::Drag;
m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::Mouse);
m_dragHandler->setEnabled(enabled);
}
} else if (m_selectionMode == QQuickSelectionRectangle::Drag) {
+ m_effectiveSelectionMode = QQuickSelectionRectangle::Drag;
m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::AllDevices);
m_dragHandler->setEnabled(enabled);
} else {
+ m_effectiveSelectionMode = QQuickSelectionRectangle::PressAndHold;
m_dragHandler->setEnabled(false);
}
-
- // If you can't select using a drag, we always accept a PressAndHold
- m_alwaysAcceptPressAndHold = !m_dragHandler->enabled();
}
QQuickSelectionRectangleAttached *QQuickSelectionRectanglePrivate::getAttachedObject(const QObject *object) const
@@ -480,6 +568,7 @@ void QQuickSelectionRectangle::setTarget(QQuickItem *target)
d->m_tapHandler->setParent(this);
d->m_dragHandler->setParent(this);
d->m_target->disconnect(this);
+ d->m_selectable->setCallback(nullptr);
}
d->m_target = target;