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
qquickswitch.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
7
8#include <QtGui/qstylehints.h>
9#include <QtGui/qguiapplication.h>
10#include <QtQuick/private/qquickwindow_p.h>
11#include <QtQuick/private/qquickevents_p_p.h>
12
13#include <algorithm>
14
15QT_BEGIN_NAMESPACE
16
17/*!
18 \qmltype Switch
19 \inherits AbstractButton
20//! \nativetype QQuickSwitch
21 \inqmlmodule QtQuick.Controls
22 \since 5.7
23 \ingroup qtquickcontrols-buttons
24 \brief Switch button that can be toggled on or off.
25
26 \image qtquickcontrols-switch.gif
27
28 Switch is an option button that can be dragged or toggled on (checked) or
29 off (unchecked). Switches are typically used to select between two states.
30 For larger sets of options, such as those in a list, consider using
31 \l SwitchDelegate instead.
32
33 Switch inherits its API from \l AbstractButton. For instance, the state
34 of the switch can be set with the \l {AbstractButton::}{checked} property.
35 The \l {AbstractButton::}{clicked} and \l {AbstractButton::toggled} signals
36 are emitted when the switch is interactively clicked by the user via touch,
37 mouse, or keyboard.
38
39 \code
40 ColumnLayout {
41 Switch {
42 text: qsTr("Wi-Fi")
43 checked: Networking.wifiEnabled
44 onClicked: Networking.wifiEnabled = checked
45 }
46 Switch {
47 text: qsTr("Bluetooth")
48 checked: Networking.bluetoothEnabled
49 onClicked: Networking.bluetoothEnabled = checked
50 }
51 }
52 \endcode
53
54 \sa {Customizing Switch}, {Button Controls}
55*/
56
57class QQuickSwitchPrivate : public QQuickAbstractButtonPrivate
58{
59 Q_DECLARE_PUBLIC(QQuickSwitch)
60
61public:
62 qreal positionAt(const QPointF &point) const;
63
64 bool canDrag(const QPointF &movePoint) const;
65 bool handleMove(const QPointF &point, ulong timestamp) override;
66 bool handleRelease(const QPointF &point, ulong timestamp) override;
67
68 QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::Switch); }
69
70 qreal position = 0;
71};
72
73qreal QQuickSwitchPrivate::positionAt(const QPointF &point) const
74{
75 Q_Q(const QQuickSwitch);
76 qreal pos = 0.0;
77 if (indicator)
78 pos = indicator->mapFromItem(q, point).x() / indicator->width();
79 if (q->isMirrored())
80 return 1.0 - pos;
81 return pos;
82}
83
84bool QQuickSwitchPrivate::canDrag(const QPointF &movePoint) const
85{
86 // don't start dragging the handle unless the initial press was at the indicator,
87 // or the drag has reached the indicator area. this prevents unnatural jumps when
88 // dragging far outside the indicator.
89 const qreal pressPos = positionAt(pressPoint);
90 const qreal movePos = positionAt(movePoint);
91 return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0);
92}
93
94bool QQuickSwitchPrivate::handleMove(const QPointF &point, ulong timestamp)
95{
96 Q_Q(QQuickSwitch);
97 QQuickAbstractButtonPrivate::handleMove(point, timestamp);
98 if (q->keepMouseGrab() || q->keepTouchGrab())
99 q->setPosition(positionAt(point));
100 return true;
101}
102
103bool QQuickSwitchPrivate::handleRelease(const QPointF &point, ulong timestamp)
104{
105 Q_Q(QQuickSwitch);
106 QQuickAbstractButtonPrivate::handleRelease(point, timestamp);
107 q->setKeepMouseGrab(false);
108 q->setKeepTouchGrab(false);
109 return true;
110}
111
112QQuickSwitch::QQuickSwitch(QQuickItem *parent)
113 : QQuickAbstractButton(*(new QQuickSwitchPrivate), parent)
114{
115 Q_D(QQuickSwitch);
116 d->keepPressed = true;
117 setCheckable(true);
118}
119
120/*!
121 \qmlproperty real QtQuick.Controls::Switch::position
122 \readonly
123
124 \input includes/qquickswitch.qdocinc position
125*/
126qreal QQuickSwitch::position() const
127{
128 Q_D(const QQuickSwitch);
129 return d->position;
130}
131
132void QQuickSwitch::setPosition(qreal position)
133{
134 Q_D(QQuickSwitch);
135 position = std::clamp(position, qreal(0.0), qreal(1.0));
136 if (qFuzzyCompare(d->position, position))
137 return;
138
139 d->position = position;
140 emit positionChanged();
141 emit visualPositionChanged();
142}
143
144/*!
145 \qmlproperty real QtQuick.Controls::Switch::visualPosition
146 \readonly
147
148 \input includes/qquickswitch.qdocinc visualPosition
149*/
150qreal QQuickSwitch::visualPosition() const
151{
152 Q_D(const QQuickSwitch);
153 if (isMirrored())
154 return 1.0 - d->position;
155 return d->position;
156}
157
158void QQuickSwitch::mouseMoveEvent(QMouseEvent *event)
159{
160 Q_D(QQuickSwitch);
161 if (!keepMouseGrab()) {
162 const QPointF movePoint = event->position();
163 if (d->canDrag(movePoint)) {
164 setKeepMouseGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(),
165 Qt::XAxis, event));
166 }
167 }
168 QQuickAbstractButton::mouseMoveEvent(event);
169}
170
171#if QT_CONFIG(quicktemplates2_multitouch)
172void QQuickSwitch::touchEvent(QTouchEvent *event)
173{
174 Q_D(QQuickSwitch);
175 if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) {
176 for (const QTouchEvent::TouchPoint &point : event->points()) {
177 if (point.id() != d->touchId || point.state() != QEventPoint::Updated)
178 continue;
179 if (d->canDrag(point.position())) {
180 setKeepTouchGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(),
181 Qt::XAxis, point));
182 }
183 }
184 }
185 QQuickAbstractButton::touchEvent(event);
186}
187#endif
188
189void QQuickSwitch::mirrorChange()
190{
191 QQuickAbstractButton::mirrorChange();
192 emit visualPositionChanged();
193}
194
195void QQuickSwitch::nextCheckState()
196{
197 Q_D(QQuickSwitch);
198 if (keepMouseGrab() || keepTouchGrab()) {
199 d->toggle(d->position > 0.5);
200 // the checked state might not change => force a position update to
201 // avoid that the handle is left somewhere in the middle (QTBUG-57944)
202 setPosition(d->checked ? 1.0 : 0.0);
203 } else {
204 QQuickAbstractButton::nextCheckState();
205 }
206}
207
208void QQuickSwitch::buttonChange(ButtonChange change)
209{
210 Q_D(QQuickSwitch);
211 if (change == ButtonCheckedChange)
212 setPosition(d->checked ? 1.0 : 0.0);
213 else
214 QQuickAbstractButton::buttonChange(change);
215}
216
217QFont QQuickSwitch::defaultFont() const
218{
219 return QQuickTheme::font(QQuickTheme::Switch);
220}
221
222QT_END_NAMESPACE
223
224#include "moc_qquickswitch_p.cpp"