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