src/hbcore/gui/hbabstractbutton.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbabstractbutton.h"
       
    27 #include "hbabstractbutton_p.h"
       
    28 #include "hbapplication.h"
       
    29 #include "hbstyleoption.h"
       
    30 #include "hbtooltip.h"
       
    31 #include "hbinstance.h"
       
    32 #include <QGraphicsSceneMouseEvent>
       
    33 #include <QGraphicsScene>
       
    34 #include <QPointer>
       
    35 #include <QStyle>
       
    36 
       
    37 #include <hbwidgetfeedback.h>
       
    38 
       
    39 namespace {
       
    40     static const int AUTO_REPEAT_DELAY = 300;
       
    41     static const int AUTO_REPEAT_INTERVAL = 100;
       
    42 }
       
    43 
       
    44 /*!
       
    45     @beta
       
    46     @hbcore
       
    47     \class HbAbstractButton
       
    48 
       
    49     \brief The HbAbstractButton class is the abstract base class of
       
    50     button widgets, providing functionality common to buttons.
       
    51 
       
    52     This class implements an \e abstract button.
       
    53     Subclasses of this class handle user actions, and specify how the button
       
    54     is drawn.
       
    55 
       
    56     HbAbstractButton provides support for both push buttons and checkable
       
    57     (toggle) buttons. Checkable buttons are implemented in the HbRadioButton
       
    58     and HbCheckBox classes. Push buttons are implemented in the
       
    59     HbPushButton and HbToolButton classes; these also provide toggle
       
    60     behavior if required.
       
    61 
       
    62     Any button can display  text and an icon. setText()
       
    63     sets the text; setIcon() sets the icon. If a button is disabled, its background
       
    64     is changed to give the button a "disabled" appearance.
       
    65 
       
    66     All of the buttons provided by Hb (HbPushButton, HbToolButton,
       
    67     HbCheckBox, and HbRadioButton) can display both text and icon.
       
    68     You can also set a tool tip for the button with \qtfunc{QGraphicsItem,setTooltip}.
       
    69 
       
    70     HbAbstractButton provides most of the states used for buttons:
       
    71 
       
    72     \li isDown() indicates whether the button is \e pressed down.
       
    73 
       
    74     \li isChecked() indicates whether the button is \e checked.  Only
       
    75     checkable buttons can be checked and unchecked (see below).
       
    76 
       
    77     \li isEnabled() indicates whether the button can be pressed by the
       
    78     user.
       
    79 
       
    80     \li setAutoRepeat() sets whether the button will auto-repeat if the
       
    81     user holds it down. \l autoRepeatDelay and \l autoRepeatInterval
       
    82     define how auto-repetition is done.
       
    83 
       
    84     \li setCheckable() sets whether the button is a toggle button or not.
       
    85 
       
    86     The difference between isDown() and isChecked() is as follows.
       
    87     When the user clicks a toggle button to check it, the button is first
       
    88     \e pressed then released into the \e checked state. When the user
       
    89     clicks it again (to uncheck it), the button moves first to the
       
    90     \e pressed state, then to the \e unchecked state (isChecked() and
       
    91     isDown() are both false).
       
    92 
       
    93     HbAbstractButton provides four signals:
       
    94 
       
    95     \li pressed() is emitted when the stylus is pressed while
       
    96     the stylus is inside the button.
       
    97 
       
    98     \li released() is emitted when the left stylus is released.
       
    99 
       
   100     \li clicked() is emitted when the button is first pressed and then
       
   101     released, when the shortcut key is typed, or when click() or
       
   102     animateClick() is called.
       
   103 
       
   104     \li toggled() is emitted when the state of a toggle button changes.
       
   105 
       
   106     To subclass HbAbstractButton, you must reimplement at least
       
   107     paint() to draw the button's outline and its text or pixmap. It
       
   108     is generally advisable to reimplement sizeHint() as well, and
       
   109     sometimes hitButton() (to determine whether a button press is within
       
   110     the button). For buttons with more than two states (like tri-state
       
   111     buttons), you will also have to reimplement checkStateSet() and
       
   112     nextCheckState().
       
   113 */
       
   114 
       
   115 /*!
       
   116     \reimp
       
   117     \fn int HbAbstractButton::type() const
       
   118  */
       
   119 
       
   120 HbAbstractButtonPrivate::HbAbstractButtonPrivate( QSizePolicy::ControlType type )
       
   121     :
       
   122     shortcutId(0),
       
   123     checkable(false), checked(false), autoRepeat(false), autoExclusive(false),
       
   124     down(false), blockRefresh(false),longPress(false),
       
   125     autoRepeatDelay(AUTO_REPEAT_DELAY),
       
   126     autoRepeatInterval(AUTO_REPEAT_INTERVAL),
       
   127     controlType(type), sizeHint(),mSizeHintPolish(false),mRepolishRequested(false)
       
   128 {
       
   129 }
       
   130 
       
   131 HbAbstractButtonPrivate::~HbAbstractButtonPrivate()
       
   132 {
       
   133 }
       
   134 
       
   135 QList<HbAbstractButton *>HbAbstractButtonPrivate::queryButtonList() const
       
   136 {
       
   137     Q_Q( const HbAbstractButton );
       
   138     
       
   139     QList<HbAbstractButton*>candidates;
       
   140     if (q->parentWidget()) {
       
   141         candidates =  qFindChildren<HbAbstractButton *>(q->parentWidget());
       
   142         if (autoExclusive) {
       
   143             for (int i = candidates.count() - 1; i >= 0; --i) {
       
   144                 HbAbstractButton *candidate = candidates.at(i);
       
   145                 if (!candidate->autoExclusive())
       
   146                     candidates.removeAt(i);
       
   147             }
       
   148         }
       
   149     }
       
   150     return candidates;
       
   151 }
       
   152 
       
   153 HbAbstractButton *HbAbstractButtonPrivate::queryCheckedButton() const
       
   154 {
       
   155     QList<HbAbstractButton *> buttonList = queryButtonList();
       
   156     if (!autoExclusive || buttonList.count() == 1) // no group
       
   157         return 0;
       
   158 
       
   159     Q_Q( const HbAbstractButton );
       
   160 
       
   161     for (int i = 0; i < buttonList.count(); ++i) {
       
   162         HbAbstractButton *b = buttonList.at(i);
       
   163         if (b->isChecked() && b != q)
       
   164             return b;
       
   165     }
       
   166     return checked  ? const_cast<HbAbstractButton *>(q) : 0;
       
   167 }
       
   168 
       
   169 void HbAbstractButtonPrivate::notifyChecked()
       
   170 {
       
   171     if (autoExclusive) {
       
   172         if (HbAbstractButton *b = queryCheckedButton())
       
   173             b->setChecked(false);
       
   174     }
       
   175 }
       
   176 
       
   177 void HbAbstractButtonPrivate::moveFocus(int key)
       
   178 {
       
   179     Q_Q( HbAbstractButton );
       
   180 
       
   181     QList<HbAbstractButton *> buttonList = queryButtonList();;
       
   182     bool exclusive = autoExclusive;
       
   183     QGraphicsItem *focusItem = q->scene()->focusItem();
       
   184     HbAbstractButton *focusButton = 0;
       
   185     if (focusItem && focusItem->isWidget()) {
       
   186         QGraphicsWidget *focusWidget = static_cast<QGraphicsWidget*>(focusItem);
       
   187         focusButton = qobject_cast<HbAbstractButton *>(focusWidget);
       
   188     }
       
   189     if (!focusButton || !buttonList.contains(focusButton))
       
   190         return;
       
   191 
       
   192     HbAbstractButton *candidate = 0;
       
   193     int bestScore = -1;
       
   194     QRect target = focusItem->sceneBoundingRect().toRect();
       
   195     QPoint goal = target.center();
       
   196 
       
   197     for (int i = 0; i < buttonList.count(); ++i) {
       
   198         HbAbstractButton *button = buttonList.at(i);
       
   199         if (button != focusItem && button->isEnabled() && button->isVisible() &&
       
   200             (autoExclusive || (button->focusPolicy() & Qt::StrongFocus) == Qt::StrongFocus)) {
       
   201             QRect buttonRect = button->sceneBoundingRect().toRect();
       
   202             QPoint p = buttonRect.center();
       
   203 
       
   204             //Priority to widgets that overlap on the same coordinate.
       
   205             //In that case, the distance in the direction will be used as significant score,
       
   206             //take also in account orthogonal distance in case two widget are in the same distance.
       
   207             int score;
       
   208             if ((buttonRect.x() < target.right() && target.x() < buttonRect.right())
       
   209                   && (key == Qt::Key_Up || key == Qt::Key_Down)) {
       
   210                 //one item's is at the vertical of the other
       
   211                 score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x());
       
   212             } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom())
       
   213                         && (key == Qt::Key_Left || key == Qt::Key_Right) ) {
       
   214                 //one item's is at the horizontal of the other
       
   215                 score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y());
       
   216             } else {
       
   217                 score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x());
       
   218             }
       
   219 
       
   220             if (score > bestScore && candidate)
       
   221                 continue;
       
   222 
       
   223             switch(key) {
       
   224             case Qt::Key_Up:
       
   225                 if (p.y() < goal.y()) {
       
   226                     candidate = button;
       
   227                     bestScore = score;
       
   228                 }
       
   229                 break;
       
   230             case Qt::Key_Down:
       
   231                 if (p.y() > goal.y()) {
       
   232                     candidate = button;
       
   233                     bestScore = score;
       
   234                 }
       
   235                 break;
       
   236             case Qt::Key_Left:
       
   237                 if (p.x() < goal.x()) {
       
   238                     candidate = button;
       
   239                     bestScore = score;
       
   240                 }
       
   241                 break;
       
   242             case Qt::Key_Right:
       
   243                 if (p.x() > goal.x()) {
       
   244                     candidate = button;
       
   245                     bestScore = score;
       
   246                 }
       
   247                 break;
       
   248             }
       
   249         }
       
   250     }
       
   251 
       
   252     if (exclusive
       
   253 #ifdef QT_KEYPAD_NAVIGATION
       
   254         && !QApplication::keypadNavigationEnabled()
       
   255 #endif
       
   256         && candidate
       
   257         && focusButton->isChecked()
       
   258         && candidate->isCheckable())
       
   259         candidate->click();
       
   260 
       
   261     if (candidate) {
       
   262         if (key == Qt::Key_Up || key == Qt::Key_Left)
       
   263             candidate->setFocus(Qt::BacktabFocusReason);
       
   264         else
       
   265             candidate->setFocus(Qt::TabFocusReason);
       
   266     }
       
   267 }
       
   268 
       
   269 void HbAbstractButtonPrivate::fixFocusPolicy()
       
   270 {
       
   271     if (!autoExclusive)
       
   272         return;
       
   273 
       
   274     Q_Q( HbAbstractButton );
       
   275 
       
   276     QList<HbAbstractButton *> buttonList = queryButtonList();
       
   277     for (int i = 0; i < buttonList.count(); ++i) {
       
   278         HbAbstractButton *b = buttonList.at(i);
       
   279         if (!b->isCheckable())
       
   280             continue;
       
   281         b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable())
       
   282                                          ? (b->focusPolicy() | Qt::TabFocus)
       
   283                                          :  (b->focusPolicy() & ~Qt::TabFocus)));
       
   284     }
       
   285 }
       
   286 
       
   287 void HbAbstractButtonPrivate::init()
       
   288 {
       
   289     Q_Q( HbAbstractButton );
       
   290 
       
   291 	q->setFocusPolicy(Qt::FocusPolicy(qApp->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
       
   292 
       
   293     // FIXME: size policy is commented out b/c of a bug in Qt #236689, also in our bugtracker.
       
   294     //q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum, controlType));
       
   295 
       
   296     //q->setForegroundRole(QPalette::ButtonText); TODO: check
       
   297     //q->setBackgroundRole(QPalette::Button); TODO: check
       
   298 }
       
   299 
       
   300 void HbAbstractButtonPrivate::refresh()
       
   301 {
       
   302     if (blockRefresh)
       
   303         return;
       
   304 
       
   305     Q_Q( HbAbstractButton );
       
   306 
       
   307     q->updatePrimitives();
       
   308 }
       
   309 
       
   310 void HbAbstractButtonPrivate::click()
       
   311 {
       
   312     Q_Q( HbAbstractButton );
       
   313 
       
   314     down = false;
       
   315     blockRefresh = true;
       
   316     bool changeState = true;
       
   317     if (checked && queryCheckedButton() == q) {
       
   318         // the checked button of an exclusive or autoexclusive group cannot be unchecked
       
   319         if (autoExclusive)
       
   320             changeState = false;
       
   321     }
       
   322 
       
   323     QPointer<HbAbstractButton> guard(q);
       
   324     if (changeState) {
       
   325         q->nextCheckState();
       
   326         if (!guard)
       
   327             return;
       
   328     }
       
   329     blockRefresh = false;
       
   330     refresh();
       
   331     if (guard)
       
   332         emitReleased();
       
   333     if (guard && !longPress)
       
   334         emitClicked();
       
   335     if(guard && longPress)
       
   336         longPress = false;
       
   337 }
       
   338 
       
   339 void HbAbstractButtonPrivate::emitClicked()
       
   340 {
       
   341     Q_Q( HbAbstractButton );
       
   342 
       
   343     QPointer<HbAbstractButton> guard(q);
       
   344     emit q->clicked(checked);
       
   345 }
       
   346 
       
   347 void HbAbstractButtonPrivate::emitPressed()
       
   348 {
       
   349     Q_Q( HbAbstractButton );
       
   350 
       
   351     QPointer<HbAbstractButton> guard(q);
       
   352     emit q->pressed();
       
   353 }
       
   354 
       
   355 void HbAbstractButtonPrivate::emitReleased()
       
   356 {
       
   357     Q_Q( HbAbstractButton );
       
   358 
       
   359     QPointer<HbAbstractButton> guard(q);
       
   360     emit q->released();
       
   361 }
       
   362 
       
   363 
       
   364 
       
   365 /*!
       
   366     @beta
       
   367     Constructs an abstract button with a \a parent.
       
   368 */
       
   369 HbAbstractButton::HbAbstractButton(QGraphicsItem *parent)
       
   370     : HbWidget( *new HbAbstractButtonPrivate, parent)
       
   371 {
       
   372     Q_D( HbAbstractButton );
       
   373     d->init();
       
   374 }
       
   375 
       
   376 /*!
       
   377     @beta
       
   378     \internal
       
   379  */
       
   380 HbAbstractButton::HbAbstractButton( HbAbstractButtonPrivate &dd, QGraphicsItem * parent ) :
       
   381         HbWidget( dd, parent )
       
   382 {
       
   383     Q_D( HbAbstractButton );
       
   384     d->init();
       
   385 }
       
   386 
       
   387 /*!
       
   388     Destroys the button.
       
   389  */
       
   390  HbAbstractButton::~HbAbstractButton()
       
   391 {
       
   392 }
       
   393 
       
   394 /*
       
   395 \property HbAbstractButton::shortcut
       
   396 \brief the mnemonic associated with the button
       
   397 
       
   398 void HbAbstractButton::setShortcut(const QKeySequence &key)
       
   399 {
       
   400     Q_ASSERT(mainWindow());
       
   401     if (d->shortcutId != 0)
       
   402         mainWindow()->releaseShortcut(d->shortcutId);
       
   403     d->shortcut = key;
       
   404     d->shortcutId = mainWindow()->grabShortcut(key);
       
   405 }
       
   406 
       
   407 QKeySequence HbAbstractButton::shortcut() const
       
   408 {
       
   409     return d->shortcut;
       
   410 }
       
   411 */
       
   412 
       
   413 /*!
       
   414     @beta
       
   415     Returns whether the button is checkable.
       
   416 
       
   417     By default, the button is not checkable.
       
   418 
       
   419     \sa setCheckable() checked
       
   420 */
       
   421 bool HbAbstractButton::isCheckable() const
       
   422 {
       
   423     Q_D( const HbAbstractButton );
       
   424 
       
   425     return d->checkable;
       
   426 }
       
   427 
       
   428 /*!
       
   429     @beta
       
   430     Sets whether the button is checkable.
       
   431 
       
   432     \sa isCheckable()
       
   433  */
       
   434 void HbAbstractButton::setCheckable(bool checkable)
       
   435 {
       
   436     Q_D( HbAbstractButton );
       
   437 
       
   438     if (d->checkable == checkable)
       
   439         return;
       
   440 
       
   441     d->checkable = checkable;
       
   442     d->checked = false;
       
   443 }
       
   444 
       
   445 /*!
       
   446     @beta
       
   447     Returns whether the button is checked.
       
   448 
       
   449     Only checkable buttons can be checked. By default, the button is unchecked.
       
   450 
       
   451     \sa setChecked() setCheckable()
       
   452 */
       
   453 bool HbAbstractButton::isChecked() const
       
   454 {
       
   455     Q_D( const HbAbstractButton );
       
   456 
       
   457     return d->checked;
       
   458 }
       
   459 
       
   460 /*!
       
   461     @beta
       
   462     Sets whether the button is checked.
       
   463 
       
   464     Only checkable buttons can be checked. By default, the button is unchecked.
       
   465 
       
   466     \sa isChecked() isCheckable()
       
   467 */
       
   468 void HbAbstractButton::setChecked(bool checked)
       
   469 {
       
   470     Q_D( HbAbstractButton );
       
   471 
       
   472     if (!d->checkable || d->checked == checked) {
       
   473         if (!d->blockRefresh)
       
   474             checkStateSet();
       
   475         return;
       
   476     }
       
   477     if (!checked && d->queryCheckedButton() == this) {
       
   478         // the checked button of an exclusive or autoexclusive group cannot be  unchecked
       
   479         if (d->autoExclusive)
       
   480             return;
       
   481     }
       
   482 
       
   483     QPointer<HbAbstractButton> guard(this);
       
   484 
       
   485     d->checked = checked;
       
   486     if (!d->blockRefresh)
       
   487         checkStateSet();
       
   488 
       
   489     d->refresh();
       
   490 
       
   491     if (guard && checked)
       
   492         d->notifyChecked();
       
   493     if (guard)
       
   494         emit toggled(checked);
       
   495 }
       
   496 
       
   497 /*!
       
   498     @beta
       
   499     Returns whether the button is pressed down.
       
   500 
       
   501     If this property is \c true, the button is pressed down.
       
   502     The default value is \c false.
       
   503 
       
   504     \sa setDown()
       
   505 */
       
   506 bool HbAbstractButton::isDown() const
       
   507 {
       
   508     Q_D( const HbAbstractButton );
       
   509 
       
   510     return d->down;
       
   511 }
       
   512 
       
   513 /*!
       
   514     @beta
       
   515     Sets whether the button is pressed down.
       
   516 
       
   517     The signals pressed() and clicked() are not emitted
       
   518     if you set this property to \c true.
       
   519 
       
   520     \sa isDown()
       
   521  */
       
   522 void HbAbstractButton::setDown(bool down)
       
   523 {
       
   524     Q_D( HbAbstractButton );
       
   525 
       
   526     if (d->down == down)
       
   527         return;
       
   528     d->down = down;
       
   529     d->refresh();
       
   530     if (d->autoRepeat && d->down)
       
   531         d->repeatTimer.start(d->autoRepeatDelay, this);
       
   532     else
       
   533         d->repeatTimer.stop();
       
   534 }
       
   535 
       
   536 /*!
       
   537     @beta
       
   538     Returns whether autoRepeat is enabled.
       
   539 
       
   540     If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at
       
   541     regular intervals when the button is down. autoRepeat is off by default.
       
   542     The initial delay and the repetition interval are defined in milliseconds by \l
       
   543     autoRepeatDelay and \l autoRepeatInterval.
       
   544 
       
   545     Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the
       
   546     system and not by this class. The pressed(), released(), and clicked() signals will be emitted
       
   547     like in the normal case.
       
   548 */
       
   549 bool HbAbstractButton::autoRepeat() const
       
   550 {
       
   551     Q_D( const HbAbstractButton );
       
   552 
       
   553     return d->autoRepeat;
       
   554 }
       
   555 
       
   556 /*!
       
   557     @beta
       
   558     Sets whether autoRepeat is enabled.
       
   559  */
       
   560 void HbAbstractButton::setAutoRepeat(bool autoRepeat)
       
   561 {
       
   562     Q_D( HbAbstractButton );
       
   563 
       
   564     if (d->autoRepeat == autoRepeat)
       
   565         return;
       
   566     d->autoRepeat = autoRepeat;
       
   567     if (d->autoRepeat && d->down)
       
   568         d->repeatTimer.start(d->autoRepeatDelay, this);
       
   569     else
       
   570         d->repeatTimer.stop();
       
   571 }
       
   572 
       
   573 /*!
       
   574     @beta
       
   575     Returns the initial delay of auto-repetition in milliseconds.
       
   576 
       
   577     If \l autoRepeat is enabled, then autoRepeatDelay defines the initial
       
   578     delay in milliseconds before auto-repetition kicks in.
       
   579 
       
   580     \sa autoRepeat, autoRepeatInterval
       
   581 */
       
   582 int HbAbstractButton::autoRepeatDelay() const
       
   583 {
       
   584     Q_D( const HbAbstractButton );
       
   585 
       
   586     return d->autoRepeatDelay;
       
   587 }
       
   588 
       
   589 /*!
       
   590     @beta
       
   591     Sets the initial delay of auto-repetition in milliseconds.
       
   592  */
       
   593 void HbAbstractButton::setAutoRepeatDelay(int autoRepeatDelay)
       
   594 {
       
   595     Q_D( HbAbstractButton );
       
   596 
       
   597     d->autoRepeatDelay = autoRepeatDelay;
       
   598 }
       
   599 
       
   600 /*!
       
   601     @beta
       
   602     Returns the interval of auto-repetition.
       
   603 
       
   604     If \l autoRepeat is enabled, then autoRepeatInterval defines the
       
   605     length of the auto-repetition interval in millisecons.
       
   606 
       
   607     \sa autoRepeat, autoRepeatDelay
       
   608 */
       
   609 int HbAbstractButton::autoRepeatInterval() const
       
   610 {
       
   611     Q_D( const HbAbstractButton );
       
   612 
       
   613     return d->autoRepeatInterval;
       
   614 }
       
   615 
       
   616 /*!
       
   617     @beta
       
   618     Sets the interval of auto-repetition.
       
   619  */
       
   620 void HbAbstractButton::setAutoRepeatInterval(int autoRepeatInterval)
       
   621 {
       
   622     Q_D( HbAbstractButton );
       
   623 
       
   624     d->autoRepeatInterval = autoRepeatInterval;
       
   625 }
       
   626 
       
   627 /*!
       
   628     @beta
       
   629     Returns whether auto-exclusivity is enabled.
       
   630 
       
   631     If auto-exclusivity is enabled, checkable buttons that belong to the
       
   632     same parent widget behave as if they were part of the same
       
   633     exclusive button group. In an exclusive button group, only one button
       
   634     can be checked at any time; checking another button automatically
       
   635     unchecks the previously checked one.
       
   636 
       
   637     The property has no effect on buttons that belong to a button
       
   638     group.
       
   639 
       
   640     autoExclusive is off by default, except for radio buttons.
       
   641 
       
   642     \sa setAutoExclusive()
       
   643 */
       
   644 bool HbAbstractButton::autoExclusive() const
       
   645 {
       
   646     Q_D( const HbAbstractButton );
       
   647 
       
   648     return d->autoExclusive;
       
   649 }
       
   650 
       
   651 /*!
       
   652     @beta
       
   653     Sets whether auto-exclusivity is enabled.
       
   654 
       
   655     \sa autoExclusive()
       
   656  */
       
   657 void HbAbstractButton::setAutoExclusive(bool autoExclusive)
       
   658 {
       
   659     Q_D( HbAbstractButton );
       
   660 
       
   661     d->autoExclusive = autoExclusive;
       
   662 }
       
   663 
       
   664 
       
   665 
       
   666 /*!
       
   667     Performs an animated click: the button is pressed immediately, and
       
   668     released \a msec milliseconds later (the default is 100 ms).
       
   669 
       
   670     Calling this function again before the button was released will reset
       
   671     the release timer.
       
   672 
       
   673     All signals associated with a click are emitted as appropriate.
       
   674 
       
   675     This function does nothing if the button is \link setEnabled()
       
   676     disabled. \endlink
       
   677 
       
   678     \sa click()
       
   679 */
       
   680 void HbAbstractButton::animateClick(int msec)
       
   681 {
       
   682     Q_D( HbAbstractButton );
       
   683 
       
   684     if (!isEnabled())
       
   685         return;
       
   686     if (d->checkable && focusPolicy() & Qt::ClickFocus)
       
   687         setFocus();
       
   688     setDown(true);
       
   689     updatePrimitives();
       
   690 
       
   691     if (!d->animateTimer.isActive())
       
   692         d->emitPressed();
       
   693     d->animateTimer.start(msec, this);
       
   694 }
       
   695 
       
   696 /*!
       
   697     Performs a click.
       
   698 
       
   699     All the usual signals associated with a click are emitted as
       
   700     appropriate. If the button is checkable, the state of the button is
       
   701     toggled.
       
   702 
       
   703     This function does nothing if the button is \link setEnabled()
       
   704     disabled. \endlink
       
   705 
       
   706     \sa animateClick()
       
   707  */
       
   708 void HbAbstractButton::click()
       
   709 {
       
   710     Q_D( HbAbstractButton );
       
   711 
       
   712     if (!isEnabled())
       
   713         return;
       
   714     QPointer<HbAbstractButton> guard(this);
       
   715     d->down = true;
       
   716     d->emitPressed();
       
   717     if (guard) {
       
   718         d->down = false;
       
   719         nextCheckState();
       
   720         if (guard)
       
   721             d->emitReleased();
       
   722         if (guard && !d->longPress)
       
   723             d->emitClicked();
       
   724     }
       
   725 }
       
   726 
       
   727 /*!
       
   728     \fn void HbAbstractButton::toggle()
       
   729 
       
   730     Toggles the state of a checkable button.
       
   731 
       
   732      \sa checked
       
   733 */
       
   734 void HbAbstractButton::toggle()
       
   735 {
       
   736     Q_D( HbAbstractButton );
       
   737 
       
   738     setChecked(!d->checked);
       
   739 }
       
   740 
       
   741 /*!
       
   742     This virtual handler is called when setChecked() was called,
       
   743     unless it was called from within nextCheckState(). It allows
       
   744     subclasses to reset their intermediate button states.
       
   745 
       
   746     \sa nextCheckState()
       
   747  */
       
   748 void HbAbstractButton::checkStateSet()
       
   749 {
       
   750 }
       
   751 
       
   752 /*!
       
   753     This virtual handler is called when a button is clicked. The
       
   754     default implementation calls setChecked(!isChecked()) if the button
       
   755     isCheckable().  It allows subclasses to implement intermediate button
       
   756     states.
       
   757 
       
   758     \sa checkStateSet()
       
   759 */
       
   760 void HbAbstractButton::nextCheckState()
       
   761 {
       
   762     if (isCheckable())
       
   763         setChecked(!isChecked());
       
   764 }
       
   765 
       
   766 /*!
       
   767     Returns \c true if \a pos is inside the clickable button rectangle;
       
   768     otherwise returns \c false.
       
   769 
       
   770     By default, the clickable area is the entire widget. Subclasses
       
   771     may reimplement this function to provide support for clickable
       
   772     areas of different shapes and sizes.
       
   773 */
       
   774 bool HbAbstractButton::hitButton(const QPointF &pos) const
       
   775 {
       
   776     return rect().contains(pos);
       
   777 }
       
   778 
       
   779 /*!
       
   780     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.
       
   781  */
       
   782 void HbAbstractButton::initStyleOption(HbStyleOption *option) const
       
   783 {
       
   784     HbWidget::initStyleOption(option);
       
   785     Q_ASSERT(option);
       
   786     option->state |= (isChecked() | isDown() ? QStyle::State_On : QStyle::State_Off);
       
   787 }
       
   788 
       
   789 /*!
       
   790     \reimp
       
   791  */
       
   792 bool HbAbstractButton::event(QEvent *event)
       
   793 {
       
   794     // as opposed to other widgets, disabled buttons accept mouse
       
   795     // events. This avoids surprising click-through scenarios	
       
   796     Q_D( HbAbstractButton );
       
   797     if (!isEnabled()) {
       
   798         switch(event->type()) {
       
   799         case QEvent::TabletPress:
       
   800         case QEvent::TabletRelease:
       
   801         case QEvent::TabletMove:
       
   802         case QEvent::MouseButtonPress:
       
   803         case QEvent::MouseButtonRelease:
       
   804         case QEvent::MouseButtonDblClick:
       
   805         case QEvent::MouseMove:
       
   806         case QEvent::HoverMove:
       
   807         case QEvent::HoverEnter:
       
   808         case QEvent::HoverLeave:
       
   809         case QEvent::ContextMenu:
       
   810 #ifndef QT_NO_WHEELEVENT
       
   811         case QEvent::Wheel:
       
   812 #endif
       
   813             return true;
       
   814         default:
       
   815             break;
       
   816         }
       
   817     }
       
   818     if(event->type() ==  QEvent::MouseMove) {
       
   819         return true;
       
   820     }
       
   821 
       
   822 #ifndef QT_NO_SHORTCUT
       
   823     if (event->type() == QEvent::Shortcut) {
       
   824         QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
       
   825         if (d->shortcutId != se->shortcutId())
       
   826             return false;
       
   827         if (!se->isAmbiguous()) {
       
   828             if (!d->animateTimer.isActive())
       
   829                 animateClick();
       
   830         } else {
       
   831             if (focusPolicy() != Qt::NoFocus)
       
   832                 setFocus(Qt::ShortcutFocusReason);
       
   833             window()->setAttribute(Qt::WA_KeyboardFocusChange);
       
   834         }
       
   835         return true;
       
   836     }
       
   837 #endif
       
   838     return HbWidget::event(event);
       
   839 }
       
   840 
       
   841 /*!
       
   842     \reimp
       
   843  */
       
   844 void HbAbstractButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
   845 {
       
   846     Q_D( HbAbstractButton );
       
   847 
       
   848     if (event->button() != Qt::LeftButton) {
       
   849         event->ignore();
       
   850         return;
       
   851     }
       
   852     if (hitButton(event->pos())) {
       
   853         setDown(true);
       
   854         HbWidgetFeedback::triggered(this, Hb::InstantPressed);
       
   855         updatePrimitives();
       
   856         d->emitPressed();
       
   857         event->accept();
       
   858     } else {
       
   859         event->ignore();
       
   860     }
       
   861 }
       
   862 
       
   863 /*!
       
   864     \reimp
       
   865  */
       
   866 void HbAbstractButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
       
   867 {
       
   868     //This check is not required for s60 env
       
   869 #ifndef Q_OS_SYMBIAN    
       
   870     if (event->button() != Qt::LeftButton) {
       
   871         event->ignore();
       
   872         return;
       
   873     }
       
   874 #endif
       
   875 
       
   876     Q_D( HbAbstractButton );
       
   877 
       
   878     //TODO: this code will be unnecessary when event filter of HbToolTipLabel will be implemented!!
       
   879     //HbToolTip::hideText();
       
   880 
       
   881     if (!d->down) {
       
   882         event->ignore();
       
   883         return;
       
   884     }
       
   885     if (hitButton(event->pos()) && !d->longPress) {
       
   886         HbWidgetFeedback::triggered(this, Hb::InstantClicked);
       
   887     }
       
   888     HbWidgetFeedback::triggered(this, Hb::InstantReleased);
       
   889     if (hitButton(event->pos())) {
       
   890         d->repeatTimer.stop();
       
   891         d->click();
       
   892         event->accept();
       
   893     } else {
       
   894         setDown(false);
       
   895         event->ignore();
       
   896     }
       
   897     d->longPress = false;
       
   898 }
       
   899 
       
   900 /*!
       
   901     \reimp
       
   902  */
       
   903 void HbAbstractButton::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
       
   904 {
       
   905     if (!(event->buttons() & Qt::LeftButton)) {
       
   906         event->ignore();
       
   907         return;
       
   908     }
       
   909 
       
   910     Q_D( HbAbstractButton );
       
   911 
       
   912     bool hit = hitButton(event->pos());
       
   913     if (!hit) {
       
   914         //TODO: this code will be unnecessary when event filter of HbToolTipLabel will be implemented!!
       
   915         //HbToolTip::hideText();
       
   916     }
       
   917 
       
   918     if (hit != d->down) {
       
   919         setDown(!d->down);
       
   920         updatePrimitives();
       
   921         if (d->down) {
       
   922             // this call show tooltip for button,
       
   923             // for the case press, move outside and come back to same button.
       
   924             HbToolTip::showText(toolTip(), this);
       
   925             d->emitPressed();
       
   926             HbWidgetFeedback::triggered(this, Hb::InstantPressed);
       
   927         } else {
       
   928             d->emitReleased();
       
   929             d->longPress = false;
       
   930             HbWidgetFeedback::triggered(this, Hb::InstantReleased);
       
   931         }
       
   932         event->accept();
       
   933     } else if (!hit) {
       
   934         event->ignore();
       
   935     }
       
   936 }
       
   937 
       
   938 /*!
       
   939     \reimp
       
   940  */
       
   941 void HbAbstractButton::keyPressEvent(QKeyEvent *event)
       
   942 {
       
   943     Q_D( HbAbstractButton );
       
   944 
       
   945     bool next = true;
       
   946     switch (event->key()) {
       
   947  
       
   948     case Qt::Key_Select:
       
   949     case Qt::Key_Enter:
       
   950     case Qt::Key_Return:
       
   951         if (!event->isAutoRepeat()) {
       
   952             setDown(true);
       
   953             updatePrimitives();
       
   954             d->emitPressed();
       
   955         }
       
   956         break;
       
   957     case Qt::Key_Up:
       
   958     case Qt::Key_Left:
       
   959         next = false;
       
   960         // fall through
       
   961     case Qt::Key_Right:
       
   962     case Qt::Key_Down:
       
   963 #ifdef QT_KEYPAD_NAVIGATION
       
   964         if (QApplication::keypadNavigationEnabled() && (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right)) {
       
   965             event->ignore();
       
   966             return;
       
   967         }
       
   968 #endif
       
   969         if (d->autoExclusive) {
       
   970             // ### Using qobject_cast to check if the parent is a viewport of
       
   971             // QAbstractItemView is a crude hack, and should be revisited and
       
   972             // cleaned up when fixing task 194373. It's here to ensure that we
       
   973             // keep compatibility outside QAbstractItemView.
       
   974             d->moveFocus(event->key());
       
   975             if (hasFocus()) // nothing happend, propagate
       
   976                 event->ignore();
       
   977         } else {
       
   978             focusNextPrevChild(next);
       
   979         }
       
   980         break;
       
   981     case Qt::Key_Escape:
       
   982         if (d->down) {
       
   983             setDown(false);
       
   984             updatePrimitives();
       
   985             d->emitReleased();
       
   986             break;
       
   987         }
       
   988         // fall through
       
   989     default:
       
   990         event->ignore();
       
   991     }
       
   992 }
       
   993 
       
   994 /*!
       
   995     \reimp
       
   996  */
       
   997 void HbAbstractButton::keyReleaseEvent(QKeyEvent *event)
       
   998 {
       
   999     Q_D( HbAbstractButton );
       
  1000 
       
  1001     if (!event->isAutoRepeat())
       
  1002         d->repeatTimer.stop();
       
  1003 
       
  1004     switch (event->key()) {
       
  1005         case Qt::Key_Select:
       
  1006         case Qt::Key_Enter:
       
  1007         case Qt::Key_Return: {
       
  1008             if (!event->isAutoRepeat() /*&& d->down*/) {
       
  1009                 if (d->down && !d->longPress) {
       
  1010                     HbWidgetFeedback::triggered(this, Hb::InstantClicked);
       
  1011                 }
       
  1012                 d->click();
       
  1013             }
       
  1014 	    break;
       
  1015         }
       
  1016         default:
       
  1017             event->ignore();
       
  1018     }
       
  1019 }
       
  1020 
       
  1021 /*!
       
  1022     \reimp
       
  1023  */
       
  1024 void HbAbstractButton::timerEvent(QTimerEvent *event)
       
  1025 {
       
  1026     Q_D( HbAbstractButton );
       
  1027 
       
  1028     if (event->timerId() == d->repeatTimer.timerId()) {
       
  1029         d->repeatTimer.start(d->autoRepeatInterval, this);
       
  1030         if (d->down) {
       
  1031             QPointer<HbAbstractButton> guard(this);
       
  1032             d->emitReleased();
       
  1033             if (guard) {
       
  1034                 d->emitClicked();
       
  1035             }
       
  1036             if (guard) {
       
  1037                 d->emitPressed();
       
  1038                 HbWidgetFeedback::triggered(this, Hb::InstantKeyRepeated);
       
  1039             }
       
  1040         }
       
  1041     } else if (event->timerId() == d->animateTimer.timerId()) {
       
  1042         d->animateTimer.stop();
       
  1043         d->click();
       
  1044     }
       
  1045 }
       
  1046 
       
  1047 
       
  1048 /*!
       
  1049     \reimp
       
  1050  */
       
  1051 void HbAbstractButton::focusInEvent(QFocusEvent *event)
       
  1052 {
       
  1053     Q_D( HbAbstractButton );
       
  1054 
       
  1055 #ifdef QT_KEYPAD_NAVIGATION
       
  1056     if (!QApplication::keypadNavigationEnabled())
       
  1057 #endif
       
  1058     d->fixFocusPolicy();
       
  1059     HbWidget::focusInEvent(event);
       
  1060 }
       
  1061 
       
  1062 /*!
       
  1063     \reimp
       
  1064  */
       
  1065 void HbAbstractButton::changeEvent(QEvent *event)
       
  1066 {
       
  1067     Q_D( HbAbstractButton );
       
  1068 
       
  1069     switch (event->type()) {
       
  1070     case QEvent::EnabledChange:
       
  1071         if (!isEnabled())
       
  1072             setDown(false);
       
  1073         break;
       
  1074     default:
       
  1075         d->sizeHint = QSize();
       
  1076         break;
       
  1077     }
       
  1078     HbWidget::changeEvent(event);
       
  1079 }
       
  1080 
       
  1081 /*!
       
  1082     \reimp
       
  1083 */
       
  1084 void HbAbstractButton::polish(HbStyleParameters& params)
       
  1085 {
       
  1086         Q_D( HbAbstractButton );
       
  1087 
       
  1088     if (d->mSizeHintPolish) {
       
  1089         d->mSizeHintPolish = false;
       
  1090         return;
       
  1091     }
       
  1092     d->mRepolishRequested = false;
       
  1093     HbWidget::polish(params);
       
  1094 }
       
  1095 
       
  1096 /*!
       
  1097     \reimp
       
  1098 */
       
  1099 QSizeF HbAbstractButton::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
  1100 {
       
  1101     Q_D(const HbAbstractButton);
       
  1102     if (d->mRepolishRequested && isVisible()) {
       
  1103         d->mRepolishRequested = false;
       
  1104         // force the polish event in order to get the real size
       
  1105         QEvent polishEvent(QEvent::Polish);
       
  1106         QCoreApplication::sendEvent(const_cast<HbAbstractButton *>(this), &polishEvent);
       
  1107         d->mSizeHintPolish = true;
       
  1108     }
       
  1109     return HbWidget::sizeHint(which, constraint);
       
  1110 }
       
  1111 
       
  1112 /*!
       
  1113     \fn void HbAbstractButton::pressed()
       
  1114 
       
  1115     This signal is emitted when the button is pressed down.
       
  1116 
       
  1117     \sa released(), clicked()
       
  1118 */
       
  1119 
       
  1120 /*!
       
  1121     \fn void HbAbstractButton::released()
       
  1122 
       
  1123     This signal is emitted when the button is released.
       
  1124 
       
  1125     \sa pressed(), clicked(), toggled()
       
  1126 */
       
  1127 
       
  1128 /*!
       
  1129     \fn void HbAbstractButton::clicked(bool checked)
       
  1130 
       
  1131     This signal is emitted when the button is activated (i.e. pressed down
       
  1132     then released while the stylus is inside the button), when the
       
  1133     shortcut key is typed, or when click() or animateClick() is called.
       
  1134     Notably, this signal is \e not emitted if you call setDown(),
       
  1135     setChecked() or toggle().
       
  1136 
       
  1137     If the button is checkable, \a checked is true if the button is
       
  1138     checked, or false if the button is unchecked.
       
  1139 
       
  1140     \sa pressed(), released(), toggled()
       
  1141 */
       
  1142 
       
  1143 /*!
       
  1144     \fn void HbAbstractButton::toggled(bool checked)
       
  1145 
       
  1146     This signal is emitted whenever a checkable button changes its state.
       
  1147     \a checked is true if the button is checked, or false if the button is
       
  1148     unchecked.
       
  1149 
       
  1150     This may be the result of a user action, click() slot activation,
       
  1151     or because setChecked() was called.
       
  1152 
       
  1153     \sa checked, clicked()
       
  1154 */
       
  1155 
       
  1156 #include "moc_hbabstractbutton.cpp"