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: |
60 | QRadioButtonPrivate() : QAbstractButtonPrivate(QSizePolicy::RadioButton), hovering(true) {} |
61 | void init(); |
62 | uint hovering : 1; |
63 | }; |
64 | |
65 | /* |
66 | Initializes the radio button. |
67 | */ |
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(element: 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 | |
133 | QRadioButton::QRadioButton(QWidget *parent) |
134 | : QAbstractButton(*new QRadioButtonPrivate, parent) |
135 | { |
136 | Q_D(QRadioButton); |
137 | d->init(); |
138 | } |
139 | |
140 | /*! |
141 | Destructor. |
142 | */ |
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 | |
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 | */ |
166 | void QRadioButton::initStyleOption(QStyleOptionButton *option) const |
167 | { |
168 | if (!option) |
169 | return; |
170 | Q_D(const QRadioButton); |
171 | option->initFrom(w: 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(attribute: Qt::WA_Hover) && underMouse()) { |
179 | option->state.setFlag(flag: QStyle::State_MouseOver, on: d->hovering); |
180 | } |
181 | } |
182 | |
183 | /*! |
184 | \reimp |
185 | */ |
186 | 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(option: &opt); |
194 | QSize sz = style()->itemTextRect(fm: fontMetrics(), r: QRect(), flags: Qt::TextShowMnemonic, |
195 | enabled: false, text: text()).size(); |
196 | if (!opt.icon.isNull()) |
197 | sz = QSize(sz.width() + opt.iconSize.width() + 4, qMax(a: sz.height(), b: opt.iconSize.height())); |
198 | d->sizeHint = (style()->sizeFromContents(ct: QStyle::CT_RadioButton, opt: &opt, contentsSize: sz, w: this). |
199 | expandedTo(otherSize: QApplication::globalStrut())); |
200 | return d->sizeHint; |
201 | } |
202 | |
203 | /*! |
204 | \reimp |
205 | */ |
206 | QSize QRadioButton::minimumSizeHint() const |
207 | { |
208 | return sizeHint(); |
209 | } |
210 | |
211 | /*! |
212 | \reimp |
213 | */ |
214 | bool QRadioButton::hitButton(const QPoint &pos) const |
215 | { |
216 | QStyleOptionButton opt; |
217 | initStyleOption(option: &opt); |
218 | return style()->subElementRect(subElement: QStyle::SE_RadioButtonClickRect, option: &opt, widget: this).contains(p: pos); |
219 | } |
220 | |
221 | /*! |
222 | \reimp |
223 | */ |
224 | void QRadioButton::mouseMoveEvent(QMouseEvent *e) |
225 | { |
226 | Q_D(QRadioButton); |
227 | if (testAttribute(attribute: Qt::WA_Hover)) { |
228 | bool hit = false; |
229 | if (underMouse()) |
230 | hit = hitButton(pos: 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 | */ |
243 | void QRadioButton::paintEvent(QPaintEvent *) |
244 | { |
245 | QStylePainter p(this); |
246 | QStyleOptionButton opt; |
247 | initStyleOption(option: &opt); |
248 | p.drawControl(ce: QStyle::CE_RadioButton, opt); |
249 | } |
250 | |
251 | /*! \reimp */ |
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(element: QStyle::SE_RadioButtonLayoutItem); |
261 | return QAbstractButton::event(e); |
262 | } |
263 | |
264 | |
265 | QT_END_NAMESPACE |
266 | |
267 | #include "moc_qradiobutton.cpp" |
268 | |