blob: 6c49c2bbe5362a55eaa5ad218507229ac07422d0 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtoolbutton.h"
#ifndef QT_NO_TOOLBUTTON
#include <qapplication.h>
#include <qdesktopwidget.h>
#include <qdrawutil.h>
#include <qevent.h>
#include <qicon.h>
#include <qmenu.h>
#include <qpainter.h>
#include <qpointer.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qtooltip.h>
#include <qmainwindow.h>
#include <qtoolbar.h>
#include <qvariant.h>
#include <qstylepainter.h>
#include <private/qabstractbutton_p.h>
#include <private/qaction_p.h>
#include <private/qmenu_p.h>
QT_BEGIN_NAMESPACE
class QToolButtonPrivate : public QAbstractButtonPrivate
{
Q_DECLARE_PUBLIC(QToolButton)
public:
void init();
#ifndef QT_NO_MENU
void _q_buttonPressed();
void popupTimerDone();
void _q_updateButtonDown();
void _q_menuTriggered(QAction *);
#endif
bool updateHoverControl(const QPoint &pos);
void _q_actionTriggered();
QStyle::SubControl newHoverControl(const QPoint &pos);
QStyle::SubControl hoverControl;
QRect hoverRect;
QPointer<QAction> menuAction; //the menu set by the user (setMenu)
QBasicTimer popupTimer;
int delay;
Qt::ArrowType arrowType;
Qt::ToolButtonStyle toolButtonStyle;
QToolButton::ToolButtonPopupMode popupMode;
enum { NoButtonPressed=0, MenuButtonPressed=1, ToolButtonPressed=2 };
uint buttonPressed : 2;
uint menuButtonDown : 1;
uint autoRaise : 1;
uint repeat : 1;
QAction *defaultAction;
#ifndef QT_NO_MENU
bool hasMenu() const;
//workaround for task 177850
QList<QAction *> actionsCopy;
#endif
#ifdef QT3_SUPPORT
bool userDefinedPopupDelay;
#endif
};
#ifndef QT_NO_MENU
bool QToolButtonPrivate::hasMenu() const
{
return ((defaultAction && defaultAction->menu())
|| (menuAction && menuAction->menu())
|| actions.size() > (defaultAction ? 1 : 0));
}
#endif
/*!
\class QToolButton
\brief The QToolButton class provides a quick-access button to
commands or options, usually used inside a QToolBar.
\ingroup basicwidgets
A tool button is a special button that provides quick-access to
specific commands or options. As opposed to a normal command
button, a tool button usually doesn't show a text label, but shows
an icon instead.
Tool buttons are normally created when new QAction instances are
created with QToolBar::addAction() or existing actions are added
to a toolbar with QToolBar::addAction(). It is also possible to
construct tool buttons in the same way as any other widget, and
arrange them alongside other widgets in layouts.
One classic use of a tool button is to select tools; for example,
the "pen" tool in a drawing program. This would be implemented
by using a QToolButton as a toggle button (see setToggleButton()).
QToolButton supports auto-raising. In auto-raise mode, the button
draws a 3D frame only when the mouse points at it. The feature is
automatically turned on when a button is used inside a QToolBar.
Change it with setAutoRaise().
A tool button's icon is set as QIcon. This makes it possible to
specify different pixmaps for the disabled and active state. The
disabled pixmap is used when the button's functionality is not
available. The active pixmap is displayed when the button is
auto-raised because the mouse pointer is hovering over it.
The button's look and dimension is adjustable with
setToolButtonStyle() and setIconSize(). When used inside a
QToolBar in a QMainWindow, the button automatically adjusts to
QMainWindow's settings (see QMainWindow::setToolButtonStyle() and
QMainWindow::setIconSize()). Instead of an icon, a tool button can
also display an arrow symbol, specified with
\l{QToolButton::arrowType} {arrowType}.
A tool button can offer additional choices in a popup menu. The
popup menu can be set using setMenu(). Use setPopupMode() to
configure the different modes available for tool buttons with a
menu set. The default mode is DelayedPopupMode which is sometimes
used with the "Back" button in a web browser. After pressing and
holding the button down for a while, a menu pops up showing a list
of possible pages to jump to. The default delay is 600 ms; you can
adjust it with setPopupDelay().
\table 100%
\row \o \inlineimage assistant-toolbar.png Qt Assistant's toolbar with tool buttons
\row \o Qt Assistant's toolbar contains tool buttons that are associated
with actions used in other parts of the main window.
\endtable
\sa QPushButton, QToolBar, QMainWindow, QAction,
{fowler}{GUI Design Handbook: Push Button}
*/
/*!
\fn void QToolButton::triggered(QAction *action)
This signal is emitted when the given \a action is triggered.
The action may also be associated with other parts of the user interface,
such as menu items and keyboard shortcuts. Sharing actions in this
way helps make the user interface more consistent and is often less work
to implement.
*/
/*!
Constructs an empty tool button with parent \a
parent.
*/
QToolButton::QToolButton(QWidget * parent)
: QAbstractButton(*new QToolButtonPrivate, parent)
{
Q_D(QToolButton);
d->init();
}
#ifdef QT3_SUPPORT
/*!
Constructs an empty tool button called \a name, with parent \a
parent.
*/
QToolButton::QToolButton(QWidget * parent, const char *name)
: QAbstractButton(*new QToolButtonPrivate, parent)
{
Q_D(QToolButton);
setObjectName(QString::fromAscii(name));
d->init();
}
/*!
Constructs a tool button called \a name, that is a child of \a
parent.
The tool button will display the given \a icon, with its text
label and tool tip set to \a textLabel and its status bar message
set to \a statusTip. It will be connected to the \a slot in
object \a receiver.
*/
QToolButton::QToolButton(const QIcon& icon, const QString &textLabel,
const QString& statusTip,
QObject * receiver, const char *slot,
QWidget * parent, const char *name)
: QAbstractButton(*new QToolButtonPrivate, parent)
{
Q_D(QToolButton);
setObjectName(QString::fromAscii(name));
d->init();
setIcon(icon);
setText(textLabel);
if (receiver && slot)
connect(this, SIGNAL(clicked()), receiver, slot);
#ifndef QT_NO_TOOLTIP
if (!textLabel.isEmpty())
setToolTip(textLabel);
#endif
#ifndef QT_NO_STATUSTIP
if (!statusTip.isEmpty())
setStatusTip(statusTip);
#else
Q_UNUSED(statusTip);
#endif
}
/*!
Constructs a tool button as an arrow button. The Qt::ArrowType \a
type defines the arrow direction. Possible values are
Qt::LeftArrow, Qt::RightArrow, Qt::UpArrow, and Qt::DownArrow.
An arrow button has auto-repeat turned on by default.
The \a parent and \a name arguments are sent to the QWidget
constructor.
*/
QToolButton::QToolButton(Qt::ArrowType type, QWidget *parent, const char *name)
: QAbstractButton(*new QToolButtonPrivate, parent)
{
Q_D(QToolButton);
setObjectName(QString::fromAscii(name));
d->init();
setAutoRepeat(true);
d->arrowType = type;
}
#endif
/* Set-up code common to all the constructors */
void QToolButtonPrivate::init()
{
Q_Q(QToolButton);
delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, q);
#ifdef QT3_SUPPORT
userDefinedPopupDelay = false;
#endif
defaultAction = 0;
#ifndef QT_NO_TOOLBAR
if (qobject_cast<QToolBar*>(parent))
autoRaise = true;
else
#endif
autoRaise = false;
arrowType = Qt::NoArrow;
menuButtonDown = false;
popupMode = QToolButton::DelayedPopup;
buttonPressed = QToolButtonPrivate::NoButtonPressed;
toolButtonStyle = Qt::ToolButtonIconOnly;
hoverControl = QStyle::SC_None;
q->setFocusPolicy(Qt::TabFocus);
q->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed,
QSizePolicy::ToolButton));
#ifndef QT_NO_MENU
QObject::connect(q, SIGNAL(pressed()), q, SLOT(_q_buttonPressed()));
#endif
setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
}
/*!
Initialize \a option with the values from this QToolButton. This method
is useful for subclasses when they need a QStyleOptionToolButton, but don't want
to fill in all the information themselves.
\sa QStyleOption::initFrom()
*/
void QToolButton::initStyleOption(QStyleOptionToolButton *option) const
{
if (!option)
return;
Q_D(const QToolButton);
option->initFrom(this);
bool forceNoText = false;
option->iconSize = iconSize(); //default value
#ifndef QT_NO_TOOLBAR
if (parentWidget()) {
if (QToolBar *toolBar = qobject_cast<QToolBar *>(parentWidget())) {
option->iconSize = toolBar->iconSize();
}
#ifdef QT3_SUPPORT
else if (parentWidget()->inherits("Q3ToolBar")) {
if (!option->iconSize.isValid()) {
int iconSize = style()->pixelMetric(QStyle::PM_ToolBarIconSize, option, this);
option->iconSize = d->icon.actualSize(QSize(iconSize, iconSize));
}
forceNoText = d->toolButtonStyle == Qt::ToolButtonIconOnly;
}
#endif
}
#endif // QT_NO_TOOLBAR
if (!forceNoText)
option->text = d->text;
option->icon = d->icon;
option->arrowType = d->arrowType;
if (d->down)
option->state |= QStyle::State_Sunken;
if (d->checked)
option->state |= QStyle::State_On;
if (d->autoRaise)
option->state |= QStyle::State_AutoRaise;
if (!d->checked && !d->down)
option->state |= QStyle::State_Raised;
option->subControls = QStyle::SC_ToolButton;
option->activeSubControls = QStyle::SC_None;
option->features = QStyleOptionToolButton::None;
if (d->popupMode == QToolButton::MenuButtonPopup) {
option->subControls |= QStyle::SC_ToolButtonMenu;
option->features |= QStyleOptionToolButton::MenuButtonPopup;
}
if (option->state & QStyle::State_MouseOver) {
option->activeSubControls = d->hoverControl;
}
if (d->menuButtonDown) {
option->state |= QStyle::State_Sunken;
option->activeSubControls |= QStyle::SC_ToolButtonMenu;
}
if (d->down) {
option->state |= QStyle::State_Sunken;
option->activeSubControls |= QStyle::SC_ToolButton;
}
if (d->arrowType != Qt::NoArrow)
option->features |= QStyleOptionToolButton::Arrow;
if (d->popupMode == QToolButton::DelayedPopup)
option->features |= QStyleOptionToolButton::PopupDelay;
#ifndef QT_NO_MENU
if (d->hasMenu())
option->features |= QStyleOptionToolButton::HasMenu;
#endif
if (d->toolButtonStyle == Qt::ToolButtonFollowStyle) {
option->toolButtonStyle = Qt::ToolButtonStyle(style()->styleHint(QStyle::SH_ToolButtonStyle, option, this));
} else
option->toolButtonStyle = d->toolButtonStyle;
if (option->toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
// If the action is not prioritized, remove the text label to save space
if (d->defaultAction && d->defaultAction->priority() < QAction::NormalPriority)
option->toolButtonStyle = Qt::ToolButtonIconOnly;
}
if (d->icon.isNull() && d->arrowType == Qt::NoArrow && !forceNoText) {
if (!d->text.isEmpty())
option->toolButtonStyle = Qt::ToolButtonTextOnly;
else if (option->toolButtonStyle != Qt::ToolButtonTextOnly)
option->toolButtonStyle = Qt::ToolButtonIconOnly;
} else {
if (d->text.isEmpty() && option->toolButtonStyle != Qt::ToolButtonIconOnly)
option->toolButtonStyle = Qt::ToolButtonIconOnly;
}
option->pos = pos();
option->font = font();
}
/*!
Destroys the object and frees any allocated resources.
*/
QToolButton::~QToolButton()
{
}
/*!
\reimp
*/
QSize QToolButton::sizeHint() const
{
Q_D(const QToolButton);
if (d->sizeHint.isValid())
return d->sizeHint;
ensurePolished();
int w = 0, h = 0;
QStyleOptionToolButton opt;
initStyleOption(&opt);
QFontMetrics fm = fontMetrics();
if (opt.toolButtonStyle != Qt::ToolButtonTextOnly) {
QSize icon = opt.iconSize;
w = icon.width();
h = icon.height();
}
if (opt.toolButtonStyle != Qt::ToolButtonIconOnly) {
QSize textSize = fm.size(Qt::TextShowMnemonic, text());
textSize.setWidth(textSize.width() + fm.width(QLatin1Char(' '))*2);
if (opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
h += 4 + textSize.height();
if (textSize.width() > w)
w = textSize.width();
} else if (opt.toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
w += 4 + textSize.width();
if (textSize.height() > h)
h = textSize.height();
} else { // TextOnly
w = textSize.width();
h = textSize.height();
}
}
opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
if (d->popupMode == MenuButtonPopup)
w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
d->sizeHint = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this).
expandedTo(QApplication::globalStrut());
return d->sizeHint;
}
/*!
\reimp
*/
QSize QToolButton::minimumSizeHint() const
{
return sizeHint();
}
/*!
\enum QToolButton::TextPosition
\compat
This enum describes the position of the tool button's text label in
relation to the tool button's icon.
\value BesideIcon The text appears beside the icon.
\value BelowIcon The text appears below the icon.
\omitvalue Right
\omitvalue Under
*/
/*!
\property QToolButton::toolButtonStyle
\brief whether the tool button displays an icon only, text only,
or text beside/below the icon.
The default is Qt::ToolButtonIconOnly.
To have the style of toolbuttons follow the system settings (as available
in GNOME and KDE desktop environments), set this property to Qt::ToolButtonFollowStyle.
QToolButton automatically connects this slot to the relevant
signal in the QMainWindow in which is resides.
*/
/*!
\property QToolButton::arrowType
\brief whether the button displays an arrow instead of a normal icon
This displays an arrow as the icon for the QToolButton.
By default, this property is set to Qt::NoArrow.
*/
Qt::ToolButtonStyle QToolButton::toolButtonStyle() const
{
Q_D(const QToolButton);
return d->toolButtonStyle;
}
Qt::ArrowType QToolButton::arrowType() const
{
Q_D(const QToolButton);
return d->arrowType;
}
void QToolButton::setToolButtonStyle(Qt::ToolButtonStyle style)
{
Q_D(QToolButton);
if (d->toolButtonStyle == style)
return;
d->toolButtonStyle = style;
d->sizeHint = QSize();
updateGeometry();
if (isVisible()) {
update();
}
}
void QToolButton::setArrowType(Qt::ArrowType type)
{
Q_D(QToolButton);
if (d->arrowType == type)
return;
d->arrowType = type;
d->sizeHint = QSize();
updateGeometry();
if (isVisible()) {
update();
}
}
/*!
\fn void QToolButton::paintEvent(QPaintEvent *event)
Paints the button in response to the paint \a event.
*/
void QToolButton::paintEvent(QPaintEvent *)
{
QStylePainter p(this);
QStyleOptionToolButton opt;
initStyleOption(&opt);
p.drawComplexControl(QStyle::CC_ToolButton, opt);
}
/*!
\reimp
*/
void QToolButton::actionEvent(QActionEvent *event)
{
Q_D(QToolButton);
QAction *action = event->action();
switch (event->type()) {
case QEvent::ActionChanged:
if (action == d->defaultAction)
setDefaultAction(action); // update button state
break;
case QEvent::ActionAdded:
connect(action, SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
break;
case QEvent::ActionRemoved:
if (d->defaultAction == action)
d->defaultAction = 0;
#ifndef QT_NO_MENU
if (action == d->menuAction)
d->menuAction = 0;
#endif
action->disconnect(this);
break;
default:
;
}
QAbstractButton::actionEvent(event);
}
QStyle::SubControl QToolButtonPrivate::newHoverControl(const QPoint &pos)
{
Q_Q(QToolButton);
QStyleOptionToolButton opt;
q->initStyleOption(&opt);
opt.subControls = QStyle::SC_All;
hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ToolButton, &opt, pos, q);
if (hoverControl == QStyle::SC_None)
hoverRect = QRect();
else
hoverRect = q->style()->subControlRect(QStyle::CC_ToolButton, &opt, hoverControl, q);
return hoverControl;
}
bool QToolButtonPrivate::updateHoverControl(const QPoint &pos)
{
Q_Q(QToolButton);
QRect lastHoverRect = hoverRect;
QStyle::SubControl lastHoverControl = hoverControl;
bool doesHover = q->testAttribute(Qt::WA_Hover);
if (lastHoverControl != newHoverControl(pos) && doesHover) {
q->update(lastHoverRect);
q->update(hoverRect);
return true;
}
return !doesHover;
}
void QToolButtonPrivate::_q_actionTriggered()
{
Q_Q(QToolButton);
if (QAction *action = qobject_cast<QAction *>(q->sender()))
emit q->triggered(action);
}
/*!
\reimp
*/
void QToolButton::enterEvent(QEvent * e)
{
Q_D(QToolButton);
if (d->autoRaise)
update();
if (d->defaultAction)
d->defaultAction->hover();
QAbstractButton::enterEvent(e);
}
/*!
\reimp
*/
void QToolButton::leaveEvent(QEvent * e)
{
Q_D(QToolButton);
if (d->autoRaise)
update();
QAbstractButton::leaveEvent(e);
}
/*!
\reimp
*/
void QToolButton::timerEvent(QTimerEvent *e)
{
#ifndef QT_NO_MENU
Q_D(QToolButton);
if (e->timerId() == d->popupTimer.timerId()) {
d->popupTimerDone();
return;
}
#endif
QAbstractButton::timerEvent(e);
}
/*!
\reimp
*/
void QToolButton::changeEvent(QEvent *e)
{
#ifndef QT_NO_TOOLBAR
Q_D(QToolButton);
if (e->type() == QEvent::ParentChange) {
if (qobject_cast<QToolBar*>(parentWidget()))
d->autoRaise = true;
} else if (e->type() == QEvent::StyleChange
#ifdef Q_WS_MAC
|| e->type() == QEvent::MacSizeChange
#endif
) {
#ifdef QT3_SUPPORT
if (!d->userDefinedPopupDelay)
#endif
d->delay = style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, this);
d->setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
}
#endif
QAbstractButton::changeEvent(e);
}
/*!
\reimp
*/
void QToolButton::mousePressEvent(QMouseEvent *e)
{
Q_D(QToolButton);
#ifndef QT_NO_MENU
QStyleOptionToolButton opt;
initStyleOption(&opt);
if (e->button() == Qt::LeftButton && (d->popupMode == MenuButtonPopup)) {
QRect popupr = style()->subControlRect(QStyle::CC_ToolButton, &opt,
QStyle::SC_ToolButtonMenu, this);
if (popupr.isValid() && popupr.contains(e->pos())) {
d->buttonPressed = QToolButtonPrivate::MenuButtonPressed;
showMenu();
return;
}
}
#endif
d->buttonPressed = QToolButtonPrivate::ToolButtonPressed;
QAbstractButton::mousePressEvent(e);
}
/*!
\reimp
*/
void QToolButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QToolButton);
QAbstractButton::mouseReleaseEvent(e);
d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
}
/*!
\reimp
*/
bool QToolButton::hitButton(const QPoint &pos) const
{
Q_D(const QToolButton);
if(QAbstractButton::hitButton(pos))
return (d->buttonPressed != QToolButtonPrivate::MenuButtonPressed);
return false;
}
#ifdef QT3_SUPPORT
/*!
Use icon() instead.
*/
QIcon QToolButton::onIconSet() const
{
return icon();
}
/*!
Use icon() instead.
*/
QIcon QToolButton::offIconSet() const
{
return icon();
}
/*!
\obsolete
Use setIcon() instead.
*/
void QToolButton::setOnIconSet(const QIcon& set)
{
setIcon(set);
}
/*!
\obsolete
Use setIcon() instead.
*/
void QToolButton::setOffIconSet(const QIcon& set)
{
setIcon(set);
}
/*! \overload
\obsolete
Since Qt 3.0, QIcon contains both the On and Off icons.
For ease of porting, this function ignores the \a on parameter and
sets the \l{QAbstractButton::icon} {icon} property. If you relied on
the \a on parameter, you probably want to update your code to use
the QIcon On/Off mechanism.
\sa icon QIcon::State
*/
void QToolButton::setIconSet(const QIcon & set, bool /* on */)
{
QAbstractButton::setIcon(set);
}
/*! \overload
\obsolete
Since Qt 3.0, QIcon contains both the On and Off icons.
For ease of porting, this function ignores the \a on parameter and
returns the \l{QAbstractButton::icon} {icon} property. If you relied
on the \a on parameter, you probably want to update your code to use
the QIcon On/Off mechanism.
*/
QIcon QToolButton::iconSet(bool /* on */) const
{
return QAbstractButton::icon();
}
#endif
#ifndef QT_NO_MENU
/*!
Associates the given \a menu with this tool button.
The menu will be shown according to the button's \l popupMode.
Ownership of the menu is not transferred to the tool button.
\sa menu()
*/
void QToolButton::setMenu(QMenu* menu)
{
Q_D(QToolButton);
if (d->menuAction)
removeAction(d->menuAction);
if (menu) {
d->menuAction = menu->menuAction();
addAction(d->menuAction);
} else {
d->menuAction = 0;
}
update();
}
/*!
Returns the associated menu, or 0 if no menu has been defined.
\sa setMenu()
*/
QMenu* QToolButton::menu() const
{
Q_D(const QToolButton);
if (d->menuAction)
return d->menuAction->menu();
return 0;
}
/*!
Shows (pops up) the associated popup menu. If there is no such
menu, this function does nothing. This function does not return
until the popup menu has been closed by the user.
*/
void QToolButton::showMenu()
{
Q_D(QToolButton);
if (!d->hasMenu()) {
d->menuButtonDown = false;
return; // no menu to show
}
d->menuButtonDown = true;
repaint();
d->popupTimer.stop();
d->popupTimerDone();
}
void QToolButtonPrivate::_q_buttonPressed()
{
Q_Q(QToolButton);
if (!hasMenu())
return; // no menu to show
if (popupMode == QToolButton::MenuButtonPopup)
return;
else if (delay > 0 && !popupTimer.isActive() && popupMode == QToolButton::DelayedPopup)
popupTimer.start(delay, q);
else if (delay == 0 || popupMode == QToolButton::InstantPopup)
q->showMenu();
}
void QToolButtonPrivate::popupTimerDone()
{
Q_Q(QToolButton);
popupTimer.stop();
if (!menuButtonDown && !down)
return;
menuButtonDown = true;
QPointer<QMenu> actualMenu;
bool mustDeleteActualMenu = false;
if(menuAction) {
actualMenu = menuAction->menu();
} else if (defaultAction && defaultAction->menu()) {
actualMenu = defaultAction->menu();
} else {
actualMenu = new QMenu(q);
mustDeleteActualMenu = true;
for(int i = 0; i < actions.size(); i++)
actualMenu->addAction(actions.at(i));
}
repeat = q->autoRepeat();
q->setAutoRepeat(false);
bool horizontal = true;
#if !defined(QT_NO_TOOLBAR)
QToolBar *tb = qobject_cast<QToolBar*>(parent);
if (tb && tb->orientation() == Qt::Vertical)
horizontal = false;
#endif
QPoint p;
QRect screen = QApplication::desktop()->availableGeometry(q);
QSize sh = ((QToolButton*)(QMenu*)actualMenu)->receivers(SIGNAL(aboutToShow()))? QSize() : actualMenu->sizeHint();
QRect rect = q->rect();
if (horizontal) {
if (q->isRightToLeft()) {
if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
p = q->mapToGlobal(rect.bottomRight());
} else {
p = q->mapToGlobal(rect.topRight() - QPoint(0, sh.height()));
}
p.rx() -= sh.width();
} else {
if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) {
p = q->mapToGlobal(rect.bottomLeft());
} else {
p = q->mapToGlobal(rect.topLeft() - QPoint(0, sh.height()));
}
}
} else {
if (q->isRightToLeft()) {
if (q->mapToGlobal(QPoint(rect.left(), 0)).x() - sh.width() <= screen.x()) {
p = q->mapToGlobal(rect.topRight());
} else {
p = q->mapToGlobal(rect.topLeft());
p.rx() -= sh.width();
}
} else {
if (q->mapToGlobal(QPoint(rect.right(), 0)).x() + sh.width() <= screen.right()) {
p = q->mapToGlobal(rect.topRight());
} else {
p = q->mapToGlobal(rect.topLeft() - QPoint(sh.width(), 0));
}
}
}
p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width()));
p.ry() += 1;
QPointer<QToolButton> that = q;
actualMenu->setNoReplayFor(q);
if (!mustDeleteActualMenu) //only if action are not in this widget
QObject::connect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
QObject::connect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
actualMenu->d_func()->causedPopup.widget = q;
actualMenu->d_func()->causedPopup.action = defaultAction;
actionsCopy = q->actions(); //(the list of action may be modified in slots)
actualMenu->exec(p);
QObject::disconnect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
if (mustDeleteActualMenu)
delete actualMenu;
else
QObject::disconnect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
if (!that)
return;
actionsCopy.clear();
if (repeat)
q->setAutoRepeat(true);
}
void QToolButtonPrivate::_q_updateButtonDown()
{
Q_Q(QToolButton);
menuButtonDown = false;
if (q->isDown())
q->setDown(false);
else
q->repaint();
}
void QToolButtonPrivate::_q_menuTriggered(QAction *action)
{
Q_Q(QToolButton);
if (action && !actionsCopy.contains(action))
emit q->triggered(action);
}
#endif // QT_NO_MENU
#ifdef QT3_SUPPORT
/*!
\fn void QToolButton::setPopupDelay(int delay)
Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
*/
void QToolButton::setPopupDelay(int delay)
{
Q_D(QToolButton);
d->userDefinedPopupDelay = true;
d->delay = delay;
update();
}
/*!
Use the style hint QStyle::SH_ToolButton_PopupDelay instead.
*/
int QToolButton::popupDelay() const
{
Q_D(const QToolButton);
return d->delay;
}
#endif
#ifndef QT_NO_MENU
/*! \enum QToolButton::ToolButtonPopupMode
Describes how a menu should be popped up for tool buttons that has
a menu set or contains a list of actions.
\value DelayedPopup After pressing and holding the tool button
down for a certain amount of time (the timeout is style dependant,
see QStyle::SH_ToolButton_PopupDelay), the menu is displayed. A
typical application example is the "back" button in some web
browsers's tool bars. If the user clicks it, the browser simply
browses back to the previous page. If the user presses and holds
the button down for a while, the tool button shows a menu
containing the current history list
\value MenuButtonPopup In this mode the tool button displays a
special arrow to indicate that a menu is present. The menu is
displayed when the arrow part of the button is pressed.
\value InstantPopup The menu is displayed, without delay, when
the tool button is pressed. In this mode, the button's own action
is not triggered.
*/
/*!
\property QToolButton::popupMode
\brief describes the way that popup menus are used with tool buttons
By default, this property is set to \l DelayedPopup.
*/
void QToolButton::setPopupMode(ToolButtonPopupMode mode)
{
Q_D(QToolButton);
d->popupMode = mode;
}
QToolButton::ToolButtonPopupMode QToolButton::popupMode() const
{
Q_D(const QToolButton);
return d->popupMode;
}
#endif
/*!
\property QToolButton::autoRaise
\brief whether auto-raising is enabled or not.
The default is disabled (i.e. false).
This property is currently ignored on Mac OS X when using QMacStyle.
*/
void QToolButton::setAutoRaise(bool enable)
{
Q_D(QToolButton);
d->autoRaise = enable;
update();
}
bool QToolButton::autoRaise() const
{
Q_D(const QToolButton);
return d->autoRaise;
}
/*!
Sets the default action to \a action.
If a tool button has a default action, the action defines the
button's properties like text, icon, tool tip, etc.
*/
void QToolButton::setDefaultAction(QAction *action)
{
Q_D(QToolButton);
#ifndef QT_NO_MENU
bool hadMenu = false;
hadMenu = d->hasMenu();
#endif
d->defaultAction = action;
if (!action)
return;
if (!actions().contains(action))
addAction(action);
setText(action->iconText());
setIcon(action->icon());
#ifndef QT_NO_TOOLTIP
setToolTip(action->toolTip());
#endif
#ifndef QT_NO_STATUSTIP
setStatusTip(action->statusTip());
#endif
#ifndef QT_NO_WHATSTHIS
setWhatsThis(action->whatsThis());
#endif
#ifndef QT_NO_MENU
if (action->menu() && !hadMenu) {
// new 'default' popup mode defined introduced by tool bar. We
// should have changed QToolButton's default instead. Do that
// in 4.2.
setPopupMode(QToolButton::MenuButtonPopup);
}
#endif
setCheckable(action->isCheckable());
setChecked(action->isChecked());
setEnabled(action->isEnabled());
if (action->d_func()->fontSet)
setFont(action->font());
}
/*!
Returns the default action.
\sa setDefaultAction()
*/
QAction *QToolButton::defaultAction() const
{
Q_D(const QToolButton);
return d->defaultAction;
}
/*!
\reimp
*/
void QToolButton::nextCheckState()
{
Q_D(QToolButton);
if (!d->defaultAction)
QAbstractButton::nextCheckState();
else
d->defaultAction->trigger();
}
/*! \reimp */
bool QToolButton::event(QEvent *event)
{
switch(event->type()) {
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove:
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
d_func()->updateHoverControl(he->pos());
break;
default:
break;
}
return QAbstractButton::event(event);
}
/*! \internal
*/
QToolButton::QToolButton(QToolButtonPrivate &dd, QWidget *parent)
:QAbstractButton(dd, parent)
{
Q_D(QToolButton);
d->init();
}
/*!
\fn void QToolButton::setPixmap(const QPixmap &pixmap)
Use setIcon(QIcon(pixmap)) instead.
*/
/*!
\fn void QToolButton::setIconSet(const QIcon &icon)
Use setIcon() instead.
*/
/*!
\fn void QToolButton::setTextLabel(const QString &text, bool tooltip)
Use setText() and setToolTip() instead.
*/
/*!
\fn QString QToolButton::textLabel() const
Use text() instead.
*/
/*!
\fn QIcon QToolButton::iconSet() const
Use icon() instead.
*/
/*!
\fn void QToolButton::openPopup()
Use showMenu() instead.
*/
/*!
\fn void QToolButton::setPopup(QMenu* popup)
Use setMenu() instead.
*/
/*!
\fn QMenu* QToolButton::popup() const
Use menu() instead.
*/
/*!
\fn TextPosition QToolButton::textPosition() const
Use toolButtonStyle() instead.
*/
/*!
\fn void QToolButton::setTextPosition(QToolButton::TextPosition pos)
Use setToolButtonStyle() instead.
*/
/*!
\fn bool QToolButton::usesBigPixmap() const
Use iconSize() instead.
*/
/*!
\fn void QToolButton::setUsesBigPixmap(bool enable)
Use setIconSize() instead.
*/
/*!
\fn bool QToolButton::usesTextLabel() const
Use toolButtonStyle() instead.
*/
/*!
\fn void QToolButton::setUsesTextLabel(bool enable)
Use setToolButtonStyle() instead.
*/
QT_END_NAMESPACE
#include "moc_qtoolbutton.cpp"
#endif