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