| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, you may use this file under the terms of the BSD license |
| ** as follows: |
| ** |
| ** "Redistribution and use in source and binary forms, with or without |
| ** modification, are permitted provided that the following conditions are |
| ** met: |
| ** * Redistributions of source code must retain the above copyright |
| ** notice, this list of conditions and the following disclaimer. |
| ** * Redistributions in binary form must reproduce the above copyright |
| ** notice, this list of conditions and the following disclaimer in |
| ** the documentation and/or other materials provided with the |
| ** distribution. |
| ** * Neither the name of The Qt Company Ltd nor the names of its |
| ** contributors may be used to endorse or promote products derived |
| ** from this software without specific prior written permission. |
| ** |
| ** |
| ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| QAbstractSliderPrivate::QAbstractSliderPrivate() |
| : minimum(0), maximum(99), singleStep(1), pageStep(10), |
| value(0), position(0), pressValue(-1), tracking(true), blocktracking(false), pressed(false), |
| invertedAppearance(false), invertedControls(false), |
| orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction) |
| { |
| } |
| |
| QAbstractSliderPrivate::~QAbstractSliderPrivate() |
| { |
| } |
| |
| void QAbstractSlider::setRange(int min, int max) |
| { |
| Q_D(QAbstractSlider); |
| int oldMin = d->minimum; |
| int oldMax = d->maximum; |
| d->minimum = min; |
| d->maximum = qMax(min, max); |
| if (oldMin != d->minimum || oldMax != d->maximum) { |
| sliderChange(SliderRangeChange); |
| emit rangeChanged(d->minimum, d->maximum); |
| setValue(d->value); // re-bound |
| } |
| } |
| |
| |
| void QAbstractSliderPrivate::setSteps(int single, int page) |
| { |
| Q_Q(QAbstractSlider); |
| singleStep = qAbs(single); |
| pageStep = qAbs(page); |
| q->sliderChange(QAbstractSlider::SliderStepsChange); |
| } |
| |
| AbstractSlider::QAbstractSlider(QWidget *parent) |
| :QWidget(*new QAbstractSliderPrivate, parent, 0) |
| { |
| } |
| |
| QAbstractSlider::QAbstractSlider(QAbstractSliderPrivate &dd, QWidget *parent) |
| :QWidget(dd, parent, 0) |
| { |
| } |
| |
| QAbstractSlider::~QAbstractSlider() |
| { |
| } |
| |
| void QAbstractSlider::setOrientation(Qt::Orientation orientation) |
| { |
| Q_D(QAbstractSlider); |
| if (d->orientation == orientation) |
| return; |
| |
| d->orientation = orientation; |
| if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) { |
| QSizePolicy sp = sizePolicy(); |
| sp.transpose(); |
| setSizePolicy(sp); |
| setAttribute(Qt::WA_WState_OwnSizePolicy, false); |
| } |
| update(); |
| updateGeometry(); |
| } |
| |
| Qt::Orientation QAbstractSlider::orientation() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->orientation; |
| } |
| |
| |
| void QAbstractSlider::setMinimum(int min) |
| { |
| Q_D(QAbstractSlider); |
| setRange(min, qMax(d->maximum, min)); |
| } |
| |
| int QAbstractSlider::minimum() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->minimum; |
| } |
| |
| |
| void QAbstractSlider::setMaximum(int max) |
| { |
| Q_D(QAbstractSlider); |
| setRange(qMin(d->minimum, max), max); |
| } |
| |
| int QAbstractSlider::maximum() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->maximum; |
| } |
| |
| |
| |
| void QAbstractSlider::setSingleStep(int step) |
| { |
| Q_D(QAbstractSlider); |
| d->setSteps(step, d->pageStep); |
| } |
| |
| int QAbstractSlider::singleStep() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->singleStep; |
| } |
| |
| |
| void QAbstractSlider::setPageStep(int step) |
| { |
| Q_D(QAbstractSlider); |
| d->setSteps(d->singleStep, step); |
| } |
| |
| int QAbstractSlider::pageStep() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->pageStep; |
| } |
| |
| oid QAbstractSlider::setTracking(bool enable) |
| { |
| Q_D(QAbstractSlider); |
| d->tracking = enable; |
| } |
| |
| bool QAbstractSlider::hasTracking() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->tracking; |
| } |
| |
| |
| |
| void QAbstractSlider::setSliderDown(bool down) |
| { |
| Q_D(QAbstractSlider); |
| bool doEmit = d->pressed != down; |
| |
| d->pressed = down; |
| |
| if (doEmit) { |
| if (down) |
| emit sliderPressed(); |
| else |
| emit sliderReleased(); |
| } |
| |
| if (!down && d->position != d->value) |
| triggerAction(SliderMove); |
| } |
| |
| bool QAbstractSlider::isSliderDown() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->pressed; |
| } |
| |
| |
| void QAbstractSlider::setSliderPosition(int position) |
| { |
| Q_D(QAbstractSlider); |
| position = d->bound(position); |
| if (position == d->position) |
| return; |
| d->position = position; |
| if (!d->tracking) |
| update(); |
| if (d->pressed) |
| emit sliderMoved(position); |
| if (d->tracking && !d->blocktracking) |
| triggerAction(SliderMove); |
| } |
| |
| int QAbstractSlider::sliderPosition() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->position; |
| } |
| |
| |
| |
| int QAbstractSlider::value() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->value; |
| } |
| |
| //! [0] |
| void QAbstractSlider::setValue(int value) |
| //! [0] |
| { |
| Q_D(QAbstractSlider); |
| value = d->bound(value); |
| if (d->value == value && d->position == value) |
| return; |
| d->value = value; |
| if (d->position != value) { |
| d->position = value; |
| if (d->pressed) |
| emit sliderMoved((d->position = value)); |
| } |
| #ifndef QT_NO_ACCESSIBILITY |
| //! [1] |
| QAccessibleValueChangeEvent event(this, d->value); |
| QAccessible::updateAccessibility(&event); |
| //! [1] |
| #endif |
| sliderChange(SliderValueChange); |
| emit valueChanged(value); |
| //! [2] |
| } |
| //! [2] |
| |
| bool QAbstractSlider::invertedAppearance() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->invertedAppearance; |
| } |
| |
| void QAbstractSlider::setInvertedAppearance(bool invert) |
| { |
| Q_D(QAbstractSlider); |
| d->invertedAppearance = invert; |
| update(); |
| } |
| |
| |
| |
| bool QAbstractSlider::invertedControls() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->invertedControls; |
| } |
| |
| void QAbstractSlider::setInvertedControls(bool invert) |
| { |
| Q_D(QAbstractSlider); |
| d->invertedControls = invert; |
| } |
| |
| void QAbstractSlider::triggerAction(SliderAction action) |
| { |
| Q_D(QAbstractSlider); |
| d->blocktracking = true; |
| switch (action) { |
| case SliderSingleStepAdd: |
| setSliderPosition(d->value + d->singleStep); |
| break; |
| case SliderSingleStepSub: |
| setSliderPosition(d->value - d->singleStep); |
| break; |
| case SliderPageStepAdd: |
| setSliderPosition(d->value + d->pageStep); |
| break; |
| case SliderPageStepSub: |
| setSliderPosition(d->value - d->pageStep); |
| break; |
| case SliderToMinimum: |
| setSliderPosition(d->minimum); |
| break; |
| case SliderToMaximum: |
| setSliderPosition(d->maximum); |
| break; |
| case SliderMove: |
| case SliderNoAction: |
| break; |
| }; |
| emit actionTriggered(action); |
| d->blocktracking = false; |
| setValue(d->position); |
| } |
| |
| void QAbstractSlider::setRepeatAction(SliderAction action, int thresholdTime, int repeatTime) |
| { |
| Q_D(QAbstractSlider); |
| if ((d->repeatAction = action) == SliderNoAction) { |
| d->repeatActionTimer.stop(); |
| } else { |
| d->repeatActionTime = repeatTime; |
| d->repeatActionTimer.start(thresholdTime, this); |
| } |
| } |
| |
| QAbstractSlider::SliderAction QAbstractSlider::repeatAction() const |
| { |
| Q_D(const QAbstractSlider); |
| return d->repeatAction; |
| } |
| |
| void QAbstractSlider::timerEvent(QTimerEvent *e) |
| { |
| Q_D(QAbstractSlider); |
| if (e->timerId() == d->repeatActionTimer.timerId()) { |
| if (d->repeatActionTime) { // was threshold time, use repeat time next time |
| d->repeatActionTimer.start(d->repeatActionTime, this); |
| d->repeatActionTime = 0; |
| } |
| if (d->repeatAction == SliderPageStepAdd) |
| d->setAdjustedSliderPosition(d->value + d->pageStep); |
| else if (d->repeatAction == SliderPageStepSub) |
| d->setAdjustedSliderPosition(d->value - d->pageStep); |
| else |
| triggerAction(d->repeatAction); |
| } |
| } |
| |
| oid QAbstractSlider::sliderChange(SliderChange) |
| { |
| update(); |
| } |
| |
| |
| #ifndef QT_NO_WHEELEVENT |
| void QAbstractSlider::wheelEvent(QWheelEvent * e) |
| { |
| Q_D(QAbstractSlider); |
| e->ignore(); |
| if (e->orientation() != d->orientation && !rect().contains(e->pos())) |
| return; |
| |
| static qreal offset = 0; |
| static QAbstractSlider *offset_owner = 0; |
| if (offset_owner != this){ |
| offset_owner = this; |
| offset = 0; |
| } |
| |
| int step = qMin(QApplication::wheelScrollLines() * d->singleStep, d->pageStep); |
| if ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::ShiftModifier)) |
| step = d->pageStep; |
| offset += e->delta() * step / 120; |
| if (d->invertedControls) |
| offset = -offset; |
| |
| if (qAbs(offset) < 1) |
| return; |
| |
| int prevValue = d->value; |
| d->position = d->value + int(offset); // value will be updated by triggerAction() |
| triggerAction(SliderMove); |
| if (prevValue == d->value) { |
| offset = 0; |
| } else { |
| offset -= int(offset); |
| e->accept(); |
| } |
| } |
| #endif |
| void QAbstractSlider::keyPressEvent(QKeyEvent *ev) |
| { |
| Q_D(QAbstractSlider); |
| SliderAction action = SliderNoAction; |
| switch (ev->key()) { |
| #ifdef QT_KEYPAD_NAVIGATION |
| case Qt::Key_Select: |
| if (QApplication::keypadNavigationEnabled()) |
| setEditFocus(!hasEditFocus()); |
| else |
| ev->ignore(); |
| break; |
| case Qt::Key_Back: |
| if (QApplication::keypadNavigationEnabled() && hasEditFocus()) { |
| setValue(d->origValue); |
| setEditFocus(false); |
| } else |
| ev->ignore(); |
| break; |
| #endif |
| |
| // It seems we need to use invertedAppearance for Left and right, otherwise, things look weird. |
| case Qt::Key_Left: |
| #ifdef QT_KEYPAD_NAVIGATION |
| if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { |
| ev->ignore(); |
| return; |
| } |
| if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical) |
| action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd; |
| else |
| #endif |
| action = !d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd; |
| break; |
| case Qt::Key_Right: |
| #ifdef QT_KEYPAD_NAVIGATION |
| if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { |
| ev->ignore(); |
| return; |
| } |
| if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical) |
| action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub; |
| else |
| #endif |
| action = !d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub; |
| break; |
| case Qt::Key_Up: |
| #ifdef QT_KEYPAD_NAVIGATION |
| if (QApplication::keypadNavigationEnabled()) { |
| ev->ignore(); |
| break; |
| } |
| #endif |
| action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd; |
| break; |
| case Qt::Key_Down: |
| #ifdef QT_KEYPAD_NAVIGATION |
| if (QApplication::keypadNavigationEnabled()) { |
| ev->ignore(); |
| break; |
| } |
| #endif |
| action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub; |
| break; |
| case Qt::Key_PageUp: |
| action = d->invertedControls ? SliderPageStepSub : SliderPageStepAdd; |
| break; |
| case Qt::Key_PageDown: |
| action = d->invertedControls ? SliderPageStepAdd : SliderPageStepSub; |
| break; |
| case Qt::Key_Home: |
| action = SliderToMinimum; |
| break; |
| case Qt::Key_End: |
| action = SliderToMaximum; |
| break; |
| default: |
| ev->ignore(); |
| break; |
| } |
| if (action) |
| triggerAction(action); |
| } |
| |
| void QAbstractSlider::changeEvent(QEvent *ev) |
| { |
| Q_D(QAbstractSlider); |
| switch (ev->type()) { |
| case QEvent::EnabledChange: |
| if (!isEnabled()) { |
| d->repeatActionTimer.stop(); |
| setSliderDown(false); |
| } |
| // fall through... |
| default: |
| QWidget::changeEvent(ev); |
| } |
| } |
| |
| bool QAbstractSlider::event(QEvent *e) |
| { |
| #ifdef QT_KEYPAD_NAVIGATION |
| Q_D(QAbstractSlider); |
| switch (e->type()) { |
| case QEvent::FocusIn: |
| d->origValue = d->value; |
| break; |
| default: |
| break; |
| } |
| #endif |
| |
| return QWidget::event(e); |
| } |
| |
| |