aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates/qquickswitchdelegate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates/qquickswitchdelegate.cpp')
-rw-r--r--src/quicktemplates/qquickswitchdelegate.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/quicktemplates/qquickswitchdelegate.cpp b/src/quicktemplates/qquickswitchdelegate.cpp
new file mode 100644
index 0000000000..f17faf8aa9
--- /dev/null
+++ b/src/quicktemplates/qquickswitchdelegate.cpp
@@ -0,0 +1,207 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickswitchdelegate_p.h"
+
+#include "qquickitemdelegate_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SwitchDelegate
+ \inherits ItemDelegate
+//! \instantiates QQuickSwitchDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols-delegates
+ \brief Item delegate with a switch indicator that can be toggled on or off.
+
+ \image qtquickcontrols-switchdelegate.gif
+
+ SwitchDelegate presents an item delegate that can be toggled on (checked) or
+ off (unchecked). Switch delegates are typically used to select one or more
+ options from a set of options. For smaller sets of options, or for options
+ that need to be uniquely identifiable, consider using \l Switch instead.
+
+ SwitchDelegate inherits its API from \l ItemDelegate, which is inherited
+ from \l AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
+ and react to \l {AbstractButton::clicked}{clicks} using the \l AbstractButton
+ API. The state of the switch delegate can be set with the
+ \l {AbstractButton::}{checked} property.
+
+ \code
+ ListView {
+ model: ["Option 1", "Option 2", "Option 3"]
+ delegate: SwitchDelegate {
+ text: modelData
+ }
+ }
+ \endcode
+
+ \sa {Customizing SwitchDelegate}, {Delegate Controls}
+*/
+
+class QQuickSwitchDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwitchDelegate)
+
+public:
+ qreal positionAt(const QPointF &point) const;
+
+ bool canDrag(const QPointF &movePoint) const;
+ bool handleMove(const QPointF &point, ulong timestamp) override;
+ bool handleRelease(const QPointF &point, ulong timestamp) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ListView); }
+
+ qreal position = 0;
+};
+
+qreal QQuickSwitchDelegatePrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickSwitchDelegate);
+ qreal pos = 0.0;
+ if (indicator)
+ pos = indicator->mapFromItem(q, point).x() / indicator->width();
+ if (q->isMirrored())
+ return 1.0 - pos;
+ return pos;
+}
+
+bool QQuickSwitchDelegatePrivate::canDrag(const QPointF &movePoint) const
+{
+ // don't start dragging the handle unless the initial press was at the indicator,
+ // or the drag has reached the indicator area. this prevents unnatural jumps when
+ // dragging far outside the indicator.
+ const qreal pressPos = positionAt(pressPoint);
+ const qreal movePos = positionAt(movePoint);
+ return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0);
+}
+
+bool QQuickSwitchDelegatePrivate::handleMove(const QPointF &point, ulong timestamp)
+{
+ Q_Q(QQuickSwitchDelegate);
+ QQuickItemDelegatePrivate::handleMove(point, timestamp);
+ if (q->keepMouseGrab() || q->keepTouchGrab())
+ q->setPosition(positionAt(point));
+ return true;
+}
+
+bool QQuickSwitchDelegatePrivate::handleRelease(const QPointF &point, ulong timestamp)
+{
+ Q_Q(QQuickSwitchDelegate);
+ QQuickItemDelegatePrivate::handleRelease(point, timestamp);
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+ return true;
+}
+
+QQuickSwitchDelegate::QQuickSwitchDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickSwitchDelegatePrivate), parent)
+{
+ Q_D(QQuickSwitchDelegate);
+ d->keepPressed = true;
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::SwitchDelegate::position
+ \readonly
+
+ \input includes/qquickswitch.qdocinc position
+*/
+qreal QQuickSwitchDelegate::position() const
+{
+ Q_D(const QQuickSwitchDelegate);
+ return d->position;
+}
+
+void QQuickSwitchDelegate::setPosition(qreal position)
+{
+ Q_D(QQuickSwitchDelegate);
+ position = qBound<qreal>(0.0, position, 1.0);
+ if (qFuzzyCompare(d->position, position))
+ return;
+
+ d->position = position;
+ emit positionChanged();
+ emit visualPositionChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::SwitchDelegate::visualPosition
+ \readonly
+
+ \input includes/qquickswitch.qdocinc visualPosition
+*/
+qreal QQuickSwitchDelegate::visualPosition() const
+{
+ Q_D(const QQuickSwitchDelegate);
+ if (isMirrored())
+ return 1.0 - d->position;
+ return d->position;
+}
+
+void QQuickSwitchDelegate::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (!keepMouseGrab()) {
+ const QPointF movePoint = event->position();
+ if (d->canDrag(movePoint))
+ setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event));
+ }
+ QQuickItemDelegate::mouseMoveEvent(event);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickSwitchDelegate::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) {
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (point.id() != d->touchId || point.state() != QEventPoint::Updated)
+ continue;
+ if (d->canDrag(point.position()))
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(), Qt::XAxis, &point));
+ }
+ }
+ QQuickItemDelegate::touchEvent(event);
+}
+#endif
+
+QFont QQuickSwitchDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ListView);
+}
+
+void QQuickSwitchDelegate::mirrorChange()
+{
+ QQuickItemDelegate::mirrorChange();
+ emit visualPositionChanged();
+}
+
+void QQuickSwitchDelegate::nextCheckState()
+{
+ Q_D(QQuickSwitchDelegate);
+ if (keepMouseGrab() || keepTouchGrab()) {
+ d->toggle(d->position > 0.5);
+ // the checked state might not change => force a position update to
+ // avoid that the handle is left somewhere in the middle (QTBUG-57944)
+ setPosition(d->checked ? 1.0 : 0.0);
+ } else {
+ QQuickItemDelegate::nextCheckState();
+ }
+}
+
+void QQuickSwitchDelegate::buttonChange(ButtonChange change)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (change == ButtonCheckedChange)
+ setPosition(d->checked ? 1.0 : 0.0);
+ else
+ QQuickAbstractButton::buttonChange(change);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickswitchdelegate_p.cpp"