diff -r 000000000000 -r 16d8024aca5e src/hbcore/gui/hbabstractbutton.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbcore/gui/hbabstractbutton.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,1156 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (developer.feedback@nokia.com) +** +** This file is part of the HbCore module of the UI Extensions for Mobile. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at developer.feedback@nokia.com. +** +****************************************************************************/ + +#include "hbabstractbutton.h" +#include "hbabstractbutton_p.h" +#include "hbapplication.h" +#include "hbstyleoption.h" +#include "hbtooltip.h" +#include "hbinstance.h" +#include +#include +#include +#include + +#include + +namespace { + static const int AUTO_REPEAT_DELAY = 300; + static const int AUTO_REPEAT_INTERVAL = 100; +} + +/*! + @beta + @hbcore + \class HbAbstractButton + + \brief The HbAbstractButton class is the abstract base class of + button widgets, providing functionality common to buttons. + + This class implements an \e abstract button. + Subclasses of this class handle user actions, and specify how the button + is drawn. + + HbAbstractButton provides support for both push buttons and checkable + (toggle) buttons. Checkable buttons are implemented in the HbRadioButton + and HbCheckBox classes. Push buttons are implemented in the + HbPushButton and HbToolButton classes; these also provide toggle + behavior if required. + + Any button can display text and an icon. setText() + sets the text; setIcon() sets the icon. If a button is disabled, its background + is changed to give the button a "disabled" appearance. + + All of the buttons provided by Hb (HbPushButton, HbToolButton, + HbCheckBox, and HbRadioButton) can display both text and icon. + You can also set a tool tip for the button with \qtfunc{QGraphicsItem,setTooltip}. + + HbAbstractButton provides most of the states used for buttons: + + \li isDown() indicates whether the button is \e pressed down. + + \li isChecked() indicates whether the button is \e checked. Only + checkable buttons can be checked and unchecked (see below). + + \li isEnabled() indicates whether the button can be pressed by the + user. + + \li 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. + + \li setCheckable() sets whether the button is a toggle button or not. + + 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). + + HbAbstractButton provides four signals: + + \li pressed() is emitted when the stylus is pressed while + the stylus is inside the button. + + \li released() is emitted when the left stylus is released. + + \li 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. + + \li toggled() is emitted when the state of a toggle button changes. + + To subclass HbAbstractButton, you must reimplement at least + paint() 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(). +*/ + +/*! + \reimp + \fn int HbAbstractButton::type() const + */ + +HbAbstractButtonPrivate::HbAbstractButtonPrivate( QSizePolicy::ControlType type ) + : + shortcutId(0), + checkable(false), checked(false), autoRepeat(false), autoExclusive(false), + down(false), blockRefresh(false),longPress(false), + autoRepeatDelay(AUTO_REPEAT_DELAY), + autoRepeatInterval(AUTO_REPEAT_INTERVAL), + controlType(type), sizeHint(),mSizeHintPolish(false),mRepolishRequested(false) +{ +} + +HbAbstractButtonPrivate::~HbAbstractButtonPrivate() +{ +} + +QListHbAbstractButtonPrivate::queryButtonList() const +{ + Q_Q( const HbAbstractButton ); + + QListcandidates; + if (q->parentWidget()) { + candidates = qFindChildren(q->parentWidget()); + if (autoExclusive) { + for (int i = candidates.count() - 1; i >= 0; --i) { + HbAbstractButton *candidate = candidates.at(i); + if (!candidate->autoExclusive()) + candidates.removeAt(i); + } + } + } + return candidates; +} + +HbAbstractButton *HbAbstractButtonPrivate::queryCheckedButton() const +{ + QList buttonList = queryButtonList(); + if (!autoExclusive || buttonList.count() == 1) // no group + return 0; + + Q_Q( const HbAbstractButton ); + + for (int i = 0; i < buttonList.count(); ++i) { + HbAbstractButton *b = buttonList.at(i); + if (b->isChecked() && b != q) + return b; + } + return checked ? const_cast(q) : 0; +} + +void HbAbstractButtonPrivate::notifyChecked() +{ + if (autoExclusive) { + if (HbAbstractButton *b = queryCheckedButton()) + b->setChecked(false); + } +} + +void HbAbstractButtonPrivate::moveFocus(int key) +{ + Q_Q( HbAbstractButton ); + + QList buttonList = queryButtonList();; + bool exclusive = autoExclusive; + QGraphicsItem *focusItem = q->scene()->focusItem(); + HbAbstractButton *focusButton = 0; + if (focusItem && focusItem->isWidget()) { + QGraphicsWidget *focusWidget = static_cast(focusItem); + focusButton = qobject_cast(focusWidget); + } + if (!focusButton || !buttonList.contains(focusButton)) + return; + + HbAbstractButton *candidate = 0; + int bestScore = -1; + QRect target = focusItem->sceneBoundingRect().toRect(); + QPoint goal = target.center(); + + for (int i = 0; i < buttonList.count(); ++i) { + HbAbstractButton *button = buttonList.at(i); + if (button != focusItem && button->isEnabled() && button->isVisible() && + (autoExclusive || (button->focusPolicy() & Qt::StrongFocus) == Qt::StrongFocus)) { + QRect buttonRect = button->sceneBoundingRect().toRect(); + 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 + && focusButton->isChecked() + && candidate->isCheckable()) + candidate->click(); + + if (candidate) { + if (key == Qt::Key_Up || key == Qt::Key_Left) + candidate->setFocus(Qt::BacktabFocusReason); + else + candidate->setFocus(Qt::TabFocusReason); + } +} + +void HbAbstractButtonPrivate::fixFocusPolicy() +{ + if (!autoExclusive) + return; + + Q_Q( HbAbstractButton ); + + QList buttonList = queryButtonList(); + for (int i = 0; i < buttonList.count(); ++i) { + HbAbstractButton *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 HbAbstractButtonPrivate::init() +{ + Q_Q( HbAbstractButton ); + + q->setFocusPolicy(Qt::FocusPolicy(qApp->style()->styleHint(QStyle::SH_Button_FocusPolicy))); + + // FIXME: size policy is commented out b/c of a bug in Qt #236689, also in our bugtracker. + //q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum, controlType)); + + //q->setForegroundRole(QPalette::ButtonText); TODO: check + //q->setBackgroundRole(QPalette::Button); TODO: check +} + +void HbAbstractButtonPrivate::refresh() +{ + if (blockRefresh) + return; + + Q_Q( HbAbstractButton ); + + q->updatePrimitives(); +} + +void HbAbstractButtonPrivate::click() +{ + Q_Q( HbAbstractButton ); + + down = false; + blockRefresh = true; + bool changeState = true; + if (checked && queryCheckedButton() == q) { + // the checked button of an exclusive or autoexclusive group cannot be unchecked + if (autoExclusive) + changeState = false; + } + + QPointer guard(q); + if (changeState) { + q->nextCheckState(); + if (!guard) + return; + } + blockRefresh = false; + refresh(); + if (guard) + emitReleased(); + if (guard && !longPress) + emitClicked(); + if(guard && longPress) + longPress = false; +} + +void HbAbstractButtonPrivate::emitClicked() +{ + Q_Q( HbAbstractButton ); + + QPointer guard(q); + emit q->clicked(checked); +} + +void HbAbstractButtonPrivate::emitPressed() +{ + Q_Q( HbAbstractButton ); + + QPointer guard(q); + emit q->pressed(); +} + +void HbAbstractButtonPrivate::emitReleased() +{ + Q_Q( HbAbstractButton ); + + QPointer guard(q); + emit q->released(); +} + + + +/*! + @beta + Constructs an abstract button with a \a parent. +*/ +HbAbstractButton::HbAbstractButton(QGraphicsItem *parent) + : HbWidget( *new HbAbstractButtonPrivate, parent) +{ + Q_D( HbAbstractButton ); + d->init(); +} + +/*! + @beta + \internal + */ +HbAbstractButton::HbAbstractButton( HbAbstractButtonPrivate &dd, QGraphicsItem * parent ) : + HbWidget( dd, parent ) +{ + Q_D( HbAbstractButton ); + d->init(); +} + +/*! + Destroys the button. + */ + HbAbstractButton::~HbAbstractButton() +{ +} + +/* +\property HbAbstractButton::shortcut +\brief the mnemonic associated with the button + +void HbAbstractButton::setShortcut(const QKeySequence &key) +{ + Q_ASSERT(mainWindow()); + if (d->shortcutId != 0) + mainWindow()->releaseShortcut(d->shortcutId); + d->shortcut = key; + d->shortcutId = mainWindow()->grabShortcut(key); +} + +QKeySequence HbAbstractButton::shortcut() const +{ + return d->shortcut; +} +*/ + +/*! + @beta + Returns whether the button is checkable. + + By default, the button is not checkable. + + \sa setCheckable() checked +*/ +bool HbAbstractButton::isCheckable() const +{ + Q_D( const HbAbstractButton ); + + return d->checkable; +} + +/*! + @beta + Sets whether the button is checkable. + + \sa isCheckable() + */ +void HbAbstractButton::setCheckable(bool checkable) +{ + Q_D( HbAbstractButton ); + + if (d->checkable == checkable) + return; + + d->checkable = checkable; + d->checked = false; +} + +/*! + @beta + Returns whether the button is checked. + + Only checkable buttons can be checked. By default, the button is unchecked. + + \sa setChecked() setCheckable() +*/ +bool HbAbstractButton::isChecked() const +{ + Q_D( const HbAbstractButton ); + + return d->checked; +} + +/*! + @beta + Sets whether the button is checked. + + Only checkable buttons can be checked. By default, the button is unchecked. + + \sa isChecked() isCheckable() +*/ +void HbAbstractButton::setChecked(bool checked) +{ + Q_D( HbAbstractButton ); + + 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 + if (d->autoExclusive) + return; + } + + QPointer guard(this); + + d->checked = checked; + if (!d->blockRefresh) + checkStateSet(); + + d->refresh(); + + if (guard && checked) + d->notifyChecked(); + if (guard) + emit toggled(checked); +} + +/*! + @beta + Returns whether the button is pressed down. + + If this property is \c true, the button is pressed down. + The default value is \c false. + + \sa setDown() +*/ +bool HbAbstractButton::isDown() const +{ + Q_D( const HbAbstractButton ); + + return d->down; +} + +/*! + @beta + Sets whether the button is pressed down. + + The signals pressed() and clicked() are not emitted + if you set this property to \c true. + + \sa isDown() + */ +void HbAbstractButton::setDown(bool down) +{ + Q_D( HbAbstractButton ); + + 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(); +} + +/*! + @beta + Returns 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. +*/ +bool HbAbstractButton::autoRepeat() const +{ + Q_D( const HbAbstractButton ); + + return d->autoRepeat; +} + +/*! + @beta + Sets whether autoRepeat is enabled. + */ +void HbAbstractButton::setAutoRepeat(bool autoRepeat) +{ + Q_D( HbAbstractButton ); + + if (d->autoRepeat == autoRepeat) + return; + d->autoRepeat = autoRepeat; + if (d->autoRepeat && d->down) + d->repeatTimer.start(d->autoRepeatDelay, this); + else + d->repeatTimer.stop(); +} + +/*! + @beta + Returns the initial delay of auto-repetition in milliseconds. + + If \l autoRepeat is enabled, then autoRepeatDelay defines the initial + delay in milliseconds before auto-repetition kicks in. + + \sa autoRepeat, autoRepeatInterval +*/ +int HbAbstractButton::autoRepeatDelay() const +{ + Q_D( const HbAbstractButton ); + + return d->autoRepeatDelay; +} + +/*! + @beta + Sets the initial delay of auto-repetition in milliseconds. + */ +void HbAbstractButton::setAutoRepeatDelay(int autoRepeatDelay) +{ + Q_D( HbAbstractButton ); + + d->autoRepeatDelay = autoRepeatDelay; +} + +/*! + @beta + Returns the interval of auto-repetition. + + If \l autoRepeat is enabled, then autoRepeatInterval defines the + length of the auto-repetition interval in millisecons. + + \sa autoRepeat, autoRepeatDelay +*/ +int HbAbstractButton::autoRepeatInterval() const +{ + Q_D( const HbAbstractButton ); + + return d->autoRepeatInterval; +} + +/*! + @beta + Sets the interval of auto-repetition. + */ +void HbAbstractButton::setAutoRepeatInterval(int autoRepeatInterval) +{ + Q_D( HbAbstractButton ); + + d->autoRepeatInterval = autoRepeatInterval; +} + +/*! + @beta + Returns 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 setAutoExclusive() +*/ +bool HbAbstractButton::autoExclusive() const +{ + Q_D( const HbAbstractButton ); + + return d->autoExclusive; +} + +/*! + @beta + Sets whether auto-exclusivity is enabled. + + \sa autoExclusive() + */ +void HbAbstractButton::setAutoExclusive(bool autoExclusive) +{ + Q_D( HbAbstractButton ); + + d->autoExclusive = autoExclusive; +} + + + +/*! + 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 HbAbstractButton::animateClick(int msec) +{ + Q_D( HbAbstractButton ); + + if (!isEnabled()) + return; + if (d->checkable && focusPolicy() & Qt::ClickFocus) + setFocus(); + setDown(true); + updatePrimitives(); + + 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 HbAbstractButton::click() +{ + Q_D( HbAbstractButton ); + + if (!isEnabled()) + return; + QPointer guard(this); + d->down = true; + d->emitPressed(); + if (guard) { + d->down = false; + nextCheckState(); + if (guard) + d->emitReleased(); + if (guard && !d->longPress) + d->emitClicked(); + } +} + +/*! + \fn void HbAbstractButton::toggle() + + Toggles the state of a checkable button. + + \sa checked +*/ +void HbAbstractButton::toggle() +{ + Q_D( HbAbstractButton ); + + 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 HbAbstractButton::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 HbAbstractButton::nextCheckState() +{ + if (isCheckable()) + setChecked(!isChecked()); +} + +/*! + Returns \c true if \a pos is inside the clickable button rectangle; + otherwise returns \c 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 HbAbstractButton::hitButton(const QPointF &pos) const +{ + return rect().contains(pos); +} + +/*! + Initializes \a option with the values from this HbAbstractButton. This method is useful for subclasses when they need a HbStyleOption, but don't want to fill in the pressed state information themselves. + */ +void HbAbstractButton::initStyleOption(HbStyleOption *option) const +{ + HbWidget::initStyleOption(option); + Q_ASSERT(option); + option->state |= (isChecked() | isDown() ? QStyle::State_On : QStyle::State_Off); +} + +/*! + \reimp + */ +bool HbAbstractButton::event(QEvent *event) +{ + // as opposed to other widgets, disabled buttons accept mouse + // events. This avoids surprising click-through scenarios + Q_D( HbAbstractButton ); + if (!isEnabled()) { + switch(event->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; + } + } + if(event->type() == QEvent::MouseMove) { + return true; + } + +#ifndef QT_NO_SHORTCUT + if (event->type() == QEvent::Shortcut) { + QShortcutEvent *se = static_cast(event); + 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 HbWidget::event(event); +} + +/*! + \reimp + */ +void HbAbstractButton::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D( HbAbstractButton ); + + if (event->button() != Qt::LeftButton) { + event->ignore(); + return; + } + if (hitButton(event->pos())) { + setDown(true); + HbWidgetFeedback::triggered(this, Hb::InstantPressed); + updatePrimitives(); + d->emitPressed(); + event->accept(); + } else { + event->ignore(); + } +} + +/*! + \reimp + */ +void HbAbstractButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + //This check is not required for s60 env +#ifndef Q_OS_SYMBIAN + if (event->button() != Qt::LeftButton) { + event->ignore(); + return; + } +#endif + + Q_D( HbAbstractButton ); + + //TODO: this code will be unnecessary when event filter of HbToolTipLabel will be implemented!! + //HbToolTip::hideText(); + + if (!d->down) { + event->ignore(); + return; + } + if (hitButton(event->pos()) && !d->longPress) { + HbWidgetFeedback::triggered(this, Hb::InstantClicked); + } + HbWidgetFeedback::triggered(this, Hb::InstantReleased); + if (hitButton(event->pos())) { + d->repeatTimer.stop(); + d->click(); + event->accept(); + } else { + setDown(false); + event->ignore(); + } + d->longPress = false; +} + +/*! + \reimp + */ +void HbAbstractButton::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (!(event->buttons() & Qt::LeftButton)) { + event->ignore(); + return; + } + + Q_D( HbAbstractButton ); + + bool hit = hitButton(event->pos()); + if (!hit) { + //TODO: this code will be unnecessary when event filter of HbToolTipLabel will be implemented!! + //HbToolTip::hideText(); + } + + if (hit != d->down) { + setDown(!d->down); + updatePrimitives(); + if (d->down) { + // this call show tooltip for button, + // for the case press, move outside and come back to same button. + HbToolTip::showText(toolTip(), this); + d->emitPressed(); + HbWidgetFeedback::triggered(this, Hb::InstantPressed); + } else { + d->emitReleased(); + d->longPress = false; + HbWidgetFeedback::triggered(this, Hb::InstantReleased); + } + event->accept(); + } else if (!hit) { + event->ignore(); + } +} + +/*! + \reimp + */ +void HbAbstractButton::keyPressEvent(QKeyEvent *event) +{ + Q_D( HbAbstractButton ); + + bool next = true; + switch (event->key()) { + + case Qt::Key_Select: + case Qt::Key_Enter: + case Qt::Key_Return: + if (!event->isAutoRepeat()) { + setDown(true); + updatePrimitives(); + 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() && (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right)) { + event->ignore(); + return; + } +#endif + if (d->autoExclusive) { + // ### 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(event->key()); + if (hasFocus()) // nothing happend, propagate + event->ignore(); + } else { + focusNextPrevChild(next); + } + break; + case Qt::Key_Escape: + if (d->down) { + setDown(false); + updatePrimitives(); + d->emitReleased(); + break; + } + // fall through + default: + event->ignore(); + } +} + +/*! + \reimp + */ +void HbAbstractButton::keyReleaseEvent(QKeyEvent *event) +{ + Q_D( HbAbstractButton ); + + if (!event->isAutoRepeat()) + d->repeatTimer.stop(); + + switch (event->key()) { + case Qt::Key_Select: + case Qt::Key_Enter: + case Qt::Key_Return: { + if (!event->isAutoRepeat() /*&& d->down*/) { + if (d->down && !d->longPress) { + HbWidgetFeedback::triggered(this, Hb::InstantClicked); + } + d->click(); + } + break; + } + default: + event->ignore(); + } +} + +/*! + \reimp + */ +void HbAbstractButton::timerEvent(QTimerEvent *event) +{ + Q_D( HbAbstractButton ); + + if (event->timerId() == d->repeatTimer.timerId()) { + d->repeatTimer.start(d->autoRepeatInterval, this); + if (d->down) { + QPointer guard(this); + d->emitReleased(); + if (guard) { + d->emitClicked(); + } + if (guard) { + d->emitPressed(); + HbWidgetFeedback::triggered(this, Hb::InstantKeyRepeated); + } + } + } else if (event->timerId() == d->animateTimer.timerId()) { + d->animateTimer.stop(); + d->click(); + } +} + + +/*! + \reimp + */ +void HbAbstractButton::focusInEvent(QFocusEvent *event) +{ + Q_D( HbAbstractButton ); + +#ifdef QT_KEYPAD_NAVIGATION + if (!QApplication::keypadNavigationEnabled()) +#endif + d->fixFocusPolicy(); + HbWidget::focusInEvent(event); +} + +/*! + \reimp + */ +void HbAbstractButton::changeEvent(QEvent *event) +{ + Q_D( HbAbstractButton ); + + switch (event->type()) { + case QEvent::EnabledChange: + if (!isEnabled()) + setDown(false); + break; + default: + d->sizeHint = QSize(); + break; + } + HbWidget::changeEvent(event); +} + +/*! + \reimp +*/ +void HbAbstractButton::polish(HbStyleParameters& params) +{ + Q_D( HbAbstractButton ); + + if (d->mSizeHintPolish) { + d->mSizeHintPolish = false; + return; + } + d->mRepolishRequested = false; + HbWidget::polish(params); +} + +/*! + \reimp +*/ +QSizeF HbAbstractButton::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const +{ + Q_D(const HbAbstractButton); + if (d->mRepolishRequested && isVisible()) { + d->mRepolishRequested = false; + // force the polish event in order to get the real size + QEvent polishEvent(QEvent::Polish); + QCoreApplication::sendEvent(const_cast(this), &polishEvent); + d->mSizeHintPolish = true; + } + return HbWidget::sizeHint(which, constraint); +} + +/*! + \fn void HbAbstractButton::pressed() + + This signal is emitted when the button is pressed down. + + \sa released(), clicked() +*/ + +/*! + \fn void HbAbstractButton::released() + + This signal is emitted when the button is released. + + \sa pressed(), clicked(), toggled() +*/ + +/*! + \fn void HbAbstractButton::clicked(bool checked) + + This signal is emitted when the button is activated (i.e. pressed down + then released while the stylus 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 HbAbstractButton::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. + + \sa checked, clicked() +*/ + +#include "moc_hbabstractbutton.cpp"