File indexing completed on 2024-05-19 15:02:21
0001 #include "qxtspanslider.h" 0002 /**************************************************************************** 0003 ** Copyright (c) 2006 - 2011, the LibQxt project. 0004 ** See the Qxt AUTHORS file for a list of authors and copyright holders. 0005 ** All rights reserved. 0006 ** 0007 ** Redistribution and use in source and binary forms, with or without 0008 ** modification, are permitted provided that the following conditions are met: 0009 ** * Redistributions of source code must retain the above copyright 0010 ** notice, this list of conditions and the following disclaimer. 0011 ** * Redistributions in binary form must reproduce the above copyright 0012 ** notice, this list of conditions and the following disclaimer in the 0013 ** documentation and/or other materials provided with the distribution. 0014 ** * Neither the name of the LibQxt project nor the 0015 ** names of its contributors may be used to endorse or promote products 0016 ** derived from this software without specific prior written permission. 0017 ** 0018 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 0019 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 0020 ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 0021 ** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 0022 ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 0023 ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 0024 ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 0025 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0026 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 0027 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0028 ** 0029 ** <http://libqxt.org> <foundation@libqxt.org> 0030 *****************************************************************************/ 0031 0032 #include "qxtspanslider_p.h" 0033 #include <QKeyEvent> 0034 #include <QMouseEvent> 0035 #include <QStylePainter> 0036 #include <QStyleOptionSlider> 0037 0038 QxtSpanSliderPrivate::QxtSpanSliderPrivate() : 0039 lower(0), 0040 upper(0), 0041 lowerPos(0), 0042 upperPos(0), 0043 offset(0), 0044 position(0), 0045 lastPressed(QxtSpanSlider::NoHandle), 0046 mainControl(QxtSpanSlider::LowerHandle), 0047 lowerPressed(QStyle::SC_None), 0048 upperPressed(QStyle::SC_None), 0049 movement(QxtSpanSlider::FreeMovement), 0050 firstMovement(false), 0051 blockTracking(false) { 0052 } 0053 0054 void QxtSpanSliderPrivate::initStyleOption(QStyleOptionSlider* option, QxtSpanSlider::SpanHandle handle) const { 0055 const QxtSpanSlider* p = &qxt_p(); 0056 p->initStyleOption(option); 0057 option->sliderPosition = (handle == QxtSpanSlider::LowerHandle ? lowerPos : upperPos); 0058 option->sliderValue = (handle == QxtSpanSlider::LowerHandle ? lower : upper); 0059 } 0060 0061 int QxtSpanSliderPrivate::pixelPosToRangeValue(int pos) const { 0062 QStyleOptionSlider opt; 0063 initStyleOption(&opt); 0064 0065 int sliderMin = 0; 0066 int sliderMax = 0; 0067 int sliderLength = 0; 0068 const QSlider* p = &qxt_p(); 0069 const QRect gr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p); 0070 const QRect sr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, p); 0071 if (p->orientation() == Qt::Horizontal) { 0072 sliderLength = sr.width(); 0073 sliderMin = gr.x(); 0074 sliderMax = gr.right() - sliderLength + 1; 0075 } else { 0076 sliderLength = sr.height(); 0077 sliderMin = gr.y(); 0078 sliderMax = gr.bottom() - sliderLength + 1; 0079 } 0080 return QStyle::sliderValueFromPosition(p->minimum(), p->maximum(), pos - sliderMin, 0081 sliderMax - sliderMin, opt.upsideDown); 0082 } 0083 0084 void QxtSpanSliderPrivate::handleMousePress(QPoint pos, QStyle::SubControl& control, int value, QxtSpanSlider::SpanHandle handle) { 0085 QStyleOptionSlider opt; 0086 initStyleOption(&opt, handle); 0087 QxtSpanSlider* p = &qxt_p(); 0088 const QStyle::SubControl oldControl = control; 0089 control = p->style()->hitTestComplexControl(QStyle::CC_Slider, &opt, pos, p); 0090 const QRect sr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, p); 0091 if (control == QStyle::SC_SliderHandle) { 0092 position = value; 0093 offset = pick(pos - sr.topLeft()); 0094 lastPressed = handle; 0095 p->setSliderDown(true); 0096 emit p->sliderPressed(handle); 0097 } 0098 if (control != oldControl) 0099 p->update(sr); 0100 } 0101 0102 void QxtSpanSliderPrivate::setupPainter(QPainter* painter, Qt::Orientation orientation, qreal x1, qreal y1, qreal x2, qreal y2) const { 0103 QColor highlight = qxt_p().palette().color(QPalette::Highlight); 0104 QLinearGradient gradient(x1, y1, x2, y2); 0105 gradient.setColorAt(0, highlight.darker(120)); 0106 gradient.setColorAt(1, highlight.lighter(108)); 0107 painter->setBrush(gradient); 0108 0109 if (orientation == Qt::Horizontal) 0110 painter->setPen(QPen(highlight.darker(130), 0)); 0111 else 0112 painter->setPen(QPen(highlight.darker(150), 0)); 0113 } 0114 0115 void QxtSpanSliderPrivate::drawSpan(QStylePainter* painter, QRect rect) const { 0116 QStyleOptionSlider opt; 0117 initStyleOption(&opt); 0118 const QSlider* p = &qxt_p(); 0119 0120 // area 0121 QRect groove = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p); 0122 if (opt.orientation == Qt::Horizontal) 0123 groove.adjust(0, 0, -1, 0); 0124 else 0125 groove.adjust(0, 0, 0, -1); 0126 0127 // pen & brush 0128 painter->setPen(QPen(p->palette().color(QPalette::Dark).lighter(110), 0)); 0129 if (opt.orientation == Qt::Horizontal) 0130 setupPainter(painter, opt.orientation, groove.center().x(), groove.top(), groove.center().x(), groove.bottom()); 0131 else 0132 setupPainter(painter, opt.orientation, groove.left(), groove.center().y(), groove.right(), groove.center().y()); 0133 0134 // draw groove 0135 painter->drawRect(rect.intersected(groove)); 0136 } 0137 0138 void QxtSpanSliderPrivate::drawHandle(QStylePainter* painter, QxtSpanSlider::SpanHandle handle) const { 0139 QStyleOptionSlider opt; 0140 initStyleOption(&opt, handle); 0141 opt.subControls = QStyle::SC_SliderHandle; 0142 QStyle::SubControl pressed = (handle == QxtSpanSlider::LowerHandle ? lowerPressed : upperPressed); 0143 if (pressed == QStyle::SC_SliderHandle) { 0144 opt.activeSubControls = pressed; 0145 opt.state |= QStyle::State_Sunken; 0146 } 0147 painter->drawComplexControl(QStyle::CC_Slider, opt); 0148 } 0149 0150 void QxtSpanSliderPrivate::triggerAction(QAbstractSlider::SliderAction action, bool main) { 0151 int value = 0; 0152 bool update = true; 0153 bool isUpperHandle = false; 0154 const int min = qxt_p().minimum(); 0155 const int max = qxt_p().maximum(); 0156 const QxtSpanSlider::SpanHandle altControl = (mainControl == QxtSpanSlider::LowerHandle ? QxtSpanSlider::UpperHandle : QxtSpanSlider::LowerHandle); 0157 0158 blockTracking = true; 0159 0160 switch (action) { 0161 case QAbstractSlider::SliderSingleStepAdd: 0162 if ((main && mainControl == QxtSpanSlider::UpperHandle) || (!main && altControl == QxtSpanSlider::UpperHandle)) { 0163 value = qBound(min, upper + qxt_p().singleStep(), max); 0164 isUpperHandle = true; 0165 } else { 0166 value = qBound(min, lower + qxt_p().singleStep(), max); 0167 } 0168 break; 0169 case QAbstractSlider::SliderSingleStepSub: 0170 if ((main && mainControl == QxtSpanSlider::UpperHandle) || (!main && altControl == QxtSpanSlider::UpperHandle)) { 0171 value = qBound(min, upper - qxt_p().singleStep(), max); 0172 isUpperHandle = true; 0173 } else { 0174 value = qBound(min, lower - qxt_p().singleStep(), max); 0175 } 0176 break; 0177 case QAbstractSlider::SliderToMinimum: 0178 value = min; 0179 if ((main && mainControl == QxtSpanSlider::UpperHandle) || (!main && altControl == QxtSpanSlider::UpperHandle)) 0180 isUpperHandle = true; 0181 break; 0182 case QAbstractSlider::SliderToMaximum: 0183 value = max; 0184 if ((main && mainControl == QxtSpanSlider::UpperHandle) || (!main && altControl == QxtSpanSlider::UpperHandle)) 0185 isUpperHandle = true; 0186 break; 0187 case QAbstractSlider::SliderMove: 0188 // This is handled not here, but in QxtSpanSlider::mouseMoveEvent 0189 // so update not needed 0190 update = false; 0191 break; 0192 case QAbstractSlider::SliderNoAction: 0193 update = false; 0194 break; 0195 case QAbstractSlider::SliderPageStepAdd: 0196 case QAbstractSlider::SliderPageStepSub: 0197 break; 0198 } 0199 0200 if (update) { 0201 if ( isUpperHandle ) { 0202 if (movement == QxtSpanSlider::NoCrossing) 0203 value = qMin(value, upper); 0204 else if (movement == QxtSpanSlider::NoOverlapping) 0205 value = qMin(value, upper - 1); 0206 0207 if (movement == QxtSpanSlider::FreeMovement && value < lower) { 0208 swapControls(); 0209 qxt_p().setLowerPosition(value); 0210 } else 0211 qxt_p().setUpperPosition(value); 0212 } else { 0213 if (movement == QxtSpanSlider::NoCrossing) 0214 value = qMax(value, lower); 0215 else if (movement == QxtSpanSlider::NoOverlapping) 0216 value = qMax(value, lower + 1); 0217 0218 if (movement == QxtSpanSlider::FreeMovement && value > upper) { 0219 swapControls(); 0220 qxt_p().setUpperPosition(value); 0221 } else 0222 qxt_p().setLowerPosition(value); 0223 } 0224 } 0225 0226 blockTracking = false; 0227 qxt_p().setLowerValue(lowerPos); 0228 qxt_p().setUpperValue(upperPos); 0229 } 0230 0231 void QxtSpanSliderPrivate::swapControls() { 0232 qSwap(lower, upper); 0233 qSwap(lowerPressed, upperPressed); 0234 lastPressed = (lastPressed == QxtSpanSlider::LowerHandle ? QxtSpanSlider::UpperHandle : QxtSpanSlider::LowerHandle); 0235 mainControl = (mainControl == QxtSpanSlider::LowerHandle ? QxtSpanSlider::UpperHandle : QxtSpanSlider::LowerHandle); 0236 } 0237 0238 void QxtSpanSliderPrivate::updateRange(int min, int max) { 0239 Q_UNUSED(min); 0240 Q_UNUSED(max); 0241 // setSpan() takes care of keeping span in range 0242 qxt_p().setSpan(lower, upper); 0243 } 0244 0245 void QxtSpanSliderPrivate::movePressedHandle() { 0246 switch (lastPressed) { 0247 case QxtSpanSlider::LowerHandle: 0248 if (lowerPos != lower) { 0249 bool main = (mainControl == QxtSpanSlider::LowerHandle); 0250 triggerAction(QAbstractSlider::SliderMove, main); 0251 } 0252 break; 0253 case QxtSpanSlider::UpperHandle: 0254 if (upperPos != upper) { 0255 bool main = (mainControl == QxtSpanSlider::UpperHandle); 0256 triggerAction(QAbstractSlider::SliderMove, main); 0257 } 0258 break; 0259 case QxtSpanSlider::NoHandle: 0260 break; 0261 } 0262 } 0263 0264 /*! 0265 \class QxtSpanSlider 0266 \inmodule QxtWidgets 0267 \brief The QxtSpanSlider widget is a QSlider with two handles. 0268 0269 QxtSpanSlider is a slider with two handles. QxtSpanSlider is 0270 handy for letting user to choose an span between min/max. 0271 0272 The span color is calculated based on QPalette::Highlight. 0273 0274 The keys are bound according to the following table: 0275 <table> 0276 <tr><th>Orientation <th>Key <th>Handle 0277 <tr><td>Qt::Horizontal <td>Qt::Key_Left <td>lower 0278 <tr><td>Qt::Horizontal <td>Qt::Key_Right <td>lower 0279 <tr><td>Qt::Horizontal <td>Qt::Key_Up <td>upper 0280 <tr><td>Qt::Horizontal <td>Qt::Key_Down <td>upper 0281 <tr><td>Qt::Vertical <td>Qt::Key_Up <td>lower 0282 <tr><td>Qt::Vertical <td>Qt::Key_Down <td>lower 0283 <tr><td>Qt::Vertical <td>Qt::Key_Left <td>upper 0284 <tr><td>Qt::Vertical <td>Qt::Key_Right <td>upper 0285 </table> 0286 0287 Keys are bound by the time the slider is created. A key is bound 0288 to same handle for the lifetime of the slider. So even if the handle 0289 representation might change from lower to upper, the same key binding 0290 remains. 0291 0292 \image qxtspanslider.png "QxtSpanSlider in Plastique style." 0293 0294 <b>Note:</b> QxtSpanSlider inherits QSlider for implementation specific 0295 reasons. Adjusting any single handle specific properties like 0296 -# QAbstractSlider::sliderPosition 0297 -# QAbstractSlider::value 0298 has no effect. However, all slider specific properties like 0299 -# QAbstractSlider::invertedAppearance 0300 -# QAbstractSlider::invertedControls 0301 -# QAbstractSlider::minimum 0302 -# QAbstractSlider::maximum 0303 -# QAbstractSlider::orientation 0304 -# QAbstractSlider::pageStep 0305 -# QAbstractSlider::singleStep 0306 -# QSlider::tickInterval 0307 -# QSlider::tickPosition 0308 are taken into consideration. 0309 */ 0310 0311 /*! 0312 \enum QxtSpanSlider::HandleMovementMode 0313 0314 This enum describes the available handle movement modes. 0315 0316 \value FreeMovement The handles can be moved freely. 0317 \value NoCrossing The handles cannot cross, but they can still overlap each other. The lower and upper values can be the same. 0318 \value NoOverlapping The handles cannot overlap each other. The lower and upper values cannot be the same. 0319 */ 0320 0321 /*! 0322 \enum QxtSpanSlider::SpanHandle 0323 0324 This enum describes the available span handles. 0325 0326 \omitvalue NoHandle \omit Internal only (for now). \endomit 0327 \var LowerHandle The lower boundary handle. 0328 \var UpperHandle The upper boundary handle. 0329 */ 0330 0331 /*! 0332 \fn QxtSpanSlider::lowerValueChanged(int lower) 0333 0334 This signal is emitted whenever the \a lower value has changed. 0335 */ 0336 0337 /*! 0338 \fn QxtSpanSlider::upperValueChanged(int upper) 0339 0340 This signal is emitted whenever the \a upper value has changed. 0341 */ 0342 0343 /*! 0344 \fn QxtSpanSlider::spanChanged(int lower, int upper) 0345 0346 This signal is emitted whenever both the \a lower and the \a upper 0347 values have changed ie. the span has changed. 0348 */ 0349 0350 /*! 0351 \fn QxtSpanSlider::lowerPositionChanged(int lower) 0352 0353 This signal is emitted whenever the \a lower position has changed. 0354 */ 0355 0356 /*! 0357 \fn QxtSpanSlider::upperPositionChanged(int upper) 0358 0359 This signal is emitted whenever the \a upper position has changed. 0360 */ 0361 0362 /*! 0363 \fn QxtSpanSlider::sliderPressed(SpanHandle handle) 0364 0365 This signal is emitted whenever the \a handle has been pressed. 0366 */ 0367 0368 /*! 0369 Constructs a new QxtSpanSlider with \a parent. 0370 */ 0371 QxtSpanSlider::QxtSpanSlider(QWidget* parent) : QSlider(parent) { 0372 QXT_INIT_PRIVATE(QxtSpanSlider); 0373 connect(this, SIGNAL(rangeChanged(int,int)), &qxt_d(), SLOT(updateRange(int,int))); 0374 connect(this, SIGNAL(sliderReleased()), &qxt_d(), SLOT(movePressedHandle())); 0375 } 0376 0377 /*! 0378 Constructs a new QxtSpanSlider with \a orientation and \a parent. 0379 */ 0380 QxtSpanSlider::QxtSpanSlider(Qt::Orientation orientation, QWidget* parent) : QSlider(orientation, parent) { 0381 QXT_INIT_PRIVATE(QxtSpanSlider); 0382 connect(this, SIGNAL(rangeChanged(int,int)), &qxt_d(), SLOT(updateRange(int,int))); 0383 connect(this, SIGNAL(sliderReleased()), &qxt_d(), SLOT(movePressedHandle())); 0384 } 0385 0386 /*! 0387 Destructs the span slider. 0388 */ 0389 QxtSpanSlider::~QxtSpanSlider() = default; 0390 0391 /*! 0392 \property QxtSpanSlider::handleMovementMode 0393 \brief the handle movement mode 0394 */ 0395 QxtSpanSlider::HandleMovementMode QxtSpanSlider::handleMovementMode() const { 0396 return qxt_d().movement; 0397 } 0398 0399 void QxtSpanSlider::setHandleMovementMode(QxtSpanSlider::HandleMovementMode mode) { 0400 qxt_d().movement = mode; 0401 } 0402 0403 /*! 0404 \property QxtSpanSlider::lowerValue 0405 \brief the lower value of the span 0406 */ 0407 int QxtSpanSlider::lowerValue() const { 0408 return qMin(qxt_d().lower, qxt_d().upper); 0409 } 0410 0411 void QxtSpanSlider::setLowerValue(int lower) { 0412 setSpan(lower, qxt_d().upper); 0413 } 0414 0415 /*! 0416 \property QxtSpanSlider::upperValue 0417 \brief the upper value of the span 0418 */ 0419 int QxtSpanSlider::upperValue() const { 0420 return qMax(qxt_d().lower, qxt_d().upper); 0421 } 0422 0423 void QxtSpanSlider::setUpperValue(int upper) { 0424 setSpan(qxt_d().lower, upper); 0425 } 0426 0427 /*! 0428 Sets the span from \a lower to \a upper. 0429 */ 0430 void QxtSpanSlider::setSpan(int lower, int upper) { 0431 const int low = qBound(minimum(), qMin(lower, upper), maximum()); 0432 const int upp = qBound(minimum(), qMax(lower, upper), maximum()); 0433 if (low != qxt_d().lower || upp != qxt_d().upper) { 0434 if (low != qxt_d().lower) { 0435 qxt_d().lower = low; 0436 qxt_d().lowerPos = low; 0437 emit lowerValueChanged(low); 0438 } 0439 if (upp != qxt_d().upper) { 0440 qxt_d().upper = upp; 0441 qxt_d().upperPos = upp; 0442 emit upperValueChanged(upp); 0443 } 0444 emit spanChanged(qxt_d().lower, qxt_d().upper); 0445 update(); 0446 } 0447 } 0448 0449 /*! 0450 \property QxtSpanSlider::lowerPosition 0451 \brief the lower position of the span 0452 */ 0453 int QxtSpanSlider::lowerPosition() const { 0454 return qxt_d().lowerPos; 0455 } 0456 0457 void QxtSpanSlider::setLowerPosition(int lower) { 0458 if (qxt_d().lowerPos != lower) { 0459 qxt_d().lowerPos = lower; 0460 if (!hasTracking()) 0461 update(); 0462 if (isSliderDown()) 0463 emit lowerPositionChanged(lower); 0464 if (hasTracking() && !qxt_d().blockTracking) { 0465 bool main = (qxt_d().mainControl == QxtSpanSlider::LowerHandle); 0466 qxt_d().triggerAction(SliderMove, main); 0467 } 0468 } 0469 } 0470 0471 /*! 0472 \property QxtSpanSlider::upperPosition 0473 \brief the upper position of the span 0474 */ 0475 int QxtSpanSlider::upperPosition() const { 0476 return qxt_d().upperPos; 0477 } 0478 0479 void QxtSpanSlider::setUpperPosition(int upper) { 0480 if (qxt_d().upperPos != upper) { 0481 qxt_d().upperPos = upper; 0482 if (!hasTracking()) 0483 update(); 0484 if (isSliderDown()) 0485 emit upperPositionChanged(upper); 0486 if (hasTracking() && !qxt_d().blockTracking) { 0487 bool main = (qxt_d().mainControl == QxtSpanSlider::UpperHandle); 0488 qxt_d().triggerAction(SliderMove, main); 0489 } 0490 } 0491 } 0492 0493 /*! 0494 \reimp 0495 */ 0496 void QxtSpanSlider::keyPressEvent(QKeyEvent* event) { 0497 QSlider::keyPressEvent(event); 0498 0499 bool main = true; 0500 SliderAction action = SliderNoAction; 0501 switch (event->key()) { 0502 case Qt::Key_Left: 0503 main = (orientation() == Qt::Horizontal); 0504 action = !invertedAppearance() ? SliderSingleStepSub : SliderSingleStepAdd; 0505 break; 0506 case Qt::Key_Right: 0507 main = (orientation() == Qt::Horizontal); 0508 action = !invertedAppearance() ? SliderSingleStepAdd : SliderSingleStepSub; 0509 break; 0510 case Qt::Key_Up: 0511 main = (orientation() == Qt::Vertical); 0512 action = invertedControls() ? SliderSingleStepSub : SliderSingleStepAdd; 0513 break; 0514 case Qt::Key_Down: 0515 main = (orientation() == Qt::Vertical); 0516 action = invertedControls() ? SliderSingleStepAdd : SliderSingleStepSub; 0517 break; 0518 case Qt::Key_Home: 0519 main = (qxt_d().mainControl == QxtSpanSlider::LowerHandle); 0520 action = SliderToMinimum; 0521 break; 0522 case Qt::Key_End: 0523 main = (qxt_d().mainControl == QxtSpanSlider::UpperHandle); 0524 action = SliderToMaximum; 0525 break; 0526 default: 0527 event->ignore(); 0528 break; 0529 } 0530 0531 if (action) 0532 qxt_d().triggerAction(action, main); 0533 } 0534 0535 /*! 0536 \reimp 0537 */ 0538 void QxtSpanSlider::mousePressEvent(QMouseEvent* event) { 0539 if (minimum() == maximum() || (event->buttons() ^ event->button())) { 0540 event->ignore(); 0541 return; 0542 } 0543 0544 qxt_d().handleMousePress(event->pos(), qxt_d().upperPressed, qxt_d().upper, QxtSpanSlider::UpperHandle); 0545 if (qxt_d().upperPressed != QStyle::SC_SliderHandle) 0546 qxt_d().handleMousePress(event->pos(), qxt_d().lowerPressed, qxt_d().lower, QxtSpanSlider::LowerHandle); 0547 0548 qxt_d().firstMovement = true; 0549 event->accept(); 0550 } 0551 0552 /*! 0553 \reimp 0554 */ 0555 void QxtSpanSlider::mouseMoveEvent(QMouseEvent* event) { 0556 if (qxt_d().lowerPressed != QStyle::SC_SliderHandle && qxt_d().upperPressed != QStyle::SC_SliderHandle) { 0557 event->ignore(); 0558 return; 0559 } 0560 0561 QStyleOptionSlider opt; 0562 qxt_d().initStyleOption(&opt); 0563 const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); 0564 int newPosition = qxt_d().pixelPosToRangeValue(qxt_d().pick(event->pos()) - qxt_d().offset); 0565 if (m >= 0) { 0566 const QRect r = rect().adjusted(-m, -m, m, m); 0567 if (!r.contains(event->pos())) 0568 newPosition = qxt_d().position; 0569 } 0570 0571 // pick the preferred handle on the first movement 0572 if (qxt_d().firstMovement) { 0573 if (qxt_d().lower == qxt_d().upper) { 0574 if (newPosition < lowerValue()) { 0575 qxt_d().swapControls(); 0576 qxt_d().firstMovement = false; 0577 } 0578 } else 0579 qxt_d().firstMovement = false; 0580 } 0581 0582 if (qxt_d().lowerPressed == QStyle::SC_SliderHandle) { 0583 if (qxt_d().movement == NoCrossing) 0584 newPosition = qMin(newPosition, upperValue()); 0585 else if (qxt_d().movement == NoOverlapping) 0586 newPosition = qMin(newPosition, upperValue() - 1); 0587 0588 if (qxt_d().movement == FreeMovement && newPosition > qxt_d().upper) { 0589 qxt_d().swapControls(); 0590 setUpperPosition(newPosition); 0591 } else 0592 setLowerPosition(newPosition); 0593 } else if (qxt_d().upperPressed == QStyle::SC_SliderHandle) { 0594 if (qxt_d().movement == NoCrossing) 0595 newPosition = qMax(newPosition, lowerValue()); 0596 else if (qxt_d().movement == NoOverlapping) 0597 newPosition = qMax(newPosition, lowerValue() + 1); 0598 0599 if (qxt_d().movement == FreeMovement && newPosition < qxt_d().lower) { 0600 qxt_d().swapControls(); 0601 setLowerPosition(newPosition); 0602 } else 0603 setUpperPosition(newPosition); 0604 } 0605 event->accept(); 0606 } 0607 0608 /*! 0609 \reimp 0610 */ 0611 void QxtSpanSlider::mouseReleaseEvent(QMouseEvent* event) { 0612 QSlider::mouseReleaseEvent(event); 0613 setSliderDown(false); 0614 qxt_d().lowerPressed = QStyle::SC_None; 0615 qxt_d().upperPressed = QStyle::SC_None; 0616 update(); 0617 } 0618 0619 /*! 0620 \reimp 0621 */ 0622 void QxtSpanSlider::paintEvent(QPaintEvent* event) { 0623 Q_UNUSED(event); 0624 QStylePainter painter(this); 0625 0626 // groove & ticks 0627 QStyleOptionSlider opt; 0628 qxt_d().initStyleOption(&opt); 0629 opt.sliderValue = 0; 0630 opt.sliderPosition = 0; 0631 opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderTickmarks; 0632 painter.drawComplexControl(QStyle::CC_Slider, opt); 0633 0634 // handle rects 0635 opt.sliderPosition = qxt_d().lowerPos; 0636 const QRect lr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); 0637 const int lrv = qxt_d().pick(lr.center()); 0638 opt.sliderPosition = qxt_d().upperPos; 0639 const QRect ur = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); 0640 const int urv = qxt_d().pick(ur.center()); 0641 0642 // span 0643 const int minv = qMin(lrv, urv); 0644 const int maxv = qMax(lrv, urv); 0645 const QPoint c = QRect(lr.center(), ur.center()).center(); 0646 QRect spanRect; 0647 if (orientation() == Qt::Horizontal) 0648 spanRect = QRect(QPoint(minv, c.y() - 2), QPoint(maxv, c.y() + 1)); 0649 else 0650 spanRect = QRect(QPoint(c.x() - 2, minv), QPoint(c.x() + 1, maxv)); 0651 qxt_d().drawSpan(&painter, spanRect); 0652 0653 // handles 0654 qxt_d().drawHandle(&painter, QxtSpanSlider::UpperHandle); 0655 qxt_d().drawHandle(&painter, QxtSpanSlider::LowerHandle); 0656 }