Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickswitchdelegate.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
8
9#include <algorithm>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \qmltype SwitchDelegate
15 \inherits ItemDelegate
16//! \nativetype QQuickSwitchDelegate
17 \inqmlmodule QtQuick.Controls
18 \since 5.7
19 \ingroup qtquickcontrols-delegates
20 \brief Item delegate with a switch indicator that can be toggled on or off.
21
22 \image qtquickcontrols-switchdelegate.gif
23 {Switch delegates showing on and off states}
24
25 SwitchDelegate presents an item delegate that can be toggled on (checked) or
26 off (unchecked). Switch delegates are typically used to select one or more
27 options from a set of options. For smaller sets of options, or for options
28 that need to be uniquely identifiable, consider using \l Switch instead.
29
30 SwitchDelegate inherits its API from \l ItemDelegate, which is inherited
31 from \l AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
32 and react to \l {AbstractButton::clicked}{clicks} using the \l AbstractButton
33 API. The state of the switch delegate can be set with the
34 \l {AbstractButton::}{checked} property.
35
36 \code
37 ListView {
38 model: ["Option 1", "Option 2", "Option 3"]
39 delegate: SwitchDelegate {
40 text: modelData
41 }
42 }
43 \endcode
44
45 \sa {Customizing SwitchDelegate}, {Delegate Controls}
46*/
47
48class QQuickSwitchDelegatePrivate : public QQuickItemDelegatePrivate
49{
50 Q_DECLARE_PUBLIC(QQuickSwitchDelegate)
51
52public:
53 qreal positionAt(const QPointF &point) const;
54
55 bool canDrag(const QPointF &movePoint) const;
56 bool handleMove(const QPointF &point, ulong timestamp) override;
57 bool handleRelease(const QPointF &point, ulong timestamp) override;
58
59 QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ListView); }
60
61 qreal position = 0;
62};
63
64qreal QQuickSwitchDelegatePrivate::positionAt(const QPointF &point) const
65{
66 Q_Q(const QQuickSwitchDelegate);
67 qreal pos = 0.0;
68 if (indicator)
69 pos = indicator->mapFromItem(q, point).x() / indicator->width();
70 if (q->isMirrored())
71 return 1.0 - pos;
72 return pos;
73}
74
75bool QQuickSwitchDelegatePrivate::canDrag(const QPointF &movePoint) const
76{
77 // don't start dragging the handle unless the initial press was at the indicator,
78 // or the drag has reached the indicator area. this prevents unnatural jumps when
79 // dragging far outside the indicator.
80 const qreal pressPos = positionAt(pressPoint);
81 const qreal movePos = positionAt(movePoint);
82 return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0);
83}
84
85bool QQuickSwitchDelegatePrivate::handleMove(const QPointF &point, ulong timestamp)
86{
87 Q_Q(QQuickSwitchDelegate);
88 QQuickItemDelegatePrivate::handleMove(point, timestamp);
89 if (q->keepMouseGrab() || q->keepTouchGrab())
90 q->setPosition(positionAt(point));
91 return true;
92}
93
94bool QQuickSwitchDelegatePrivate::handleRelease(const QPointF &point, ulong timestamp)
95{
96 Q_Q(QQuickSwitchDelegate);
97 QQuickItemDelegatePrivate::handleRelease(point, timestamp);
98 q->setKeepMouseGrab(false);
99 q->setKeepTouchGrab(false);
100 return true;
101}
102
103QQuickSwitchDelegate::QQuickSwitchDelegate(QQuickItem *parent)
104 : QQuickItemDelegate(*(new QQuickSwitchDelegatePrivate), parent)
105{
106 Q_D(QQuickSwitchDelegate);
107 d->keepPressed = true;
108 setCheckable(true);
109}
110
111/*!
112 \qmlproperty real QtQuick.Controls::SwitchDelegate::position
113 \readonly
114
115 \input includes/qquickswitch.qdocinc position
116*/
117qreal QQuickSwitchDelegate::position() const
118{
119 Q_D(const QQuickSwitchDelegate);
120 return d->position;
121}
122
123void QQuickSwitchDelegate::setPosition(qreal position)
124{
125 Q_D(QQuickSwitchDelegate);
126 position = std::clamp(position, qreal(0.0), qreal(1.0));
127 if (qFuzzyCompare(d->position, position))
128 return;
129
130 d->position = position;
131 emit positionChanged();
132 emit visualPositionChanged();
133}
134
135/*!
136 \qmlproperty real QtQuick.Controls::SwitchDelegate::visualPosition
137 \readonly
138
139 \input includes/qquickswitch.qdocinc visualPosition
140*/
141qreal QQuickSwitchDelegate::visualPosition() const
142{
143 Q_D(const QQuickSwitchDelegate);
144 if (isMirrored())
145 return 1.0 - d->position;
146 return d->position;
147}
148
149void QQuickSwitchDelegate::mouseMoveEvent(QMouseEvent *event)
150{
151 Q_D(QQuickSwitchDelegate);
152 if (!keepMouseGrab()) {
153 const QPointF movePoint = event->position();
154 if (d->canDrag(movePoint)) {
155 setKeepMouseGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(),
156 Qt::XAxis, event));
157 }
158 }
159 QQuickItemDelegate::mouseMoveEvent(event);
160}
161
162#if QT_CONFIG(quicktemplates2_multitouch)
163void QQuickSwitchDelegate::touchEvent(QTouchEvent *event)
164{
165 Q_D(QQuickSwitchDelegate);
166 if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) {
167 for (const QTouchEvent::TouchPoint &point : event->points()) {
168 if (point.id() != d->touchId || point.state() != QEventPoint::Updated)
169 continue;
170 if (d->canDrag(point.position())) {
171 setKeepTouchGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(),
172 Qt::XAxis, point));
173 }
174 }
175 }
176 QQuickItemDelegate::touchEvent(event);
177}
178#endif
179
180QFont QQuickSwitchDelegate::defaultFont() const
181{
182 return QQuickTheme::font(QQuickTheme::ListView);
183}
184
185void QQuickSwitchDelegate::mirrorChange()
186{
187 QQuickItemDelegate::mirrorChange();
188 emit visualPositionChanged();
189}
190
191void QQuickSwitchDelegate::nextCheckState()
192{
193 Q_D(QQuickSwitchDelegate);
194 if (keepMouseGrab() || keepTouchGrab()) {
195 d->toggle(d->position > 0.5);
196 // the checked state might not change => force a position update to
197 // avoid that the handle is left somewhere in the middle (QTBUG-57944)
198 setPosition(d->checked ? 1.0 : 0.0);
199 } else {
200 QQuickItemDelegate::nextCheckState();
201 }
202}
203
204void QQuickSwitchDelegate::buttonChange(ButtonChange change)
205{
206 Q_D(QQuickSwitchDelegate);
207 if (change == ButtonCheckedChange)
208 setPosition(d->checked ? 1.0 : 0.0);
209 else
210 QQuickAbstractButton::buttonChange(change);
211}
212
213QT_END_NAMESPACE
214
215#include "moc_qquickswitchdelegate_p.cpp"