8#include <private/qdialog_p.h>
24#if QT_CONFIG(dialogbuttonbox)
25#include "qdialogbuttonbox.h"
28#if QT_CONFIG(accessibility)
29#include "qaccessible.h"
34#include "private/qmenu_p.h"
36#include "private/qpushbutton_p.h"
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
140
141
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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
188
189
192
193
194
195
196
197
198
199
202
203
205QPushButton::QPushButton(QWidget *parent)
206 : QAbstractButton(*
new QPushButtonPrivate, parent)
213
214
215
217QPushButton::QPushButton(
const QString &text, QWidget *parent)
218 : QPushButton(parent)
225
226
227
228
229
230
231QPushButton::QPushButton(
const QIcon& icon,
const QString &text, QWidget *parent)
232 : QPushButton(*
new QPushButtonPrivate, parent)
239
240QPushButton::QPushButton(QPushButtonPrivate &dd, QWidget *parent)
241 : QAbstractButton(dd, parent)
248
249
250QPushButton::~QPushButton()
255QDialog *QPushButtonPrivate::dialogParent()
const
257 Q_Q(
const QPushButton);
258 const QWidget *p = q;
259 while (p && !p->isWindow()) {
260 p = p->parentWidget();
261 if (
const QDialog *dialog = qobject_cast<
const QDialog *>(p))
262 return const_cast<QDialog *>(dialog);
269
270
271
272
273
274
275void QPushButton::initStyleOption(QStyleOptionButton *option)
const
280 Q_D(
const QPushButton);
281 option->initFrom(
this);
282 option->features = QStyleOptionButton::None;
284 option->features |= QStyleOptionButton::Flat;
287 option->features |= QStyleOptionButton::HasMenu;
290 option->features |= QStyleOptionButton::AutoDefaultButton;
291 if (d->defaultButton)
292 option->features |= QStyleOptionButton::DefaultButton;
293 option->state = d->styleButtonState(option->state);
294 option->text = d->text;
295 option->icon = d->icon;
296 option->iconSize = iconSize();
299void QPushButton::setAutoDefault(
bool enable)
302 uint state = enable ? QPushButtonPrivate::On : QPushButtonPrivate::Off;
303 if (d->autoDefault != QPushButtonPrivate::Auto && d->autoDefault == state)
305 d->autoDefault = state;
306 d->sizeHint = QSize();
311bool QPushButton::autoDefault()
const
313 Q_D(
const QPushButton);
314 if (d->autoDefault == QPushButtonPrivate::Auto)
315 return ( d->dialogParent() !=
nullptr );
316 return d->autoDefault;
319void QPushButton::setDefault(
bool enable)
322 if (d->defaultButton == enable)
324 d->defaultButton = enable;
326 if (d->defaultButton) {
327 if (QDialog *dlg = d->dialogParent())
328 dlg->d_func()->setMainDefault(
this);
332#if QT_CONFIG(accessibility)
333 QAccessible::State s;
334 s.defaultButton =
true;
335 QAccessibleStateChangeEvent event(
this, s);
336 QAccessible::updateAccessibility(&event);
340bool QPushButton::isDefault()
const
342 Q_D(
const QPushButton);
343 return d->defaultButton;
347
348
349QSize QPushButton::sizeHint()
const
351 Q_D(
const QPushButton);
352 if (d->sizeHint.isValid() && d->lastAutoDefault == autoDefault())
354 d->lastAutoDefault = autoDefault();
359 QStyleOptionButton opt;
360 initStyleOption(&opt);
363#if !defined(QT_NO_ICON) && QT_CONFIG(dialogbuttonbox)
364 bool showButtonBoxIcons = qobject_cast<QDialogButtonBox*>(parentWidget())
365 && style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons,
nullptr,
this);
367 if (!icon().isNull() || showButtonBoxIcons) {
368 int ih = opt.iconSize.height();
369 int iw = opt.iconSize.width() + 4;
375 bool empty = s.isEmpty();
377 s = QStringLiteral(
"XXXX");
378 QFontMetrics fm = fontMetrics();
379 QSize sz = fm.size(Qt::TextShowMnemonic, s);
383 h = qMax(h, sz.height());
384 opt.rect.setSize(QSize(w, h));
387 w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt,
this);
389 d->sizeHint = style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h),
this);
394
395
396QSize QPushButton::minimumSizeHint()
const
403
404void QPushButton::paintEvent(QPaintEvent *)
406 QStylePainter p(
this);
407 QStyleOptionButton option;
408 initStyleOption(&option);
409 p.drawControl(QStyle::CE_PushButton, option);
414void QPushButton::keyPressEvent(QKeyEvent *e)
420 if (autoDefault() || d->defaultButton) {
426 QAbstractButton::keyPressEvent(e);
431
432
433void QPushButton::focusInEvent(QFocusEvent *e)
436 if (e->reason() != Qt::PopupFocusReason && autoDefault() && !d->defaultButton) {
437 d->defaultButton =
true;
439 QDialog *dlg = qobject_cast<QDialog*>(window());
441 dlg->d_func()->setDefault(
this);
444 QAbstractButton::focusInEvent(e);
448
449
450void QPushButton::focusOutEvent(QFocusEvent *e)
453 if (e->reason() != Qt::PopupFocusReason && autoDefault() && d->defaultButton) {
455 QDialog *dlg = qobject_cast<QDialog*>(window());
457 dlg->d_func()->setDefault(
nullptr);
459 d->defaultButton =
false;
463 QAbstractButton::focusOutEvent(e);
465 if (d->menu && d->menu->isVisible())
471
472
473void QPushButton::mouseMoveEvent(QMouseEvent *e)
477 if (testAttribute(Qt::WA_Hover)) {
480 hit = hitButton(e->position().toPoint());
482 if (hit != d->hovering) {
488 QAbstractButton::mouseMoveEvent(e);
492
493
494bool QPushButton::hitButton(
const QPoint &pos)
const
496 QStyleOptionButton option;
497 initStyleOption(&option);
498 const QRect bevel = style()->subElementRect(QStyle::SE_PushButtonBevel, &option,
this);
499 return bevel.contains(pos);
504
505
506
507
508
509
510
511
512
513
514
515
516
517void QPushButton::setMenu(QMenu* menu)
523 if (menu && !d->menu) {
524 QObjectPrivate::connect(
this, &QPushButton::pressed,
525 d, &QPushButtonPrivate::popupPressed, Qt::UniqueConnection);
528 removeAction(d->menu->menuAction());
531 addAction(d->menu->menuAction());
533 d->resetLayoutItemMargins();
534 d->sizeHint = QSize();
540
541
542
543
544
545QMenu* QPushButton::menu()
const
547 Q_D(
const QPushButton);
552
553
554
555
556void QPushButton::showMenu()
565void QPushButtonPrivate::popupPressed()
571 menu->setNoReplayFor(q);
573 QPoint menuPos = adjustedMenuPosition();
575 QMenuPrivate::get(menu)->causedPopup.widget = q;
580 QObject::connect(menu, &QMenu::aboutToHide,
581 q, [q,
this]{ menuOpen =
false; q->setDown(
false); }, Qt::SingleShotConnection);
582 menu->popup(menuPos);
585QPoint QPushButtonPrivate::adjustedMenuPosition()
589 bool horizontal =
true;
590#if QT_CONFIG(toolbar)
591 QToolBar *tb = qobject_cast<QToolBar*>(parent);
592 if (tb && tb->orientation() == Qt::Vertical)
597 QRect rect = item.geometry();
598 rect.setRect(rect.x() - q->x(), rect.y() - q->y(), rect.width(), rect.height());
600 QSize menuSize = menu->sizeHint();
601 QPoint globalPos = q->mapToGlobal(rect.topLeft());
602 int x = globalPos.x();
603 int y = globalPos.y();
604 const QRect availableGeometry = QWidgetPrivate::availableScreenGeometry(q, q->mapToGlobal(rect.center()));
606 if (globalPos.y() + rect.height() + menuSize.height() <= availableGeometry.bottom()) {
608 }
else if (globalPos.y() - menuSize.height() >= availableGeometry.y()) {
609 y -= menuSize.height();
611 if (q->layoutDirection() == Qt::RightToLeft)
612 x += rect.width() - menuSize.width();
614 if (globalPos.x() + rect.width() + menu->sizeHint().width() <= availableGeometry.right()) {
616 }
else if (globalPos.x() - menuSize.width() >= availableGeometry.x()) {
617 x -= menuSize.width();
626void QPushButtonPrivate::init()
629 q->setAttribute(Qt::WA_MacShowFocusRect);
630 resetLayoutItemMargins();
633void QPushButtonPrivate::resetLayoutItemMargins()
636 QStyleOptionButton opt;
637 q->initStyleOption(&opt);
638 setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem, &opt);
641QStyle::State QPushButtonPrivate::styleButtonState(QStyle::State state)
const
643 Q_Q(
const QPushButton);
644 state = QAbstractButtonPrivate::styleButtonState(state);
646 state |= QStyle::State_Sunken;
648 state |= QStyle::State_On;
650 state |= QStyle::State_Raised;
651 if (q->underMouse() && q->hasMouseTracking())
652 state.setFlag(QStyle::State_MouseOver, hovering);
656void QPushButton::setFlat(
bool flat)
662 d->resetLayoutItemMargins();
663 d->sizeHint = QSize();
668bool QPushButton::isFlat()
const
670 Q_D(
const QPushButton);
675bool QPushButton::event(QEvent *e)
678 if (e->type() == QEvent::ParentChange) {
680 if (QDialog *dialog = d->dialogParent()) {
681 if (d->defaultButton)
682 dialog->d_func()->setMainDefault(
this);
685 }
else if (e->type() == QEvent::StyleChange
687 || e->type() == QEvent::MacSizeChange
690 d->resetLayoutItemMargins();
692 }
else if (e->type() == QEvent::PolishRequest) {
695 return QAbstractButton::event(e);
700#include "moc_qpushbutton.cpp"