1// Copyright (C) 2016 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
4#include "qcheckbox.h"
5#include "qapplication.h"
6#include "qbitmap.h"
7#include "qicon.h"
8#include "qstylepainter.h"
9#include "qstyle.h"
10#include "qstyleoption.h"
11#include "qevent.h"
12#if QT_CONFIG(accessibility)
13#include "qaccessible.h"
14#endif
15
16#include "private/qabstractbutton_p.h"
17
18QT_BEGIN_NAMESPACE
19
20class QCheckBoxPrivate : public QAbstractButtonPrivate
21{
22 Q_DECLARE_PUBLIC(QCheckBox)
23public:
24 QCheckBoxPrivate()
25 : QAbstractButtonPrivate(QSizePolicy::CheckBox), tristate(false), noChange(false),
26 hovering(true), publishedState(Qt::Unchecked) {}
27
28 uint tristate : 1;
29 uint noChange : 1;
30 uint hovering : 1;
31 Qt::CheckState publishedState : 2;
32
33 void init();
34};
35
36/*!
37 \class QCheckBox
38 \brief The QCheckBox widget provides a checkbox with a text label.
39
40 \ingroup basicwidgets
41 \inmodule QtWidgets
42
43 \image windows-checkbox.png
44
45 A QCheckBox is an option button that can be switched on (checked) or off
46 (unchecked). Checkboxes are typically used to represent features in an
47 application that can be enabled or disabled without affecting others.
48 Different types of behavior can be implemented. For example, a
49 QButtonGroup can be used to group check buttons logically, allowing
50 exclusive checkboxes. However, QButtonGroup does not provide any visual
51 representation.
52
53 The image below further illustrates the differences between exclusive and
54 non-exclusive checkboxes.
55
56 \table
57 \row \li \inlineimage checkboxes-exclusive.png
58 \li \inlineimage checkboxes-non-exclusive.png
59 \endtable
60
61 Whenever a checkbox is checked or cleared, it emits the signal
62 stateChanged(). Connect to this signal if you want to trigger an action
63 each time the checkbox changes state. You can use isChecked() to query
64 whether or not a checkbox is checked.
65
66 In addition to the usual checked and unchecked states, QCheckBox optionally
67 provides a third state to indicate "no change". This is useful whenever you
68 need to give the user the option of neither checking nor unchecking a
69 checkbox. If you need this third state, enable it with setTristate(), and
70 use checkState() to query the current toggle state.
71
72 Just like QPushButton, a checkbox displays text, and optionally a small
73 icon. The icon is set with setIcon(). The text can be set in the
74 constructor or with setText(). A shortcut key can be specified by preceding
75 the preferred character with an ampersand. For example:
76
77 \snippet code/src_gui_widgets_qcheckbox.cpp 0
78
79 In this example, the shortcut is \e{Alt+A}. See the \l{QShortcut#mnemonic}
80 {QShortcut} documentation for details. To display an actual ampersand,
81 use '&&'.
82
83 Important inherited functions: text(), setText(), text(), pixmap(),
84 setPixmap(), accel(), setAccel(), isToggleButton(), setDown(), isDown(),
85 isOn(), checkState(), autoRepeat(), isExclusiveToggle(), group(),
86 setAutoRepeat(), toggle(), pressed(), released(), clicked(), toggled(),
87 checkState(), and stateChanged().
88
89 \sa QAbstractButton, QRadioButton
90*/
91
92/*!
93 \fn void QCheckBox::stateChanged(int state)
94 //! Qt 7: \fn void QCheckBox::stateChanged(Qt::CheckState state)
95
96 This signal is emitted whenever the checkbox's state changes, i.e.,
97 whenever the user checks or unchecks it.
98
99 \a state contains the checkbox's new Qt::CheckState.
100*/
101
102/*!
103 \property QCheckBox::tristate
104 \brief whether the checkbox is a tri-state checkbox
105
106 The default is false, i.e., the checkbox has only two states.
107*/
108
109void QCheckBoxPrivate::init()
110{
111 Q_Q(QCheckBox);
112 q->setCheckable(true);
113 q->setMouseTracking(true);
114 q->setForegroundRole(QPalette::WindowText);
115 q->setAttribute(Qt::WA_MacShowFocusRect);
116 setLayoutItemMargins(element: QStyle::SE_CheckBoxLayoutItem);
117}
118
119/*!
120 Initializes \a option with the values from this QCheckBox. This method is
121 useful for subclasses that require a QStyleOptionButton, but do not want
122 to fill in all the information themselves.
123
124 \sa QStyleOption::initFrom()
125*/
126void QCheckBox::initStyleOption(QStyleOptionButton *option) const
127{
128 if (!option)
129 return;
130 Q_D(const QCheckBox);
131 option->initFrom(w: this);
132 if (d->down)
133 option->state |= QStyle::State_Sunken;
134 if (d->tristate && d->noChange)
135 option->state |= QStyle::State_NoChange;
136 else
137 option->state |= d->checked ? QStyle::State_On : QStyle::State_Off;
138 if (testAttribute(attribute: Qt::WA_Hover) && underMouse()) {
139 option->state.setFlag(flag: QStyle::State_MouseOver, on: d->hovering);
140 }
141 option->text = d->text;
142 option->icon = d->icon;
143 option->iconSize = iconSize();
144}
145
146/*!
147 Constructs a checkbox with the given \a parent, but with no text.
148
149 \a parent is passed on to the QAbstractButton constructor.
150*/
151
152QCheckBox::QCheckBox(QWidget *parent)
153 : QAbstractButton (*new QCheckBoxPrivate, parent)
154{
155 Q_D(QCheckBox);
156 d->init();
157}
158
159/*!
160 Constructs a checkbox with the given \a parent and \a text.
161
162 \a parent is passed on to the QAbstractButton constructor.
163*/
164
165QCheckBox::QCheckBox(const QString &text, QWidget *parent)
166 : QCheckBox(parent)
167{
168 setText(text);
169}
170
171/*!
172 Destructor.
173*/
174QCheckBox::~QCheckBox()
175{
176}
177
178void QCheckBox::setTristate(bool y)
179{
180 Q_D(QCheckBox);
181 d->tristate = y;
182}
183
184bool QCheckBox::isTristate() const
185{
186 Q_D(const QCheckBox);
187 return d->tristate;
188}
189
190
191/*!
192 Returns the checkbox's check state. If you do not need tristate support,
193 you can also use \l QAbstractButton::isChecked(), which returns a boolean.
194
195 \sa setCheckState(), Qt::CheckState
196*/
197Qt::CheckState QCheckBox::checkState() const
198{
199 Q_D(const QCheckBox);
200 if (d->tristate && d->noChange)
201 return Qt::PartiallyChecked;
202 return d->checked ? Qt::Checked : Qt::Unchecked;
203}
204
205/*!
206 Sets the checkbox's check state to \a state. If you do not need tristate
207 support, you can also use \l QAbstractButton::setChecked(), which takes a
208 boolean.
209
210 \sa checkState(), Qt::CheckState
211*/
212void QCheckBox::setCheckState(Qt::CheckState state)
213{
214 Q_D(QCheckBox);
215#if QT_CONFIG(accessibility)
216 bool noChange = d->noChange;
217#endif
218 if (state == Qt::PartiallyChecked) {
219 d->tristate = true;
220 d->noChange = true;
221 } else {
222 d->noChange = false;
223 }
224 d->blockRefresh = true;
225 setChecked(state != Qt::Unchecked);
226 d->blockRefresh = false;
227 d->refresh();
228 if (state != d->publishedState) {
229 d->publishedState = state;
230 emit stateChanged(state);
231 }
232
233#if QT_CONFIG(accessibility)
234 if (noChange != d->noChange) {
235 QAccessible::State s;
236 s.checkStateMixed = true;
237 QAccessibleStateChangeEvent event(this, s);
238 QAccessible::updateAccessibility(event: &event);
239 }
240#endif
241}
242
243
244/*!
245 \reimp
246*/
247QSize QCheckBox::sizeHint() const
248{
249 Q_D(const QCheckBox);
250 if (d->sizeHint.isValid())
251 return d->sizeHint;
252 ensurePolished();
253 QFontMetrics fm = fontMetrics();
254 QStyleOptionButton opt;
255 initStyleOption(option: &opt);
256 QSize sz = style()->itemTextRect(fm, r: QRect(), flags: Qt::TextShowMnemonic, enabled: false,
257 text: text()).size();
258 if (!opt.icon.isNull())
259 sz = QSize(sz.width() + opt.iconSize.width() + 4, qMax(a: sz.height(), b: opt.iconSize.height()));
260 d->sizeHint = style()->sizeFromContents(ct: QStyle::CT_CheckBox, opt: &opt, contentsSize: sz, w: this);
261 return d->sizeHint;
262}
263
264
265/*!
266 \reimp
267*/
268QSize QCheckBox::minimumSizeHint() const
269{
270 return sizeHint();
271}
272
273/*!
274 \reimp
275*/
276void QCheckBox::paintEvent(QPaintEvent *)
277{
278 QStylePainter p(this);
279 QStyleOptionButton opt;
280 initStyleOption(option: &opt);
281 p.drawControl(ce: QStyle::CE_CheckBox, opt);
282}
283
284/*!
285 \reimp
286*/
287void QCheckBox::mouseMoveEvent(QMouseEvent *e)
288{
289 Q_D(QCheckBox);
290 if (testAttribute(attribute: Qt::WA_Hover)) {
291 bool hit = false;
292 if (underMouse())
293 hit = hitButton(pos: e->position().toPoint());
294
295 if (hit != d->hovering) {
296 update(rect());
297 d->hovering = hit;
298 }
299 }
300
301 QAbstractButton::mouseMoveEvent(e);
302}
303
304
305/*!
306 \reimp
307*/
308bool QCheckBox::hitButton(const QPoint &pos) const
309{
310 QStyleOptionButton opt;
311 initStyleOption(option: &opt);
312 return style()->subElementRect(subElement: QStyle::SE_CheckBoxClickRect, option: &opt, widget: this).contains(p: pos);
313}
314
315/*!
316 \reimp
317*/
318void QCheckBox::checkStateSet()
319{
320 Q_D(QCheckBox);
321 d->noChange = false;
322 Qt::CheckState state = checkState();
323 if (state != d->publishedState) {
324 d->publishedState = state;
325 emit stateChanged(state);
326 }
327}
328
329/*!
330 \reimp
331*/
332void QCheckBox::nextCheckState()
333{
334 Q_D(QCheckBox);
335 if (d->tristate)
336 setCheckState((Qt::CheckState)((checkState() + 1) % 3));
337 else {
338 QAbstractButton::nextCheckState();
339 QCheckBox::checkStateSet();
340 }
341}
342
343/*!
344 \reimp
345*/
346bool QCheckBox::event(QEvent *e)
347{
348 Q_D(QCheckBox);
349 if (e->type() == QEvent::StyleChange
350#ifdef Q_OS_MAC
351 || e->type() == QEvent::MacSizeChange
352#endif
353 )
354 d->setLayoutItemMargins(element: QStyle::SE_CheckBoxLayoutItem);
355 return QAbstractButton::event(e);
356}
357
358
359
360QT_END_NAMESPACE
361
362#include "moc_qcheckbox.cpp"
363

source code of qtbase/src/widgets/widgets/qcheckbox.cpp