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 "qradiobutton.h"
41 #include "qapplication.h"
42 #include "qbitmap.h"
43 #if QT_CONFIG(buttongroup)
44 #include "qbuttongroup.h"
45 #endif
46 #include "qstylepainter.h"
47 #include "qstyle.h"
48 #include "qstyleoption.h"
49 #include "qevent.h"
50 
51 #include "private/qabstractbutton_p.h"
52 
53 QT_BEGIN_NAMESPACE
54 
55 class QRadioButtonPrivate : public QAbstractButtonPrivate
56 {
57     Q_DECLARE_PUBLIC(QRadioButton)
58 
59 public:
QRadioButtonPrivate()60     QRadioButtonPrivate() : QAbstractButtonPrivate(QSizePolicy::RadioButton), hovering(true) {}
61     void init();
62     uint hovering : 1;
63 };
64 
65 /*
66     Initializes the radio button.
67 */
init()68 void QRadioButtonPrivate::init()
69 {
70     Q_Q(QRadioButton);
71     q->setCheckable(true);
72     q->setAutoExclusive(true);
73     q->setMouseTracking(true);
74     q->setForegroundRole(QPalette::WindowText);
75     q->setAttribute(Qt::WA_MacShowFocusRect);
76     setLayoutItemMargins(QStyle::SE_RadioButtonLayoutItem);
77 }
78 
79 /*!
80     \class QRadioButton
81     \brief The QRadioButton widget provides a radio button with a text label.
82 
83     \ingroup basicwidgets
84     \inmodule QtWidgets
85 
86     \image windows-radiobutton.png
87 
88     A QRadioButton is an option button that can be switched on (checked) or
89     off (unchecked). Radio buttons typically present the user with a "one
90     of many" choice. In a group of radio buttons, only one radio button at
91     a time can be checked; if the user selects another button, the
92     previously selected button is switched off.
93 
94     Radio buttons are autoExclusive by default. If auto-exclusive is
95     enabled, radio buttons that belong to the same parent widget
96     behave as if they were part of the same exclusive button group. If
97     you need multiple exclusive button groups for radio buttons that
98     belong to the same parent widget, put them into a QButtonGroup.
99 
100     Whenever a button is switched on or off, it emits the toggled() signal.
101     Connect to this signal if you want to trigger an action each time the
102     button changes state. Use isChecked() to see if a particular button is
103     selected.
104 
105     Just like QPushButton, a radio button displays text, and
106     optionally a small icon. The icon is set with setIcon(). The text
107     can be set in the constructor or with setText(). A shortcut key
108     can be specified by preceding the preferred character with an
109     ampersand in the text. For example:
110 
111     \snippet code/src_gui_widgets_qradiobutton.cpp 0
112 
113     In this example the shortcut is \e{Alt+c}. See the \l
114     {QShortcut#mnemonic}{QShortcut} documentation for details. To
115     display an actual ampersand, use '&&'.
116 
117     Important inherited members: text(), setText(), text(),
118     setDown(), isDown(), autoRepeat(), group(), setAutoRepeat(),
119     toggle(), pressed(), released(), clicked(), and toggled().
120 
121     \sa QPushButton, QToolButton, QCheckBox, {fowler}{GUI Design Handbook: Radio Button},
122         {Group Box Example}
123 */
124 
125 
126 /*!
127     Constructs a radio button with the given \a parent, but with no text or
128     pixmap.
129 
130     The \a parent argument is passed on to the QAbstractButton constructor.
131 */
132 
QRadioButton(QWidget * parent)133 QRadioButton::QRadioButton(QWidget *parent)
134     : QAbstractButton(*new QRadioButtonPrivate, parent)
135 {
136     Q_D(QRadioButton);
137     d->init();
138 }
139 
140 /*!
141     Destructor.
142 */
~QRadioButton()143 QRadioButton::~QRadioButton()
144 {
145 }
146 
147 /*!
148     Constructs a radio button with the given \a parent and \a text string.
149 
150     The \a parent argument is passed on to the QAbstractButton constructor.
151 */
152 
QRadioButton(const QString & text,QWidget * parent)153 QRadioButton::QRadioButton(const QString &text, QWidget *parent)
154     : QRadioButton(parent)
155 {
156     setText(text);
157 }
158 
159 /*!
160     Initialize \a option with the values from this QRadioButton. This method is useful
161     for subclasses when they need a QStyleOptionButton, but don't want to fill
162     in all the information themselves.
163 
164     \sa QStyleOption::initFrom()
165 */
initStyleOption(QStyleOptionButton * option) const166 void QRadioButton::initStyleOption(QStyleOptionButton *option) const
167 {
168     if (!option)
169         return;
170     Q_D(const QRadioButton);
171     option->initFrom(this);
172     option->text = d->text;
173     option->icon = d->icon;
174     option->iconSize = iconSize();
175     if (d->down)
176         option->state |= QStyle::State_Sunken;
177     option->state |= (d->checked) ? QStyle::State_On : QStyle::State_Off;
178     if (testAttribute(Qt::WA_Hover) && underMouse()) {
179         option->state.setFlag(QStyle::State_MouseOver, d->hovering);
180     }
181 }
182 
183 /*!
184     \reimp
185 */
sizeHint() const186 QSize QRadioButton::sizeHint() const
187 {
188     Q_D(const QRadioButton);
189     if (d->sizeHint.isValid())
190         return d->sizeHint;
191     ensurePolished();
192     QStyleOptionButton opt;
193     initStyleOption(&opt);
194     QSize sz = style()->itemTextRect(fontMetrics(), QRect(), Qt::TextShowMnemonic,
195                                      false, text()).size();
196     if (!opt.icon.isNull())
197         sz = QSize(sz.width() + opt.iconSize.width() + 4, qMax(sz.height(), opt.iconSize.height()));
198     d->sizeHint = (style()->sizeFromContents(QStyle::CT_RadioButton, &opt, sz, this).
199                   expandedTo(QApplication::globalStrut()));
200     return d->sizeHint;
201 }
202 
203 /*!
204     \reimp
205 */
minimumSizeHint() const206 QSize QRadioButton::minimumSizeHint() const
207 {
208     return sizeHint();
209 }
210 
211 /*!
212     \reimp
213 */
hitButton(const QPoint & pos) const214 bool QRadioButton::hitButton(const QPoint &pos) const
215 {
216     QStyleOptionButton opt;
217     initStyleOption(&opt);
218     return style()->subElementRect(QStyle::SE_RadioButtonClickRect, &opt, this).contains(pos);
219 }
220 
221 /*!
222     \reimp
223 */
mouseMoveEvent(QMouseEvent * e)224 void QRadioButton::mouseMoveEvent(QMouseEvent *e)
225 {
226     Q_D(QRadioButton);
227     if (testAttribute(Qt::WA_Hover)) {
228         bool hit = false;
229         if (underMouse())
230             hit = hitButton(e->pos());
231 
232         if (hit != d->hovering) {
233             update();
234             d->hovering = hit;
235         }
236     }
237 
238     QAbstractButton::mouseMoveEvent(e);
239 }
240 
241 /*!\reimp
242  */
paintEvent(QPaintEvent *)243 void QRadioButton::paintEvent(QPaintEvent *)
244 {
245     QStylePainter p(this);
246     QStyleOptionButton opt;
247     initStyleOption(&opt);
248     p.drawControl(QStyle::CE_RadioButton, opt);
249 }
250 
251 /*! \reimp */
event(QEvent * e)252 bool QRadioButton::event(QEvent *e)
253 {
254     Q_D(QRadioButton);
255     if (e->type() == QEvent::StyleChange
256 #ifdef Q_OS_MAC
257             || e->type() == QEvent::MacSizeChange
258 #endif
259             )
260         d->setLayoutItemMargins(QStyle::SE_RadioButtonLayoutItem);
261     return QAbstractButton::event(e);
262 }
263 
264 
265 QT_END_NAMESPACE
266 
267 #include "moc_qradiobutton.cpp"
268