7#include <private/qdialog_p.h>
23#if QT_CONFIG(dialogbuttonbox)
24#include "qdialogbuttonbox.h"
27#if QT_CONFIG(accessibility)
28#include "qaccessible.h"
33#include "private/qmenu_p.h"
35#include "private/qpushbutton_p.h"
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
190
191
192
193
194
195
196
197
200
201
203QPushButton::QPushButton(QWidget *parent)
204 : QAbstractButton(*
new QPushButtonPrivate, parent)
211
212
213
215QPushButton::QPushButton(
const QString &text, QWidget *parent)
216 : QPushButton(parent)
223
224
225
226
227
228
229QPushButton::QPushButton(
const QIcon& icon,
const QString &text, QWidget *parent)
230 : QPushButton(*
new QPushButtonPrivate, parent)
237
238QPushButton::QPushButton(QPushButtonPrivate &dd, QWidget *parent)
239 : QAbstractButton(dd, parent)
246
247
248QPushButton::~QPushButton()
253QDialog *QPushButtonPrivate::dialogParent()
const
255 Q_Q(
const QPushButton);
256 const QWidget *p = q;
257 while (p && !p->isWindow()) {
258 p = p->parentWidget();
259 if (
const QDialog *dialog = qobject_cast<
const QDialog *>(p))
260 return const_cast<QDialog *>(dialog);
267
268
269
270
271
272
273void QPushButton::initStyleOption(QStyleOptionButton *option)
const
278 Q_D(
const QPushButton);
279 option->initFrom(
this);
280 option->features = QStyleOptionButton::None;
282 option->features |= QStyleOptionButton::Flat;
285 option->features |= QStyleOptionButton::HasMenu;
288 option->features |= QStyleOptionButton::AutoDefaultButton;
289 if (d->defaultButton)
290 option->features |= QStyleOptionButton::DefaultButton;
291 if (d->down || d->menuOpen)
292 option->state |= QStyle::State_Sunken;
294 option->state |= QStyle::State_On;
295 if (!d->flat && !d->down)
296 option->state |= QStyle::State_Raised;
297 if (underMouse() && hasMouseTracking())
298 option->state.setFlag(QStyle::State_MouseOver, d->hovering);
299 option->text = d->text;
300 option->icon = d->icon;
301 option->iconSize = iconSize();
304void QPushButton::setAutoDefault(
bool enable)
307 uint state = enable ? QPushButtonPrivate::On : QPushButtonPrivate::Off;
308 if (d->autoDefault != QPushButtonPrivate::Auto && d->autoDefault == state)
310 d->autoDefault = state;
311 d->sizeHint = QSize();
316bool QPushButton::autoDefault()
const
318 Q_D(
const QPushButton);
319 if (d->autoDefault == QPushButtonPrivate::Auto)
320 return ( d->dialogParent() !=
nullptr );
321 return d->autoDefault;
324void QPushButton::setDefault(
bool enable)
327 if (d->defaultButton == enable)
329 d->defaultButton = enable;
331 if (d->defaultButton) {
332 if (QDialog *dlg = d->dialogParent())
333 dlg->d_func()->setMainDefault(
this);
337#if QT_CONFIG(accessibility)
338 QAccessible::State s;
339 s.defaultButton =
true;
340 QAccessibleStateChangeEvent event(
this, s);
341 QAccessible::updateAccessibility(&event);
345bool QPushButton::isDefault()
const
347 Q_D(
const QPushButton);
348 return d->defaultButton;
352
353
354QSize QPushButton::sizeHint()
const
356 Q_D(
const QPushButton);
357 if (d->sizeHint.isValid() && d->lastAutoDefault == autoDefault())
359 d->lastAutoDefault = autoDefault();
364 QStyleOptionButton opt;
365 initStyleOption(&opt);
368#if !defined(QT_NO_ICON) && QT_CONFIG(dialogbuttonbox)
369 bool showButtonBoxIcons = qobject_cast<QDialogButtonBox*>(parentWidget())
370 && style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons,
nullptr,
this);
372 if (!icon().isNull() || showButtonBoxIcons) {
373 int ih = opt.iconSize.height();
374 int iw = opt.iconSize.width() + 4;
380 bool empty = s.isEmpty();
382 s = QStringLiteral(
"XXXX");
383 QFontMetrics fm = fontMetrics();
384 QSize sz = fm.size(Qt::TextShowMnemonic, s);
388 h = qMax(h, sz.height());
389 opt.rect.setSize(QSize(w, h));
392 w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt,
this);
394 d->sizeHint = style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h),
this);
399
400
401QSize QPushButton::minimumSizeHint()
const
408
409void QPushButton::paintEvent(QPaintEvent *)
411 QStylePainter p(
this);
412 QStyleOptionButton option;
413 initStyleOption(&option);
414 p.drawControl(QStyle::CE_PushButton, option);
419void QPushButton::keyPressEvent(QKeyEvent *e)
425 if (autoDefault() || d->defaultButton) {
431 QAbstractButton::keyPressEvent(e);
436
437
438void QPushButton::focusInEvent(QFocusEvent *e)
441 if (e->reason() != Qt::PopupFocusReason && autoDefault() && !d->defaultButton) {
442 d->defaultButton =
true;
444 QDialog *dlg = qobject_cast<QDialog*>(window());
446 dlg->d_func()->setDefault(
this);
449 QAbstractButton::focusInEvent(e);
453
454
455void QPushButton::focusOutEvent(QFocusEvent *e)
458 if (e->reason() != Qt::PopupFocusReason && autoDefault() && d->defaultButton) {
460 QDialog *dlg = qobject_cast<QDialog*>(window());
462 dlg->d_func()->setDefault(
nullptr);
464 d->defaultButton =
false;
468 QAbstractButton::focusOutEvent(e);
470 if (d->menu && d->menu->isVisible())
476
477
478void QPushButton::mouseMoveEvent(QMouseEvent *e)
482 if (testAttribute(Qt::WA_Hover)) {
485 hit = hitButton(e->position().toPoint());
487 if (hit != d->hovering) {
493 QAbstractButton::mouseMoveEvent(e);
497
498
499bool QPushButton::hitButton(
const QPoint &pos)
const
501 QStyleOptionButton option;
502 initStyleOption(&option);
503 const QRect bevel = style()->subElementRect(QStyle::SE_PushButtonBevel, &option,
this);
504 return bevel.contains(pos);
509
510
511
512
513
514
515
516
517
518
519
520
521void QPushButton::setMenu(QMenu* menu)
527 if (menu && !d->menu) {
528 QObjectPrivate::connect(
this, &QPushButton::pressed,
529 d, &QPushButtonPrivate::popupPressed, Qt::UniqueConnection);
532 removeAction(d->menu->menuAction());
535 addAction(d->menu->menuAction());
537 d->resetLayoutItemMargins();
538 d->sizeHint = QSize();
544
545
546
547
548
549QMenu* QPushButton::menu()
const
551 Q_D(
const QPushButton);
556
557
558
559
560void QPushButton::showMenu()
569void QPushButtonPrivate::popupPressed()
575 menu->setNoReplayFor(q);
577 QPoint menuPos = adjustedMenuPosition();
579 QMenuPrivate::get(menu)->causedPopup.widget = q;
584 QObject::connect(menu, &QMenu::aboutToHide,
585 q, [q,
this]{ menuOpen =
false; q->setDown(
false); }, Qt::SingleShotConnection);
586 menu->popup(menuPos);
589QPoint QPushButtonPrivate::adjustedMenuPosition()
593 bool horizontal =
true;
594#if QT_CONFIG(toolbar)
595 QToolBar *tb = qobject_cast<QToolBar*>(parent);
596 if (tb && tb->orientation() == Qt::Vertical)
601 QRect rect = item.geometry();
602 rect.setRect(rect.x() - q->x(), rect.y() - q->y(), rect.width(), rect.height());
604 QSize menuSize = menu->sizeHint();
605 QPoint globalPos = q->mapToGlobal(rect.topLeft());
606 int x = globalPos.x();
607 int y = globalPos.y();
608 const QRect availableGeometry = QWidgetPrivate::availableScreenGeometry(q, q->mapToGlobal(rect.center()));
610 if (globalPos.y() + rect.height() + menuSize.height() <= availableGeometry.bottom()) {
612 }
else if (globalPos.y() - menuSize.height() >= availableGeometry.y()) {
613 y -= menuSize.height();
615 if (q->layoutDirection() == Qt::RightToLeft)
616 x += rect.width() - menuSize.width();
618 if (globalPos.x() + rect.width() + menu->sizeHint().width() <= availableGeometry.right()) {
620 }
else if (globalPos.x() - menuSize.width() >= availableGeometry.x()) {
621 x -= menuSize.width();
630void QPushButtonPrivate::init()
633 q->setAttribute(Qt::WA_MacShowFocusRect);
634 resetLayoutItemMargins();
637void QPushButtonPrivate::resetLayoutItemMargins()
640 QStyleOptionButton opt;
641 q->initStyleOption(&opt);
642 setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem, &opt);
645void QPushButton::setFlat(
bool flat)
651 d->resetLayoutItemMargins();
652 d->sizeHint = QSize();
657bool QPushButton::isFlat()
const
659 Q_D(
const QPushButton);
664bool QPushButton::event(QEvent *e)
667 if (e->type() == QEvent::ParentChange) {
669 if (QDialog *dialog = d->dialogParent()) {
670 if (d->defaultButton)
671 dialog->d_func()->setMainDefault(
this);
674 }
else if (e->type() == QEvent::StyleChange
676 || e->type() == QEvent::MacSizeChange
679 d->resetLayoutItemMargins();
681 }
else if (e->type() == QEvent::PolishRequest) {
684 return QAbstractButton::event(e);
689#include "moc_qpushbutton.cpp"