aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2021-05-14 14:21:03 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2021-06-06 06:15:15 +0200
commitc52710c10c4ec975a24fcb29799522d9dfdeac2f (patch)
tree822d51f82dc2b103e9b2c1aa645d57d0a9f3afd9 /src/quicktemplates2
parent286c44ed4aef8ed5c3e7b7503fb2c9ce2713442a (diff)
Add new control: SelectionRectangle
This patch will add a SelectionRectangle to controls. A SelectionRectangle can be used together with TableView to let the user select cells using either pointer Drag or PressAndHold. It lets the developer set their own handle delegates, or simply use the included ones added to the Basic style. [ChangeLog][Controls][SelectionRectangle] A SelectionRectangle has been added to Controls. A SelectionRectangle can be used to make selections in TableView. Fixes: QTBUG-74750 Change-Id: Ia7af578c1c905b0e92df193d7820ad6ef2c9b697 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/quicktemplates2')
-rw-r--r--src/quicktemplates2/CMakeLists.txt2
-rw-r--r--src/quicktemplates2/qquickselectionrectangle.cpp540
-rw-r--r--src/quicktemplates2/qquickselectionrectangle_p.h143
-rw-r--r--src/quicktemplates2/qquickselectionrectangle_p_p.h110
-rw-r--r--src/quicktemplates2/quicktemplates2.pri2
5 files changed, 797 insertions, 0 deletions
diff --git a/src/quicktemplates2/CMakeLists.txt b/src/quicktemplates2/CMakeLists.txt
index b326e467..fe4bdf9a 100644
--- a/src/quicktemplates2/CMakeLists.txt
+++ b/src/quicktemplates2/CMakeLists.txt
@@ -88,6 +88,8 @@ qt_internal_add_qml_module(QuickTemplates2
qquickscrollbar_p_p.h
qquickscrollindicator.cpp qquickscrollindicator_p.h
qquickscrollview.cpp qquickscrollview_p.h
+ qquickselectionrectangle.cpp qquickselectionrectangle_p.h
+ qquickselectionrectangle_p_p.h
qquickshortcutcontext.cpp
qquickshortcutcontext_p_p.h
qquickslider.cpp qquickslider_p.h
diff --git a/src/quicktemplates2/qquickselectionrectangle.cpp b/src/quicktemplates2/qquickselectionrectangle.cpp
new file mode 100644
index 00000000..fbde94f4
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickselectionrectangle_p.h"
+#include "qquickselectionrectangle_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquicktableview_p_p.h>
+
+#include "qquickscrollview_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SelectionRectangle
+ \inherits Control
+//! \instantiates QQuickSelectionRectangle
+ \inqmlmodule QtQuick.Controls
+ \since 6.2
+ \ingroup utilities
+ \brief Used to select table cells inside a TableView
+
+ \image qtquickcontrols2-selectionrectangle.png
+
+ SelectionRectangle is used for selecting table cells in a TableView. It lets
+ the user start a selection by doing a pointer drag inside the viewport, or by
+ doing a long press on top of a cell.
+
+ For a SelectionRectangle to be able to select cells, TableView must have
+ an ItemSelectionModel assigned. The ItemSelectionModel will store any
+ selections done on the model, and can be used for querying
+ which cells that the user has selected.
+
+ The following example shows how you can make a SelectionRectangle target
+ a TableView:
+
+ \snippet qml/tableview/selectionmodel.qml 0
+
+ \note A SelectionRectangle itself is not shown as part of a selection. Only the
+ delegates (like topLeftHandle and bottomRightHandle) are used.
+ You should also consider \l {Selecting items}{rendering the TableView delegate as selected}.
+
+ \sa TableView, TableView::selectionModel, ItemSelectionModel
+*/
+
+/*!
+ \qmlproperty Item QtQuick.Controls::SelectionRectangle::target
+
+ This property holds the TableView on which the
+ SelectionRectangle should act.
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SelectionRectangle::active
+ \readonly
+
+ This property is \c true while the user is performing a
+ selection. The selection will be active from the time the
+ the user starts to select, and until the selection is
+ removed again, for example from tapping inside the viewport.
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SelectionRectangle::dragging
+ \readonly
+
+ This property is \c true whenever the user is doing a pointer drag or
+ a handle drag to adjust the selection rectangle.
+*/
+
+/*!
+ \qmlproperty Component QtQuick.Controls::SelectionRectangle::topLeftHandle
+
+ This property holds the delegate that will be shown on the center of the
+ top-left corner of the selection rectangle. When a handle is
+ provided, the user can drag it to adjust the selection.
+
+ You can set this property to \c null if you don't want a top-left selection handle.
+
+ \sa bottomRightHandle
+*/
+
+/*!
+ \qmlproperty Component QtQuick.Controls::SelectionRectangle::bottomRightHandle
+
+ This property holds the delegate that will be shown on the center of the
+ top-left corner of the selection rectangle. When a handle is
+ provided, the user can drag it to adjust the selection.
+
+ You can set this property to \c null if you don't want a top-left selection handle.
+
+ \sa topLeftHandle
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::SelectionRectangle::selectionMode
+
+ This property holds when a selection should start.
+
+ \value SelectionRectangle.Drag A selection will start by doing a pointer drag inside the viewport
+ \value SelectionRectangle.PressAndHold A selection will start by doing a press and hold on top a cell
+ \value SelectionRectangle.Auto SelectionRectangle will choose which mode to use based on the target
+ and the platform. This normally means \c PressAndHold on touch based platforms, and \c Drag on desktop.
+ However, \c Drag will only be used if it doesn't conflict with flicking. This means that
+ TableView will need to be configured with \c interactive set to \c false, or placed
+ inside a ScrollView (where flicking, by default, is off for mouse events), for \c Drag to be chosen.
+
+ The default value is \c Auto.
+*/
+
+/*!
+ \qmlattachedproperty SelectionRectangle QtQuick::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
+
+ This attached property will be \c true if the user is dragging on the handle.
+ It is attached to each handle instance.
+*/
+
+QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
+ : QQuickControlPrivate()
+{
+ m_tapHandler = new QQuickTapHandler();
+ m_dragHandler = new QQuickDragHandler();
+ m_dragHandler->setTarget(nullptr);
+
+ QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
+ if (m_topLeftHandle && m_draggedHandle == m_topLeftHandle)
+ m_selectable->setSelectionStartPos(m_scrollToPoint);
+ else
+ m_selectable->setSelectionEndPos(m_scrollToPoint);
+ updateHandles();
+ const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(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, [=](QEventPoint) {
+ m_selectable->clearSelection();
+ updateActiveState(false);
+ });
+
+ QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [=]() {
+ 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)
+ return;
+ } else if (m_selectionMode != QQuickSelectionRectangle::PressAndHold) {
+ return;
+ }
+ }
+
+ const QPointF pos = m_tapHandler->point().position();
+ m_selectable->clearSelection();
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ });
+
+ QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [=]() {
+ const QPointF pos = m_dragHandler->centroid().position();
+ if (m_dragHandler->active()) {
+ m_selectable->clearSelection();
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ m_draggedHandle = nullptr;
+ updateHandles();
+ updateActiveState(true);
+ updateDraggingState(true);
+ } else {
+ m_scrollTimer.stop();
+ m_selectable->normalizeSelection();
+ updateDraggingState(false);
+ }
+ });
+
+ QObject::connect(m_dragHandler, &QQuickDragHandler::centroidChanged, [=]() {
+ if (!m_dragging)
+ return;
+ const QPointF pos = m_dragHandler->centroid().position();
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ scrollTowardsPos(pos);
+ });
+}
+
+void QQuickSelectionRectanglePrivate::scrollTowardsPos(const QPointF &pos)
+{
+ m_scrollToPoint = pos;
+ if (m_scrollTimer.isActive())
+ return;
+
+ const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ if (!dist.isNull())
+ m_scrollTimer.start(1);
+}
+
+void QQuickSelectionRectanglePrivate::updateDraggingState(bool dragging)
+{
+ if (dragging != m_dragging) {
+ m_dragging = dragging;
+ emit q_func()->draggingChanged();
+ }
+
+ if (auto attached = getAttachedObject(m_draggedHandle))
+ attached->setDragging(dragging);
+}
+
+void QQuickSelectionRectanglePrivate::updateActiveState(bool active)
+{
+ if (active == m_active)
+ return;
+
+ m_active = active;
+ emit q_func()->activeChanged();
+}
+
+QQuickItem *QQuickSelectionRectanglePrivate::createHandle(QQmlComponent *delegate)
+{
+ Q_Q(QQuickSelectionRectangle);
+
+ const bool topLeft = (delegate == m_topLeftHandleDelegate);
+
+ // Incubate the handle
+ const auto handlerTarget = m_selectable->selectionPointerHandlerTarget();
+ QObject *obj = delegate->beginCreate(QQmlEngine::contextForObject(q));
+ QQuickItem *handleItem = qobject_cast<QQuickItem*>(obj);
+ if (auto attached = getAttachedObject(handleItem))
+ attached->setControl(q);
+ delegate->completeCreate();
+ handleItem->setParentItem(handlerTarget);
+ if (handleItem->z() == 0)
+ handleItem->setZ(100);
+
+ // Add pointer handlers to it
+ QQuickDragHandler *dragHandler = new QQuickDragHandler();
+ dragHandler->setTarget(nullptr);
+ dragHandler->setParent(handleItem);
+ QQuickItemPrivate::get(handleItem)->addPointerHandler(dragHandler);
+
+ QObject::connect(dragHandler, &QQuickDragHandler::activeChanged, [=]() {
+ if (dragHandler->active()) {
+ const QPointF localPos = dragHandler->centroid().position();
+ const QPointF pos = handleItem->mapToItem(handleItem->parentItem(), localPos);
+ if (topLeft)
+ m_selectable->setSelectionStartPos(pos);
+ else
+ m_selectable->setSelectionEndPos(pos);
+
+ m_draggedHandle = handleItem;
+ updateHandles();
+ updateDraggingState(true);
+ } else {
+ m_scrollTimer.stop();
+ m_selectable->normalizeSelection();
+ updateDraggingState(false);
+ }
+ });
+
+ QObject::connect(dragHandler, &QQuickDragHandler::centroidChanged, [=]() {
+ if (!m_dragging)
+ return;
+
+ const QPointF localPos = dragHandler->centroid().position();
+ const QPointF pos = handleItem->mapToItem(handleItem->parentItem(), localPos);
+ if (topLeft)
+ m_selectable->setSelectionStartPos(pos);
+ else
+ m_selectable->setSelectionEndPos(pos);
+
+ updateHandles();
+ scrollTowardsPos(pos);
+ });
+
+ return handleItem;
+}
+
+void QQuickSelectionRectanglePrivate::updateHandles()
+{
+ if (!m_selectable)
+ return;
+
+ const QRectF rect = m_selectable->selectionRectangle().normalized();
+
+ if (!m_topLeftHandle && m_topLeftHandleDelegate)
+ m_topLeftHandle = createHandle(m_topLeftHandleDelegate);
+
+ if (!m_bottomRightHandle && m_bottomRightHandleDelegate)
+ m_bottomRightHandle = createHandle(m_bottomRightHandleDelegate);
+
+ if (m_topLeftHandle) {
+ m_topLeftHandle->setX(rect.x() - (m_topLeftHandle->width() / 2));
+ m_topLeftHandle->setY(rect.y() - (m_topLeftHandle->height() / 2));
+ }
+
+ if (m_bottomRightHandle) {
+ m_bottomRightHandle->setX(rect.x() + rect.width() - (m_bottomRightHandle->width() / 2));
+ m_bottomRightHandle->setY(rect.y() + rect.height() - (m_bottomRightHandle->height() / 2));
+ }
+}
+
+void QQuickSelectionRectanglePrivate::connectToTarget()
+{
+ // To support QuickSelectionRectangle::Auto, we need to listen for changes to the target
+ if (const auto flickable = qobject_cast<QQuickFlickable *>(m_target)) {
+ connect(flickable, &QQuickFlickable::interactiveChanged, this, &QQuickSelectionRectanglePrivate::updateSelectionMode);
+ }
+}
+
+void QQuickSelectionRectanglePrivate::updateSelectionMode()
+{
+ Q_Q(QQuickSelectionRectangle);
+
+ const bool enabled = q->isEnabled();
+ m_tapHandler->setEnabled(enabled);
+
+ if (m_selectionMode == QQuickSelectionRectangle::Auto) {
+ if (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_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());
+ } else {
+ m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::Mouse);
+ m_dragHandler->setEnabled(enabled);
+ }
+ } else if (m_selectionMode == QQuickSelectionRectangle::Drag) {
+ m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::AllDevices);
+ m_dragHandler->setEnabled(enabled);
+ } else {
+ 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
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickSelectionRectangle>(object);
+ return static_cast<QQuickSelectionRectangleAttached *>(attachedObject);
+}
+
+// --------------------------------------------------------
+
+QQuickSelectionRectangle::QQuickSelectionRectangle(QQuickItem *parent)
+ : QQuickControl(*(new QQuickSelectionRectanglePrivate), parent)
+{
+ Q_D(QQuickSelectionRectangle);
+
+ QObject::connect(this, &QQuickItem::enabledChanged, [=]() {
+ d->m_scrollTimer.stop();
+ d->updateSelectionMode();
+ d->updateDraggingState(false);
+ d->updateActiveState(false);
+ });
+}
+
+QQuickItem *QQuickSelectionRectangle::target() const
+{
+ return d_func()->m_target;
+}
+
+void QQuickSelectionRectangle::setTarget(QQuickItem *target)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_target == target)
+ return;
+
+ if (d->m_selectable) {
+ d->m_scrollTimer.stop();
+ d->m_tapHandler->setParent(nullptr);
+ d->m_dragHandler->setParent(nullptr);
+ d->m_target->disconnect(this);
+ }
+
+ d->m_target = target;
+ d->m_selectable = nullptr;
+
+ if (d->m_target) {
+ d->m_selectable = dynamic_cast<QQuickSelectable *>(QObjectPrivate::get(d->m_target.data()));
+ if (!d->m_selectable)
+ qmlWarning(this) << "the assigned target is not supported by the control";
+ }
+
+ if (d->m_selectable) {
+ const auto handlerTarget = d->m_selectable->selectionPointerHandlerTarget();
+ d->m_dragHandler->setParent(handlerTarget);
+ d->m_tapHandler->setParent(handlerTarget);
+ QQuickItemPrivate::get(handlerTarget)->addPointerHandler(d->m_tapHandler);
+ QQuickItemPrivate::get(handlerTarget)->addPointerHandler(d->m_dragHandler);
+ d->connectToTarget();
+ d->updateSelectionMode();
+ }
+
+ emit targetChanged();
+}
+
+bool QQuickSelectionRectangle::active()
+{
+ return d_func()->m_active;
+}
+
+bool QQuickSelectionRectangle::dragging()
+{
+ return d_func()->m_dragging;
+}
+
+QQuickSelectionRectangle::SelectionMode QQuickSelectionRectangle::selectionMode() const
+{
+ return d_func()->m_selectionMode;
+}
+
+void QQuickSelectionRectangle::setSelectionMode(QQuickSelectionRectangle::SelectionMode selectionMode)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_selectionMode == selectionMode)
+ return;
+
+ d->m_selectionMode = selectionMode;
+
+ if (d->m_target)
+ d->updateSelectionMode();
+
+ emit selectionModeChanged();
+}
+
+QQmlComponent *QQuickSelectionRectangle::topLeftHandle() const
+{
+ return d_func()->m_topLeftHandleDelegate;
+}
+
+void QQuickSelectionRectangle::setTopLeftHandle(QQmlComponent *topLeftHandle)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_topLeftHandleDelegate == topLeftHandle)
+ return;
+
+ d->m_topLeftHandleDelegate = topLeftHandle;
+ emit topLeftHandleChanged();
+}
+
+QQmlComponent *QQuickSelectionRectangle::bottomRightHandle() const
+{
+ return d_func()->m_bottomRightHandleDelegate;
+}
+
+void QQuickSelectionRectangle::setBottomRightHandle(QQmlComponent *bottomRightHandle)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_bottomRightHandleDelegate == bottomRightHandle)
+ return;
+
+ d->m_bottomRightHandleDelegate = bottomRightHandle;
+ emit bottomRightHandleChanged();
+}
+
+QQuickSelectionRectangleAttached *QQuickSelectionRectangle::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickSelectionRectangleAttached(obj);
+}
+
+QQuickSelectionRectangleAttached::QQuickSelectionRectangleAttached(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QQuickSelectionRectangle *QQuickSelectionRectangleAttached::control() const
+{
+ return m_control;
+}
+
+void QQuickSelectionRectangleAttached::setControl(QQuickSelectionRectangle *control)
+{
+ if (m_control == control)
+ return;
+
+ m_control = control;
+ emit controlChanged();
+}
+
+bool QQuickSelectionRectangleAttached::dragging() const
+{
+ return m_dragging;
+}
+
+void QQuickSelectionRectangleAttached::setDragging(bool dragging)
+{
+ if (m_dragging == dragging)
+ return;
+
+ m_dragging = dragging;
+ emit draggingChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickselectionrectangle_p.h b/src/quicktemplates2/qquickselectionrectangle_p.h
new file mode 100644
index 00000000..3acf1b10
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle_p.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSELECTIONRECTANGLE_P_H
+#define QQUICKSELECTIONRECTANGLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSelectionRectanglePrivate;
+class QQuickSelectable;
+class QQuickSelectionRectangleAttached;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSelectionRectangle : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged FINAL)
+ Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged FINAL)
+ Q_PROPERTY(QQmlComponent *topLeftHandle READ topLeftHandle WRITE setTopLeftHandle NOTIFY topLeftHandleChanged FINAL)
+ Q_PROPERTY(QQmlComponent *bottomRightHandle READ bottomRightHandle WRITE setBottomRightHandle NOTIFY bottomRightHandleChanged FINAL)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged FINAL)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
+
+ QML_NAMED_ELEMENT(SelectionRectangle)
+ QML_ATTACHED(QQuickSelectionRectangleAttached)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ enum SelectionMode {
+ Drag,
+ PressAndHold,
+ Auto
+ };
+ Q_ENUM(SelectionMode)
+
+ explicit QQuickSelectionRectangle(QQuickItem *parent = nullptr);
+
+ QQuickItem *target() const;
+ void setTarget(QQuickItem *target);
+
+ bool active();
+ bool dragging();
+
+ SelectionMode selectionMode() const;
+ void setSelectionMode(SelectionMode selectionMode);
+
+ QQmlComponent *topLeftHandle() const;
+ void setTopLeftHandle(QQmlComponent *topLeftHandle);
+ QQmlComponent *bottomRightHandle() const;
+ void setBottomRightHandle(QQmlComponent *bottomRightHandle);
+
+ static QQuickSelectionRectangleAttached *qmlAttachedProperties(QObject *obj);
+
+Q_SIGNALS:
+ void targetChanged();
+ bool activeChanged();
+ bool draggingChanged();
+ void topLeftHandleChanged();
+ void bottomRightHandleChanged();
+ void selectionModeChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSelectionRectangle)
+ Q_DECLARE_PRIVATE(QQuickSelectionRectangle)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSelectionRectangleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickSelectionRectangle *control READ control NOTIFY controlChanged FINAL)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
+
+public:
+ QQuickSelectionRectangleAttached(QObject *parent);
+
+ QQuickSelectionRectangle *control() const;
+ void setControl(QQuickSelectionRectangle *control);
+
+ bool dragging() const;
+ void setDragging(bool dragging);
+
+Q_SIGNALS:
+ void controlChanged();
+ void draggingChanged();
+
+private:
+ QPointer<QQuickSelectionRectangle> m_control;
+ bool m_dragging = false;
+
+ friend class QQuickSelectionRectanglePrivate;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSelectionRectangle)
+
+#endif // QQUICKSELECTIONRECTANGLE_P_H
diff --git a/src/quicktemplates2/qquickselectionrectangle_p_p.h b/src/quicktemplates2/qquickselectionrectangle_p_p.h
new file mode 100644
index 00000000..2ed3e035
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle_p_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSELECTIONRECTANGLE_P_P_H
+#define QQUICKSELECTIONRECTANGLE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickselectionrectangle_p.h"
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+
+#include <QtQuick/private/qquickselectable_p.h>
+#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickdraghandler_p.h>
+
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSelectionRectanglePrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSelectionRectangle)
+
+public:
+ QQuickSelectionRectanglePrivate();
+
+ void updateDraggingState(bool isDragging);
+ void updateActiveState(bool isActive);
+ void updateHandles();
+ void updateSelectionMode();
+ void connectToTarget();
+ void scrollTowardsPos(const QPointF &pos);
+
+ QQuickItem *createHandle(QQmlComponent *delegate);
+
+ QQuickSelectionRectangleAttached *getAttachedObject(const QObject *object) const;
+
+public:
+ QPointer<QQuickItem> m_target;
+
+ QQmlComponent *m_topLeftHandleDelegate = nullptr;
+ QQmlComponent *m_bottomRightHandleDelegate = nullptr;
+ QPointer<QQuickItem> m_topLeftHandle;
+ QPointer<QQuickItem> m_bottomRightHandle;
+ QPointer<QQuickItem> m_draggedHandle = nullptr;
+
+ QQuickSelectable *m_selectable = nullptr;
+
+ QQuickTapHandler *m_tapHandler = nullptr;
+ QQuickDragHandler *m_dragHandler = nullptr;
+
+ QTimer m_scrollTimer;
+ QPointF m_scrollToPoint;
+ QSizeF m_scrollSpeed = QSizeF(1, 1);
+
+ QQuickSelectionRectangle::SelectionMode m_selectionMode = QQuickSelectionRectangle::Auto;
+ bool m_alwaysAcceptPressAndHold = false;
+
+ bool m_enabled = true;
+ bool m_active = false;
+ bool m_dragging = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSELECTIONRECTANGLE_P_P_H
diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri
index fa377f78..0f19de5e 100644
--- a/src/quicktemplates2/quicktemplates2.pri
+++ b/src/quicktemplates2/quicktemplates2.pri
@@ -71,6 +71,8 @@ HEADERS += \
$$PWD/qquickscrollbar_p_p.h \
$$PWD/qquickscrollindicator_p.h \
$$PWD/qquickscrollview_p.h \
+ $$PWD/qquickselectionrectangle_p.h \
+ $$PWD/qquickselectionrectangle_p_p.h \
$$PWD/qquickshortcutcontext_p_p.h \
$$PWD/qquickslider_p.h \
$$PWD/qquickspinbox_p.h \