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 "qgroupbox.h"
41 
42 #include "qapplication.h"
43 #include "qbitmap.h"
44 #include "qdrawutil.h"
45 #include "qevent.h"
46 #include "qlayout.h"
47 #if QT_CONFIG(radiobutton)
48 #include "qradiobutton.h"
49 #endif
50 #include "qstyle.h"
51 #include "qstyleoption.h"
52 #include "qstylepainter.h"
53 #ifndef QT_NO_ACCESSIBILITY
54 #include "qaccessible.h"
55 #endif
56 #include <private/qwidget_p.h>
57 
58 #include "qdebug.h"
59 
60 QT_BEGIN_NAMESPACE
61 
62 class QGroupBoxPrivate : public QWidgetPrivate
63 {
64     Q_DECLARE_PUBLIC(QGroupBox)
65 
66 public:
67     void skip();
68     void init();
69     void calculateFrame();
70     QString title;
71     int align;
72 #ifndef QT_NO_SHORTCUT
73     int shortcutId;
74 #endif
75 
76     void _q_fixFocus(Qt::FocusReason reason);
77     void _q_setChildrenEnabled(bool b);
78     void click();
79     bool flat;
80     bool checkable;
81     bool checked;
82     bool hover;
83     bool overCheckBox;
84     QStyle::SubControl pressedControl;
85 };
86 
87 /*!
88     Initialize \a option with the values from this QGroupBox. This method
89     is useful for subclasses when they need a QStyleOptionGroupBox, but don't want
90     to fill in all the information themselves.
91 
92     \sa QStyleOption::initFrom()
93 */
initStyleOption(QStyleOptionGroupBox * option) const94 void QGroupBox::initStyleOption(QStyleOptionGroupBox *option) const
95 {
96     if (!option)
97         return;
98 
99     Q_D(const QGroupBox);
100     option->initFrom(this);
101     option->text = d->title;
102     option->lineWidth = 1;
103     option->midLineWidth = 0;
104     option->textAlignment = Qt::Alignment(d->align);
105     option->activeSubControls |= d->pressedControl;
106     option->subControls = QStyle::SC_GroupBoxFrame;
107 
108     option->state.setFlag(QStyle::State_MouseOver, d->hover);
109     if (d->flat)
110         option->features |= QStyleOptionFrame::Flat;
111 
112     if (d->checkable) {
113         option->subControls |= QStyle::SC_GroupBoxCheckBox;
114         option->state |= (d->checked ? QStyle::State_On : QStyle::State_Off);
115         if ((d->pressedControl == QStyle::SC_GroupBoxCheckBox
116             || d->pressedControl == QStyle::SC_GroupBoxLabel) && (d->hover || d->overCheckBox))
117             option->state |= QStyle::State_Sunken;
118     }
119 
120     if (!option->palette.isBrushSet(isEnabled() ? QPalette::Active :
121                                     QPalette::Disabled, QPalette::WindowText))
122         option->textColor = QColor(style()->styleHint(QStyle::SH_GroupBox_TextLabelColor,
123                                    option, this));
124 
125     if (!d->title.isEmpty())
126         option->subControls |= QStyle::SC_GroupBoxLabel;
127 }
128 
click()129 void QGroupBoxPrivate::click()
130 {
131     Q_Q(QGroupBox);
132 
133     QPointer<QGroupBox> guard(q);
134     q->setChecked(!checked);
135     if (!guard)
136         return;
137     emit q->clicked(checked);
138 }
139 
140 /*!
141     \class QGroupBox
142     \brief The QGroupBox widget provides a group box frame with a title.
143 
144     \ingroup organizers
145     \ingroup geomanagement
146     \inmodule QtWidgets
147 
148     \image windows-groupbox.png
149 
150     A group box provides a frame, a title on top, a keyboard shortcut, and
151     displays various other widgets inside itself. The keyboard shortcut moves
152     keyboard focus to one of the group box's child widgets.
153 
154     QGroupBox also lets you set the \l title (normally set in the
155     constructor) and the title's \l alignment. Group boxes can be
156     \l checkable. Child widgets in checkable group boxes are enabled or
157     disabled depending on whether or not the group box is \l checked.
158 
159     You can minimize the space consumption of a group box by enabling
160     the \l flat property. In most \l{QStyle}{styles}, enabling this
161     property results in the removal of the left, right and bottom
162     edges of the frame.
163 
164     QGroupBox doesn't automatically lay out the child widgets (which
165     are often \l{QCheckBox}es or \l{QRadioButton}s but can be any
166     widgets). The following example shows how we can set up a
167     QGroupBox with a layout:
168 
169     \snippet widgets/groupbox/window.cpp 2
170 
171     \sa QButtonGroup, {Group Box Example}
172 */
173 
174 
175 
176 /*!
177     Constructs a group box widget with the given \a parent but with no title.
178 */
179 
QGroupBox(QWidget * parent)180 QGroupBox::QGroupBox(QWidget *parent)
181     : QWidget(*new QGroupBoxPrivate, parent, { })
182 {
183     Q_D(QGroupBox);
184     d->init();
185 }
186 
187 /*!
188     Constructs a group box with the given \a title and \a parent.
189 */
190 
QGroupBox(const QString & title,QWidget * parent)191 QGroupBox::QGroupBox(const QString &title, QWidget *parent)
192     : QGroupBox(parent)
193 {
194     setTitle(title);
195 }
196 
197 
198 /*!
199     Destroys the group box.
200 */
~QGroupBox()201 QGroupBox::~QGroupBox()
202 {
203 }
204 
init()205 void QGroupBoxPrivate::init()
206 {
207     Q_Q(QGroupBox);
208     align = Qt::AlignLeft;
209 #ifndef QT_NO_SHORTCUT
210     shortcutId = 0;
211 #endif
212     flat = false;
213     checkable = false;
214     checked = true;
215     hover = false;
216     overCheckBox = false;
217     pressedControl = QStyle::SC_None;
218     calculateFrame();
219     q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
220                      QSizePolicy::GroupBox));
221 }
222 
setTitle(const QString & title)223 void QGroupBox::setTitle(const QString &title)
224 {
225     Q_D(QGroupBox);
226     if (d->title == title)                                // no change
227         return;
228     d->title = title;
229 #ifndef QT_NO_SHORTCUT
230     releaseShortcut(d->shortcutId);
231     d->shortcutId = grabShortcut(QKeySequence::mnemonic(title));
232 #endif
233     d->calculateFrame();
234 
235     update();
236     updateGeometry();
237 #ifndef QT_NO_ACCESSIBILITY
238     QAccessibleEvent event(this, QAccessible::NameChanged);
239     QAccessible::updateAccessibility(&event);
240 #endif
241 }
242 
243 /*!
244     \property QGroupBox::title
245     \brief the group box title text
246 
247     The group box title text will have a keyboard shortcut if the title
248     contains an ampersand ('&') followed by a letter.
249 
250     \snippet code/src_gui_widgets_qgroupbox.cpp 0
251 
252     In the example above, \uicontrol Alt+U moves the keyboard focus to the
253     group box. See the \l {QShortcut#mnemonic}{QShortcut}
254     documentation for details (to display an actual ampersand, use
255     '&&').
256 
257     There is no default title text.
258 
259     \sa alignment
260 */
261 
title() const262 QString QGroupBox::title() const
263 {
264     Q_D(const QGroupBox);
265     return d->title;
266 }
267 
268 /*!
269     \property QGroupBox::alignment
270     \brief the alignment of the group box title.
271 
272     Most styles place the title at the top of the frame. The horizontal
273     alignment of the title can be specified using single values from
274     the following list:
275 
276     \list
277     \li Qt::AlignLeft aligns the title text with the left-hand side of the group box.
278     \li Qt::AlignRight aligns the title text with the right-hand side of the group box.
279     \li Qt::AlignHCenter aligns the title text with the horizontal center of the group box.
280     \endlist
281 
282     The default alignment is Qt::AlignLeft.
283 
284     \sa Qt::Alignment
285 */
alignment() const286 Qt::Alignment QGroupBox::alignment() const
287 {
288     Q_D(const QGroupBox);
289     return QFlag(d->align);
290 }
291 
setAlignment(int alignment)292 void QGroupBox::setAlignment(int alignment)
293 {
294     Q_D(QGroupBox);
295     d->align = alignment;
296     updateGeometry();
297     update();
298 }
299 
300 /*! \reimp
301 */
resizeEvent(QResizeEvent * e)302 void QGroupBox::resizeEvent(QResizeEvent *e)
303 {
304     QWidget::resizeEvent(e);
305 }
306 
307 /*! \reimp
308 */
309 
paintEvent(QPaintEvent *)310 void QGroupBox::paintEvent(QPaintEvent *)
311 {
312     QStylePainter paint(this);
313     QStyleOptionGroupBox option;
314     initStyleOption(&option);
315     paint.drawComplexControl(QStyle::CC_GroupBox, option);
316 }
317 
318 /*! \reimp  */
event(QEvent * e)319 bool QGroupBox::event(QEvent *e)
320 {
321     Q_D(QGroupBox);
322 #ifndef QT_NO_SHORTCUT
323     if (e->type() == QEvent::Shortcut) {
324         QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
325         if (se->shortcutId() == d->shortcutId) {
326             if (!isCheckable()) {
327                 d->_q_fixFocus(Qt::ShortcutFocusReason);
328             } else {
329                 d->click();
330                 setFocus(Qt::ShortcutFocusReason);
331             }
332             return true;
333         }
334     }
335 #endif
336     QStyleOptionGroupBox box;
337     initStyleOption(&box);
338     switch (e->type()) {
339     case QEvent::HoverEnter:
340     case QEvent::HoverMove: {
341         QStyle::SubControl control = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
342                                                                     static_cast<QHoverEvent *>(e)->pos(),
343                                                                     this);
344         bool oldHover = d->hover;
345         d->hover = d->checkable && (control == QStyle::SC_GroupBoxLabel || control == QStyle::SC_GroupBoxCheckBox);
346         if (oldHover != d->hover) {
347             QRect rect = style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this)
348                          | style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxLabel, this);
349             update(rect);
350         }
351         return true;
352     }
353     case QEvent::HoverLeave:
354         d->hover = false;
355         if (d->checkable) {
356             QRect rect = style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this)
357                          | style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxLabel, this);
358             update(rect);
359         }
360         return true;
361     case QEvent::KeyPress: {
362         QKeyEvent *k = static_cast<QKeyEvent*>(e);
363         if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
364             d->pressedControl = QStyle::SC_GroupBoxCheckBox;
365             update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
366             return true;
367         }
368         break;
369     }
370     case QEvent::KeyRelease: {
371         QKeyEvent *k = static_cast<QKeyEvent*>(e);
372         if (!k->isAutoRepeat() && (k->key() == Qt::Key_Select || k->key() == Qt::Key_Space)) {
373             bool toggle = (d->pressedControl == QStyle::SC_GroupBoxLabel
374                            || d->pressedControl == QStyle::SC_GroupBoxCheckBox);
375             d->pressedControl = QStyle::SC_None;
376             if (toggle)
377                 d->click();
378             return true;
379         }
380         break;
381     }
382     default:
383         break;
384     }
385     return QWidget::event(e);
386 }
387 
388 /*!\reimp */
childEvent(QChildEvent * c)389 void QGroupBox::childEvent(QChildEvent *c)
390 {
391     Q_D(QGroupBox);
392     /*
393         Children might have been enabled after being added to the group box, in which case
394         the childEvent handler ran too early, and we need to disabled children again.
395     */
396     if (!(c->added() || c->polished()) || !c->child()->isWidgetType())
397         return;
398     QWidget *w = static_cast<QWidget*>(c->child());
399     if (w->isWindow())
400         return;
401     if (d->checkable) {
402         if (d->checked) {
403             if (!w->testAttribute(Qt::WA_ForceDisabled))
404                 w->setEnabled(true);
405         } else {
406             if (w->isEnabled()) {
407                 w->setEnabled(false);
408                 w->setAttribute(Qt::WA_ForceDisabled, false);
409             }
410         }
411     }
412 }
413 
414 
415 /*!
416     \internal
417 
418     This private slot finds a widget in this group box that can accept
419     focus, and gives the focus to that widget.
420 */
421 
_q_fixFocus(Qt::FocusReason reason)422 void QGroupBoxPrivate::_q_fixFocus(Qt::FocusReason reason)
423 {
424     Q_Q(QGroupBox);
425     QWidget *fw = q->focusWidget();
426     if (!fw || fw == q) {
427         QWidget * best = nullptr;
428         QWidget * candidate = nullptr;
429         QWidget * w = q;
430         while ((w = w->nextInFocusChain()) != q) {
431             if (q->isAncestorOf(w) && (w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus && w->isVisibleTo(q)) {
432 #if QT_CONFIG(radiobutton)
433                 if (!best && qobject_cast<QRadioButton*>(w) && ((QRadioButton*)w)->isChecked())
434                     // we prefer a checked radio button or a widget that
435                     // already has focus, if there is one
436                     best = w;
437                 else
438 #endif
439                     if (!candidate)
440                         // but we'll accept anything that takes focus
441                         candidate = w;
442             }
443         }
444         if (best)
445             fw = best;
446         else if (candidate)
447                 fw = candidate;
448     }
449     if (fw)
450         fw->setFocus(reason);
451 }
452 
453 /*
454     Sets the right frame rect depending on the title.
455 */
calculateFrame()456 void QGroupBoxPrivate::calculateFrame()
457 {
458     Q_Q(QGroupBox);
459     QStyleOptionGroupBox box;
460     q->initStyleOption(&box);
461     QRect contentsRect = q->style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxContents, q);
462     q->setContentsMargins(contentsRect.left() - box.rect.left(), contentsRect.top() - box.rect.top(),
463                           box.rect.right() - contentsRect.right(), box.rect.bottom() - contentsRect.bottom());
464     setLayoutItemMargins(QStyle::SE_GroupBoxLayoutItem, &box);
465 }
466 
467 /*! \reimp
468  */
focusInEvent(QFocusEvent * fe)469 void QGroupBox::focusInEvent(QFocusEvent *fe)
470 { // note no call to super
471     Q_D(QGroupBox);
472     if (focusPolicy() == Qt::NoFocus) {
473         d->_q_fixFocus(fe->reason());
474     } else {
475         QWidget::focusInEvent(fe);
476     }
477 }
478 
479 
480 /*!
481   \reimp
482 */
minimumSizeHint() const483 QSize QGroupBox::minimumSizeHint() const
484 {
485     Q_D(const QGroupBox);
486     QStyleOptionGroupBox option;
487     initStyleOption(&option);
488 
489     QFontMetrics metrics(fontMetrics());
490 
491     int baseWidth = metrics.horizontalAdvance(d->title) + metrics.horizontalAdvance(QLatin1Char(' '));
492     int baseHeight = metrics.height();
493     if (d->checkable) {
494         baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth, &option);
495         baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &option);
496         baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight, &option));
497     }
498 
499     QSize size = style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), this);
500     return size.expandedTo(QWidget::minimumSizeHint());
501 }
502 
503 /*!
504     \property QGroupBox::flat
505     \brief whether the group box is painted flat or has a frame
506 
507     A group box usually consists of a surrounding frame with a title
508     at the top. If this property is enabled, only the top part of the frame is
509     drawn in most styles; otherwise, the whole frame is drawn.
510 
511     By default, this property is disabled, i.e., group boxes are not flat unless
512     explicitly specified.
513 
514     \b{Note:} In some styles, flat and non-flat group boxes have similar
515     representations and may not be as distinguishable as they are in other
516     styles.
517 
518     \sa title
519 */
isFlat() const520 bool QGroupBox::isFlat() const
521 {
522     Q_D(const QGroupBox);
523     return d->flat;
524 }
525 
setFlat(bool b)526 void QGroupBox::setFlat(bool b)
527 {
528     Q_D(QGroupBox);
529     if (d->flat == b)
530         return;
531     d->flat = b;
532     updateGeometry();
533     update();
534 }
535 
536 
537 /*!
538     \property QGroupBox::checkable
539     \brief whether the group box has a checkbox in its title
540 
541     If this property is \c true, the group box displays its title using
542     a checkbox in place of an ordinary label. If the checkbox is checked,
543     the group box's children are enabled; otherwise, they are disabled and
544     inaccessible.
545 
546     By default, group boxes are not checkable.
547 
548     If this property is enabled for a group box, it will also be initially
549     checked to ensure that its contents are enabled.
550 
551     \sa checked
552 */
setCheckable(bool checkable)553 void QGroupBox::setCheckable(bool checkable)
554 {
555     Q_D(QGroupBox);
556 
557     bool wasCheckable = d->checkable;
558     d->checkable = checkable;
559 
560     if (checkable) {
561         setChecked(true);
562         if (!wasCheckable) {
563             setFocusPolicy(Qt::StrongFocus);
564             d->_q_setChildrenEnabled(true);
565             updateGeometry();
566         }
567     } else {
568         if (wasCheckable) {
569             setFocusPolicy(Qt::NoFocus);
570             d->_q_setChildrenEnabled(true);
571             updateGeometry();
572         }
573         d->_q_setChildrenEnabled(true);
574     }
575 
576     if (wasCheckable != checkable) {
577         d->calculateFrame();
578         update();
579     }
580 }
581 
isCheckable() const582 bool QGroupBox::isCheckable() const
583 {
584     Q_D(const QGroupBox);
585     return d->checkable;
586 }
587 
588 
isChecked() const589 bool QGroupBox::isChecked() const
590 {
591     Q_D(const QGroupBox);
592     return d->checkable && d->checked;
593 }
594 
595 
596 /*!
597     \fn void QGroupBox::toggled(bool on)
598 
599     If the group box is checkable, this signal is emitted when the check box
600     is toggled. \a on is true if the check box is checked; otherwise, it is false.
601 
602     \sa checkable
603 */
604 
605 
606 /*!
607     \fn void QGroupBox::clicked(bool checked)
608     \since 4.2
609 
610     This signal is emitted when the check box is activated (i.e., pressed down
611     then released while the mouse cursor is inside the button), or when the
612     shortcut key is typed. Notably, this signal is \e not emitted if you call
613     setChecked().
614 
615     If the check box is checked, \a checked is true; it is false if the check
616     box is unchecked.
617 
618     \sa checkable, toggled(), checked
619 */
620 
621 /*!
622     \property QGroupBox::checked
623     \brief whether the group box is checked
624 
625     If the group box is checkable, it is displayed with a check box.
626     If the check box is checked, the group box's children are enabled;
627     otherwise, the children are disabled and are inaccessible to the user.
628 
629     By default, checkable group boxes are also checked.
630 
631     \sa checkable
632 */
setChecked(bool b)633 void QGroupBox::setChecked(bool b)
634 {
635     Q_D(QGroupBox);
636     if (d->checkable && b != d->checked) {
637         update();
638         d->checked = b;
639         d->_q_setChildrenEnabled(b);
640 #ifndef QT_NO_ACCESSIBILITY
641         QAccessible::State st;
642         st.checked = true;
643         QAccessibleStateChangeEvent e(this, st);
644         QAccessible::updateAccessibility(&e);
645 #endif
646         emit toggled(b);
647     }
648 }
649 
650 /*
651   sets all children of the group box except the qt_groupbox_checkbox
652   to either disabled/enabled
653 */
_q_setChildrenEnabled(bool b)654 void QGroupBoxPrivate::_q_setChildrenEnabled(bool b)
655 {
656     Q_Q(QGroupBox);
657     for (QObject *o : q->children()) {
658         if (o->isWidgetType()) {
659             QWidget *w = static_cast<QWidget *>(o);
660             if (b) {
661                 if (!w->testAttribute(Qt::WA_ForceDisabled))
662                     w->setEnabled(true);
663             } else {
664                 if (w->isEnabled()) {
665                     w->setEnabled(false);
666                     w->setAttribute(Qt::WA_ForceDisabled, false);
667                 }
668             }
669         }
670     }
671 }
672 
673 /*! \reimp */
changeEvent(QEvent * ev)674 void QGroupBox::changeEvent(QEvent *ev)
675 {
676     Q_D(QGroupBox);
677     if (ev->type() == QEvent::EnabledChange) {
678         if (d->checkable && isEnabled()) {
679             // we are being enabled - disable children
680             if (!d->checked)
681                 d->_q_setChildrenEnabled(false);
682         }
683     } else if (ev->type() == QEvent::FontChange
684 #ifdef Q_OS_MAC
685                || ev->type() == QEvent::MacSizeChange
686 #endif
687                || ev->type() == QEvent::StyleChange) {
688         d->calculateFrame();
689     }
690     QWidget::changeEvent(ev);
691 }
692 
693 /*! \reimp */
mousePressEvent(QMouseEvent * event)694 void QGroupBox::mousePressEvent(QMouseEvent *event)
695 {
696     if (event->button() != Qt::LeftButton) {
697         event->ignore();
698         return;
699     }
700 
701     Q_D(QGroupBox);
702     QStyleOptionGroupBox box;
703     initStyleOption(&box);
704     d->pressedControl = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
705                                                        event->pos(), this);
706     if (d->checkable && (d->pressedControl & (QStyle::SC_GroupBoxCheckBox | QStyle::SC_GroupBoxLabel))) {
707         d->overCheckBox = true;
708         update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
709     } else {
710         event->ignore();
711     }
712 }
713 
714 /*! \reimp */
mouseMoveEvent(QMouseEvent * event)715 void QGroupBox::mouseMoveEvent(QMouseEvent *event)
716 {
717     Q_D(QGroupBox);
718     QStyleOptionGroupBox box;
719     initStyleOption(&box);
720     QStyle::SubControl pressed = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
721                                                                 event->pos(), this);
722     bool oldOverCheckBox = d->overCheckBox;
723     d->overCheckBox = (pressed == QStyle::SC_GroupBoxCheckBox || pressed == QStyle::SC_GroupBoxLabel);
724     if (d->checkable && (d->pressedControl == QStyle::SC_GroupBoxCheckBox || d->pressedControl == QStyle::SC_GroupBoxLabel)
725         && (d->overCheckBox != oldOverCheckBox))
726         update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
727 
728     event->ignore();
729 }
730 
731 /*! \reimp */
mouseReleaseEvent(QMouseEvent * event)732 void QGroupBox::mouseReleaseEvent(QMouseEvent *event)
733 {
734     if (event->button() != Qt::LeftButton) {
735         event->ignore();
736         return;
737     }
738 
739     Q_D(QGroupBox);
740     if (!d->overCheckBox) {
741         event->ignore();
742         return;
743     }
744     QStyleOptionGroupBox box;
745     initStyleOption(&box);
746     QStyle::SubControl released = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
747                                                                  event->pos(), this);
748     bool toggle = d->checkable && (released == QStyle::SC_GroupBoxLabel
749                                    || released == QStyle::SC_GroupBoxCheckBox);
750     d->pressedControl = QStyle::SC_None;
751     d->overCheckBox = false;
752     if (toggle)
753         d->click();
754     else if (d->checkable)
755         update(style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this));
756 }
757 
758 QT_END_NAMESPACE
759 
760 #include "moc_qgroupbox.cpp"
761