/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the QtGui module of the Qt Toolkit.+ −
**+ −
** $QT_BEGIN_LICENSE:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.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 qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
#include "qapplication.h"+ −
#include "qcursor.h"+ −
#include "qevent.h"+ −
#include "qpainter.h"+ −
#include "qscrollbar.h"+ −
#include "qstyle.h"+ −
#include "qstyleoption.h"+ −
#include "qmenu.h"+ −
#include <QtCore/qdatetime.h>+ −
+ −
#ifndef QT_NO_SCROLLBAR+ −
+ −
#ifndef QT_NO_ACCESSIBILITY+ −
#include "qaccessible.h"+ −
#endif+ −
#include <limits.h>+ −
#include "qabstractslider_p.h"+ −
+ −
QT_BEGIN_NAMESPACE+ −
+ −
/*!+ −
\class QScrollBar+ −
\brief The QScrollBar widget provides a vertical or horizontal scroll bar.+ −
+ −
\ingroup basicwidgets+ −
+ −
A scroll bar is a control that enables the user to access parts of a+ −
document that is larger than the widget used to display it. It provides+ −
a visual indication of the user's current position within the document+ −
and the amount of the document that is visible. Scroll bars are usually+ −
equipped with other controls that enable more accurate navigation.+ −
Qt displays scroll bars in a way that is appropriate for each platform.+ −
+ −
If you need to provide a scrolling view onto another widget, it may be+ −
more convenient to use the QScrollArea class because this provides a+ −
viewport widget and scroll bars. QScrollBar is useful if you need to+ −
implement similar functionality for specialized widgets using QAbstractScrollArea;+ −
for example, if you decide to subclass QAbstractItemView.+ −
For most other situations where a slider control is used to obtain a value+ −
within a given range, the QSlider class may be more appropriate for your+ −
needs.+ −
+ −
\table+ −
\row \i \image qscrollbar-picture.png+ −
\i Scroll bars typically include four separate controls: a slider,+ −
scroll arrows, and a page control.+ −
+ −
\list+ −
\i a. The slider provides a way to quickly go to any part of the+ −
document, but does not support accurate navigation within large+ −
documents.+ −
\i b. The scroll arrows are push buttons which can be used to accurately+ −
navigate to a particular place in a document. For a vertical scroll bar+ −
connected to a text editor, these typically move the current position one+ −
"line" up or down, and adjust the position of the slider by a small+ −
amount. In editors and list boxes a "line" might mean one line of text;+ −
in an image viewer it might mean 20 pixels.+ −
\i c. The page control is the area over which the slider is dragged (the+ −
scroll bar's background). Clicking here moves the scroll bar towards+ −
the click by one "page". This value is usually the same as the length of+ −
the slider.+ −
\endlist+ −
\endtable+ −
+ −
Each scroll bar has a value that indicates how far the slider is from+ −
the start of the scroll bar; this is obtained with value() and set+ −
with setValue(). This value always lies within the range of values+ −
defined for the scroll bar, from \l{QAbstractSlider::minimum()}{minimum()}+ −
to \l{QAbstractSlider::minimum()}{maximum()} inclusive. The range of+ −
acceptable values can be set with setMinimum() and setMaximum().+ −
At the minimum value, the top edge of the slider (for a vertical scroll+ −
bar) or left edge (for a horizontal scroll bar) will be at the top (or+ −
left) end of the scroll bar. At the maximum value, the bottom (or right)+ −
edge of the slider will be at the bottom (or right) end of the scroll bar.+ −
+ −
The length of the slider is usually related to the value of the page step,+ −
and typically represents the proportion of the document area shown in a+ −
scrolling view. The page step is the amount that the value changes by+ −
when the user presses the \key{Page Up} and \key{Page Down} keys, and is+ −
set with setPageStep(). Smaller changes to the value defined by the+ −
line step are made using the cursor keys, and this quantity is set with+ −
\l{QAbstractSlider::}{setSingleStep()}.+ −
+ −
Note that the range of values used is independent of the actual size+ −
of the scroll bar widget. You do not need to take this into account when+ −
you choose values for the range and the page step.+ −
+ −
The range of values specified for the scroll bar are often determined+ −
differently to those for a QSlider because the length of the slider+ −
needs to be taken into account. If we have a document with 100 lines,+ −
and we can only show 20 lines in a widget, we may wish to construct a+ −
scroll bar with a page step of 20, a minimum value of 0, and a maximum+ −
value of 80. This would give us a scroll bar with five "pages".+ −
+ −
\table+ −
\row \i \inlineimage qscrollbar-values.png+ −
\i The relationship between a document length, the range of values used+ −
in a scroll bar, and the page step is simple in many common situations.+ −
The scroll bar's range of values is determined by subtracting a+ −
chosen page step from some value representing the length of the document.+ −
In such cases, the following equation is useful:+ −
+ −
\e{document length} = maximum() - minimum() + pageStep().+ −
\endtable+ −
+ −
QScrollBar only provides integer ranges. Note that although+ −
QScrollBar handles very large numbers, scroll bars on current+ −
screens cannot usefully represent ranges above about 100,000 pixels.+ −
Beyond that, it becomes difficult for the user to control the+ −
slider using either the keyboard or the mouse, and the scroll+ −
arrows will have limited use.+ −
+ −
ScrollBar inherits a comprehensive set of signals from QAbstractSlider:+ −
\list+ −
\i \l{QAbstractSlider::valueChanged()}{valueChanged()} is emitted when the+ −
scroll bar's value has changed. The tracking() determines whether this+ −
signal is emitted during user interaction.+ −
\i \l{QAbstractSlider::rangeChanged()}{rangeChanged()} is emitted when the+ −
scroll bar's range of values has changed.+ −
\i \l{QAbstractSlider::sliderPressed()}{sliderPressed()} is emitted when+ −
the user starts to drag the slider.+ −
\i \l{QAbstractSlider::sliderMoved()}{sliderMoved()} is emitted when the user+ −
drags the slider.+ −
\i \l{QAbstractSlider::sliderReleased()}{sliderReleased()} is emitted when+ −
the user releases the slider.+ −
\i \l{QAbstractSlider::actionTriggered()}{actionTriggered()} is emitted+ −
when the scroll bar is changed by user interaction or via the+ −
\l{QAbstractSlider::triggerAction()}{triggerAction()} function.+ −
\endlist+ −
+ −
A scroll bar can be controlled by the keyboard, but it has a+ −
default focusPolicy() of Qt::NoFocus. Use setFocusPolicy() to+ −
enable keyboard interaction with the scroll bar:+ −
\list+ −
\i Left/Right move a horizontal scroll bar by one single step.+ −
\i Up/Down move a vertical scroll bar by one single step.+ −
\i PageUp moves up one page.+ −
\i PageDown moves down one page.+ −
\i Home moves to the start (mininum).+ −
\i End moves to the end (maximum).+ −
\endlist+ −
+ −
The slider itself can be controlled by using the+ −
\l{QAbstractSlider::triggerAction()}{triggerAction()} function to simulate+ −
user interaction with the scroll bar controls. This is useful if you have+ −
many different widgets that use a common range of values.+ −
+ −
Most GUI styles use the pageStep() value to calculate the size of the+ −
slider.+ −
+ −
\table 100%+ −
\row \o \inlineimage macintosh-horizontalscrollbar.png Screenshot of a Macintosh style scroll bar+ −
\o A scroll bar shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.+ −
\row \o \inlineimage windowsxp-horizontalscrollbar.png Screenshot of a Windows XP style scroll bar+ −
\o A scroll bar shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.+ −
\row \o \inlineimage plastique-horizontalscrollbar.png Screenshot of a Plastique style scroll bar+ −
\o A scroll bar shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.+ −
\endtable+ −
+ −
\sa QScrollArea, QSlider, QDial, QSpinBox, {fowler}{GUI Design Handbook: Scroll Bar}, {Sliders Example}+ −
*/+ −
+ −
class QScrollBarPrivate : public QAbstractSliderPrivate+ −
{+ −
Q_DECLARE_PUBLIC(QScrollBar)+ −
public:+ −
QStyle::SubControl pressedControl;+ −
bool pointerOutsidePressedControl;+ −
+ −
int clickOffset, snapBackPosition;+ −
+ −
void activateControl(uint control, int threshold = 500);+ −
void stopRepeatAction();+ −
int pixelPosToRangeValue(int pos) const;+ −
void init();+ −
bool updateHoverControl(const QPoint &pos);+ −
QStyle::SubControl newHoverControl(const QPoint &pos);+ −
+ −
QStyle::SubControl hoverControl;+ −
QRect hoverRect;+ −
};+ −
+ −
bool QScrollBarPrivate::updateHoverControl(const QPoint &pos)+ −
{+ −
Q_Q(QScrollBar);+ −
QRect lastHoverRect = hoverRect;+ −
QStyle::SubControl lastHoverControl = hoverControl;+ −
bool doesHover = q->testAttribute(Qt::WA_Hover);+ −
if (lastHoverControl != newHoverControl(pos) && doesHover) {+ −
q->update(lastHoverRect);+ −
q->update(hoverRect);+ −
return true;+ −
}+ −
return !doesHover;+ −
}+ −
+ −
QStyle::SubControl QScrollBarPrivate::newHoverControl(const QPoint &pos)+ −
{+ −
Q_Q(QScrollBar);+ −
QStyleOptionSlider opt;+ −
q->initStyleOption(&opt);+ −
opt.subControls = QStyle::SC_All;+ −
hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, pos, q);+ −
if (hoverControl == QStyle::SC_None)+ −
hoverRect = QRect();+ −
else+ −
hoverRect = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, hoverControl, q);+ −
return hoverControl;+ −
}+ −
+ −
void QScrollBarPrivate::activateControl(uint control, int threshold)+ −
{+ −
QAbstractSlider::SliderAction action = QAbstractSlider::SliderNoAction;+ −
switch (control) {+ −
case QStyle::SC_ScrollBarAddPage:+ −
action = QAbstractSlider::SliderPageStepAdd;+ −
break;+ −
case QStyle::SC_ScrollBarSubPage:+ −
action = QAbstractSlider::SliderPageStepSub;+ −
break;+ −
case QStyle::SC_ScrollBarAddLine:+ −
action = QAbstractSlider::SliderSingleStepAdd;+ −
break;+ −
case QStyle::SC_ScrollBarSubLine:+ −
action = QAbstractSlider::SliderSingleStepSub;+ −
break;+ −
case QStyle::SC_ScrollBarFirst:+ −
action = QAbstractSlider::SliderToMinimum;+ −
break;+ −
case QStyle::SC_ScrollBarLast:+ −
action = QAbstractSlider::SliderToMaximum;+ −
break;+ −
default:+ −
break;+ −
}+ −
+ −
if (action) {+ −
q_func()->setRepeatAction(action, threshold);+ −
q_func()->triggerAction(action);+ −
}+ −
}+ −
+ −
void QScrollBarPrivate::stopRepeatAction()+ −
{+ −
Q_Q(QScrollBar);+ −
QStyle::SubControl tmp = pressedControl;+ −
q->setRepeatAction(QAbstractSlider::SliderNoAction);+ −
pressedControl = QStyle::SC_None;+ −
+ −
if (tmp == QStyle::SC_ScrollBarSlider)+ −
q->setSliderDown(false);+ −
+ −
QStyleOptionSlider opt;+ −
q->initStyleOption(&opt);+ −
q->repaint(q->style()->subControlRect(QStyle::CC_ScrollBar, &opt, tmp, q));+ −
}+ −
+ −
/*!+ −
Initialize \a option with the values from this QScrollBar. This method+ −
is useful for subclasses when they need a QStyleOptionSlider, but don't want+ −
to fill in all the information themselves.+ −
+ −
\sa QStyleOption::initFrom()+ −
*/+ −
void QScrollBar::initStyleOption(QStyleOptionSlider *option) const+ −
{+ −
if (!option)+ −
return;+ −
+ −
Q_D(const QScrollBar);+ −
option->initFrom(this);+ −
option->subControls = QStyle::SC_None;+ −
option->activeSubControls = QStyle::SC_None;+ −
option->orientation = d->orientation;+ −
option->minimum = d->minimum;+ −
option->maximum = d->maximum;+ −
option->sliderPosition = d->position;+ −
option->sliderValue = d->value;+ −
option->singleStep = d->singleStep;+ −
option->pageStep = d->pageStep;+ −
option->upsideDown = d->invertedAppearance;+ −
if (d->orientation == Qt::Horizontal)+ −
option->state |= QStyle::State_Horizontal;+ −
}+ −
+ −
+ −
#define HORIZONTAL (d_func()->orientation == Qt::Horizontal)+ −
#define VERTICAL !HORIZONTAL+ −
+ −
/*!+ −
Constructs a vertical scroll bar.+ −
+ −
The \a parent arguments is sent to the QWidget constructor.+ −
+ −
The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the+ −
\l {QAbstractSlider::maximum} {maximum} to 99, with a+ −
\l {QAbstractSlider::singleStep} {singleStep} size of 1 and a+ −
\l {QAbstractSlider::pageStep} {pageStep} size of 10, and an+ −
initial \l {QAbstractSlider::value} {value} of 0.+ −
*/+ −
QScrollBar::QScrollBar(QWidget *parent)+ −
: QAbstractSlider(*new QScrollBarPrivate, parent)+ −
{+ −
d_func()->orientation = Qt::Vertical;+ −
d_func()->init();+ −
}+ −
+ −
/*!+ −
Constructs a scroll bar with the given \a orientation.+ −
+ −
The \a parent argument is passed to the QWidget constructor.+ −
+ −
The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the+ −
\l {QAbstractSlider::maximum} {maximum} to 99, with a+ −
\l {QAbstractSlider::singleStep} {singleStep} size of 1 and a+ −
\l {QAbstractSlider::pageStep} {pageStep} size of 10, and an+ −
initial \l {QAbstractSlider::value} {value} of 0.+ −
*/+ −
QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent)+ −
: QAbstractSlider(*new QScrollBarPrivate, parent)+ −
{+ −
d_func()->orientation = orientation;+ −
d_func()->init();+ −
}+ −
+ −
+ −
#ifdef QT3_SUPPORT+ −
/*!+ −
Use one of the constructors that doesn't take the \a name+ −
argument and then use setObjectName() instead.+ −
*/+ −
QScrollBar::QScrollBar(QWidget *parent, const char *name)+ −
: QAbstractSlider(*new QScrollBarPrivate, parent)+ −
{+ −
setObjectName(QString::fromAscii(name));+ −
d_func()->orientation = Qt::Vertical;+ −
d_func()->init();+ −
}+ −
+ −
/*!+ −
Use one of the constructors that doesn't take the \a name+ −
argument and then use setObjectName() instead.+ −
*/+ −
QScrollBar::QScrollBar(Qt::Orientation orientation, QWidget *parent, const char *name)+ −
: QAbstractSlider(*new QScrollBarPrivate, parent)+ −
{+ −
setObjectName(QString::fromAscii(name));+ −
d_func()->orientation = orientation;+ −
d_func()->init();+ −
}+ −
+ −
/*!+ −
Use one of the constructors that doesn't take the \a name+ −
argument and then use setObjectName() instead.+ −
*/+ −
QScrollBar::QScrollBar(int minimum, int maximum, int lineStep, int pageStep,+ −
int value, Qt::Orientation orientation,+ −
QWidget *parent, const char *name)+ −
: QAbstractSlider(*new QScrollBarPrivate, parent)+ −
{+ −
Q_D(QScrollBar);+ −
setObjectName(QString::fromAscii(name));+ −
d->minimum = minimum;+ −
d->maximum = maximum;+ −
d->singleStep = lineStep;+ −
d->pageStep = pageStep;+ −
d->value = value;+ −
d->orientation = orientation;+ −
d->init();+ −
}+ −
#endif // QT3_SUPPORT+ −
+ −
/*!+ −
Destroys the scroll bar.+ −
*/+ −
QScrollBar::~QScrollBar()+ −
{+ −
}+ −
+ −
void QScrollBarPrivate::init()+ −
{+ −
Q_Q(QScrollBar);+ −
invertedControls = true;+ −
pressedControl = hoverControl = QStyle::SC_None;+ −
pointerOutsidePressedControl = false;+ −
q->setFocusPolicy(Qt::NoFocus);+ −
QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Slider);+ −
if (orientation == Qt::Vertical)+ −
sp.transpose();+ −
q->setSizePolicy(sp);+ −
q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);+ −
q->setAttribute(Qt::WA_OpaquePaintEvent);+ −
+ −
#if !defined(QT_NO_CONTEXTMENU) && defined(Q_WS_WINCE)+ −
if (!q->style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, q)) {+ −
q->setContextMenuPolicy(Qt::PreventContextMenu);+ −
}+ −
#endif+ −
}+ −
+ −
#ifndef QT_NO_CONTEXTMENU+ −
/*! \reimp */+ −
void QScrollBar::contextMenuEvent(QContextMenuEvent *event)+ −
{+ −
if (!style()->styleHint(QStyle::SH_ScrollBar_ContextMenu, 0, this)) {+ −
QAbstractSlider::contextMenuEvent(event);+ −
return ;+ −
}+ −
+ −
#ifndef QT_NO_MENU+ −
bool horiz = HORIZONTAL;+ −
QPointer<QMenu> menu = new QMenu(this);+ −
QAction *actScrollHere = menu->addAction(tr("Scroll here"));+ −
menu->addSeparator();+ −
QAction *actScrollTop = menu->addAction(horiz ? tr("Left edge") : tr("Top"));+ −
QAction *actScrollBottom = menu->addAction(horiz ? tr("Right edge") : tr("Bottom"));+ −
menu->addSeparator();+ −
QAction *actPageUp = menu->addAction(horiz ? tr("Page left") : tr("Page up"));+ −
QAction *actPageDn = menu->addAction(horiz ? tr("Page right") : tr("Page down"));+ −
menu->addSeparator();+ −
QAction *actScrollUp = menu->addAction(horiz ? tr("Scroll left") : tr("Scroll up"));+ −
QAction *actScrollDn = menu->addAction(horiz ? tr("Scroll right") : tr("Scroll down"));+ −
QAction *actionSelected = menu->exec(event->globalPos());+ −
delete menu;+ −
if (actionSelected == 0)+ −
/* do nothing */ ;+ −
else if (actionSelected == actScrollHere)+ −
setValue(d_func()->pixelPosToRangeValue(horiz ? event->pos().x() : event->pos().y()));+ −
else if (actionSelected == actScrollTop)+ −
triggerAction(QAbstractSlider::SliderToMinimum);+ −
else if (actionSelected == actScrollBottom)+ −
triggerAction(QAbstractSlider::SliderToMaximum);+ −
else if (actionSelected == actPageUp)+ −
triggerAction(QAbstractSlider::SliderPageStepSub);+ −
else if (actionSelected == actPageDn)+ −
triggerAction(QAbstractSlider::SliderPageStepAdd);+ −
else if (actionSelected == actScrollUp)+ −
triggerAction(QAbstractSlider::SliderSingleStepSub);+ −
else if (actionSelected == actScrollDn)+ −
triggerAction(QAbstractSlider::SliderSingleStepAdd);+ −
#endif // QT_NO_MENU+ −
}+ −
#endif // QT_NO_CONTEXTMENU+ −
+ −
+ −
/*! \reimp */+ −
QSize QScrollBar::sizeHint() const+ −
{+ −
ensurePolished();+ −
QStyleOptionSlider opt;+ −
initStyleOption(&opt);+ −
+ −
int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this);+ −
int scrollBarSliderMin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, &opt, this);+ −
QSize size;+ −
if (opt.orientation == Qt::Horizontal)+ −
size = QSize(scrollBarExtent * 2 + scrollBarSliderMin, scrollBarExtent);+ −
else+ −
size = QSize(scrollBarExtent, scrollBarExtent * 2 + scrollBarSliderMin);+ −
+ −
return style()->sizeFromContents(QStyle::CT_ScrollBar, &opt, size, this)+ −
.expandedTo(QApplication::globalStrut());+ −
}+ −
+ −
/*!\reimp */+ −
void QScrollBar::sliderChange(SliderChange change)+ −
{+ −
QAbstractSlider::sliderChange(change);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
bool QScrollBar::event(QEvent *event)+ −
{+ −
switch(event->type()) {+ −
case QEvent::HoverEnter:+ −
case QEvent::HoverLeave:+ −
case QEvent::HoverMove:+ −
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))+ −
d_func()->updateHoverControl(he->pos());+ −
break;+ −
#ifndef QT_NO_WHEELEVENT+ −
case QEvent::Wheel: {+ −
// override wheel event without adding virtual function override+ −
QWheelEvent *ev = static_cast<QWheelEvent *>(event);+ −
int delta = ev->delta();+ −
// scrollbar is a special case - in vertical mode it reaches minimum+ −
// value in the upper position, however QSlider's minimum value is on+ −
// the bottom. So we need to invert a value, but since the scrollbar is+ −
// inverted by default, we need to inverse the delta value for the+ −
// horizontal orientation.+ −
if (ev->orientation() == Qt::Horizontal)+ −
delta = -delta;+ −
Q_D(QScrollBar);+ −
if (d->scrollByDelta(ev->orientation(), ev->modifiers(), delta))+ −
event->accept();+ −
return true;+ −
}+ −
#endif+ −
default:+ −
break;+ −
}+ −
return QAbstractSlider::event(event);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QScrollBar::paintEvent(QPaintEvent *)+ −
{+ −
Q_D(QScrollBar);+ −
QPainter p(this);+ −
QStyleOptionSlider opt;+ −
initStyleOption(&opt);+ −
opt.subControls = QStyle::SC_All;+ −
if (d->pressedControl) {+ −
opt.activeSubControls = (QStyle::SubControl)d->pressedControl;+ −
if (!d->pointerOutsidePressedControl)+ −
opt.state |= QStyle::State_Sunken;+ −
} else {+ −
opt.activeSubControls = (QStyle::SubControl)d->hoverControl;+ −
}+ −
style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QScrollBar::mousePressEvent(QMouseEvent *e)+ −
{+ −
Q_D(QScrollBar);+ −
+ −
if (d->repeatActionTimer.isActive())+ −
d->stopRepeatAction();+ −
+ −
bool midButtonAbsPos = style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition,+ −
0, this);+ −
QStyleOptionSlider opt;+ −
initStyleOption(&opt);+ −
+ −
if (d->maximum == d->minimum // no range+ −
|| (e->buttons() & (~e->button())) // another button was clicked before+ −
|| !(e->button() == Qt::LeftButton || (midButtonAbsPos && e->button() == Qt::MidButton)))+ −
return;+ −
+ −
d->pressedControl = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);+ −
d->pointerOutsidePressedControl = false;+ −
+ −
QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt,+ −
QStyle::SC_ScrollBarSlider, this);+ −
QPoint click = e->pos();+ −
QPoint pressValue = click - sr.center() + sr.topLeft();+ −
d->pressValue = d->orientation == Qt::Horizontal ? d->pixelPosToRangeValue(pressValue.x()) :+ −
d->pixelPosToRangeValue(pressValue.y());+ −
if (d->pressedControl == QStyle::SC_ScrollBarSlider) {+ −
d->clickOffset = HORIZONTAL ? (click.x()-sr.x()) : (click.y()-sr.y());+ −
d->snapBackPosition = d->position;+ −
}+ −
+ −
if ((d->pressedControl == QStyle::SC_ScrollBarAddPage+ −
|| d->pressedControl == QStyle::SC_ScrollBarSubPage)+ −
&& ((midButtonAbsPos && e->button() == Qt::MidButton)+ −
|| (style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition, &opt, this)+ −
&& e->button() == Qt::LeftButton))) {+ −
int sliderLength = HORIZONTAL ? sr.width() : sr.height();+ −
setSliderPosition(d->pixelPosToRangeValue((HORIZONTAL ? e->pos().x()+ −
: e->pos().y()) - sliderLength / 2));+ −
d->pressedControl = QStyle::SC_ScrollBarSlider;+ −
d->clickOffset = sliderLength / 2;+ −
}+ −
const int initialDelay = 500; // default threshold+ −
d->activateControl(d->pressedControl, initialDelay);+ −
QTime time;+ −
time.start();+ −
repaint(style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this));+ −
if (time.elapsed() >= initialDelay && d->repeatActionTimer.isActive()) {+ −
// It took more than 500ms (the initial timer delay) to process the repaint(), we+ −
// therefore need to restart the timer in case we have a pending mouse release event;+ −
// otherwise we'll get a timer event right before the release event,+ −
// causing the repeat action to be invoked twice on a single mouse click.+ −
// 50ms is the default repeat time (see activateControl/setRepeatAction).+ −
d->repeatActionTimer.start(50, this);+ −
}+ −
if (d->pressedControl == QStyle::SC_ScrollBarSlider)+ −
setSliderDown(true);+ −
}+ −
+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QScrollBar::mouseReleaseEvent(QMouseEvent *e)+ −
{+ −
Q_D(QScrollBar);+ −
if (!d->pressedControl)+ −
return;+ −
+ −
if (e->buttons() & (~e->button())) // some other button is still pressed+ −
return;+ −
+ −
d->stopRepeatAction();+ −
}+ −
+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QScrollBar::mouseMoveEvent(QMouseEvent *e)+ −
{+ −
Q_D(QScrollBar);+ −
if (!d->pressedControl)+ −
return;+ −
+ −
QStyleOptionSlider opt;+ −
initStyleOption(&opt);+ −
if (!(e->buttons() & Qt::LeftButton+ −
|| ((e->buttons() & Qt::MidButton)+ −
&& style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition, &opt, this))))+ −
return;+ −
+ −
if (d->pressedControl == QStyle::SC_ScrollBarSlider) {+ −
QPoint click = e->pos();+ −
int newPosition = d->pixelPosToRangeValue((HORIZONTAL ? click.x() : click.y()) -d->clickOffset);+ −
int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);+ −
if (m >= 0) {+ −
QRect r = rect();+ −
r.adjust(-m, -m, m, m);+ −
if (! r.contains(e->pos()))+ −
newPosition = d->snapBackPosition;+ −
}+ −
setSliderPosition(newPosition);+ −
} else if (!style()->styleHint(QStyle::SH_ScrollBar_ScrollWhenPointerLeavesControl, &opt, this)) {+ −
+ −
if (style()->styleHint(QStyle::SH_ScrollBar_RollBetweenButtons, &opt, this)+ −
&& d->pressedControl & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {+ −
QStyle::SubControl newSc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, e->pos(), this);+ −
if (newSc == d->pressedControl && !d->pointerOutsidePressedControl)+ −
return; // nothing to do+ −
if (newSc & (QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine)) {+ −
d->pointerOutsidePressedControl = false;+ −
QRect scRect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, newSc, this);+ −
scRect |= style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);+ −
d->pressedControl = newSc;+ −
d->activateControl(d->pressedControl, 0);+ −
update(scRect);+ −
return;+ −
}+ −
}+ −
+ −
// stop scrolling when the mouse pointer leaves a control+ −
// similar to push buttons+ −
QRect pr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, d->pressedControl, this);+ −
if (pr.contains(e->pos()) == d->pointerOutsidePressedControl) {+ −
if ((d->pointerOutsidePressedControl = !d->pointerOutsidePressedControl)) {+ −
d->pointerOutsidePressedControl = true;+ −
setRepeatAction(SliderNoAction);+ −
repaint(pr);+ −
} else {+ −
d->activateControl(d->pressedControl);+ −
}+ −
}+ −
}+ −
}+ −
+ −
+ −
int QScrollBarPrivate::pixelPosToRangeValue(int pos) const+ −
{+ −
Q_Q(const QScrollBar);+ −
QStyleOptionSlider opt;+ −
q->initStyleOption(&opt);+ −
QRect gr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,+ −
QStyle::SC_ScrollBarGroove, q);+ −
QRect sr = q->style()->subControlRect(QStyle::CC_ScrollBar, &opt,+ −
QStyle::SC_ScrollBarSlider, q);+ −
int sliderMin, sliderMax, sliderLength;+ −
+ −
if (orientation == Qt::Horizontal) {+ −
sliderLength = sr.width();+ −
sliderMin = gr.x();+ −
sliderMax = gr.right() - sliderLength + 1;+ −
if (q->layoutDirection() == Qt::RightToLeft)+ −
opt.upsideDown = !opt.upsideDown;+ −
} else {+ −
sliderLength = sr.height();+ −
sliderMin = gr.y();+ −
sliderMax = gr.bottom() - sliderLength + 1;+ −
}+ −
+ −
return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,+ −
sliderMax - sliderMin, opt.upsideDown);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QScrollBar::hideEvent(QHideEvent *)+ −
{+ −
Q_D(QScrollBar);+ −
if (d->pressedControl) {+ −
d->pressedControl = QStyle::SC_None;+ −
setRepeatAction(SliderNoAction);+ −
}+ −
}+ −
+ −
/*!+ −
\fn bool QScrollBar::draggingSlider()+ −
+ −
Use isSliderDown() instead.+ −
*/+ −
+ −
/*! \internal+ −
Returns the style option for scroll bar.+ −
*/+ −
Q_GUI_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollbar)+ −
{+ −
QStyleOptionSlider opt;+ −
scrollbar->initStyleOption(&opt);+ −
return opt;+ −
}+ −
+ −
QT_END_NAMESPACE+ −
+ −
#endif // QT_NO_SCROLLBAR+ −