diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/widgets/qabstractbutton.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/widgets/qabstractbutton.cpp')
-rw-r--r-- | src/gui/widgets/qabstractbutton.cpp | 1468 |
1 files changed, 1468 insertions, 0 deletions
diff --git a/src/gui/widgets/qabstractbutton.cpp b/src/gui/widgets/qabstractbutton.cpp new file mode 100644 index 0000000..330a7f8 --- /dev/null +++ b/src/gui/widgets/qabstractbutton.cpp @@ -0,0 +1,1468 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractbutton.h" +#include "qabstractitemview.h" +#include "qbuttongroup.h" +#include "qabstractbutton_p.h" +#include "qevent.h" +#include "qpainter.h" +#include "qapplication.h" +#include "qstyle.h" +#include "qaction.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif + +QT_BEGIN_NAMESPACE + +#define AUTO_REPEAT_DELAY 300 +#define AUTO_REPEAT_INTERVAL 100 + +extern bool qt_tab_all_widgets; + +/*! + \class QAbstractButton + + \brief The QAbstractButton class is the abstract base class of + button widgets, providing functionality common to buttons. + + \ingroup abstractwidgets + + This class implements an \e abstract button. + Subclasses of this class handle user actions, and specify how the button + is drawn. + + QAbstractButton provides support for both push buttons and checkable + (toggle) buttons. Checkable buttons are implemented in the QRadioButton + and QCheckBox classes. Push buttons are implemented in the + QPushButton and QToolButton classes; these also provide toggle + behavior if required. + + Any button can display a label containing text and an icon. setText() + sets the text; setIcon() sets the icon. If a button is disabled, its label + is changed to give the button a "disabled" appearance. + + If the button is a text button with a string containing an + ampersand ('&'), QAbstractButton automatically creates a shortcut + key. For example: + + \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 0 + + The \key Alt+C shortcut is assigned to the button, i.e., when the + user presses \key Alt+C the button will call animateClick(). See + the \l {QShortcut#mnemonic}{QShortcut} documentation for details + (to display an actual ampersand, use '&&'). + + You can also set a custom shortcut key using the setShortcut() + function. This is useful mostly for buttons that do not have any + text, because they have no automatic shortcut. + + \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 1 + + All of the buttons provided by Qt (QPushButton, QToolButton, + QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}. + + A button can be made the default button in a dialog are provided by + QPushButton::setDefault() and QPushButton::setAutoDefault(). + + QAbstractButton provides most of the states used for buttons: + + \list + + \o isDown() indicates whether the button is \e pressed down. + + \o isChecked() indicates whether the button is \e checked. Only + checkable buttons can be checked and unchecked (see below). + + \o isEnabled() indicates whether the button can be pressed by the + user. + + \o setAutoRepeat() sets whether the button will auto-repeat if the + user holds it down. \l autoRepeatDelay and \l autoRepeatInterval + define how auto-repetition is done. + + \o setCheckable() sets whether the button is a toggle button or not. + + \endlist + + The difference between isDown() and isChecked() is as follows. + When the user clicks a toggle button to check it, the button is first + \e pressed then released into the \e checked state. When the user + clicks it again (to uncheck it), the button moves first to the + \e pressed state, then to the \e unchecked state (isChecked() and + isDown() are both false). + + QAbstractButton provides four signals: + + \list 1 + + \o pressed() is emitted when the left mouse button is pressed while + the mouse cursor is inside the button. + + \o released() is emitted when the left mouse button is released. + + \o clicked() is emitted when the button is first pressed and then + released, when the shortcut key is typed, or when click() or + animateClick() is called. + + \o toggled() is emitted when the state of a toggle button changes. + + \endlist + + To subclass QAbstractButton, you must reimplement at least + paintEvent() to draw the button's outline and its text or pixmap. It + is generally advisable to reimplement sizeHint() as well, and + sometimes hitButton() (to determine whether a button press is within + the button). For buttons with more than two states (like tri-state + buttons), you will also have to reimplement checkStateSet() and + nextCheckState(). + + \sa QButtonGroup +*/ + +QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type) + : +#ifndef QT_NO_SHORTCUT + shortcutId(0), +#endif + checkable(false), checked(false), autoRepeat(false), autoExclusive(false), + down(false), blockRefresh(false), +#ifndef QT_NO_BUTTONGROUP + group(0), +#endif + autoRepeatDelay(AUTO_REPEAT_DELAY), + autoRepeatInterval(AUTO_REPEAT_INTERVAL), + controlType(type) +{} + +#ifndef QT_NO_BUTTONGROUP + +class QButtonGroupPrivate: public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QButtonGroup) + +public: + QButtonGroupPrivate():exclusive(true){} + QList<QAbstractButton *> buttonList; + QPointer<QAbstractButton> checkedButton; + void detectCheckedButton(); + void notifyChecked(QAbstractButton *button); + bool exclusive; + QMap<QAbstractButton*, int> mapping; +}; + +QButtonGroup::QButtonGroup(QObject *parent) + : QObject(*new QButtonGroupPrivate, parent) +{ +} + +QButtonGroup::~QButtonGroup() +{ + Q_D(QButtonGroup); + for (int i = 0; i < d->buttonList.count(); ++i) + d->buttonList.at(i)->d_func()->group = 0; +} + + +bool QButtonGroup::exclusive() const +{ + Q_D(const QButtonGroup); + return d->exclusive; +} + +void QButtonGroup::setExclusive(bool exclusive) +{ + Q_D(QButtonGroup); + d->exclusive = exclusive; +} + +/*! + Adds the given \a button to the end of the group's internal list of buttons. + + \sa removeButton() +*/ +void QButtonGroup::addButton(QAbstractButton *button) +{ + addButton(button, -1); +} + +void QButtonGroup::addButton(QAbstractButton *button, int id) +{ + Q_D(QButtonGroup); + if (QButtonGroup *previous = button->d_func()->group) + previous->removeButton(button); + button->d_func()->group = this; + d->buttonList.append(button); + if (id != -1) + d->mapping[button] = id; + if (d->exclusive && button->isChecked()) + button->d_func()->notifyChecked(); +} + +void QButtonGroup::removeButton(QAbstractButton *button) +{ + Q_D(QButtonGroup); + if (d->checkedButton == button) { + d->detectCheckedButton(); + } + if (button->d_func()->group == this) { + button->d_func()->group = 0; + d->buttonList.removeAll(button); + d->mapping.remove(button); + } +} + +QList<QAbstractButton*> QButtonGroup::buttons() const +{ + Q_D(const QButtonGroup); + return d->buttonList; +} + +QAbstractButton *QButtonGroup::checkedButton() const +{ + Q_D(const QButtonGroup); + return d->checkedButton; +} + +QAbstractButton *QButtonGroup::button(int id) const +{ + Q_D(const QButtonGroup); + return d->mapping.key(id); +} + +void QButtonGroup::setId(QAbstractButton *button, int id) +{ + Q_D(QButtonGroup); + if (button && id != -1) + d->mapping[button] = id; +} + +int QButtonGroup::id(QAbstractButton *button) const +{ + Q_D(const QButtonGroup); + return d->mapping.value(button, -1); +} + +int QButtonGroup::checkedId() const +{ + Q_D(const QButtonGroup); + return d->mapping.value(d->checkedButton, -1); +} + +// detect a checked button other than the current one +void QButtonGroupPrivate::detectCheckedButton() +{ + QAbstractButton *previous = checkedButton; + checkedButton = 0; + if (exclusive) + return; + for (int i = 0; i < buttonList.count(); i++) { + if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) { + checkedButton = buttonList.at(i); + return; + } + } +} + +#endif // QT_NO_BUTTONGROUP + +QList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const +{ +#ifndef QT_NO_BUTTONGROUP + if (group) + return group->d_func()->buttonList; +#endif + + Q_Q(const QAbstractButton); + QList<QAbstractButton*>candidates; + if (q->parentWidget()) { + candidates = qFindChildren<QAbstractButton *>(q->parentWidget()); + if (autoExclusive) { + for (int i = candidates.count() - 1; i >= 0; --i) { + QAbstractButton *candidate = candidates.at(i); + if (!candidate->autoExclusive() +#ifndef QT_NO_BUTTONGROUP + || candidate->group() +#endif + ) + candidates.removeAt(i); + } + } + } + return candidates; +} + +QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const +{ +#ifndef QT_NO_BUTTONGROUP + if (group) + return group->d_func()->checkedButton; +#endif + + Q_Q(const QAbstractButton); + QList<QAbstractButton *> buttonList = queryButtonList(); + if (!autoExclusive || buttonList.count() == 1) // no group + return 0; + + for (int i = 0; i < buttonList.count(); ++i) { + QAbstractButton *b = buttonList.at(i); + if (b->d_func()->checked && b != q) + return b; + } + return checked ? const_cast<QAbstractButton *>(q) : 0; +} + +void QAbstractButtonPrivate::notifyChecked() +{ +#ifndef QT_NO_BUTTONGROUP + Q_Q(QAbstractButton); + if (group) { + QAbstractButton *previous = group->d_func()->checkedButton; + group->d_func()->checkedButton = q; + if (group->d_func()->exclusive && previous && previous != q) + previous->nextCheckState(); + } else +#endif + if (autoExclusive) { + if (QAbstractButton *b = queryCheckedButton()) + b->setChecked(false); + } +} + +void QAbstractButtonPrivate::moveFocus(int key) +{ + QList<QAbstractButton *> buttonList = queryButtonList();; +#ifndef QT_NO_BUTTONGROUP + bool exclusive = group ? group->d_func()->exclusive : autoExclusive; +#else + bool exclusive = autoExclusive; +#endif + QWidget *f = qApp->focusWidget(); + QAbstractButton *fb = qobject_cast<QAbstractButton *>(f); + if (!fb || !buttonList.contains(fb)) + return; + + QAbstractButton *candidate = 0; + int bestScore = -1; + QRect target = f->rect().translated(f->mapToGlobal(QPoint(0,0))); + QPoint goal = target.center(); + uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus; + + for (int i = 0; i < buttonList.count(); ++i) { + QAbstractButton *button = buttonList.at(i); + if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() && + (autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) { + QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0))); + QPoint p = buttonRect.center(); + + //Priority to widgets that overlap on the same coordinate. + //In that case, the distance in the direction will be used as significant score, + //take also in account orthogonal distance in case two widget are in the same distance. + int score; + if ((buttonRect.x() < target.right() && target.x() < buttonRect.right()) + && (key == Qt::Key_Up || key == Qt::Key_Down)) { + //one item's is at the vertical of the other + score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x()); + } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom()) + && (key == Qt::Key_Left || key == Qt::Key_Right) ) { + //one item's is at the horizontal of the other + score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y()); + } else { + score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x()); + } + + if (score > bestScore && candidate) + continue; + + switch(key) { + case Qt::Key_Up: + if (p.y() < goal.y()) { + candidate = button; + bestScore = score; + } + break; + case Qt::Key_Down: + if (p.y() > goal.y()) { + candidate = button; + bestScore = score; + } + break; + case Qt::Key_Left: + if (p.x() < goal.x()) { + candidate = button; + bestScore = score; + } + break; + case Qt::Key_Right: + if (p.x() > goal.x()) { + candidate = button; + bestScore = score; + } + break; + } + } + } + + if (exclusive +#ifdef QT_KEYPAD_NAVIGATION + && !QApplication::keypadNavigationEnabled() +#endif + && candidate + && fb->d_func()->checked + && candidate->d_func()->checkable) + candidate->click(); + + if (candidate) { + if (key == Qt::Key_Up || key == Qt::Key_Left) + candidate->setFocus(Qt::BacktabFocusReason); + else + candidate->setFocus(Qt::TabFocusReason); + } +} + +void QAbstractButtonPrivate::fixFocusPolicy() +{ + Q_Q(QAbstractButton); +#ifndef QT_NO_BUTTONGROUP + if (!group && !autoExclusive) +#else + if (!autoExclusive) +#endif + return; + + QList<QAbstractButton *> buttonList = queryButtonList(); + for (int i = 0; i < buttonList.count(); ++i) { + QAbstractButton *b = buttonList.at(i); + if (!b->isCheckable()) + continue; + b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable()) + ? (b->focusPolicy() | Qt::TabFocus) + : (b->focusPolicy() & ~Qt::TabFocus))); + } +} + +void QAbstractButtonPrivate::init() +{ + Q_Q(QAbstractButton); + + q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy))); + q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType)); + q->setAttribute(Qt::WA_WState_OwnSizePolicy, false); + q->setForegroundRole(QPalette::ButtonText); + q->setBackgroundRole(QPalette::Button); +} + +void QAbstractButtonPrivate::refresh() +{ + Q_Q(QAbstractButton); + + if (blockRefresh) + return; + q->update(); +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(q, 0, QAccessible::StateChanged); +#endif +} + +void QAbstractButtonPrivate::click() +{ + Q_Q(QAbstractButton); + + down = false; + blockRefresh = true; + bool changeState = true; + if (checked && queryCheckedButton() == q) { + // the checked button of an exclusive or autoexclusive group cannot be unchecked +#ifndef QT_NO_BUTTONGROUP + if (group ? group->d_func()->exclusive : autoExclusive) +#else + if (autoExclusive) +#endif + changeState = false; + } + + QPointer<QAbstractButton> guard(q); + if (changeState) { + q->nextCheckState(); + if (!guard) + return; + } + blockRefresh = false; + refresh(); + q->repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + if (guard) + emitReleased(); + if (guard) + emitClicked(); +} + +void QAbstractButtonPrivate::emitClicked() +{ + Q_Q(QAbstractButton); + QPointer<QAbstractButton> guard(q); + emit q->clicked(checked); +#ifndef QT_NO_BUTTONGROUP + if (guard && group) { + emit group->buttonClicked(group->id(q)); + if (guard && group) + emit group->buttonClicked(q); + } +#endif +} + +void QAbstractButtonPrivate::emitPressed() +{ + Q_Q(QAbstractButton); + QPointer<QAbstractButton> guard(q); + emit q->pressed(); +#ifndef QT_NO_BUTTONGROUP + if (guard && group) { + emit group->buttonPressed(group->id(q)); + if (guard && group) + emit group->buttonPressed(q); + } +#endif +} + +void QAbstractButtonPrivate::emitReleased() +{ + Q_Q(QAbstractButton); + QPointer<QAbstractButton> guard(q); + emit q->released(); +#ifndef QT_NO_BUTTONGROUP + if (guard && group) { + emit group->buttonReleased(group->id(q)); + if (guard && group) + emit group->buttonReleased(q); + } +#endif +} + +/*! + Constructs an abstract button with a \a parent. +*/ +QAbstractButton::QAbstractButton(QWidget *parent) + : QWidget(*new QAbstractButtonPrivate, parent, 0) +{ + Q_D(QAbstractButton); + d->init(); +} + +/*! + Destroys the button. + */ + QAbstractButton::~QAbstractButton() +{ +#ifndef QT_NO_BUTTONGROUP + Q_D(QAbstractButton); + if (d->group) + d->group->removeButton(this); +#endif +} + + +/*! \internal + */ +QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent) + : QWidget(dd, parent, 0) +{ + Q_D(QAbstractButton); + d->init(); +} + +/*! +\property QAbstractButton::text +\brief the text shown on the button + +If the button has no text, the text() function will return a an empty +string. + +If the text contains an ampersand character ('&'), a shortcut is +automatically created for it. The character that follows the '&' will +be used as the shortcut key. Any previous shortcut will be +overwritten, or cleared if no shortcut is defined by the text. See the +\l {QShortcut#mnemonic}{QShortcut} documentation for details (to +display an actual ampersand, use '&&'). + +There is no default text. +*/ + +void QAbstractButton::setText(const QString &text) +{ + Q_D(QAbstractButton); + if (d->text == text) + return; + d->text = text; +#ifndef QT_NO_SHORTCUT + QKeySequence newMnemonic = QKeySequence::mnemonic(text); + setShortcut(newMnemonic); +#endif + d->sizeHint = QSize(); + update(); + updateGeometry(); +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged); +#endif +} + +QString QAbstractButton::text() const +{ + Q_D(const QAbstractButton); + return d->text; +} + + +/*! + \property QAbstractButton::icon + \brief the icon shown on the button + + The icon's default size is defined by the GUI style, but can be + adjusted by setting the \l iconSize property. +*/ +void QAbstractButton::setIcon(const QIcon &icon) +{ + Q_D(QAbstractButton); + d->icon = icon; + d->sizeHint = QSize(); + update(); + updateGeometry(); +} + +QIcon QAbstractButton::icon() const +{ + Q_D(const QAbstractButton); + return d->icon; +} + +#ifndef QT_NO_SHORTCUT +/*! +\property QAbstractButton::shortcut +\brief the mnemonic associated with the button +*/ + +void QAbstractButton::setShortcut(const QKeySequence &key) +{ + Q_D(QAbstractButton); + if (d->shortcutId != 0) + releaseShortcut(d->shortcutId); + d->shortcut = key; + d->shortcutId = grabShortcut(key); +} + +QKeySequence QAbstractButton::shortcut() const +{ + Q_D(const QAbstractButton); + return d->shortcut; +} +#endif // QT_NO_SHORTCUT + +/*! +\property QAbstractButton::checkable +\brief whether the button is checkable + +By default, the button is not checkable. + +\sa checked +*/ +void QAbstractButton::setCheckable(bool checkable) +{ + Q_D(QAbstractButton); + if (d->checkable == checkable) + return; + + d->checkable = checkable; + d->checked = false; +} + +bool QAbstractButton::isCheckable() const +{ + Q_D(const QAbstractButton); + return d->checkable; +} + +/*! +\property QAbstractButton::checked +\brief whether the button is checked + +Only checkable buttons can be checked. By default, the button is unchecked. + +\sa checkable +*/ +void QAbstractButton::setChecked(bool checked) +{ + Q_D(QAbstractButton); + if (!d->checkable || d->checked == checked) { + if (!d->blockRefresh) + checkStateSet(); + return; + } + + if (!checked && d->queryCheckedButton() == this) { + // the checked button of an exclusive or autoexclusive group cannot be unchecked +#ifndef QT_NO_BUTTONGROUP + if (d->group ? d->group->d_func()->exclusive : d->autoExclusive) + return; + if (d->group) + d->group->d_func()->detectCheckedButton(); +#else + if (d->autoExclusive) + return; +#endif + } + + QPointer<QAbstractButton> guard(this); + + d->checked = checked; + if (!d->blockRefresh) + checkStateSet(); + d->refresh(); + + if (guard && checked) + d->notifyChecked(); + if (guard) + emit toggled(checked); +} + +bool QAbstractButton::isChecked() const +{ + Q_D(const QAbstractButton); + return d->checked; +} + +/*! + \property QAbstractButton::down + \brief whether the button is pressed down + + If this property is true, the button is pressed down. The signals + pressed() and clicked() are not emitted if you set this property + to true. The default is false. +*/ + +void QAbstractButton::setDown(bool down) +{ + Q_D(QAbstractButton); + if (d->down == down) + return; + d->down = down; + d->refresh(); + if (d->autoRepeat && d->down) + d->repeatTimer.start(d->autoRepeatDelay, this); + else + d->repeatTimer.stop(); +} + +bool QAbstractButton::isDown() const +{ + Q_D(const QAbstractButton); + return d->down; +} + +/*! +\property QAbstractButton::autoRepeat +\brief whether autoRepeat is enabled + +If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at +regular intervals when the button is down. autoRepeat is off by default. +The initial delay and the repetition interval are defined in milliseconds by \l +autoRepeatDelay and \l autoRepeatInterval. + +Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the +system and not by this class. The pressed(), released(), and clicked() signals will be emitted +like in the normal case. +*/ + +void QAbstractButton::setAutoRepeat(bool autoRepeat) +{ + Q_D(QAbstractButton); + if (d->autoRepeat == autoRepeat) + return; + d->autoRepeat = autoRepeat; + if (d->autoRepeat && d->down) + d->repeatTimer.start(d->autoRepeatDelay, this); + else + d->repeatTimer.stop(); +} + +bool QAbstractButton::autoRepeat() const +{ + Q_D(const QAbstractButton); + return d->autoRepeat; +} + +/*! + \property QAbstractButton::autoRepeatDelay + \brief the initial delay of auto-repetition + \since 4.2 + + If \l autoRepeat is enabled, then autoRepeatDelay defines the initial + delay in milliseconds before auto-repetition kicks in. + + \sa autoRepeat, autoRepeatInterval +*/ + +void QAbstractButton::setAutoRepeatDelay(int autoRepeatDelay) +{ + Q_D(QAbstractButton); + d->autoRepeatDelay = autoRepeatDelay; +} + +int QAbstractButton::autoRepeatDelay() const +{ + Q_D(const QAbstractButton); + return d->autoRepeatDelay; +} + +/*! + \property QAbstractButton::autoRepeatInterval + \brief the interval of auto-repetition + \since 4.2 + + If \l autoRepeat is enabled, then autoRepeatInterval defines the + length of the auto-repetition interval in millisecons. + + \sa autoRepeat, autoRepeatDelay +*/ + +void QAbstractButton::setAutoRepeatInterval(int autoRepeatInterval) +{ + Q_D(QAbstractButton); + d->autoRepeatInterval = autoRepeatInterval; +} + +int QAbstractButton::autoRepeatInterval() const +{ + Q_D(const QAbstractButton); + return d->autoRepeatInterval; +} + + + +/*! +\property QAbstractButton::autoExclusive +\brief whether auto-exclusivity is enabled + +If auto-exclusivity is enabled, checkable buttons that belong to the +same parent widget behave as if they were part of the same +exclusive button group. In an exclusive button group, only one button +can be checked at any time; checking another button automatically +unchecks the previously checked one. + +The property has no effect on buttons that belong to a button +group. + +autoExclusive is off by default, except for radio buttons. + +\sa QRadioButton +*/ +void QAbstractButton::setAutoExclusive(bool autoExclusive) +{ + Q_D(QAbstractButton); + d->autoExclusive = autoExclusive; +} + +bool QAbstractButton::autoExclusive() const +{ + Q_D(const QAbstractButton); + return d->autoExclusive; +} + +#ifndef QT_NO_BUTTONGROUP +/*! + Returns the group that this button belongs to. + + If the button is not a member of any QButtonGroup, this function + returns 0. + + \sa QButtonGroup +*/ +QButtonGroup *QAbstractButton::group() const +{ + Q_D(const QAbstractButton); + return d->group; +} +#endif // QT_NO_BUTTONGROUP + +/*! +Performs an animated click: the button is pressed immediately, and +released \a msec milliseconds later (the default is 100 ms). + +Calling this function again before the button was released will reset +the release timer. + +All signals associated with a click are emitted as appropriate. + +This function does nothing if the button is \link setEnabled() +disabled. \endlink + +\sa click() +*/ +void QAbstractButton::animateClick(int msec) +{ + if (!isEnabled()) + return; + Q_D(QAbstractButton); + if (d->checkable && focusPolicy() & Qt::ClickFocus) + setFocus(); + setDown(true); + repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + if (!d->animateTimer.isActive()) + d->emitPressed(); + d->animateTimer.start(msec, this); +} + +/*! +Performs a click. + +All the usual signals associated with a click are emitted as +appropriate. If the button is checkable, the state of the button is +toggled. + +This function does nothing if the button is \link setEnabled() +disabled. \endlink + +\sa animateClick() + */ +void QAbstractButton::click() +{ + if (!isEnabled()) + return; + Q_D(QAbstractButton); + QPointer<QAbstractButton> guard(this); + d->down = true; + d->emitPressed(); + if (guard) { + d->down = false; + nextCheckState(); + if (guard) + d->emitReleased(); + if (guard) + d->emitClicked(); + } +} + +/*! \fn void QAbstractButton::toggle() + + Toggles the state of a checkable button. + + \sa checked +*/ +void QAbstractButton::toggle() +{ + Q_D(QAbstractButton); + setChecked(!d->checked); +} + + +/*! This virtual handler is called when setChecked() was called, +unless it was called from within nextCheckState(). It allows +subclasses to reset their intermediate button states. + +\sa nextCheckState() + */ +void QAbstractButton::checkStateSet() +{ +} + +/*! This virtual handler is called when a button is clicked. The +default implementation calls setChecked(!isChecked()) if the button +isCheckable(). It allows subclasses to implement intermediate button +states. + +\sa checkStateSet() +*/ +void QAbstractButton::nextCheckState() +{ + if (isCheckable()) + setChecked(!isChecked()); +} + +/*! +Returns true if \a pos is inside the clickable button rectangle; +otherwise returns false. + +By default, the clickable area is the entire widget. Subclasses +may reimplement this function to provide support for clickable +areas of different shapes and sizes. +*/ +bool QAbstractButton::hitButton(const QPoint &pos) const +{ + return rect().contains(pos); +} + +/*! \reimp */ +bool QAbstractButton::event(QEvent *e) +{ + // as opposed to other widgets, disabled buttons accept mouse + // events. This avoids surprising click-through scenarios + if (!isEnabled()) { + switch(e->type()) { + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::TabletMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::HoverMove: + case QEvent::HoverEnter: + case QEvent::HoverLeave: + case QEvent::ContextMenu: +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: +#endif + return true; + default: + break; + } + } + +#ifndef QT_NO_SHORTCUT + if (e->type() == QEvent::Shortcut) { + Q_D(QAbstractButton); + QShortcutEvent *se = static_cast<QShortcutEvent *>(e); + if (d->shortcutId != se->shortcutId()) + return false; + if (!se->isAmbiguous()) { + if (!d->animateTimer.isActive()) + animateClick(); + } else { + if (focusPolicy() != Qt::NoFocus) + setFocus(Qt::ShortcutFocusReason); + window()->setAttribute(Qt::WA_KeyboardFocusChange); + } + return true; + } +#endif + return QWidget::event(e); +} + +/*! \reimp */ +void QAbstractButton::mousePressEvent(QMouseEvent *e) +{ + Q_D(QAbstractButton); + if (e->button() != Qt::LeftButton) { + e->ignore(); + return; + } + if (hitButton(e->pos())) { + setDown(true); + repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + d->emitPressed(); + e->accept(); + } else { + e->ignore(); + } +} + +/*! \reimp */ +void QAbstractButton::mouseReleaseEvent(QMouseEvent *e) +{ + Q_D(QAbstractButton); + if (e->button() != Qt::LeftButton) { + e->ignore(); + return; + } + + if (!d->down) { + e->ignore(); + return; + } + + if (hitButton(e->pos())) { + d->repeatTimer.stop(); + d->click(); + e->accept(); + } else { + setDown(false); + e->ignore(); + } +} + +/*! \reimp */ +void QAbstractButton::mouseMoveEvent(QMouseEvent *e) +{ + Q_D(QAbstractButton); + if (!(e->buttons() & Qt::LeftButton)) { + e->ignore(); + return; + } + + if (hitButton(e->pos()) != d->down) { + setDown(!d->down); + repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + if (d->down) + d->emitPressed(); + else + d->emitReleased(); + e->accept(); + } else if (!hitButton(e->pos())) { + e->ignore(); + } +} + +/*! \reimp */ +void QAbstractButton::keyPressEvent(QKeyEvent *e) +{ + Q_D(QAbstractButton); + bool next = true; + switch (e->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + e->ignore(); + break; + case Qt::Key_Select: + case Qt::Key_Space: + if (!e->isAutoRepeat()) { + setDown(true); + repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + d->emitPressed(); + } + break; + case Qt::Key_Up: + case Qt::Key_Left: + next = false; + // fall through + case Qt::Key_Right: + case Qt::Key_Down: +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled() && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right)) { + e->ignore(); + return; + } +#endif + QWidget *pw; + if (d->autoExclusive +#ifndef QT_NO_BUTTONGROUP + || d->group +#endif +#ifndef QT_NO_ITEMVIEWS + || ((pw = parentWidget()) && qobject_cast<QAbstractItemView *>(pw->parentWidget())) +#endif + ) { + // ### Using qobject_cast to check if the parent is a viewport of + // QAbstractItemView is a crude hack, and should be revisited and + // cleaned up when fixing task 194373. It's here to ensure that we + // keep compatibility outside QAbstractItemView. + d->moveFocus(e->key()); + if (hasFocus()) // nothing happend, propagate + e->ignore(); + } else { + focusNextPrevChild(next); + } + break; + case Qt::Key_Escape: + if (d->down) { + setDown(false); + repaint(); //flush paint event before invoking potentially expensive operation + QApplication::flush(); + d->emitReleased(); + break; + } + // fall through + default: + e->ignore(); + } +} + +/*! \reimp */ +void QAbstractButton::keyReleaseEvent(QKeyEvent *e) +{ + Q_D(QAbstractButton); + + if (!e->isAutoRepeat()) + d->repeatTimer.stop(); + + switch (e->key()) { + case Qt::Key_Select: + case Qt::Key_Space: + if (!e->isAutoRepeat() && d->down) + d->click(); + break; + default: + e->ignore(); + } +} + +/*!\reimp + */ +void QAbstractButton::timerEvent(QTimerEvent *e) +{ + Q_D(QAbstractButton); + if (e->timerId() == d->repeatTimer.timerId()) { + d->repeatTimer.start(d->autoRepeatInterval, this); + if (d->down) { + QPointer<QAbstractButton> guard(this); + d->emitReleased(); + if (guard) + d->emitClicked(); + if (guard) + d->emitPressed(); + } + } else if (e->timerId() == d->animateTimer.timerId()) { + d->animateTimer.stop(); + d->click(); + } +} + +#if defined(Q_OS_WINCE) && !defined(QT_NO_CONTEXTMENU) +/*! \reimp */ +void QAbstractButton::contextMenuEvent(QContextMenuEvent *e) +{ + e->ignore(); + setDown(false); +} +#endif + +/*! \reimp */ +void QAbstractButton::focusInEvent(QFocusEvent *e) +{ + Q_D(QAbstractButton); +#ifdef QT_KEYPAD_NAVIGATION + if (!QApplication::keypadNavigationEnabled()) +#endif + d->fixFocusPolicy(); + QWidget::focusInEvent(e); +} + +/*! \reimp */ +void QAbstractButton::focusOutEvent(QFocusEvent *e) +{ + Q_D(QAbstractButton); + if (e->reason() != Qt::PopupFocusReason) + d->down = false; + QWidget::focusOutEvent(e); +} + +/*! \reimp */ +void QAbstractButton::changeEvent(QEvent *e) +{ + Q_D(QAbstractButton); + switch (e->type()) { + case QEvent::EnabledChange: + if (!isEnabled()) + setDown(false); + break; + default: + d->sizeHint = QSize(); + break; + } + QWidget::changeEvent(e); +} + +/*! + \fn void QAbstractButton::paintEvent(QPaintEvent *e) + \reimp +*/ + +/*! + \fn void QAbstractButton::pressed() + + This signal is emitted when the button is pressed down. + + \sa released(), clicked() +*/ + +/*! + \fn void QAbstractButton::released() + + This signal is emitted when the button is released. + + \sa pressed(), clicked(), toggled() +*/ + +/*! +\fn void QAbstractButton::clicked(bool checked) + +This signal is emitted when the button is activated (i.e. pressed down +then released while the mouse cursor is inside the button), when the +shortcut key is typed, or when click() or animateClick() is called. +Notably, this signal is \e not emitted if you call setDown(), +setChecked() or toggle(). + +If the button is checkable, \a checked is true if the button is +checked, or false if the button is unchecked. + +\sa pressed(), released(), toggled() +*/ + +/*! +\fn void QAbstractButton::toggled(bool checked) + +This signal is emitted whenever a checkable button changes its state. +\a checked is true if the button is checked, or false if the button is +unchecked. + +This may be the result of a user action, click() slot activation, +or because setChecked() was called. + +The states of buttons in exclusive button groups are updated before this +signal is emitted. This means that slots can act on either the "off" +signal or the "on" signal emitted by the buttons in the group whose +states have changed. + +For example, a slot that reacts to signals emitted by newly checked +buttons but which ignores signals from buttons that have been unchecked +can be implemented using the following pattern: + +\snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 2 + +Button groups can be created using the QButtonGroup class, and +updates to the button states monitored with the +\l{QButtonGroup::buttonClicked()} signal. + +\sa checked, clicked() +*/ + +/*! + \property QAbstractButton::iconSize + \brief the icon size used for this button. + + The default size is defined by the GUI style. This is a maximum + size for the icons. Smaller icons will not be scaled up. +*/ + +QSize QAbstractButton::iconSize() const +{ + Q_D(const QAbstractButton); + if (d->iconSize.isValid()) + return d->iconSize; + int e = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this); + return QSize(e, e); +} + +void QAbstractButton::setIconSize(const QSize &size) +{ + Q_D(QAbstractButton); + if (d->iconSize == size) + return; + + d->iconSize = size; + d->sizeHint = QSize(); + updateGeometry(); + if (isVisible()) { + update(); + } +} + + +#ifdef QT3_SUPPORT +/*! + Use icon() instead. +*/ +QIcon *QAbstractButton::iconSet() const +{ + Q_D(const QAbstractButton); + if (!d->icon.isNull()) + return const_cast<QIcon *>(&d->icon); + return 0; +} + +/*! + Use QAbstractButton(QWidget *) instead. + + Call setObjectName() if you want to specify an object name, and + setParent() if you want to set the window flags. +*/ +QAbstractButton::QAbstractButton(QWidget *parent, const char *name, Qt::WindowFlags f) + : QWidget(*new QAbstractButtonPrivate, parent, f) +{ + Q_D(QAbstractButton); + setObjectName(QString::fromAscii(name)); + d->init(); +} + +/*! \fn bool QAbstractButton::isOn() const + + Use isChecked() instead. +*/ + +/*! + \fn QPixmap *QAbstractButton::pixmap() const + + This compatibility function always returns 0. + + Use icon() instead. +*/ + +/*! \fn void QAbstractButton::setPixmap(const QPixmap &p) + + Use setIcon() instead. +*/ + +/*! \fn void QAbstractButton::setIconSet(const QIcon &icon) + + Use setIcon() instead. +*/ + +/*! \fn void QAbstractButton::setOn(bool b) + + Use setChecked() instead. +*/ + +/*! \fn bool QAbstractButton::isToggleButton() const + + Use isCheckable() instead. +*/ + +/*! + \fn void QAbstractButton::setToggleButton(bool b) + + Use setCheckable() instead. +*/ + +/*! \fn void QAbstractButton::setAccel(const QKeySequence &key) + + Use setShortcut() instead. +*/ + +/*! \fn QKeySequence QAbstractButton::accel() const + + Use shortcut() instead. +*/ +#endif + +QT_END_NAMESPACE |