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