summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qslider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qslider.cpp')
-rw-r--r--src/widgets/widgets/qslider.cpp666
1 files changed, 666 insertions, 0 deletions
diff --git a/src/widgets/widgets/qslider.cpp b/src/widgets/widgets/qslider.cpp
new file mode 100644
index 0000000000..7529c3c923
--- /dev/null
+++ b/src/widgets/widgets/qslider.cpp
@@ -0,0 +1,666 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qslider.h"
+#ifndef QT_NO_SLIDER
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include "qapplication.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "private/qabstractslider_p.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSliderPrivate : public QAbstractSliderPrivate
+{
+ Q_DECLARE_PUBLIC(QSlider)
+public:
+ QStyle::SubControl pressedControl;
+ int tickInterval;
+ QSlider::TickPosition tickPosition;
+ int clickOffset;
+ void init();
+ void resetLayoutItemMargins();
+ int pixelPosToRangeValue(int pos) const;
+ inline int pick(const QPoint &pt) const;
+
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+ bool updateHoverControl(const QPoint &pos);
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+};
+
+void QSliderPrivate::init()
+{
+ Q_Q(QSlider);
+ pressedControl = QStyle::SC_None;
+ tickInterval = 0;
+ tickPosition = QSlider::NoTicks;
+ hoverControl = QStyle::SC_None;
+ q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
+ QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::Slider);
+ if (orientation == Qt::Vertical)
+ sp.transpose();
+ q->setSizePolicy(sp);
+ q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
+ resetLayoutItemMargins();
+}
+
+void QSliderPrivate::resetLayoutItemMargins()
+{
+ Q_Q(QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ setLayoutItemMargins(QStyle::SE_SliderLayoutItem, &opt);
+}
+
+int QSliderPrivate::pixelPosToRangeValue(int pos) const
+{
+ Q_Q(const QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ QRect gr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
+ QRect sr = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
+ int sliderMin, sliderMax, sliderLength;
+
+ if (orientation == Qt::Horizontal) {
+ sliderLength = sr.width();
+ sliderMin = gr.x();
+ sliderMax = gr.right() - sliderLength + 1;
+ } else {
+ sliderLength = sr.height();
+ sliderMin = gr.y();
+ sliderMax = gr.bottom() - sliderLength + 1;
+ }
+ return QStyle::sliderValueFromPosition(minimum, maximum, pos - sliderMin,
+ sliderMax - sliderMin, opt.upsideDown);
+}
+
+inline int QSliderPrivate::pick(const QPoint &pt) const
+{
+ return orientation == Qt::Horizontal ? pt.x() : pt.y();
+}
+
+/*!
+ Initialize \a option with the values from this QSlider. 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 QSlider::initStyleOption(QStyleOptionSlider *option) const
+{
+ if (!option)
+ return;
+
+ Q_D(const QSlider);
+ option->initFrom(this);
+ option->subControls = QStyle::SC_None;
+ option->activeSubControls = QStyle::SC_None;
+ option->orientation = d->orientation;
+ option->maximum = d->maximum;
+ option->minimum = d->minimum;
+ option->tickPosition = (QSlider::TickPosition)d->tickPosition;
+ option->tickInterval = d->tickInterval;
+ option->upsideDown = (d->orientation == Qt::Horizontal) ?
+ (d->invertedAppearance != (option->direction == Qt::RightToLeft))
+ : (!d->invertedAppearance);
+ option->direction = Qt::LeftToRight; // we use the upsideDown option instead
+ option->sliderPosition = d->position;
+ option->sliderValue = d->value;
+ option->singleStep = d->singleStep;
+ option->pageStep = d->pageStep;
+ if (d->orientation == Qt::Horizontal)
+ option->state |= QStyle::State_Horizontal;
+}
+
+bool QSliderPrivate::updateHoverControl(const QPoint &pos)
+{
+ Q_Q(QSlider);
+ 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 QSliderPrivate::newHoverControl(const QPoint &pos)
+{
+ Q_Q(QSlider);
+ QStyleOptionSlider opt;
+ q->initStyleOption(&opt);
+ opt.subControls = QStyle::SC_All;
+ QRect handleRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, q);
+ QRect grooveRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, q);
+ QRect tickmarksRect = q->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderTickmarks, q);
+
+ if (handleRect.contains(pos)) {
+ hoverRect = handleRect;
+ hoverControl = QStyle::SC_SliderHandle;
+ } else if (grooveRect.contains(pos)) {
+ hoverRect = grooveRect;
+ hoverControl = QStyle::SC_SliderGroove;
+ } else if (tickmarksRect.contains(pos)) {
+ hoverRect = tickmarksRect;
+ hoverControl = QStyle::SC_SliderTickmarks;
+ } else {
+ hoverRect = QRect();
+ hoverControl = QStyle::SC_None;
+ }
+
+ return hoverControl;
+}
+
+/*!
+ \class QSlider
+ \brief The QSlider widget provides a vertical or horizontal slider.
+
+ \ingroup basicwidgets
+
+
+ The slider is the classic widget for controlling a bounded value.
+ It lets the user move a slider handle along a horizontal or vertical
+ groove and translates the handle's position into an integer value
+ within the legal range.
+
+ QSlider has very few of its own functions; most of the functionality is in
+ QAbstractSlider. The most useful functions are setValue() to set
+ the slider directly to some value; triggerAction() to simulate
+ the effects of clicking (useful for shortcut keys);
+ setSingleStep(), setPageStep() to set the steps; and setMinimum()
+ and setMaximum() to define the range of the scroll bar.
+
+ QSlider provides methods for controlling tickmarks. You can use
+ setTickPosition() to indicate where you want the tickmarks to be,
+ setTickInterval() to indicate how many of them you want. the
+ currently set tick position and interval can be queried using the
+ tickPosition() and tickInterval() functions, respectively.
+
+ QSlider inherits a comprehensive set of signals:
+ \table
+ \header \o Signal \o Description
+ \row \o \l valueChanged()
+ \o Emitted when the slider's value has changed. The tracking()
+ determines whether this signal is emitted during user
+ interaction.
+ \row \o \l sliderPressed()
+ \o Emitted when the user starts to drag the slider.
+ \row \o \l sliderMoved()
+ \o Emitted when the user drags the slider.
+ \row \o \l sliderReleased()
+ \o Emitted when the user releases the slider.
+ \endtable
+
+ QSlider only provides integer ranges. Note that although
+ QSlider handles very large numbers, it becomes difficult for users
+ to use a slider accurately for very large ranges.
+
+ A slider accepts focus on Tab and provides both a mouse wheel and a
+ keyboard interface. The keyboard interface is the following:
+
+ \list
+ \o Left/Right move a horizontal slider by one single step.
+ \o Up/Down move a vertical slider by one single step.
+ \o PageUp moves up one page.
+ \o PageDown moves down one page.
+ \o Home moves to the start (mininum).
+ \o End moves to the end (maximum).
+ \endlist
+
+ \table 100%
+ \row \o \inlineimage macintosh-slider.png Screenshot of a Macintosh slider
+ \o A slider shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \row \o \inlineimage windows-slider.png Screenshot of a Windows XP slider
+ \o A slider shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-slider.png Screenshot of a Plastique slider
+ \o A slider shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \endtable
+
+ \sa QScrollBar, QSpinBox, QDial, {fowler}{GUI Design Handbook: Slider}, {Sliders Example}
+*/
+
+
+/*!
+ \enum QSlider::TickPosition
+
+ This enum specifies where the tick marks are to be drawn relative
+ to the slider's groove and the handle the user moves.
+
+ \value NoTicks Do not draw any tick marks.
+ \value TicksBothSides Draw tick marks on both sides of the groove.
+ \value TicksAbove Draw tick marks above the (horizontal) slider
+ \value TicksBelow Draw tick marks below the (horizontal) slider
+ \value TicksLeft Draw tick marks to the left of the (vertical) slider
+ \value TicksRight Draw tick marks to the right of the (vertical) slider
+
+ \omitvalue NoMarks
+ \omitvalue Above
+ \omitvalue Left
+ \omitvalue Below
+ \omitvalue Right
+ \omitvalue Both
+*/
+
+
+/*!
+ Constructs a vertical slider with the given \a parent.
+*/
+QSlider::QSlider(QWidget *parent)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Constructs a slider with the given \a parent. The \a orientation
+ parameter determines whether the slider is horizontal or vertical;
+ the valid values are Qt::Vertical and Qt::Horizontal.
+*/
+
+QSlider::QSlider(Qt::Orientation orientation, QWidget *parent)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use QSlider() and QObject::setObjectName() instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(parent);
+ mySlider->setObjectName(name);
+ \endcode
+*/
+QSlider::QSlider(QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = Qt::Vertical;
+ d_func()->init();
+}
+
+/*!
+ Use QSlider() and QObject::setObjectName() instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(orientation, parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(orientation, parent);
+ mySlider->setObjectName(name);
+ \endcode
+*/
+QSlider::QSlider(Qt::Orientation orientation, QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ setObjectName(QString::fromAscii(name));
+ d_func()->orientation = orientation;
+ d_func()->init();
+}
+
+/*!
+ Use QSlider(), QObject::setObjectName() and the functionality
+ inherited from QAbstractSlider instead.
+
+ \oldcode
+ QSlider *mySlider = new QSlider(minValue, maxValue, pageStep,
+ value, orientation, parent, name);
+ \newcode
+ QSlider *mySlider = new QSlider(orientation, parent);
+ mySlider->setObjectName(name);
+ mySlider->setMinimum(minValue);
+ mySlider->setMaximum(maxValue);
+ mySlider->setPageStep(pageStep);
+ mySlider->setValue(value);
+ \endcode
+*/
+QSlider::QSlider(int minValue, int maxValue, int pageStep, int value, Qt::Orientation orientation,
+ QWidget *parent, const char *name)
+ : QAbstractSlider(*new QSliderPrivate, parent)
+{
+ Q_D(QSlider);
+ setObjectName(QString::fromAscii(name));
+ d->minimum = minValue;
+ d->maximum = maxValue;
+ d->pageStep = pageStep;
+ d->position = d->value = value;
+ d->orientation = orientation;
+ d->init();
+}
+#endif
+
+/*!
+ Destroys this slider.
+*/
+QSlider::~QSlider()
+{
+}
+
+/*!
+ \reimp
+*/
+void QSlider::paintEvent(QPaintEvent *)
+{
+ Q_D(QSlider);
+ QPainter p(this);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+
+ opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
+ if (d->tickPosition != NoTicks)
+ opt.subControls |= QStyle::SC_SliderTickmarks;
+ if (d->pressedControl) {
+ opt.activeSubControls = d->pressedControl;
+ opt.state |= QStyle::State_Sunken;
+ } else {
+ opt.activeSubControls = d->hoverControl;
+ }
+
+ style()->drawComplexControl(QStyle::CC_Slider, &opt, &p, this);
+}
+
+/*!
+ \reimp
+*/
+
+bool QSlider::event(QEvent *event)
+{
+ Q_D(QSlider);
+
+ switch(event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave:
+ case QEvent::HoverMove:
+ if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
+ d->updateHoverControl(he->pos());
+ break;
+ case QEvent::StyleChange:
+ case QEvent::MacSizeChange:
+ d->resetLayoutItemMargins();
+ break;
+ default:
+ break;
+ }
+ return QAbstractSlider::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QSlider::mousePressEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->maximum == d->minimum || (ev->buttons() ^ ev->button())) {
+ ev->ignore();
+ return;
+ }
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ setEditFocus(true);
+#endif
+ ev->accept();
+ if ((ev->button() & style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons)) == ev->button()) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ const QPoint center = sliderRect.center() - sliderRect.topLeft();
+ // to take half of the slider off for the setSliderPosition call we use the center - topLeft
+
+ setSliderPosition(d->pixelPosToRangeValue(d->pick(ev->pos() - center)));
+ triggerAction(SliderMove);
+ setRepeatAction(SliderNoAction);
+ d->pressedControl = QStyle::SC_SliderHandle;
+ update();
+ } else if ((ev->button() & style()->styleHint(QStyle::SH_Slider_PageSetButtons)) == ev->button()) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ d->pressedControl = style()->hitTestComplexControl(QStyle::CC_Slider,
+ &opt, ev->pos(), this);
+ SliderAction action = SliderNoAction;
+ if (d->pressedControl == QStyle::SC_SliderGroove) {
+ const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ int pressValue = d->pixelPosToRangeValue(d->pick(ev->pos() - sliderRect.center() + sliderRect.topLeft()));
+ d->pressValue = pressValue;
+ if (pressValue > d->value)
+ action = SliderPageStepAdd;
+ else if (pressValue < d->value)
+ action = SliderPageStepSub;
+ if (action) {
+ triggerAction(action);
+ setRepeatAction(action);
+ }
+ }
+ } else {
+ ev->ignore();
+ return;
+ }
+
+ if (d->pressedControl == QStyle::SC_SliderHandle) {
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ setRepeatAction(SliderNoAction);
+ QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
+ d->clickOffset = d->pick(ev->pos() - sr.topLeft());
+ update(sr);
+ setSliderDown(true);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSlider::mouseMoveEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->pressedControl != QStyle::SC_SliderHandle) {
+ ev->ignore();
+ return;
+ }
+ ev->accept();
+ int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ setSliderPosition(newPosition);
+}
+
+
+/*!
+ \reimp
+*/
+void QSlider::mouseReleaseEvent(QMouseEvent *ev)
+{
+ Q_D(QSlider);
+ if (d->pressedControl == QStyle::SC_None || ev->buttons()) {
+ ev->ignore();
+ return;
+ }
+ ev->accept();
+ QStyle::SubControl oldPressed = QStyle::SubControl(d->pressedControl);
+ d->pressedControl = QStyle::SC_None;
+ setRepeatAction(SliderNoAction);
+ if (oldPressed == QStyle::SC_SliderHandle)
+ setSliderDown(false);
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ opt.subControls = oldPressed;
+ update(style()->subControlRect(QStyle::CC_Slider, &opt, oldPressed, this));
+}
+
+/*!
+ \reimp
+*/
+QSize QSlider::sizeHint() const
+{
+ Q_D(const QSlider);
+ ensurePolished();
+ const int SliderLength = 84, TickSpace = 5;
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ int thick = style()->pixelMetric(QStyle::PM_SliderThickness, &opt, this);
+ if (d->tickPosition & TicksAbove)
+ thick += TickSpace;
+ if (d->tickPosition & TicksBelow)
+ thick += TickSpace;
+ int w = thick, h = SliderLength;
+ if (d->orientation == Qt::Horizontal) {
+ w = SliderLength;
+ h = thick;
+ }
+ return style()->sizeFromContents(QStyle::CT_Slider, &opt, QSize(w, h), this).expandedTo(QApplication::globalStrut());
+}
+
+/*!
+ \reimp
+*/
+QSize QSlider::minimumSizeHint() const
+{
+ Q_D(const QSlider);
+ QSize s = sizeHint();
+ QStyleOptionSlider opt;
+ initStyleOption(&opt);
+ int length = style()->pixelMetric(QStyle::PM_SliderLength, &opt, this);
+ if (d->orientation == Qt::Horizontal)
+ s.setWidth(length);
+ else
+ s.setHeight(length);
+ return s;
+}
+
+/*!
+ \property QSlider::tickPosition
+ \brief the tickmark position for this slider
+
+ The valid values are described by the QSlider::TickPosition enum.
+
+ The default value is \l QSlider::NoTicks.
+
+ \sa tickInterval
+*/
+
+void QSlider::setTickPosition(TickPosition position)
+{
+ Q_D(QSlider);
+ d->tickPosition = position;
+ d->resetLayoutItemMargins();
+ update();
+ updateGeometry();
+}
+
+QSlider::TickPosition QSlider::tickPosition() const
+{
+ return d_func()->tickPosition;
+}
+
+/*!
+ \fn TickPosition QSlider::tickmarks() const
+ \compat
+
+ Use tickPosition() instead.
+*/
+
+/*!
+ \fn QSlider::setTickmarks(TickPosition position)
+ \compat
+
+ Use setTickPosition() instead.
+*/
+
+/*!
+ \property QSlider::tickInterval
+ \brief the interval between tickmarks
+
+ This is a value interval, not a pixel interval. If it is 0, the
+ slider will choose between singleStep() and pageStep().
+
+ The default value is 0.
+
+ \sa tickPosition, lineStep(), pageStep()
+*/
+
+void QSlider::setTickInterval(int ts)
+{
+ d_func()->tickInterval = qMax(0, ts);
+ update();
+}
+
+int QSlider::tickInterval() const
+{
+ return d_func()->tickInterval;
+}
+
+/*!
+ \fn void QSlider::addStep()
+
+ Use setValue() instead.
+*/
+
+/*!
+ \fn void QSlider::subtractStep()
+
+ Use setValue() instead.
+*/
+
+/*! \internal
+ Returns the style option for slider.
+*/
+Q_GUI_EXPORT QStyleOptionSlider qt_qsliderStyleOption(QSlider *slider)
+{
+ QStyleOptionSlider sliderOption;
+ slider->initStyleOption(&sliderOption);
+ return sliderOption;
+}
+
+#endif
+
+QT_END_NAMESPACE