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 return d->sizeHint;
297}
298
299
300/*!
301 \reimp
302*/
303QSize QCheckBox::minimumSizeHint() const
304{
305 return sizeHint();
306}
307
308/*!
309 \reimp
310*/
311void QCheckBox::paintEvent(QPaintEvent *)
312{
313 QStylePainter p(this);
314 QStyleOptionButton opt;
315 initStyleOption(&opt);
316 p.drawControl(QStyle::CE_CheckBox, opt);
317}
318
319/*!
320 \reimp
321*/
322void QCheckBox::mouseMoveEvent(QMouseEvent *e)
323{
324 Q_D(QCheckBox);
325 if (testAttribute(Qt::WA_Hover)) {
326 bool hit = false;
327 if (underMouse())
328 hit = hitButton(e->position().toPoint());
329
330 if (hit != d->hovering) {
331 update(rect());
332 d->hovering = hit;
333 }
334 }
335
336 QAbstractButton::mouseMoveEvent(e);
337}
338
339
340/*!
341 \reimp
342*/
343bool QCheckBox::hitButton(const QPoint &pos) const
344{
345 QStyleOptionButton opt;
346 initStyleOption(&opt);
347 return style()->subElementRect(QStyle::SE_CheckBoxClickRect, &opt, this).contains(pos);
348}
349
350/*!
351 \reimp
352*/
353void QCheckBox::checkStateSet()
354{
355 Q_D(QCheckBox);
356 d->noChange = false;
357 Qt::CheckState state = checkState();
358 if ((uint)state != d->publishedState) {
359 d->publishedState = state;
360 emit stateChanged(state);
361 }
362}
363
364/*!
365 \reimp
366*/
367void QCheckBox::nextCheckState()
368{
369 Q_D(QCheckBox);
370 if (d->tristate)
371 setCheckState((Qt::CheckState)((checkState() + 1) % 3));
372 else {
373 QAbstractButton::nextCheckState();
374 QCheckBox::checkStateSet();
375 }
376}
377
378/*!
379 \reimp
380*/
381bool QCheckBox::event(QEvent *e)
382{
383 Q_D(QCheckBox);
384 if (e->type() == QEvent::StyleChange
385#ifdef Q_OS_MAC
386 || e->type() == QEvent::MacSizeChange
387#endif
388 )
389 d->setLayoutItemMargins(QStyle::SE_CheckBoxLayoutItem);
390 return QAbstractButton::event(e);
391}
392
393
394
395QT_END_NAMESPACE
396
397#include "moc_qcheckbox.cpp"
398