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