src/gui/widgets/qscrollbar.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qapplication.h"
       
    43 #include "qcursor.h"
       
    44 #include "qevent.h"
       
    45 #include "qpainter.h"
       
    46 #include "qscrollbar.h"
       
    47 #include "qstyle.h"
       
    48 #include "qstyleoption.h"
       
    49 #include "qmenu.h"
       
    50 #include <QtCore/qdatetime.h>
       
    51 
       
    52 #ifndef QT_NO_SCROLLBAR
       
    53 
       
    54 #ifndef QT_NO_ACCESSIBILITY
       
    55 #include "qaccessible.h"
       
    56 #endif
       
    57 #include <limits.h>
       
    58 #include "qabstractslider_p.h"
       
    59 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 /*!
       
    63     \class QScrollBar
       
    64     \brief The QScrollBar widget provides a vertical or horizontal scroll bar.
       
    65 
       
    66     \ingroup basicwidgets
       
    67 
       
    68     A scroll bar is a control that enables the user to access parts of a
       
    69     document that is larger than the widget used to display it. It provides
       
    70     a visual indication of the user's current position within the document
       
    71     and the amount of the document that is visible. Scroll bars are usually
       
    72     equipped with other controls that enable more accurate navigation.
       
    73     Qt displays scroll bars in a way that is appropriate for each platform.
       
    74 
       
    75     If you need to provide a scrolling view onto another widget, it may be
       
    76     more convenient to use the QScrollArea class because this provides a
       
    77     viewport widget and scroll bars. QScrollBar is useful if you need to
       
    78     implement similar functionality for specialized widgets using QAbstractScrollArea;
       
    79     for example, if you decide to subclass QAbstractItemView.
       
    80     For most other situations where a slider control is used to obtain a value
       
    81     within a given range, the QSlider class may be more appropriate for your
       
    82     needs.
       
    83 
       
    84     \table
       
    85     \row \i \image qscrollbar-picture.png
       
    86     \i Scroll bars typically include four separate controls: a slider,
       
    87     scroll arrows, and a page control.
       
    88 
       
    89     \list
       
    90     \i a. The slider provides a way to quickly go to any part of the
       
    91     document, but does not support accurate navigation within large
       
    92     documents.
       
    93     \i b. The scroll arrows are push buttons which can be used to accurately
       
    94     navigate to a particular place in a document. For a vertical scroll bar
       
    95     connected to a text editor, these typically move the current position one
       
    96     "line" up or down, and adjust the position of the slider by a small
       
    97     amount. In editors and list boxes a "line" might mean one line of text;
       
    98     in an image viewer it might mean 20 pixels.
       
    99     \i c. The page control is the area over which the slider is dragged (the
       
   100     scroll bar's background). Clicking here moves the scroll bar towards
       
   101     the click by one "page". This value is usually the same as the length of
       
   102     the slider.
       
   103     \endlist
       
   104     \endtable
       
   105 
       
   106     Each scroll bar has a value that indicates how far the slider is from
       
   107     the start of the scroll bar; this is obtained with value() and set
       
   108     with setValue(). This value always lies within the range of values
       
   109     defined for the scroll bar, from \l{QAbstractSlider::minimum()}{minimum()}
       
   110     to \l{QAbstractSlider::minimum()}{maximum()} inclusive. The range of
       
   111     acceptable values can be set with setMinimum() and setMaximum().
       
   112     At the minimum value, the top edge of the slider (for a vertical scroll
       
   113     bar) or left edge (for a horizontal scroll bar) will be at the top (or
       
   114     left) end of the scroll bar. At the maximum value, the bottom (or right)
       
   115     edge of the slider will be at the bottom (or right) end of the scroll bar.
       
   116 
       
   117     The length of the slider is usually related to the value of the page step,
       
   118     and typically represents the proportion of the document area shown in a
       
   119     scrolling view. The page step is the amount that the value changes by
       
   120     when the user presses the \key{Page Up} and \key{Page Down} keys, and is
       
   121     set with setPageStep(). Smaller changes to the value defined by the
       
   122     line step are made using the cursor keys, and this quantity is set with
       
   123     \l{QAbstractSlider::}{setSingleStep()}.
       
   124 
       
   125     Note that the range of values used is independent of the actual size
       
   126     of the scroll bar widget. You do not need to take this into account when
       
   127     you choose values for the range and the page step.
       
   128 
       
   129     The range of values specified for the scroll bar are often determined
       
   130     differently to those for a QSlider because the length of the slider
       
   131     needs to be taken into account. If we have a document with 100 lines,
       
   132     and we can only show 20 lines in a widget, we may wish to construct a
       
   133     scroll bar with a page step of 20, a minimum value of 0, and a maximum
       
   134     value of 80. This would give us a scroll bar with five "pages".
       
   135 
       
   136     \table
       
   137     \row \i \inlineimage qscrollbar-values.png
       
   138     \i The relationship between a document length, the range of values used
       
   139     in a scroll bar, and the page step is simple in many common situations.
       
   140     The scroll bar's range of values is determined by subtracting a
       
   141     chosen page step from some value representing the length of the document.
       
   142     In such cases, the following equation is useful:
       
   143 
       
   144     \e{document length} = maximum() - minimum() + pageStep().
       
   145     \endtable
       
   146 
       
   147     QScrollBar only provides integer ranges. Note that although
       
   148     QScrollBar handles very large numbers, scroll bars on current
       
   149     screens cannot usefully represent ranges above about 100,000 pixels.
       
   150     Beyond that, it becomes difficult for the user to control the
       
   151     slider using either the keyboard or the mouse, and the scroll
       
   152     arrows will have limited use.
       
   153 
       
   154     ScrollBar inherits a comprehensive set of signals from QAbstractSlider:
       
   155     \list
       
   156     \i \l{QAbstractSlider::valueChanged()}{valueChanged()} is emitted when the
       
   157        scroll bar's value has changed. The tracking() determines whether this
       
   158        signal is emitted during user interaction.
       
   159     \i \l{QAbstractSlider::rangeChanged()}{rangeChanged()} is emitted when the
       
   160        scroll bar's range of values has changed.
       
   161     \i \l{QAbstractSlider::sliderPressed()}{sliderPressed()} is emitted when
       
   162        the user starts to drag the slider.
       
   163     \i \l{QAbstractSlider::sliderMoved()}{sliderMoved()} is emitted when the user
       
   164        drags the slider.
       
   165     \i \l{QAbstractSlider::sliderReleased()}{sliderReleased()} is emitted when
       
   166        the user releases the slider.
       
   167     \i \l{QAbstractSlider::actionTriggered()}{actionTriggered()} is emitted
       
   168        when the scroll bar is changed by user interaction or via the
       
   169        \l{QAbstractSlider::triggerAction()}{triggerAction()} function.
       
   170     \endlist
       
   171 
       
   172     A scroll bar can be controlled by the keyboard, but it has a
       
   173     default focusPolicy() of Qt::NoFocus. Use setFocusPolicy() to
       
   174     enable keyboard interaction with the scroll bar:
       
   175     \list
       
   176          \i Left/Right move a horizontal scroll bar by one single step.
       
   177          \i Up/Down move a vertical scroll bar by one single step.
       
   178          \i PageUp moves up one page.
       
   179          \i PageDown moves down one page.
       
   180          \i Home moves to the start (mininum).
       
   181          \i End moves to the end (maximum).
       
   182      \endlist
       
   183 
       
   184     The slider itself can be controlled by using the
       
   185     \l{QAbstractSlider::triggerAction()}{triggerAction()} function to simulate
       
   186     user interaction with the scroll bar controls. This is useful if you have
       
   187     many different widgets that use a common range of values.
       
   188 
       
   189     Most GUI styles use the pageStep() value to calculate the size of the
       
   190     slider.
       
   191 
       
   192     \table 100%
       
   193     \row \o \inlineimage macintosh-horizontalscrollbar.png Screenshot of a Macintosh style scroll bar
       
   194          \o A scroll bar shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
       
   195     \row \o \inlineimage windowsxp-horizontalscrollbar.png Screenshot of a Windows XP style scroll bar
       
   196          \o A scroll bar shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
       
   197     \row \o \inlineimage plastique-horizontalscrollbar.png Screenshot of a Plastique style scroll bar
       
   198          \o A scroll bar shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
       
   199     \endtable
       
   200 
       
   201     \sa QScrollArea, QSlider, QDial, QSpinBox, {fowler}{GUI Design Handbook: Scroll Bar}, {Sliders Example}
       
   202 */
       
   203 
       
   204 class QScrollBarPrivate : public QAbstractSliderPrivate
       
   205 {
       
   206     Q_DECLARE_PUBLIC(QScrollBar)
       
   207 public:
       
   208     QStyle::SubControl pressedControl;
       
   209     bool pointerOutsidePressedControl;
       
   210 
       
   211     int clickOffset, snapBackPosition;
       
   212 
       
   213     void activateControl(uint control, int threshold = 500);
       
   214     void stopRepeatAction();
       
   215     int pixelPosToRangeValue(int pos) const;
       
   216     void init();
       
   217     bool updateHoverControl(const QPoint &pos);
       
   218     QStyle::SubControl newHoverControl(const QPoint &pos);
       
   219 
       
   220     QStyle::SubControl hoverControl;
       
   221     QRect hoverRect;
       
   222 };
       
   223 
       
   224 bool QScrollBarPrivate::updateHoverControl(const QPoint &pos)
       
   225 {
       
   226     Q_Q(QScrollBar);
       
   227     QRect lastHoverRect = hoverRect;
       
   228     QStyle::SubControl lastHoverControl = hoverControl;
       
   229     bool doesHover = q->testAttribute(Qt::WA_Hover);
       
   230     if (lastHoverControl != newHoverControl(pos) && doesHover) {
       
   231         q->update(lastHoverRect);
       
   232         q->update(hoverRect);
       
   233         return true;
       
   234     }
       
   235     return !doesHover;
       
   236 }
       
   237 
       
   238 QStyle::SubControl QScrollBarPrivate::newHoverControl(const QPoint &pos)
       
   239 {
       
   240     Q_Q(QScrollBar);
       
   241     QStyleOptionSlider opt;
       
   242     q->initStyleOption(&opt);
       
   243     opt.subControls = QStyle::SC_All;
       
   244     hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, pos, q);
       
   245     if (hoverControl == QStyle::SC_None)
       
   246         hoverRect = QRect();
       
   247     else
       
   248         hoverRect = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, hoverControl, q);
       
   249     return hoverControl;
       
   250 }
       
   251 
       
   252 void QScrollBarPrivate::activateControl(uint control, int threshold)
       
   253 {
       
   254     QAbstractSlider::SliderAction action = QAbstractSlider::SliderNoAction;
       
   255     switch (control) {
       
   256     case QStyle::SC_ScrollBarAddPage:
       
   257         action = QAbstractSlider::SliderPageStepAdd;
       
   258         break;
       
   259     case QStyle::SC_ScrollBarSubPage:
       
   260         action = QAbstractSlider::SliderPageStepSub;
       
   261         break;
       
   262     case QStyle::SC_ScrollBarAddLine:
       
   263         action = QAbstractSlider::SliderSingleStepAdd;
       
   264         break;
       
   265     case QStyle::SC_ScrollBarSubLine:
       
   266         action = QAbstractSlider::SliderSingleStepSub;
       
   267         break;
       
   268     case QStyle::SC_ScrollBarFirst:
       
   269         action = QAbstractSlider::SliderToMinimum;
       
   270         break;
       
   271     case QStyle::SC_ScrollBarLast:
       
   272         action = QAbstractSlider::SliderToMaximum;
       
   273         break;
       
   274     default:
       
   275         break;
       
   276     }
       
   277 
       
   278     if (action) {
       
   279         q_func()->setRepeatAction(action, threshold);
       
   280         q_func()->triggerAction(action);
       
   281     }
       
   282 }
       
   283 
       
   284 void QScrollBarPrivate::stopRepeatAction()
       
   285 {
       
   286     Q_Q(QScrollBar);
       
   287     QStyle::SubControl tmp = pressedControl;
       
   288     q->setRepeatAction(QAbstractSlider::SliderNoAction);
       
   289     pressedControl = QStyle::SC_None;
       
   290 
       
   291     if (tmp == QStyle::SC_ScrollBarSlider)
       
   292         q->setSliderDown(false);
       
   293 
       
   294     QStyleOptionSlider opt;
       
   295     q->initStyleOption(&opt);
       
   296     q->repaint(q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, tmp, q));
       
   297 }
       
   298 
       
   299 /*!
       
   300     Initialize \a option with the values from this QScrollBar. This method
       
   301     is useful for subclasses when they need a QStyleOptionSlider, but don't want
       
   302     to fill in all the information themselves.
       
   303 
       
   304     \sa QStyleOption::initFrom()
       
   305 */
       
   306 void QScrollBar::initStyleOption(QStyleOptionSlider *option) const
       
   307 {
       
   308     if (!option)
       
   309         return;
       
   310 
       
   311     Q_D(const QScrollBar);
       
   312     option->initFrom(this);
       
   313     option->subControls = QStyle::SC_None;
       
   314     option->activeSubControls = QStyle::SC_None;
       
   315     option->orientation = d->orientation;
       
   316     option->minimum = d->minimum;
       
   317     option->maximum = d->maximum;
       
   318     option->sliderPosition = d->position;
       
   319     option->sliderValue = d->value;
       
   320     option->singleStep = d->singleStep;
       
   321     option->pageStep = d->pageStep;
       
   322     option->upsideDown = d->invertedAppearance;
       
   323     if (d->orientation == Qt::Horizontal)
       
   324         option->state |= QStyle::State_Horizontal;
       
   325 }
       
   326 
       
   327 
       
   328 #define HORIZONTAL (d_func()->orientation == Qt::Horizontal)
       
   329 #define VERTICAL !HORIZONTAL
       
   330 
       
   331 /*!
       
   332     Constructs a vertical scroll bar.
       
   333 
       
   334     The \a parent arguments is sent to the QWidget constructor.
       
   335 
       
   336     The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the
       
   337     \l {QAbstractSlider::maximum} {maximum} to 99, with a
       
   338     \l {QAbstractSlider::singleStep} {singleStep} size of 1 and a
       
   339     \l {QAbstractSlider::pageStep} {pageStep} size of 10, and an
       
   340     initial \l {QAbstractSlider::value} {value} of 0.
       
   341 */
       
   342 QScrollBar::QScrollBar(QWidget *parent)
       
   343     : QAbstractSlider(*new QScrollBarPrivate, parent)
       
   344 {
       
   345     d_func()->orientation = Qt::Vertical;
       
   346     d_func()->init();
       
   347 }
       
   348 
       
   349 /*!
       
   350     Constructs a scroll bar with the given \a orientation.
       
   351 
       
   352     The \a parent argument is passed to the QWidget constructor.
       
   353 
       
   354     The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the
       
   355     \l {QAbstractSlider::maximum} {maximum} to 99, with a
       
   356     \l {QAbstractSlider::singleStep} {singleStep} size of 1 and a
       
   357     \l {QAbstractSlider::pageStep} {pageStep} size of 10, and an
       
   358     initial \l {QAbstractSlider::value} {value} of 0.
       
   359 */
       
   360 QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent)
       
   361     : QAbstractSlider(*new QScrollBarPrivate, parent)
       
   362 {
       
   363     d_func()->orientation = orientation;
       
   364     d_func()->init();
       
   365 }
       
   366 
       
   367 
       
   368 #ifdef QT3_SUPPORT
       
   369 /*!
       
   370     Use one of the constructors that doesn't take the \a name
       
   371     argument and then use setObjectName() instead.
       
   372 */
       
   373 QScrollBar::QScrollBar(QWidget *parent, const char *name)
       
   374     : QAbstractSlider(*new QScrollBarPrivate, parent)
       
   375 {
       
   376     setObjectName(QString::fromAscii(name));
       
   377     d_func()->orientation = Qt::Vertical;
       
   378     d_func()->init();
       
   379 }
       
   380 
       
   381 /*!
       
   382     Use one of the constructors that doesn't take the \a name
       
   383     argument and then use setObjectName() instead.
       
   384 */
       
   385 QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent, const char *name)
       
   386     : QAbstractSlider(*new QScrollBarPrivate, parent)
       
   387 {
       
   388     setObjectName(QString::fromAscii(name));
       
   389     d_func()->orientation = orientation;
       
   390     d_func()->init();
       
   391 }
       
   392 
       
   393 /*!
       
   394     Use one of the constructors that doesn't take the \a name
       
   395     argument and then use setObjectName() instead.
       
   396 */
       
   397 QScrollBar::QScrollBar(int minimum, int maximum, int lineStep, int pageStep,
       
   398                         int value, Qt::Orientation orientation,
       
   399                         QWidget *parent, const char *name)
       
   400     : QAbstractSlider(*new QScrollBarPrivate, parent)
       
   401 {
       
   402     Q_D(QScrollBar);
       
   403     setObjectName(QString::fromAscii(name));
       
   404     d->minimum = minimum;
       
   405     d->maximum = maximum;
       
   406     d->singleStep = lineStep;
       
   407     d->pageStep = pageStep;
       
   408     d->value = value;
       
   409     d->orientation = orientation;
       
   410     d->init();
       
   411 }
       
   412 #endif // QT3_SUPPORT
       
   413 
       
   414 /*!
       
   415     Destroys the scroll bar.
       
   416 */
       
   417 QScrollBar::~QScrollBar()
       
   418 {
       
   419 }
       
   420 
       
   421 void QScrollBarPrivate::init()
       
   422 {
       
   423     Q_Q(QScrollBar);
       
   424     invertedControls = true;
       
   425     pressedControl = hoverControl = QStyle::SC_None;
       
   426     pointerOutsidePressedControl = false;
       
   427     q->setFocusPolicy(Qt::NoFocus);
       
   428     QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Slider);
       
   429     if (orientation == Qt::Vertical)
       
   430         sp.transpose();
       
   431     q->setSizePolicy(sp);
       
   432     q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
       
   433     q->setAttribute(Qt::WA_OpaquePaintEvent);
       
   434 
       
   435 #if !defined(QT_NO_CONTEXTMENU) && defined(Q_WS_WINCE)
       
   436     if (!q->style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, q)) {
       
   437         q->setContextMenuPolicy(Qt::PreventContextMenu);
       
   438     }
       
   439 #endif
       
   440 }
       
   441 
       
   442 #ifndef QT_NO_CONTEXTMENU
       
   443 /*! \reimp */
       
   444 void QScrollBar::contextMenuEvent(QContextMenuEvent *event)
       
   445 {
       
   446     if (!style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, this)) {
       
   447         QAbstractSlider::contextMenuEvent(event);
       
   448         return ;
       
   449     }
       
   450 
       
   451 #ifndef QT_NO_MENU
       
   452     bool horiz = HORIZONTAL;
       
   453     QPointer<QMenu> menu = new QMenu(this);
       
   454     QAction *actScrollHere = menu->addAction(tr("Scroll here"));
       
   455     menu->addSeparator();
       
   456     QAction *actScrollTop =  menu->addAction(horiz ? tr("Left edge") : tr("Top"));
       
   457     QAction *actScrollBottom = menu->addAction(horiz ? tr("Right edge") : tr("Bottom"));
       
   458     menu->addSeparator();
       
   459     QAction *actPageUp = menu->addAction(horiz ? tr("Page left") : tr("Page up"));
       
   460     QAction *actPageDn = menu->addAction(horiz ? tr("Page right") : tr("Page down"));
       
   461     menu->addSeparator();
       
   462     QAction *actScrollUp = menu->addAction(horiz ? tr("Scroll left") : tr("Scroll up"));
       
   463     QAction *actScrollDn = menu->addAction(horiz ? tr("Scroll right") : tr("Scroll down"));
       
   464     QAction *actionSelected = menu->exec(event->globalPos());
       
   465     delete menu;
       
   466     if (actionSelected == 0)
       
   467         /* do nothing */ ;
       
   468     else if (actionSelected == actScrollHere)
       
   469         setValue(d_func()->pixelPosToRangeValue(horiz ? event->pos().x() : event->pos().y()));
       
   470     else if (actionSelected == actScrollTop)
       
   471         triggerAction(QAbstractSlider::SliderToMinimum);
       
   472     else if (actionSelected == actScrollBottom)
       
   473         triggerAction(QAbstractSlider::SliderToMaximum);
       
   474     else if (actionSelected == actPageUp)
       
   475         triggerAction(QAbstractSlider::SliderPageStepSub);
       
   476     else if (actionSelected == actPageDn)
       
   477         triggerAction(QAbstractSlider::SliderPageStepAdd);
       
   478     else if (actionSelected == actScrollUp)
       
   479         triggerAction(QAbstractSlider::SliderSingleStepSub);
       
   480     else if (actionSelected == actScrollDn)
       
   481         triggerAction(QAbstractSlider::SliderSingleStepAdd);
       
   482 #endif // QT_NO_MENU
       
   483 }
       
   484 #endif // QT_NO_CONTEXTMENU
       
   485 
       
   486 
       
   487 /*! \reimp */
       
   488 QSize QScrollBar::sizeHint() const
       
   489 {
       
   490     ensurePolished();
       
   491     QStyleOptionSlider opt;
       
   492     initStyleOption(&opt);
       
   493 
       
   494     int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this);
       
   495     int scrollBarSliderMin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &opt, this);
       
   496     QSize size;
       
   497     if (opt.orientation == Qt::Horizontal)
       
   498         size = QSize(scrollBarExtent * 2 + scrollBarSliderMin, scrollBarExtent);
       
   499     else
       
   500         size = QSize(scrollBarExtent, scrollBarExtent * 2 + scrollBarSliderMin);
       
   501 
       
   502     return style()->sizeFromContents(QStyle::CT_ScrollBar, &opt, size, this)
       
   503         .expandedTo(QApplication::globalStrut());
       
   504  }
       
   505 
       
   506 /*!\reimp */
       
   507 void QScrollBar::sliderChange(SliderChange change)
       
   508 {
       
   509     QAbstractSlider::sliderChange(change);
       
   510 }
       
   511 
       
   512 /*!
       
   513     \reimp
       
   514 */
       
   515 bool QScrollBar::event(QEvent *event)
       
   516 {
       
   517     switch(event->type()) {
       
   518     case QEvent::HoverEnter:
       
   519     case QEvent::HoverLeave:
       
   520     case QEvent::HoverMove:
       
   521     if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
       
   522         d_func()->updateHoverControl(he->pos());
       
   523         break;
       
   524     default:
       
   525         break;
       
   526     }
       
   527     return QAbstractSlider::event(event);
       
   528 }
       
   529 
       
   530 /*!
       
   531     \reimp
       
   532 */
       
   533 void QScrollBar::paintEvent(QPaintEvent *)
       
   534 {
       
   535     Q_D(QScrollBar);
       
   536     QPainter p(this);
       
   537     QStyleOptionSlider opt;
       
   538     initStyleOption(&opt);
       
   539     opt.subControls = QStyle::SC_All;
       
   540     if (d->pressedControl) {
       
   541         opt.activeSubControls = (QStyle::SubControl)d->pressedControl;
       
   542         if (!d->pointerOutsidePressedControl)
       
   543             opt.state |= QStyle::State_Sunken;
       
   544     } else {
       
   545         opt.activeSubControls = (QStyle::SubControl)d->hoverControl;
       
   546     }
       
   547     style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);
       
   548 }
       
   549 
       
   550 /*!
       
   551     \reimp
       
   552 */
       
   553 void QScrollBar::mousePressEvent(QMouseEvent *e)
       
   554 {
       
   555     Q_D(QScrollBar);
       
   556 
       
   557     if (d->repeatActionTimer.isActive())
       
   558         d->stopRepeatAction();
       
   559 
       
   560     bool midButtonAbsPos = style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition,
       
   561                                              0, this);
       
   562     QStyleOptionSlider opt;
       
   563     initStyleOption(&opt);
       
   564 
       
   565     if (d->maximum == d->minimum // no range
       
   566         || (e->buttons() & (~e->button())) // another button was clicked before
       
   567         || !(e->button() == Qt::LeftButton || (midButtonAbsPos && e->button() == Qt::MidButton)))
       
   568         return;
       
   569 
       
   570     d->pressedControl = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);
       
   571     d->pointerOutsidePressedControl = false;
       
   572 
       
   573     QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt,
       
   574                                        QStyle::SC_ScrollBarSlider, this);
       
   575     QPoint click = e->pos();
       
   576     QPoint pressValue = click - sr.center() + sr.topLeft();
       
   577     d->pressValue = d->orientation == Qt::Horizontal ? d->pixelPosToRangeValue(pressValue.x()) :
       
   578         d->pixelPosToRangeValue(pressValue.y());
       
   579     if (d->pressedControl == QStyle::SC_ScrollBarSlider) {
       
   580         d->clickOffset = HORIZONTAL ? (click.x()-sr.x()) : (click.y()-sr.y());
       
   581         d->snapBackPosition = d->position;
       
   582     }
       
   583 
       
   584     if ((d->pressedControl == QStyle::SC_ScrollBarAddPage
       
   585           || d->pressedControl == QStyle::SC_ScrollBarSubPage)
       
   586         && ((midButtonAbsPos && e->button() == Qt::MidButton)
       
   587             || (style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition, &opt, this)
       
   588                 && e->button() == Qt::LeftButton))) {
       
   589         int sliderLength = HORIZONTAL ? sr.width() : sr.height();
       
   590         setSliderPosition(d->pixelPosToRangeValue((HORIZONTAL ? e->pos().x()
       
   591                                                               : e->pos().y()) - sliderLength / 2));
       
   592         d->pressedControl = QStyle::SC_ScrollBarSlider;
       
   593         d->clickOffset = sliderLength / 2;
       
   594     }
       
   595     const int initialDelay = 500; // default threshold
       
   596     d->activateControl(d->pressedControl, initialDelay);
       
   597     QTime time;
       
   598     time.start();
       
   599     repaint(style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this));
       
   600     if (time.elapsed() >= initialDelay && d->repeatActionTimer.isActive()) {
       
   601         // It took more than 500ms (the initial timer delay) to process the repaint(), we
       
   602         // therefore need to restart the timer in case we have a pending mouse release event;
       
   603         // otherwise we'll get a timer event right before the release event,
       
   604         // causing the repeat action to be invoked twice on a single mouse click.
       
   605         // 50ms is the default repeat time (see activateControl/setRepeatAction).
       
   606         d->repeatActionTimer.start(50, this);
       
   607     }
       
   608     if (d->pressedControl == QStyle::SC_ScrollBarSlider)
       
   609         setSliderDown(true);
       
   610 }
       
   611 
       
   612 
       
   613 /*!
       
   614     \reimp
       
   615 */
       
   616 void QScrollBar::mouseReleaseEvent(QMouseEvent *e)
       
   617 {
       
   618     Q_D(QScrollBar);
       
   619     if (!d->pressedControl)
       
   620         return;
       
   621 
       
   622     if (e->buttons() & (~e->button())) // some other button is still pressed
       
   623         return;
       
   624 
       
   625     d->stopRepeatAction();
       
   626 }
       
   627 
       
   628 
       
   629 /*!
       
   630     \reimp
       
   631 */
       
   632 void QScrollBar::mouseMoveEvent(QMouseEvent *e)
       
   633 {
       
   634     Q_D(QScrollBar);
       
   635     if (!d->pressedControl)
       
   636         return;
       
   637 
       
   638     QStyleOptionSlider opt;
       
   639     initStyleOption(&opt);
       
   640     if (!(e->buttons() & Qt::LeftButton
       
   641           ||  ((e->buttons() & Qt::MidButton)
       
   642                && style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition, &opt, this))))
       
   643         return;
       
   644 
       
   645     if (d->pressedControl == QStyle::SC_ScrollBarSlider) {
       
   646         QPoint click = e->pos();
       
   647         int newPosition = d->pixelPosToRangeValue((HORIZONTAL ? click.x() : click.y()) -d->clickOffset);
       
   648         int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
       
   649         if (m >= 0) {
       
   650             QRect r = rect();
       
   651             r.adjust(-m, -m, m, m);
       
   652             if (! r.contains(e->pos()))
       
   653                 newPosition = d->snapBackPosition;
       
   654         }
       
   655         setSliderPosition(newPosition);
       
   656     } else if (!style()->styleHint(QStyle::SH_ScrollBar_ScrollWhenPointerLeavesControl, &opt, this)) {
       
   657 
       
   658         if (style()->styleHint(QStyle::SH_ScrollBar_RollBetweenButtons, &opt, this)
       
   659                 && d->pressedControl & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {
       
   660             QStyle::SubControl newSc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);
       
   661             if (newSc == d->pressedControl && !d->pointerOutsidePressedControl)
       
   662                 return; // nothing to do
       
   663             if (newSc & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {
       
   664                 d->pointerOutsidePressedControl = false;
       
   665                 QRect scRect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, newSc, this);
       
   666                 scRect |= style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);
       
   667                 d->pressedControl = newSc;
       
   668                 d->activateControl(d->pressedControl, 0);
       
   669                 update(scRect);
       
   670                 return;
       
   671             }
       
   672         }
       
   673 
       
   674         // stop scrolling when the mouse pointer leaves a control
       
   675         // similar to push buttons
       
   676         QRect pr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);
       
   677         if (pr.contains(e->pos()) == d->pointerOutsidePressedControl) {
       
   678             if ((d->pointerOutsidePressedControl = !d->pointerOutsidePressedControl)) {
       
   679                 d->pointerOutsidePressedControl = true;
       
   680                 setRepeatAction(SliderNoAction);
       
   681                 repaint(pr);
       
   682             } else  {
       
   683                 d->activateControl(d->pressedControl);
       
   684             }
       
   685         }
       
   686     }
       
   687 }
       
   688 
       
   689 
       
   690 int QScrollBarPrivate::pixelPosToRangeValue(int pos) const
       
   691 {
       
   692     Q_Q(const QScrollBar);
       
   693     QStyleOptionSlider opt;
       
   694     q->initStyleOption(&opt);
       
   695     QRect gr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,
       
   696                                           QStyle::SC_ScrollBarGroove, q);
       
   697     QRect sr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,
       
   698                                           QStyle::SC_ScrollBarSlider, q);
       
   699     int sliderMin, sliderMax, sliderLength;
       
   700 
       
   701     if (orientation == Qt::Horizontal) {
       
   702         sliderLength = sr.width();
       
   703         sliderMin = gr.x();
       
   704         sliderMax = gr.right() - sliderLength + 1;
       
   705         if (q->layoutDirection() == Qt::RightToLeft)
       
   706             opt.upsideDown = !opt.upsideDown;
       
   707     } else {
       
   708         sliderLength = sr.height();
       
   709         sliderMin = gr.y();
       
   710         sliderMax = gr.bottom() - sliderLength + 1;
       
   711     }
       
   712 
       
   713     return  QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,
       
   714                                             sliderMax - sliderMin, opt.upsideDown);
       
   715 }
       
   716 
       
   717 /*! \reimp
       
   718 */
       
   719 void QScrollBar::hideEvent(QHideEvent *)
       
   720 {
       
   721     Q_D(QScrollBar);
       
   722     if (d->pressedControl) {
       
   723         d->pressedControl = QStyle::SC_None;
       
   724         setRepeatAction(SliderNoAction);
       
   725     }
       
   726 }
       
   727 
       
   728 /*!
       
   729     \fn bool QScrollBar::draggingSlider()
       
   730 
       
   731     Use isSliderDown() instead.
       
   732 */
       
   733 
       
   734 /*! \internal
       
   735     Returns the style option for scroll bar.
       
   736 */
       
   737 Q_GUI_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollbar)
       
   738 {
       
   739     QStyleOptionSlider opt;
       
   740     scrollbar->initStyleOption(&opt);
       
   741     return opt;
       
   742 }
       
   743 
       
   744 QT_END_NAMESPACE
       
   745 
       
   746 #endif // QT_NO_SCROLLBAR