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