1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qtoolbutton.h"
43 #ifndef QT_NO_TOOLBUTTON
44
45 #include <qapplication.h>
46 #include <qdesktopwidget.h>
47 #include <qdrawutil.h>
48 #include <qevent.h>
49 #include <qicon.h>
50 #include <qmenu.h>
51 #include <qpainter.h>
52 #include <qpointer.h>
53 #include <qstyle.h>
54 #include <qstyleoption.h>
55 #include <qtooltip.h>
56 #include <qmainwindow.h>
57 #include <qtoolbar.h>
58 #include <qvariant.h>
59 #include <qstylepainter.h>
60 #include <private/qabstractbutton_p.h>
61 #include <private/qaction_p.h>
62 #include <private/qmenu_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 class QToolButtonPrivate : public QAbstractButtonPrivate
67 {
68 Q_DECLARE_PUBLIC(QToolButton)
69 public:
70 void init();
71 #ifndef QT_NO_MENU
72 void _q_buttonPressed();
73 void popupTimerDone();
74 void _q_updateButtonDown();
75 void _q_menuTriggered(QAction *);
76 #endif
77 bool updateHoverControl(const QPoint &pos);
78 void _q_actionTriggered();
79 QStyle::SubControl newHoverControl(const QPoint &pos);
80 QStyle::SubControl hoverControl;
81 QRect hoverRect;
82 QPointer<QAction> menuAction; //the menu set by the user (setMenu)
83 QBasicTimer popupTimer;
84 int delay;
85 Qt::ArrowType arrowType;
86 Qt::ToolButtonStyle toolButtonStyle;
87 QToolButton::ToolButtonPopupMode popupMode;
88 enum { NoButtonPressed=0, MenuButtonPressed=1, ToolButtonPressed=2 };
89 uint buttonPressed : 2;
90 uint menuButtonDown : 1;
91 uint autoRaise : 1;
92 uint repeat : 1;
93 QAction *defaultAction;
94 #ifndef QT_NO_MENU
95 bool hasMenu() const;
96 //workaround for task 177850
97 QList<QAction *> actionsCopy;
98 #endif
99 #ifdef QT3_SUPPORT
100 bool userDefinedPopupDelay;
101 #endif
102 };
103
104 #ifndef QT_NO_MENU
hasMenu() const105 bool QToolButtonPrivate::hasMenu() const
106 {
107 return ((defaultAction && defaultAction->menu())
108 || (menuAction && menuAction->menu())
109 || actions.size() > (defaultAction ? 1 : 0));
110 }
111 #endif
112
113 /*!
114 \class QToolButton
115 \brief The QToolButton class provides a quick-access button to
116 commands or options, usually used inside a QToolBar.
117
118 \ingroup basicwidgets
119
120
121 A tool button is a special button that provides quick-access to
122 specific commands or options. As opposed to a normal command
123 button, a tool button usually doesn't show a text label, but shows
124 an icon instead.
125
126 Tool buttons are normally created when new QAction instances are
127 created with QToolBar::addAction() or existing actions are added
128 to a toolbar with QToolBar::addAction(). It is also possible to
129 construct tool buttons in the same way as any other widget, and
130 arrange them alongside other widgets in layouts.
131
132 One classic use of a tool button is to select tools; for example,
133 the "pen" tool in a drawing program. This would be implemented
134 by using a QToolButton as a toggle button (see setToggleButton()).
135
136 QToolButton supports auto-raising. In auto-raise mode, the button
137 draws a 3D frame only when the mouse points at it. The feature is
138 automatically turned on when a button is used inside a QToolBar.
139 Change it with setAutoRaise().
140
141 A tool button's icon is set as QIcon. This makes it possible to
142 specify different pixmaps for the disabled and active state. The
143 disabled pixmap is used when the button's functionality is not
144 available. The active pixmap is displayed when the button is
145 auto-raised because the mouse pointer is hovering over it.
146
147 The button's look and dimension is adjustable with
148 setToolButtonStyle() and setIconSize(). When used inside a
149 QToolBar in a QMainWindow, the button automatically adjusts to
150 QMainWindow's settings (see QMainWindow::setToolButtonStyle() and
151 QMainWindow::setIconSize()). Instead of an icon, a tool button can
152 also display an arrow symbol, specified with
153 \l{QToolButton::arrowType} {arrowType}.
154
155 A tool button can offer additional choices in a popup menu. The
156 popup menu can be set using setMenu(). Use setPopupMode() to
157 configure the different modes available for tool buttons with a
158 menu set. The default mode is DelayedPopupMode which is sometimes
159 used with the "Back" button in a web browser. After pressing and
160 holding the button down for a while, a menu pops up showing a list
161 of possible pages to jump to. The default delay is 600 ms; you can
162 adjust it with setPopupDelay().
163
164 \table 100%
165 \row \o \inlineimage assistant-toolbar.png Qt Assistant's toolbar with tool buttons
166 \row \o Qt Assistant's toolbar contains tool buttons that are associated
167 with actions used in other parts of the main window.
168 \endtable
169
170 \sa QPushButton, QToolBar, QMainWindow, QAction,
171 {fowler}{GUI Design Handbook: Push Button}
172 */
173
174 /*!
175 \fn void QToolButton::triggered(QAction *action)
176
177 This signal is emitted when the given \a action is triggered.
178
179 The action may also be associated with other parts of the user interface,
180 such as menu items and keyboard shortcuts. Sharing actions in this
181 way helps make the user interface more consistent and is often less work
182 to implement.
183 */
184
185 /*!
186 Constructs an empty tool button with parent \a
187 parent.
188 */
QToolButton(QWidget * parent)189 QToolButton::QToolButton(QWidget * parent)
190 : QAbstractButton(*new QToolButtonPrivate, parent)
191 {
192 Q_D(QToolButton);
193 d->init();
194 }
195
196 #ifdef QT3_SUPPORT
197 /*!
198 Constructs an empty tool button called \a name, with parent \a
199 parent.
200 */
201
QToolButton(QWidget * parent,const char * name)202 QToolButton::QToolButton(QWidget * parent, const char *name)
203 : QAbstractButton(*new QToolButtonPrivate, parent)
204 {
205 Q_D(QToolButton);
206 setObjectName(QString::fromAscii(name));
207 d->init();
208 }
209
210 /*!
211 Constructs a tool button called \a name, that is a child of \a
212 parent.
213
214 The tool button will display the given \a icon, with its text
215 label and tool tip set to \a textLabel and its status bar message
216 set to \a statusTip. It will be connected to the \a slot in
217 object \a receiver.
218 */
219
QToolButton(const QIcon & icon,const QString & textLabel,const QString & statusTip,QObject * receiver,const char * slot,QWidget * parent,const char * name)220 QToolButton::QToolButton(const QIcon& icon, const QString &textLabel,
221 const QString& statusTip,
222 QObject * receiver, const char *slot,
223 QWidget * parent, const char *name)
224 : QAbstractButton(*new QToolButtonPrivate, parent)
225 {
226 Q_D(QToolButton);
227 setObjectName(QString::fromAscii(name));
228 d->init();
229 setIcon(icon);
230 setText(textLabel);
231 if (receiver && slot)
232 connect(this, SIGNAL(clicked()), receiver, slot);
233 #ifndef QT_NO_TOOLTIP
234 if (!textLabel.isEmpty())
235 setToolTip(textLabel);
236 #endif
237 #ifndef QT_NO_STATUSTIP
238 if (!statusTip.isEmpty())
239 setStatusTip(statusTip);
240 #else
241 Q_UNUSED(statusTip);
242 #endif
243 }
244
245
246 /*!
247 Constructs a tool button as an arrow button. The Qt::ArrowType \a
248 type defines the arrow direction. Possible values are
249 Qt::LeftArrow, Qt::RightArrow, Qt::UpArrow, and Qt::DownArrow.
250
251 An arrow button has auto-repeat turned on by default.
252
253 The \a parent and \a name arguments are sent to the QWidget
254 constructor.
255 */
QToolButton(Qt::ArrowType type,QWidget * parent,const char * name)256 QToolButton::QToolButton(Qt::ArrowType type, QWidget *parent, const char *name)
257 : QAbstractButton(*new QToolButtonPrivate, parent)
258 {
259 Q_D(QToolButton);
260 setObjectName(QString::fromAscii(name));
261 d->init();
262 setAutoRepeat(true);
263 d->arrowType = type;
264 }
265
266 #endif
267
268
269 /* Set-up code common to all the constructors */
270
init()271 void QToolButtonPrivate::init()
272 {
273 Q_Q(QToolButton);
274 delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, q);
275 #ifdef QT3_SUPPORT
276 userDefinedPopupDelay = false;
277 #endif
278 defaultAction = 0;
279 #ifndef QT_NO_TOOLBAR
280 if (qobject_cast<QToolBar*>(parent))
281 autoRaise = true;
282 else
283 #endif
284 autoRaise = false;
285 arrowType = Qt::NoArrow;
286 menuButtonDown = false;
287 popupMode = QToolButton::DelayedPopup;
288 buttonPressed = QToolButtonPrivate::NoButtonPressed;
289
290 toolButtonStyle = Qt::ToolButtonIconOnly;
291 hoverControl = QStyle::SC_None;
292
293 q->setFocusPolicy(Qt::TabFocus);
294 q->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed,
295 QSizePolicy::ToolButton));
296
297 #ifndef QT_NO_MENU
298 QObject::connect(q, SIGNAL(pressed()), q, SLOT(_q_buttonPressed()));
299 #endif
300
301 setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
302
303 }
304
305 /*!
306 Initialize \a option with the values from this QToolButton. This method
307 is useful for subclasses when they need a QStyleOptionToolButton, but don't want
308 to fill in all the information themselves.
309
310 \sa QStyleOption::initFrom()
311 */
initStyleOption(QStyleOptionToolButton * option) const312 void QToolButton::initStyleOption(QStyleOptionToolButton *option) const
313 {
314 if (!option)
315 return;
316
317 Q_D(const QToolButton);
318 option->initFrom(this);
319 bool forceNoText = false;
320 option->iconSize = iconSize(); //default value
321
322 #ifndef QT_NO_TOOLBAR
323 if (parentWidget()) {
324 if (QToolBar *toolBar = qobject_cast<QToolBar *>(parentWidget())) {
325 option->iconSize = toolBar->iconSize();
326 }
327 #ifdef QT3_SUPPORT
328 else if (parentWidget()->inherits("Q3ToolBar")) {
329 if (!option->iconSize.isValid()) {
330 int iconSize = style()->pixelMetric(QStyle::PM_ToolBarIconSize, option, this);
331 option->iconSize = d->icon.actualSize(QSize(iconSize, iconSize));
332 }
333 forceNoText = d->toolButtonStyle == Qt::ToolButtonIconOnly;
334 }
335 #endif
336 }
337 #endif // QT_NO_TOOLBAR
338
339 if (!forceNoText)
340 option->text = d->text;
341 option->icon = d->icon;
342 option->arrowType = d->arrowType;
343 if (d->down)
344 option->state |= QStyle::State_Sunken;
345 if (d->checked)
346 option->state |= QStyle::State_On;
347 if (d->autoRaise)
348 option->state |= QStyle::State_AutoRaise;
349 if (!d->checked && !d->down)
350 option->state |= QStyle::State_Raised;
351
352 option->subControls = QStyle::SC_ToolButton;
353 option->activeSubControls = QStyle::SC_None;
354
355 option->features = QStyleOptionToolButton::None;
356 if (d->popupMode == QToolButton::MenuButtonPopup) {
357 option->subControls |= QStyle::SC_ToolButtonMenu;
358 option->features |= QStyleOptionToolButton::MenuButtonPopup;
359 }
360 if (option->state & QStyle::State_MouseOver) {
361 option->activeSubControls = d->hoverControl;
362 }
363 if (d->menuButtonDown) {
364 option->state |= QStyle::State_Sunken;
365 option->activeSubControls |= QStyle::SC_ToolButtonMenu;
366 }
367 if (d->down) {
368 option->state |= QStyle::State_Sunken;
369 option->activeSubControls |= QStyle::SC_ToolButton;
370 }
371
372
373 if (d->arrowType != Qt::NoArrow)
374 option->features |= QStyleOptionToolButton::Arrow;
375 if (d->popupMode == QToolButton::DelayedPopup)
376 option->features |= QStyleOptionToolButton::PopupDelay;
377 #ifndef QT_NO_MENU
378 if (d->hasMenu())
379 option->features |= QStyleOptionToolButton::HasMenu;
380 #endif
381 if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) {
382 option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option, this));
383 } else
384 option->toolButtonStyle = d->toolButtonStyle;
385
386 if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
387 // If the action is not prioritized, remove the text label to save space
388 if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority)
389 option->toolButtonStyle = Qt::ToolButtonIconOnly;
390 }
391
392 if (d->icon.isNull() && d->arrowType == Qt::NoArrow && !forceNoText) {
393 if (!d->text.isEmpty())
394 option->toolButtonStyle = Qt::ToolButtonTextOnly;
395 else if (option->toolButtonStyle != Qt::ToolButtonTextOnly)
396 option->toolButtonStyle = Qt::ToolButtonIconOnly;
397 }
398
399 option->pos = pos();
400 option->font = font();
401 }
402
403 /*!
404 Destroys the object and frees any allocated resources.
405 */
406
~QToolButton()407 QToolButton::~QToolButton()
408 {
409 }
410
411 /*!
412 \reimp
413 */
sizeHint() const414 QSize QToolButton::sizeHint() const
415 {
416 Q_D(const QToolButton);
417 if (d->sizeHint.isValid())
418 return d->sizeHint;
419 ensurePolished();
420
421 int w = 0, h = 0;
422 QStyleOptionToolButton opt;
423 initStyleOption(&opt);
424
425 QFontMetrics fm = fontMetrics();
426 if (opt.toolButtonStyle != Qt::ToolButtonTextOnly) {
427 QSize icon = opt.iconSize;
428 w = icon.width();
429 h = icon.height();
430 #ifdef Q_WS_MAC
431 extern CGFloat qt_mac_get_scalefactor();
432 w /= qt_mac_get_scalefactor();
433 h /= qt_mac_get_scalefactor();
434 #endif
435 }
436
437 if (opt.toolButtonStyle != Qt::ToolButtonIconOnly) {
438 QSize textSize = fm.size(Qt::TextShowMnemonic, text());
439 textSize.setWidth(textSize.width() + fm.width(QLatin1Char(' '))*2);
440 if (opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
441 h += 4 + textSize.height();
442 if (textSize.width() > w)
443 w = textSize.width();
444 } else if (opt.toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
445 w += 4 + textSize.width();
446 if (textSize.height() > h)
447 h = textSize.height();
448 } else { // TextOnly
449 w = textSize.width();
450 h = textSize.height();
451 }
452 }
453
454 opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
455 if (d->popupMode == MenuButtonPopup)
456 w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
457
458 d->sizeHint = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this).
459 expandedTo(QApplication::globalStrut());
460 return d->sizeHint;
461 }
462
463 /*!
464 \reimp
465 */
minimumSizeHint() const466 QSize QToolButton::minimumSizeHint() const
467 {
468 return sizeHint();
469 }
470
471 /*!
472 \enum QToolButton::TextPosition
473 \compat
474
475 This enum describes the position of the tool button's text label in
476 relation to the tool button's icon.
477
478 \value BesideIcon The text appears beside the icon.
479 \value BelowIcon The text appears below the icon.
480 \omitvalue Right
481 \omitvalue Under
482 */
483
484 /*!
485 \property QToolButton::toolButtonStyle
486 \brief whether the tool button displays an icon only, text only,
487 or text beside/below the icon.
488
489 The default is Qt::ToolButtonIconOnly.
490
491 To have the style of toolbuttons follow the system settings (as available
492 in GNOME and KDE desktop environments), set this property to Qt::ToolButtonFollowStyle.
493
494 QToolButton automatically connects this slot to the relevant
495 signal in the QMainWindow in which is resides.
496 */
497
498 /*!
499 \property QToolButton::arrowType
500 \brief whether the button displays an arrow instead of a normal icon
501
502 This displays an arrow as the icon for the QToolButton.
503
504 By default, this property is set to Qt::NoArrow.
505 */
506
toolButtonStyle() const507 Qt::ToolButtonStyle QToolButton::toolButtonStyle() const
508 {
509 Q_D(const QToolButton);
510 return d->toolButtonStyle;
511 }
512
arrowType() const513 Qt::ArrowType QToolButton::arrowType() const
514 {
515 Q_D(const QToolButton);
516 return d->arrowType;
517 }
518
519
setToolButtonStyle(Qt::ToolButtonStyle style)520 void QToolButton::setToolButtonStyle(Qt::ToolButtonStyle style)
521 {
522 Q_D(QToolButton);
523 if (d->toolButtonStyle == style)
524 return;
525
526 d->toolButtonStyle = style;
527 d->sizeHint = QSize();
528 updateGeometry();
529 if (isVisible()) {
530 update();
531 }
532 }
533
setArrowType(Qt::ArrowType type)534 void QToolButton::setArrowType(Qt::ArrowType type)
535 {
536 Q_D(QToolButton);
537 if (d->arrowType == type)
538 return;
539
540 d->arrowType = type;
541 d->sizeHint = QSize();
542 updateGeometry();
543 if (isVisible()) {
544 update();
545 }
546 }
547
548 /*!
549 \fn void QToolButton::paintEvent(QPaintEvent *event)
550
551 Paints the button in response to the paint \a event.
552 */
paintEvent(QPaintEvent *)553 void QToolButton::paintEvent(QPaintEvent *)
554 {
555 QStylePainter p(this);
556 QStyleOptionToolButton opt;
557 initStyleOption(&opt);
558 p.drawComplexControl(QStyle::CC_ToolButton, opt);
559 }
560
561 /*!
562 \reimp
563 */
actionEvent(QActionEvent * event)564 void QToolButton::actionEvent(QActionEvent *event)
565 {
566 Q_D(QToolButton);
567 QAction *action = event->action();
568 switch (event->type()) {
569 case QEvent::ActionChanged:
570 if (action == d->defaultAction)
571 setDefaultAction(action); // update button state
572 break;
573 case QEvent::ActionAdded:
574 connect(action, SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
575 break;
576 case QEvent::ActionRemoved:
577 if (d->defaultAction == action)
578 d->defaultAction = 0;
579 #ifndef QT_NO_MENU
580 if (action == d->menuAction)
581 d->menuAction = 0;
582 #endif
583 action->disconnect(this);
584 break;
585 default:
586 ;
587 }
588 QAbstractButton::actionEvent(event);
589 }
590
newHoverControl(const QPoint & pos)591 QStyle::SubControl QToolButtonPrivate::newHoverControl(const QPoint &pos)
592 {
593 Q_Q(QToolButton);
594 QStyleOptionToolButton opt;
595 q->initStyleOption(&opt);
596 opt.subControls = QStyle::SC_All;
597 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ToolButton, &opt, pos, q);
598 if (hoverControl == QStyle::SC_None)
599 hoverRect = QRect();
600 else
601 hoverRect = q->style()->subControlRect(QStyle::CC_ToolButton, &opt, hoverControl, q);
602 return hoverControl;
603 }
604
updateHoverControl(const QPoint & pos)605 bool QToolButtonPrivate::updateHoverControl(const QPoint &pos)
606 {
607 Q_Q(QToolButton);
608 QRect lastHoverRect = hoverRect;
609 QStyle::SubControl lastHoverControl = hoverControl;
610 bool doesHover = q->testAttribute(Qt::WA_Hover);
611 if (lastHoverControl != newHoverControl(pos) && doesHover) {
612 q->update(lastHoverRect);
613 q->update(hoverRect);
614 return true;
615 }
616 return !doesHover;
617 }
618
_q_actionTriggered()619 void QToolButtonPrivate::_q_actionTriggered()
620 {
621 Q_Q(QToolButton);
622 if (QAction *action = qobject_cast<QAction *>(q->sender()))
623 emit q->triggered(action);
624 }
625
626 /*!
627 \reimp
628 */
enterEvent(QEvent * e)629 void QToolButton::enterEvent(QEvent * e)
630 {
631 Q_D(QToolButton);
632 if (d->autoRaise)
633 update();
634 if (d->defaultAction)
635 d->defaultAction->hover();
636 QAbstractButton::enterEvent(e);
637 }
638
639
640 /*!
641 \reimp
642 */
leaveEvent(QEvent * e)643 void QToolButton::leaveEvent(QEvent * e)
644 {
645 Q_D(QToolButton);
646 if (d->autoRaise)
647 update();
648
649 QAbstractButton::leaveEvent(e);
650 }
651
652
653 /*!
654 \reimp
655 */
timerEvent(QTimerEvent * e)656 void QToolButton::timerEvent(QTimerEvent *e)
657 {
658 #ifndef QT_NO_MENU
659 Q_D(QToolButton);
660 if (e->timerId() == d->popupTimer.timerId()) {
661 d->popupTimerDone();
662 return;
663 }
664 #endif
665 QAbstractButton::timerEvent(e);
666 }
667
668
669 /*!
670 \reimp
671 */
changeEvent(QEvent * e)672 void QToolButton::changeEvent(QEvent *e)
673 {
674 #ifndef QT_NO_TOOLBAR
675 Q_D(QToolButton);
676 if (e->type() == QEvent::ParentChange) {
677 if (qobject_cast<QToolBar*>(parentWidget()))
678 d->autoRaise = true;
679 } else if (e->type() == QEvent::StyleChange
680 #ifdef Q_WS_MAC
681 || e->type() == QEvent::MacSizeChange
682 #endif
683 ) {
684 #ifdef QT3_SUPPORT
685 if (!d->userDefinedPopupDelay)
686 #endif
687 d->delay = style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, this);
688 d->setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
689 }
690 #endif
691 QAbstractButton::changeEvent(e);
692 }
693
694 /*!
695 \reimp
696 */
mousePressEvent(QMouseEvent * e)697 void QToolButton::mousePressEvent(QMouseEvent *e)
698 {
699 Q_D(QToolButton);
700 #ifndef QT_NO_MENU
701 QStyleOptionToolButton opt;
702 initStyleOption(&opt);
703 if (e->button() == Qt::LeftButton && (d->popupMode == MenuButtonPopup)) {
704 QRect popupr = style()->subControlRect(QStyle::CC_ToolButton, &opt,
705 QStyle::SC_ToolButtonMenu, this);
706 if (popupr.isValid() && popupr.contains(e->pos())) {
707 d->buttonPressed = QToolButtonPrivate::MenuButtonPressed;
708 showMenu();
709 return;
710 }
711 }
712 #endif
713 d->buttonPressed = QToolButtonPrivate::ToolButtonPressed;
714 QAbstractButton::mousePressEvent(e);
715 }
716
717 /*!
718 \reimp
719 */
mouseReleaseEvent(QMouseEvent * e)720 void QToolButton::mouseReleaseEvent(QMouseEvent *e)
721 {
722 Q_D(QToolButton);
723 QAbstractButton::mouseReleaseEvent(e);
724 d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
725 }
726
727 /*!
728 \reimp
729 */
hitButton(const QPoint & pos) const730 bool QToolButton::hitButton(const QPoint &pos) const
731 {
732 Q_D(const QToolButton);
733 if(QAbstractButton::hitButton(pos))
734 return (d->buttonPressed != QToolButtonPrivate::MenuButtonPressed);
735 return false;
736 }
737
738 #ifdef QT3_SUPPORT
739
740 /*!
741 Use icon() instead.
742 */
onIconSet() const743 QIcon QToolButton::onIconSet() const
744 {
745 return icon();
746 }
747
748 /*!
749 Use icon() instead.
750 */
offIconSet() const751 QIcon QToolButton::offIconSet() const
752 {
753 return icon();
754 }
755
756
757 /*!
758 \obsolete
759
760 Use setIcon() instead.
761 */
setOnIconSet(const QIcon & set)762 void QToolButton::setOnIconSet(const QIcon& set)
763 {
764 setIcon(set);
765 }
766
767 /*!
768 \obsolete
769
770 Use setIcon() instead.
771 */
setOffIconSet(const QIcon & set)772 void QToolButton::setOffIconSet(const QIcon& set)
773 {
774 setIcon(set);
775 }
776
777
778 /*! \overload
779 \obsolete
780
781 Since Qt 3.0, QIcon contains both the On and Off icons.
782
783 For ease of porting, this function ignores the \a on parameter and
784 sets the \l{QAbstractButton::icon} {icon} property. If you relied on
785 the \a on parameter, you probably want to update your code to use
786 the QIcon On/Off mechanism.
787
788 \sa icon QIcon::State
789 */
790
setIconSet(const QIcon & set,bool)791 void QToolButton::setIconSet(const QIcon & set, bool /* on */)
792 {
793 QAbstractButton::setIcon(set);
794 }
795
796 /*! \overload
797 \obsolete
798
799 Since Qt 3.0, QIcon contains both the On and Off icons.
800
801 For ease of porting, this function ignores the \a on parameter and
802 returns the \l{QAbstractButton::icon} {icon} property. If you relied
803 on the \a on parameter, you probably want to update your code to use
804 the QIcon On/Off mechanism.
805 */
iconSet(bool) const806 QIcon QToolButton::iconSet(bool /* on */) const
807 {
808 return QAbstractButton::icon();
809 }
810
811 #endif
812
813 #ifndef QT_NO_MENU
814 /*!
815 Associates the given \a menu with this tool button.
816
817 The menu will be shown according to the button's \l popupMode.
818
819 Ownership of the menu is not transferred to the tool button.
820
821 \sa menu()
822 */
setMenu(QMenu * menu)823 void QToolButton::setMenu(QMenu* menu)
824 {
825 Q_D(QToolButton);
826
827 if (d->menuAction)
828 removeAction(d->menuAction);
829
830 if (menu) {
831 d->menuAction = menu->menuAction();
832 addAction(d->menuAction);
833 } else {
834 d->menuAction = 0;
835 }
836 update();
837 }
838
839 /*!
840 Returns the associated menu, or 0 if no menu has been defined.
841
842 \sa setMenu()
843 */
menu() const844 QMenu* QToolButton::menu() const
845 {
846 Q_D(const QToolButton);
847 if (d->menuAction)
848 return d->menuAction->menu();
849 return 0;
850 }
851
852 /*!
853 Shows (pops up) the associated popup menu. If there is no such
854 menu, this function does nothing. This function does not return
855 until the popup menu has been closed by the user.
856 */
showMenu()857 void QToolButton::showMenu()
858 {
859 Q_D(QToolButton);
860 if (!d->hasMenu()) {
861 d->menuButtonDown = false;
862 return; // no menu to show
863 }
864 // prevent recursions spinning another event loop
865 if (d->menuButtonDown)
866 return;
867
868 d->menuButtonDown = true;
869 repaint();
870 d->popupTimer.stop();
871 d->popupTimerDone();
872 }
873
_q_buttonPressed()874 void QToolButtonPrivate::_q_buttonPressed()
875 {
876 Q_Q(QToolButton);
877 if (!hasMenu())
878 return; // no menu to show
879 if (popupMode == QToolButton::MenuButtonPopup)
880 return;
881 else if (delay > 0 && !popupTimer.isActive() && popupMode == QToolButton::DelayedPopup)
882 popupTimer.start(delay, q);
883 else if (delay == 0 || popupMode == QToolButton::InstantPopup)
884 q->showMenu();
885 }
886
popupTimerDone()887 void QToolButtonPrivate::popupTimerDone()
888 {
889 Q_Q(QToolButton);
890 popupTimer.stop();
891 if (!menuButtonDown && !down)
892 return;
893
894 menuButtonDown = true;
895 QPointer<QMenu> actualMenu;
896 bool mustDeleteActualMenu = false;
897 if(menuAction) {
898 actualMenu = menuAction->menu();
899 } else if (defaultAction && defaultAction->menu()) {
900 actualMenu = defaultAction->menu();
901 } else {
902 actualMenu = new QMenu(q);
903 mustDeleteActualMenu = true;
904 for(int i = 0; i < actions.size(); i++)
905 actualMenu->addAction(actions.at(i));
906 }
907 repeat = q->autoRepeat();
908 q->setAutoRepeat(false);
909 bool horizontal = true;
910 #if !defined(QT_NO_TOOLBAR)
911 QToolBar *tb = qobject_cast<QToolBar*>(parent);
912 if (tb && tb->orientation() == Qt::Vertical)
913 horizontal = false;
914 #endif
915 QPoint p;
916 QRect screen = QApplication::desktop()->availableGeometry(q);
917 QSize sh = ((QToolButton*)(QMenu*)actualMenu)->receivers(SIGNAL(aboutToShow()))? QSize() : actualMenu->sizeHint();
918 QRect rect = q->rect();
919 if (horizontal) {
920 if (q->isRightToLeft()) {
921 if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
922 p = q->mapToGlobal(rect.bottomRight());
923 } else {
924 p = q->mapToGlobal(rect.topRight() - QPoint(0, sh.height()));
925 }
926 p.rx() -= sh.width();
927 } else {
928 if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
929 p = q->mapToGlobal(rect.bottomLeft());
930 } else {
931 p = q->mapToGlobal(rect.topLeft() - QPoint(0, sh.height()));
932 }
933 }
934 } else {
935 if (q->isRightToLeft()) {
936 if (q->mapToGlobal(QPoint(rect.left(), 0)).x() - sh.width() <= screen.x()) {
937 p = q->mapToGlobal(rect.topRight());
938 } else {
939 p = q->mapToGlobal(rect.topLeft());
940 p.rx() -= sh.width();
941 }
942 } else {
943 if (q->mapToGlobal(QPoint(rect.right(), 0)).x() + sh.width() <= screen.right()) {
944 p = q->mapToGlobal(rect.topRight());
945 } else {
946 p = q->mapToGlobal(rect.topLeft() - QPoint(sh.width(), 0));
947 }
948 }
949 }
950 p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width()));
951 p.ry() += 1;
952 QPointer<QToolButton> that = q;
953 actualMenu->setNoReplayFor(q);
954 if (!mustDeleteActualMenu) //only if action are not in this widget
955 QObject::connect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
956 QObject::connect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
957 actualMenu->d_func()->causedPopup.widget = q;
958 actualMenu->d_func()->causedPopup.action = defaultAction;
959 actionsCopy = q->actions(); //(the list of action may be modified in slots)
960 actualMenu->exec(p);
961 QObject::disconnect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
962 if (mustDeleteActualMenu)
963 delete actualMenu;
964 else
965 QObject::disconnect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
966
967 if (!that)
968 return;
969
970 actionsCopy.clear();
971
972 if (repeat)
973 q->setAutoRepeat(true);
974 }
975
_q_updateButtonDown()976 void QToolButtonPrivate::_q_updateButtonDown()
977 {
978 Q_Q(QToolButton);
979 menuButtonDown = false;
980 if (q->isDown())
981 q->setDown(false);
982 else
983 q->repaint();
984 }
985
_q_menuTriggered(QAction * action)986 void QToolButtonPrivate::_q_menuTriggered(QAction *action)
987 {
988 Q_Q(QToolButton);
989 if (action && !actionsCopy.contains(action))
990 emit q->triggered(action);
991 }
992 #endif // QT_NO_MENU
993
994 #ifdef QT3_SUPPORT
995 /*!
996 \fn void QToolButton::setPopupDelay(int delay)
997
998 Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
999 */
setPopupDelay(int delay)1000 void QToolButton::setPopupDelay(int delay)
1001 {
1002 Q_D(QToolButton);
1003 d->userDefinedPopupDelay = true;
1004 d->delay = delay;
1005
1006 update();
1007 }
1008
1009 /*!
1010 Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
1011 */
popupDelay() const1012 int QToolButton::popupDelay() const
1013 {
1014 Q_D(const QToolButton);
1015 return d->delay;
1016 }
1017 #endif
1018
1019 #ifndef QT_NO_MENU
1020 /*! \enum QToolButton::ToolButtonPopupMode
1021
1022 Describes how a menu should be popped up for tool buttons that has
1023 a menu set or contains a list of actions.
1024
1025 \value DelayedPopup After pressing and holding the tool button
1026 down for a certain amount of time (the timeout is style dependant,
1027 see QStyle::SH_ToolButton_PopupDelay), the menu is displayed. A
1028 typical application example is the "back" button in some web
1029 browsers's tool bars. If the user clicks it, the browser simply
1030 browses back to the previous page. If the user presses and holds
1031 the button down for a while, the tool button shows a menu
1032 containing the current history list
1033
1034 \value MenuButtonPopup In this mode the tool button displays a
1035 special arrow to indicate that a menu is present. The menu is
1036 displayed when the arrow part of the button is pressed.
1037
1038 \value InstantPopup The menu is displayed, without delay, when
1039 the tool button is pressed. In this mode, the button's own action
1040 is not triggered.
1041 */
1042
1043 /*!
1044 \property QToolButton::popupMode
1045 \brief describes the way that popup menus are used with tool buttons
1046
1047 By default, this property is set to \l DelayedPopup.
1048 */
1049
setPopupMode(ToolButtonPopupMode mode)1050 void QToolButton::setPopupMode(ToolButtonPopupMode mode)
1051 {
1052 Q_D(QToolButton);
1053 d->popupMode = mode;
1054 }
1055
popupMode() const1056 QToolButton::ToolButtonPopupMode QToolButton::popupMode() const
1057 {
1058 Q_D(const QToolButton);
1059 return d->popupMode;
1060 }
1061 #endif
1062
1063 /*!
1064 \property QToolButton::autoRaise
1065 \brief whether auto-raising is enabled or not.
1066
1067 The default is disabled (i.e. false).
1068
1069 This property is currently ignored on Mac OS X when using QMacStyle.
1070 */
setAutoRaise(bool enable)1071 void QToolButton::setAutoRaise(bool enable)
1072 {
1073 Q_D(QToolButton);
1074 d->autoRaise = enable;
1075
1076 update();
1077 }
1078
autoRaise() const1079 bool QToolButton::autoRaise() const
1080 {
1081 Q_D(const QToolButton);
1082 return d->autoRaise;
1083 }
1084
1085 /*!
1086 Sets the default action to \a action.
1087
1088 If a tool button has a default action, the action defines the
1089 button's properties like text, icon, tool tip, etc.
1090 */
setDefaultAction(QAction * action)1091 void QToolButton::setDefaultAction(QAction *action)
1092 {
1093 Q_D(QToolButton);
1094 #ifndef QT_NO_MENU
1095 bool hadMenu = false;
1096 hadMenu = d->hasMenu();
1097 #endif
1098 d->defaultAction = action;
1099 if (!action)
1100 return;
1101 if (!actions().contains(action))
1102 addAction(action);
1103 setText(action->iconText());
1104 setIcon(action->icon());
1105 #ifndef QT_NO_TOOLTIP
1106 setToolTip(action->toolTip());
1107 #endif
1108 #ifndef QT_NO_STATUSTIP
1109 setStatusTip(action->statusTip());
1110 #endif
1111 #ifndef QT_NO_WHATSTHIS
1112 setWhatsThis(action->whatsThis());
1113 #endif
1114 #ifndef QT_NO_MENU
1115 if (action->menu() && !hadMenu) {
1116 // new 'default' popup mode defined introduced by tool bar. We
1117 // should have changed QToolButton's default instead. Do that
1118 // in 4.2.
1119 setPopupMode(QToolButton::MenuButtonPopup);
1120 }
1121 #endif
1122 setCheckable(action->isCheckable());
1123 setChecked(action->isChecked());
1124 setEnabled(action->isEnabled());
1125 if (action->d_func()->fontSet)
1126 setFont(action->font());
1127 }
1128
1129
1130 /*!
1131 Returns the default action.
1132
1133 \sa setDefaultAction()
1134 */
defaultAction() const1135 QAction *QToolButton::defaultAction() const
1136 {
1137 Q_D(const QToolButton);
1138 return d->defaultAction;
1139 }
1140
1141
1142
1143 /*!
1144 \reimp
1145 */
nextCheckState()1146 void QToolButton::nextCheckState()
1147 {
1148 Q_D(QToolButton);
1149 if (!d->defaultAction)
1150 QAbstractButton::nextCheckState();
1151 else
1152 d->defaultAction->trigger();
1153 }
1154
1155 /*! \reimp */
event(QEvent * event)1156 bool QToolButton::event(QEvent *event)
1157 {
1158 switch(event->type()) {
1159 case QEvent::HoverEnter:
1160 case QEvent::HoverLeave:
1161 case QEvent::HoverMove:
1162 if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
1163 d_func()->updateHoverControl(he->pos());
1164 break;
1165 default:
1166 break;
1167 }
1168 return QAbstractButton::event(event);
1169 }
1170
1171 /*! \internal
1172 */
QToolButton(QToolButtonPrivate & dd,QWidget * parent)1173 QToolButton::QToolButton(QToolButtonPrivate &dd, QWidget *parent)
1174 :QAbstractButton(dd, parent)
1175 {
1176 Q_D(QToolButton);
1177 d->init();
1178 }
1179
1180 /*!
1181 \fn void QToolButton::setPixmap(const QPixmap &pixmap)
1182
1183 Use setIcon(QIcon(pixmap)) instead.
1184 */
1185
1186 /*!
1187 \fn void QToolButton::setIconSet(const QIcon &icon)
1188
1189 Use setIcon() instead.
1190 */
1191
1192 /*!
1193 \fn void QToolButton::setTextLabel(const QString &text, bool tooltip)
1194
1195 Use setText() and setToolTip() instead.
1196 */
1197
1198 /*!
1199 \fn QString QToolButton::textLabel() const
1200
1201 Use text() instead.
1202 */
1203
1204 /*!
1205 \fn QIcon QToolButton::iconSet() const
1206
1207 Use icon() instead.
1208 */
1209
1210 /*!
1211 \fn void QToolButton::openPopup()
1212
1213 Use showMenu() instead.
1214 */
1215
1216 /*!
1217 \fn void QToolButton::setPopup(QMenu* popup)
1218
1219 Use setMenu() instead.
1220 */
1221
1222 /*!
1223 \fn QMenu* QToolButton::popup() const
1224
1225 Use menu() instead.
1226 */
1227
1228 /*!
1229 \fn TextPosition QToolButton::textPosition() const
1230
1231 Use toolButtonStyle() instead.
1232 */
1233
1234 /*!
1235 \fn void QToolButton::setTextPosition(QToolButton::TextPosition pos)
1236
1237 Use setToolButtonStyle() instead.
1238 */
1239
1240 /*!
1241 \fn bool QToolButton::usesBigPixmap() const
1242
1243 Use iconSize() instead.
1244 */
1245
1246 /*!
1247 \fn void QToolButton::setUsesBigPixmap(bool enable)
1248
1249 Use setIconSize() instead.
1250 */
1251
1252 /*!
1253 \fn bool QToolButton::usesTextLabel() const
1254
1255 Use toolButtonStyle() instead.
1256 */
1257
1258 /*!
1259 \fn void QToolButton::setUsesTextLabel(bool enable)
1260
1261 Use setToolButtonStyle() instead.
1262 */
1263
1264 QT_END_NAMESPACE
1265
1266 #include "moc_qtoolbutton.cpp"
1267
1268 #endif
1269