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
142
143
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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
190
191
194
195
196
197
198
199
200
201
204
205
207QPushButton::QPushButton(QWidget *parent)
208 : QAbstractButton(*
new QPushButtonPrivate, parent)
215
216
217
219QPushButton::QPushButton(
const QString &text, QWidget *parent)
220 : QPushButton(parent)
227
228
229
230
231
232
233QPushButton::QPushButton(
const QIcon& icon,
const QString &text, QWidget *parent)
234 : QPushButton(*
new QPushButtonPrivate, parent)
241
242QPushButton::QPushButton(QPushButtonPrivate &dd, QWidget *parent)
243 : QAbstractButton(dd, parent)
250
251
252QPushButton::~QPushButton()
257QDialog *QPushButtonPrivate::dialogParent()
const
259 Q_Q(
const QPushButton);
260 const QWidget *p = q;
261 while (p && !p->isWindow()) {
262 p = p->parentWidget();
263 if (
const QDialog *dialog = qobject_cast<
const QDialog *>(p))
264 return const_cast<QDialog *>(dialog);
271
272
273
274
275
276
277void QPushButton::initStyleOption(QStyleOptionButton *option)
const
282 Q_D(
const QPushButton);
283 option->initFrom(
this);
284 option->features = QStyleOptionButton::None;
286 option->features |= QStyleOptionButton::Flat;
289 option->features |= QStyleOptionButton::HasMenu;
292 option->features |= QStyleOptionButton::AutoDefaultButton;
293 if (d->defaultButton)
294 option->features |= QStyleOptionButton::DefaultButton;
295 option->state = d->styleButtonState(option->state);
296 option->text = d->text;
297 option->icon = d->icon;
298 option->iconSize = iconSize();
301void QPushButton::setAutoDefault(
bool enable)
304 uint state = enable ? QPushButtonPrivate::On : QPushButtonPrivate::Off;
305 if (d->autoDefault != QPushButtonPrivate::Auto && d->autoDefault == state)
307 d->autoDefault = state;
308 d->sizeHint = QSize();
313bool QPushButton::autoDefault()
const
315 Q_D(
const QPushButton);
316 if (d->autoDefault == QPushButtonPrivate::Auto)
317 return ( d->dialogParent() !=
nullptr );
318 return d->autoDefault;
321void QPushButton::setDefault(
bool enable)
324 if (d->defaultButton == enable)
326 d->defaultButton = enable;
328 if (d->defaultButton) {
329 if (QDialog *dlg = d->dialogParent())
330 dlg->d_func()->setMainDefault(
this);
334#if QT_CONFIG(accessibility)
335 QAccessible::State s;
336 s.defaultButton =
true;
337 QAccessibleStateChangeEvent event(
this, s);
338 QAccessible::updateAccessibility(&event);
342bool QPushButton::isDefault()
const
344 Q_D(
const QPushButton);
345 return d->defaultButton;
349
350
351QSize QPushButton::sizeHint()
const
353 Q_D(
const QPushButton);
354 if (d->sizeHint.isValid() && d->lastAutoDefault == autoDefault())
356 d->lastAutoDefault = autoDefault();
361 QStyleOptionButton opt;
362 initStyleOption(&opt);
365#if !defined(QT_NO_ICON) && QT_CONFIG(dialogbuttonbox)
366 bool showButtonBoxIcons = qobject_cast<QDialogButtonBox*>(parentWidget())
367 && style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons,
nullptr,
this);
369 if (!icon().isNull() || showButtonBoxIcons) {
370 int ih = opt.iconSize.height();
371 int iw = opt.iconSize.width() + 4;
377 bool empty = s.isEmpty();
379 s = QStringLiteral(
"XXXX");
380 QFontMetrics fm = fontMetrics();
381 QSize sz = fm.size(Qt::TextShowMnemonic, s);
385 h = qMax(h, sz.height());
386 opt.rect.setSize(QSize(w, h));
389 w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt,
this);
391 d->sizeHint = style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h),
this);
396
397
398QSize QPushButton::minimumSizeHint()
const
405
406void QPushButton::paintEvent(QPaintEvent *)
408 QStylePainter p(
this);
409 QStyleOptionButton option;
410 initStyleOption(&option);
411 p.drawControl(QStyle::CE_PushButton, option);
416void QPushButton::keyPressEvent(QKeyEvent *e)
422 if (autoDefault() || d->defaultButton) {
428 QAbstractButton::keyPressEvent(e);
433
434
435void QPushButton::focusInEvent(QFocusEvent *e)
438 if (e->reason() != Qt::PopupFocusReason && autoDefault() && !d->defaultButton) {
439 d->defaultButton =
true;
441 QDialog *dlg = qobject_cast<QDialog*>(window());
443 dlg->d_func()->setDefault(
this);
446 QAbstractButton::focusInEvent(e);
450
451
452void QPushButton::focusOutEvent(QFocusEvent *e)
455 if (e->reason() != Qt::PopupFocusReason && autoDefault() && d->defaultButton) {
457 QDialog *dlg = qobject_cast<QDialog*>(window());
459 dlg->d_func()->setDefault(
nullptr);
461 d->defaultButton =
false;
465 QAbstractButton::focusOutEvent(e);
467 if (d->menu && d->menu->isVisible())
473
474
475void QPushButton::mouseMoveEvent(QMouseEvent *e)
479 if (testAttribute(Qt::WA_Hover)) {
482 hit = hitButton(e->position().toPoint());
484 if (hit != d->hovering) {
490 QAbstractButton::mouseMoveEvent(e);
494
495
496bool QPushButton::hitButton(
const QPoint &pos)
const
498 QStyleOptionButton option;
499 initStyleOption(&option);
500 const QRect bevel = style()->subElementRect(QStyle::SE_PushButtonBevel, &option,
this);
501 return bevel.contains(pos);
506
507
508
509
510
511
512
513
514
515
516
517
518
519void QPushButton::setMenu(QMenu* menu)
525 if (menu && !d->menu) {
526 QObjectPrivate::connect(
this, &QPushButton::pressed,
527 d, &QPushButtonPrivate::popupPressed, Qt::UniqueConnection);
530 removeAction(d->menu->menuAction());
533 addAction(d->menu->menuAction());
535 d->resetLayoutItemMargins();
536 d->sizeHint = QSize();
542
543
544
545
546
547QMenu* QPushButton::menu()
const
549 Q_D(
const QPushButton);
554
555
556
557
558void QPushButton::showMenu()
567void QPushButtonPrivate::popupPressed()
573 menu->setNoReplayFor(q);
575 QPoint menuPos = adjustedMenuPosition();
577 QMenuPrivate::get(menu)->causedPopup.widget = q;
582 QObject::connect(menu, &QMenu::aboutToHide,
583 q, [q,
this]{ menuOpen =
false; q->setDown(
false); }, Qt::SingleShotConnection);
584 menu->popup(menuPos);
587QPoint QPushButtonPrivate::adjustedMenuPosition()
591 bool horizontal =
true;
592#if QT_CONFIG(toolbar)
593 QToolBar *tb = qobject_cast<QToolBar*>(parent);
594 if (tb && tb->orientation() == Qt::Vertical)
599 QRect rect = item.geometry();
600 rect.setRect(rect.x() - q->x(), rect.y() - q->y(), rect.width(), rect.height());
602 QSize menuSize = menu->sizeHint();
603 QPoint globalPos = q->mapToGlobal(rect.topLeft());
604 int x = globalPos.x();
605 int y = globalPos.y();
606 const QRect availableGeometry = QWidgetPrivate::availableScreenGeometry(q, q->mapToGlobal(rect.center()));
608 if (globalPos.y() + rect.height() + menuSize.height() <= availableGeometry.bottom()) {
610 }
else if (globalPos.y() - menuSize.height() >= availableGeometry.y()) {
611 y -= menuSize.height();
613 if (q->layoutDirection() == Qt::RightToLeft)
614 x += rect.width() - menuSize.width();
616 if (globalPos.x() + rect.width() + menu->sizeHint().width() <= availableGeometry.right()) {
618 }
else if (globalPos.x() - menuSize.width() >= availableGeometry.x()) {
619 x -= menuSize.width();
628void QPushButtonPrivate::init()
631 q->setAttribute(Qt::WA_MacShowFocusRect);
632 resetLayoutItemMargins();
635void QPushButtonPrivate::resetLayoutItemMargins()
638 QStyleOptionButton opt;
639 q->initStyleOption(&opt);
640 setLayoutItemMargins(QStyle::SE_PushButtonLayoutItem, &opt);
643QStyle::State QPushButtonPrivate::styleButtonState(QStyle::State state)
const
645 Q_Q(
const QPushButton);
646 state = QAbstractButtonPrivate::styleButtonState(state);
648 state |= QStyle::State_Sunken;
650 state |= QStyle::State_On;
652 state |= QStyle::State_Raised;
653 if (q->underMouse() && q->hasMouseTracking())
654 state.setFlag(QStyle::State_MouseOver, hovering);
658void QPushButton::setFlat(
bool flat)
664 d->resetLayoutItemMargins();
665 d->sizeHint = QSize();
670bool QPushButton::isFlat()
const
672 Q_D(
const QPushButton);
677bool QPushButton::event(QEvent *e)
680 if (e->type() == QEvent::ParentChange) {
682 if (QDialog *dialog = d->dialogParent()) {
683 if (d->defaultButton)
684 dialog->d_func()->setMainDefault(
this);
687 }
else if (e->type() == QEvent::StyleChange
689 || e->type() == QEvent::MacSizeChange
692 d->resetLayoutItemMargins();
694 }
else if (e->type() == QEvent::PolishRequest) {
697 return QAbstractButton::event(e);
702#include "moc_qpushbutton.cpp"