7#include <qapplication.h>
14#include <qstyleoption.h>
18#if QT_CONFIG(mainwindow)
19#include <qmainwindow.h>
25#include <qstylepainter.h>
26#include <private/qabstractbutton_p.h>
27#include <private/qaction_p.h>
30#include <private/qmenu_p.h>
35using namespace Qt::StringLiterals;
39 Q_DECLARE_PUBLIC(QToolButton)
76bool QToolButtonPrivate::hasMenu()
const
78 return ((defaultAction && defaultAction->menu())
79 || (menuAction && menuAction->menu())
80 || actions.size() > (defaultAction ? 1 : 0));
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
155
156
157
158QToolButton::QToolButton(QWidget * parent)
159 : QAbstractButton(*
new QToolButtonPrivate, parent)
173#if QT_CONFIG(toolbar)
174 if (qobject_cast<QToolBar*>(parent))
179 arrowType = Qt::NoArrow;
180 menuButtonDown =
false;
181 popupMode = QToolButton::DelayedPopup;
182 popupModeSetByUser =
false;
183 buttonPressed = QToolButtonPrivate::NoButtonPressed;
185 toolButtonStyle = Qt::ToolButtonIconOnly;
186 hoverControl = QStyle::SC_None;
188 q->setFocusPolicy(Qt::TabFocus);
189 q->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed,
190 QSizePolicy::ToolButton));
193 QObjectPrivate::connect(q, &QAbstractButton::pressed,
194 this, &QToolButtonPrivate::onButtonPressed);
195 QObjectPrivate::connect(q, &QAbstractButton::released,
196 this, &QToolButtonPrivate::onButtonReleased);
199 setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
200 delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay,
nullptr, q);
204
205
206
207
208
209
210void QToolButton::initStyleOption(QStyleOptionToolButton *option)
const
215 Q_D(
const QToolButton);
216 option->initFrom(
this);
217 option->iconSize = iconSize();
219#if QT_CONFIG(toolbar)
220 if (parentWidget()) {
221 if (QToolBar *toolBar = qobject_cast<QToolBar *>(parentWidget())) {
222 option->iconSize = toolBar->iconSize();
227 option->text = d->text;
228 option->icon = d->icon;
229 option->arrowType = d->arrowType;
231 option->state |= QStyle::State_Sunken;
233 option->state |= QStyle::State_On;
235 option->state |= QStyle::State_AutoRaise;
236 if (!d->checked && !d->down)
237 option->state |= QStyle::State_Raised;
239 option->subControls = QStyle::SC_ToolButton;
240 option->activeSubControls = QStyle::SC_None;
242 option->features = QStyleOptionToolButton::None;
243 if (d->popupMode == QToolButton::MenuButtonPopup) {
244 option->subControls |= QStyle::SC_ToolButtonMenu;
245 option->features |= QStyleOptionToolButton::MenuButtonPopup;
247 if (option->state & QStyle::State_MouseOver) {
248 option->activeSubControls = d->hoverControl;
250 if (d->menuButtonDown) {
251 option->state |= QStyle::State_Sunken;
252 option->activeSubControls |= QStyle::SC_ToolButtonMenu;
255 option->state |= QStyle::State_Sunken;
256 option->activeSubControls |= QStyle::SC_ToolButton;
260 if (d->arrowType != Qt::NoArrow)
261 option->features |= QStyleOptionToolButton::Arrow;
262 if (d->popupMode == QToolButton::DelayedPopup)
263 option->features |= QStyleOptionToolButton::PopupDelay;
266 option->features |= QStyleOptionToolButton::HasMenu;
268 if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) {
269 option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option,
this));
271 option->toolButtonStyle = d->toolButtonStyle;
273 if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
275 if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority)
276 option->toolButtonStyle = Qt::ToolButtonIconOnly;
279 if (d->icon.isNull() && d->arrowType == Qt::NoArrow) {
280 if (!d->text.isEmpty())
281 option->toolButtonStyle = Qt::ToolButtonTextOnly;
282 else if (option->toolButtonStyle != Qt::ToolButtonTextOnly)
283 option->toolButtonStyle = Qt::ToolButtonIconOnly;
287 option->font = font();
291
292
294QToolButton::~QToolButton()
299
300
301QSize QToolButton::sizeHint()
const
303 Q_D(
const QToolButton);
304 if (d->sizeHint.isValid())
309 QStyleOptionToolButton opt;
310 initStyleOption(&opt);
312 QFontMetrics fm = fontMetrics();
313 if (opt.toolButtonStyle != Qt::ToolButtonTextOnly) {
314 QSize icon = opt.iconSize;
319 if (opt.toolButtonStyle != Qt::ToolButtonIconOnly) {
320 QSize textSize = fm.size(Qt::TextShowMnemonic, text());
321 textSize.setWidth(textSize.width() + fm.horizontalAdvance(u' ') * 2);
322 if (opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
323 h += 4 + textSize.height();
324 if (textSize.width() > w)
325 w = textSize.width();
326 }
else if (opt.toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
327 w += 4 + textSize.width();
328 if (textSize.height() > h)
329 h = textSize.height();
331 w = textSize.width();
332 h = textSize.height();
336 opt.rect.setSize(QSize(w, h));
337 if (d->popupMode == MenuButtonPopup)
338 w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt,
this);
340 d->sizeHint = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h),
this);
345
346
347QSize QToolButton::minimumSizeHint()
const
353
354
355
356
357
358
359
360
361
362
363
364
365
368
369
370
371
372
373
374
376Qt::ToolButtonStyle QToolButton::toolButtonStyle()
const
378 Q_D(
const QToolButton);
379 return d->toolButtonStyle;
382Qt::ArrowType QToolButton::arrowType()
const
384 Q_D(
const QToolButton);
389void QToolButton::setToolButtonStyle(Qt::ToolButtonStyle style)
392 if (d->toolButtonStyle == style)
395 d->toolButtonStyle = style;
396 d->sizeHint = QSize();
403void QToolButton::setArrowType(Qt::ArrowType type)
406 if (d->arrowType == type)
410 d->sizeHint = QSize();
418
419
420
421
422void QToolButton::paintEvent(QPaintEvent *)
424 QStylePainter p(
this);
425 QStyleOptionToolButton opt;
426 initStyleOption(&opt);
427 p.drawComplexControl(QStyle::CC_ToolButton, opt);
431
432
433void QToolButton::actionEvent(QActionEvent *event)
436 auto action =
static_cast<QAction *>(event->action());
437 switch (event->type()) {
438 case QEvent::ActionChanged:
439 if (action == d->defaultAction)
440 setDefaultAction(action);
442 case QEvent::ActionAdded:
443 QObjectPrivate::connect(action, &QAction::triggered, d,
444 &QToolButtonPrivate::onActionTriggered);
446 case QEvent::ActionRemoved:
447 if (d->defaultAction == action)
448 d->defaultAction =
nullptr;
450 if (action == d->menuAction)
451 d->menuAction =
nullptr;
453 action->disconnect(
this);
458 QAbstractButton::actionEvent(event);
464 QStyleOptionToolButton opt;
465 q->initStyleOption(&opt);
466 opt.subControls = QStyle::SC_All;
467 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ToolButton, &opt, pos, q);
468 if (hoverControl == QStyle::SC_None)
471 hoverRect = q->style()->subControlRect(QStyle::CC_ToolButton, &opt, hoverControl, q);
478 QRect lastHoverRect = hoverRect;
479 QStyle::SubControl lastHoverControl = hoverControl;
480 bool doesHover = q->testAttribute(Qt::WA_Hover);
481 if (lastHoverControl != newHoverControl(pos) && doesHover) {
482 q->update(lastHoverRect);
483 q->update(hoverRect);
492 if (QAction *action = qobject_cast<QAction *>(q->sender()))
493 emit q->triggered(action);
497
498
499void QToolButton::enterEvent(QEnterEvent * e)
504 if (d->defaultAction)
505 d->defaultAction->hover();
506 QAbstractButton::enterEvent(e);
511
512
513void QToolButton::leaveEvent(QEvent * e)
519 QAbstractButton::leaveEvent(e);
524
525
526void QToolButton::timerEvent(QTimerEvent *e)
530 if (e->timerId() == d->popupTimer.timerId()) {
535 QAbstractButton::timerEvent(e);
540
541
542void QToolButton::changeEvent(QEvent *e)
544#if QT_CONFIG(toolbar)
546 if (e->type() == QEvent::ParentChange) {
547 if (qobject_cast<QToolBar*>(parentWidget()))
549 }
else if (e->type() == QEvent::StyleChange
551 || e->type() == QEvent::MacSizeChange
554 d->delay = style()->styleHint(QStyle::SH_ToolButton_PopupDelay,
nullptr,
this);
555 d->setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
558 QAbstractButton::changeEvent(e);
562
563
564void QToolButton::mousePressEvent(QMouseEvent *e)
568 QStyleOptionToolButton opt;
569 initStyleOption(&opt);
570 if (e->button() == Qt::LeftButton && (d->popupMode == MenuButtonPopup)) {
571 QRect popupr = style()->subControlRect(QStyle::CC_ToolButton, &opt,
572 QStyle::SC_ToolButtonMenu,
this);
573 if (popupr.isValid() && popupr.contains(e->position().toPoint())) {
574 d->buttonPressed = QToolButtonPrivate::MenuButtonPressed;
580 d->buttonPressed = QToolButtonPrivate::ToolButtonPressed;
581 QAbstractButton::mousePressEvent(e);
585
586
587void QToolButton::mouseReleaseEvent(QMouseEvent *e)
590 QPointer<QAbstractButton> guard(
this);
591 QAbstractButton::mouseReleaseEvent(e);
593 d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
597
598
599bool QToolButton::hitButton(
const QPoint &pos)
const
601 Q_D(
const QToolButton);
602 if (QAbstractButton::hitButton(pos))
603 return (d->buttonPressed != QToolButtonPrivate::MenuButtonPressed);
610
611
612
613
614
615
616
617
618void QToolButton::setMenu(QMenu* menu)
622 if (d->menuAction == (menu ? menu->menuAction() :
nullptr))
626 removeAction(d->menuAction);
629 d->menuAction = menu->menuAction();
630 addAction(d->menuAction);
632 d->menuAction =
nullptr;
636 d->sizeHint = QSize();
642
643
644
645
646
647QMenu* QToolButton::menu()
const
649 Q_D(
const QToolButton);
651 return d->menuAction->menu();
656
657
658
659
660void QToolButton::showMenu()
664 d->menuButtonDown =
false;
668 if (d->menuButtonDown)
672 d->menuButtonDown =
true;
674 d->popupTimer.stop();
678void QToolButtonPrivate::onButtonPressed()
683 if (popupMode == QToolButton::MenuButtonPopup)
685 else if (delay > 0 && popupMode == QToolButton::DelayedPopup)
686 popupTimer.start(delay, q);
687 else if (delay == 0 || popupMode == QToolButton::InstantPopup)
691void QToolButtonPrivate::onButtonReleased()
696static QPoint positionMenu(
const QToolButton *q,
bool horizontal,
700 const QRect rect = q->rect();
701 const QRect screen = QWidgetPrivate::availableScreenGeometry(q, q->mapToGlobal(rect.center()));
703 if (q->isRightToLeft()) {
704 if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.bottom()) {
705 p = q->mapToGlobal(rect.bottomRight());
707 p = q->mapToGlobal(rect.topRight() - QPoint(0, sh.height()));
709 p.rx() -= sh.width();
711 if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.bottom()) {
712 p = q->mapToGlobal(rect.bottomLeft());
714 p = q->mapToGlobal(rect.topLeft() - QPoint(0, sh.height()));
718 if (q->isRightToLeft()) {
719 if (q->mapToGlobal(QPoint(rect.left(), 0)).x() - sh.width() <= screen.x()) {
720 p = q->mapToGlobal(rect.topRight());
722 p = q->mapToGlobal(rect.topLeft());
723 p.rx() -= sh.width();
726 if (q->mapToGlobal(QPoint(rect.right(), 0)).x() + sh.width() <= screen.right()) {
727 p = q->mapToGlobal(rect.topRight());
729 p = q->mapToGlobal(rect.topLeft() - QPoint(sh.width(), 0));
738 p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width()));
739 p.ry() = qMax(screen.top(), qMin(p.y() + 1, screen.bottom()));
743void QToolButtonPrivate::popupTimerDone()
747 if (!menuButtonDown && !down)
750 menuButtonDown =
true;
751 QPointer<QMenu> actualMenu;
752 bool mustDeleteActualMenu =
false;
754 actualMenu = menuAction->menu();
755 }
else if (defaultAction && defaultAction->menu()) {
756 actualMenu = defaultAction->menu();
758 actualMenu =
new QMenu(q);
759 mustDeleteActualMenu =
true;
760 for (
int i = 0; i < actions.size(); i++)
761 actualMenu->addAction(actions.at(i));
763 repeat = q->autoRepeat();
764 q->setAutoRepeat(
false);
765 bool horizontal =
true;
766#if QT_CONFIG(toolbar)
767 QToolBar *tb = qobject_cast<QToolBar*>(parent);
768 if (tb && tb->orientation() == Qt::Vertical)
771 QPointer<QToolButton> that = q;
772 actualMenu->setNoReplayFor(q);
773 if (!mustDeleteActualMenu) {
774 QObjectPrivate::connect(actualMenu, &QMenu::triggered,
775 this, &QToolButtonPrivate::onMenuTriggered);
777 QObjectPrivate::connect(actualMenu, &QMenu::aboutToHide,
778 this, &QToolButtonPrivate::updateButtonDown);
779 actualMenu->d_func()->causedPopup.widget = q;
780 actualMenu->d_func()->causedPopup.action = defaultAction;
781 actionsCopy = q->actions();
784 auto positionFunction = [q, horizontal](
const QSize &sizeHint) {
785 return positionMenu(q, horizontal, sizeHint); };
786 const auto initialPos = positionFunction(actualMenu->sizeHint());
787 actualMenu->d_func()->exec(initialPos,
nullptr, positionFunction);
792 QObjectPrivate::disconnect(actualMenu, &QMenu::aboutToHide,
793 this, &QToolButtonPrivate::updateButtonDown);
794 if (menuButtonDown) {
799 if (mustDeleteActualMenu) {
802 QObjectPrivate::disconnect(actualMenu, &QMenu::triggered,
803 this, &QToolButtonPrivate::onMenuTriggered);
809 q->setAutoRepeat(
true);
812void QToolButtonPrivate::updateButtonDown()
815 menuButtonDown =
false;
822void QToolButtonPrivate::onMenuTriggered(QAction *action)
825 if (action && !actionsCopy.contains(action))
826 emit q->triggered(action);
829void QToolButtonPrivate::onDefaultActionChanged()
832 if (defaultAction && defaultAction->menu() && !popupModeSetByUser)
833 q->setPopupMode(QToolButton::MenuButtonPopup);
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
860
861
862
863
864
866void QToolButton::setPopupMode(ToolButtonPopupMode mode)
869 d->popupModeSetByUser =
true;
873QToolButton::ToolButtonPopupMode QToolButton::popupMode()
const
875 Q_D(
const QToolButton);
881
882
883
884
885
886
887
888void QToolButton::setAutoRaise(
bool enable)
891 d->autoRaise = enable;
896bool QToolButton::autoRaise()
const
898 Q_D(
const QToolButton);
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924void QToolButton::setDefaultAction(QAction *action)
928 if (d->defaultAction && d->defaultAction != action) {
929 QObjectPrivate::disconnect(d->defaultAction, &QAction::changed, d,
930 &QToolButtonPrivate::onDefaultActionChanged);
932 const bool hadMenu = d->hasMenu();
934 d->defaultAction = action;
937 if (!actions().contains(action))
939 QString buttonText = action->iconText();
942 if (QActionPrivate::get(action)->iconText.isEmpty())
943 buttonText.replace(
"&"_L1,
"&&"_L1);
945 setIcon(action->icon());
946#if QT_CONFIG(tooltip)
947 setToolTip(action->toolTip());
949#if QT_CONFIG(statustip)
950 setStatusTip(action->statusTip());
952#if QT_CONFIG(whatsthis)
953 setWhatsThis(action->whatsThis());
956 if (!hadMenu && !d->popupModeSetByUser) {
961 if (action->menu()) {
962 setPopupMode(QToolButton::MenuButtonPopup);
964 QObjectPrivate::connect(d->defaultAction, &QAction::changed, d,
965 &QToolButtonPrivate::onDefaultActionChanged);
969 setCheckable(action->isCheckable());
970 setChecked(action->isChecked());
971 setEnabled(action->isEnabled());
972 if (action->d_func()->fontSet)
973 setFont(action->font());
978
979
980
981
982QAction *QToolButton::defaultAction()
const
984 Q_D(
const QToolButton);
985 return d->defaultAction;
989
990
991void QToolButton::checkStateSet()
994 if (d->defaultAction && d->defaultAction->isCheckable())
995 d->defaultAction->setChecked(isChecked());
999
1000
1001void QToolButton::nextCheckState()
1004 if (!d->defaultAction)
1005 QAbstractButton::nextCheckState();
1007 d->defaultAction->trigger();
1011bool QToolButton::event(QEvent *event)
1013 switch(event->type()) {
1014 case QEvent::HoverEnter:
1015 case QEvent::HoverLeave:
1016 case QEvent::HoverMove:
1017 if (
const QHoverEvent *he =
static_cast<
const QHoverEvent *>(event))
1018 d_func()->updateHoverControl(he->position().toPoint());
1023 return QAbstractButton::event(event);
1028#include "moc_qtoolbutton.cpp"
\inmodule QtCore\reentrant