File indexing completed on 2024-04-14 14:08:53
0001 /* 0002 SPDX-FileCopyrightText: Kitware Inc. 0003 SPDX-License-Identifier: Apache-2.0 0004 */ 0005 0006 // Qt includes 0007 #include <QDebug> 0008 #include <QMouseEvent> 0009 #include <QKeyEvent> 0010 #include <QStyleOptionSlider> 0011 #include <QApplication> 0012 #include <QStylePainter> 0013 #include <QStyle> 0014 #include <QToolTip> 0015 0016 // CTK includes 0017 #include "ctkrangeslider.h" 0018 0019 class ctkRangeSliderPrivate 0020 { 0021 Q_DECLARE_PUBLIC(ctkRangeSlider) 0022 protected: 0023 ctkRangeSlider* const q_ptr; 0024 public: 0025 /// Boolean indicates the selected handle 0026 /// True for the minimum range handle, false for the maximum range handle 0027 enum Handle { 0028 NoHandle = 0x0, 0029 MinimumHandle = 0x1, 0030 MaximumHandle = 0x2 0031 }; 0032 Q_DECLARE_FLAGS(Handles, Handle) 0033 0034 ctkRangeSliderPrivate(ctkRangeSlider& object); 0035 void init(); 0036 0037 /// Return the handle at the given pos, or none if no handle is at the pos. 0038 /// If a handle is selected, handleRect is set to the handle rect. 0039 /// otherwise return NoHandle and handleRect is set to the combined rect of 0040 /// the min and max handles 0041 Handle handleAtPos(const QPoint& pos, QRect& handleRect)const; 0042 0043 /// Copied verbatim from QSliderPrivate class (see QSlider.cpp) 0044 int pixelPosToRangeValue(int pos) const; 0045 int pixelPosFromRangeValue(int val) const; 0046 0047 /// Draw the bottom and top sliders. 0048 void drawMinimumSlider( QStylePainter* painter ) const; 0049 void drawMaximumSlider( QStylePainter* painter ) const; 0050 0051 /// End points of the range on the Model 0052 int m_MaximumValue; 0053 int m_MinimumValue; 0054 0055 /// End points of the range on the GUI. This is synced with the model. 0056 int m_MaximumPosition; 0057 int m_MinimumPosition; 0058 0059 /// Controls selected ? 0060 QStyle::SubControl m_MinimumSliderSelected; 0061 QStyle::SubControl m_MaximumSliderSelected; 0062 0063 /// See QSliderPrivate::clickOffset. 0064 /// Overrides this ivar 0065 int m_SubclassClickOffset; 0066 0067 /// See QSliderPrivate::position 0068 /// Overrides this ivar. 0069 int m_SubclassPosition; 0070 0071 /// Original width between the 2 bounds before any moves 0072 int m_SubclassWidth; 0073 0074 ctkRangeSliderPrivate::Handles m_SelectedHandles; 0075 0076 /// When symmetricMoves is true, moving a handle will move the other handle 0077 /// symmetrically, otherwise the handles are independent. 0078 bool m_SymmetricMoves; 0079 0080 QString m_HandleToolTip; 0081 0082 private: 0083 Q_DISABLE_COPY(ctkRangeSliderPrivate) 0084 }; 0085 0086 // -------------------------------------------------------------------------- 0087 ctkRangeSliderPrivate::ctkRangeSliderPrivate(ctkRangeSlider& object) 0088 :q_ptr(&object) 0089 { 0090 this->m_MinimumValue = 0; 0091 this->m_MaximumValue = 100; 0092 this->m_MinimumPosition = 0; 0093 this->m_MaximumPosition = 100; 0094 this->m_MinimumSliderSelected = QStyle::SC_None; 0095 this->m_MaximumSliderSelected = QStyle::SC_None; 0096 this->m_SubclassClickOffset = 0; 0097 this->m_SubclassPosition = 0; 0098 this->m_SubclassWidth = 0; 0099 this->m_SelectedHandles = ctkRangeSliderPrivate::NoHandle; 0100 this->m_SymmetricMoves = false; 0101 } 0102 0103 // -------------------------------------------------------------------------- 0104 void ctkRangeSliderPrivate::init() 0105 { 0106 Q_Q(ctkRangeSlider); 0107 this->m_MinimumValue = q->minimum(); 0108 this->m_MaximumValue = q->maximum(); 0109 this->m_MinimumPosition = q->minimum(); 0110 this->m_MaximumPosition = q->maximum(); 0111 q->connect(q, SIGNAL(rangeChanged(int,int)), q, SLOT(onRangeChanged(int,int))); 0112 } 0113 0114 // -------------------------------------------------------------------------- 0115 ctkRangeSliderPrivate::Handle ctkRangeSliderPrivate::handleAtPos(const QPoint& pos, QRect& handleRect)const 0116 { 0117 Q_Q(const ctkRangeSlider); 0118 0119 QStyleOptionSlider option; 0120 q->initStyleOption( &option ); 0121 0122 // The functions hitTestComplexControl only know about 1 handle. As we have 0123 // 2, we change the position of the handle and test if the pos correspond to 0124 // any of the 2 positions. 0125 0126 // Test the MinimumHandle 0127 option.sliderPosition = this->m_MinimumPosition; 0128 option.sliderValue = this->m_MinimumValue; 0129 0130 QStyle::SubControl minimumControl = q->style()->hitTestComplexControl( 0131 QStyle::CC_Slider, &option, pos, q); 0132 QRect minimumHandleRect = q->style()->subControlRect( 0133 QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q); 0134 0135 // Test if the pos is under the Maximum handle 0136 option.sliderPosition = this->m_MaximumPosition; 0137 option.sliderValue = this->m_MaximumValue; 0138 0139 QStyle::SubControl maximumControl = q->style()->hitTestComplexControl( 0140 QStyle::CC_Slider, &option, pos, q); 0141 QRect maximumHandleRect = q->style()->subControlRect( 0142 QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q); 0143 0144 // The pos is above both handles, select the closest handle 0145 if (minimumControl == QStyle::SC_SliderHandle && 0146 maximumControl == QStyle::SC_SliderHandle) 0147 { 0148 int minDist = 0; 0149 int maxDist = 0; 0150 if (q->orientation() == Qt::Horizontal) 0151 { 0152 minDist = pos.x() - minimumHandleRect.left(); 0153 maxDist = maximumHandleRect.right() - pos.x(); 0154 } 0155 else //if (q->orientation() == Qt::Vertical) 0156 { 0157 minDist = minimumHandleRect.bottom() - pos.y(); 0158 maxDist = pos.y() - maximumHandleRect.top(); 0159 } 0160 Q_ASSERT( minDist >= 0 && maxDist >= 0); 0161 minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None; 0162 } 0163 0164 if (minimumControl == QStyle::SC_SliderHandle) 0165 { 0166 handleRect = minimumHandleRect; 0167 return MinimumHandle; 0168 } 0169 else if (maximumControl == QStyle::SC_SliderHandle) 0170 { 0171 handleRect = maximumHandleRect; 0172 return MaximumHandle; 0173 } 0174 handleRect = minimumHandleRect.united(maximumHandleRect); 0175 return NoHandle; 0176 } 0177 0178 // -------------------------------------------------------------------------- 0179 // Copied verbatim from QSliderPrivate::pixelPosToRangeValue. See QSlider.cpp 0180 // 0181 int ctkRangeSliderPrivate::pixelPosToRangeValue( int pos ) const 0182 { 0183 Q_Q(const ctkRangeSlider); 0184 QStyleOptionSlider option; 0185 q->initStyleOption( &option ); 0186 0187 QRect gr = q->style()->subControlRect( QStyle::CC_Slider, 0188 &option, 0189 QStyle::SC_SliderGroove, 0190 q ); 0191 QRect sr = q->style()->subControlRect( QStyle::CC_Slider, 0192 &option, 0193 QStyle::SC_SliderHandle, 0194 q ); 0195 int sliderMin, sliderMax, sliderLength; 0196 if (option.orientation == Qt::Horizontal) 0197 { 0198 sliderLength = sr.width(); 0199 sliderMin = gr.x(); 0200 sliderMax = gr.right() - sliderLength + 1; 0201 } 0202 else 0203 { 0204 sliderLength = sr.height(); 0205 sliderMin = gr.y(); 0206 sliderMax = gr.bottom() - sliderLength + 1; 0207 } 0208 0209 return QStyle::sliderValueFromPosition( q->minimum(), 0210 q->maximum(), 0211 pos - sliderMin, 0212 sliderMax - sliderMin, 0213 option.upsideDown ); 0214 } 0215 0216 //--------------------------------------------------------------------------- 0217 int ctkRangeSliderPrivate::pixelPosFromRangeValue( int val ) const 0218 { 0219 Q_Q(const ctkRangeSlider); 0220 QStyleOptionSlider option; 0221 q->initStyleOption( &option ); 0222 0223 QRect gr = q->style()->subControlRect( QStyle::CC_Slider, 0224 &option, 0225 QStyle::SC_SliderGroove, 0226 q ); 0227 QRect sr = q->style()->subControlRect( QStyle::CC_Slider, 0228 &option, 0229 QStyle::SC_SliderHandle, 0230 q ); 0231 int sliderMin, sliderMax, sliderLength; 0232 if (option.orientation == Qt::Horizontal) 0233 { 0234 sliderLength = sr.width(); 0235 sliderMin = gr.x(); 0236 sliderMax = gr.right() - sliderLength + 1; 0237 } 0238 else 0239 { 0240 sliderLength = sr.height(); 0241 sliderMin = gr.y(); 0242 sliderMax = gr.bottom() - sliderLength + 1; 0243 } 0244 0245 return QStyle::sliderPositionFromValue( q->minimum(), 0246 q->maximum(), 0247 val, 0248 sliderMax - sliderMin, 0249 option.upsideDown ) + sliderMin; 0250 } 0251 0252 //--------------------------------------------------------------------------- 0253 // Draw slider at the bottom end of the range 0254 void ctkRangeSliderPrivate::drawMinimumSlider( QStylePainter* painter ) const 0255 { 0256 Q_Q(const ctkRangeSlider); 0257 QStyleOptionSlider option; 0258 q->initMinimumSliderStyleOption( &option ); 0259 0260 option.subControls = QStyle::SC_SliderHandle; 0261 option.sliderValue = m_MinimumValue; 0262 option.sliderPosition = m_MinimumPosition; 0263 if (q->isMinimumSliderDown()) 0264 { 0265 option.activeSubControls = QStyle::SC_SliderHandle; 0266 option.state |= QStyle::State_Sunken; 0267 } 0268 #ifdef Q_OS_MAC 0269 // On mac style, drawing just the handle actually draws also the groove. 0270 QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option, 0271 QStyle::SC_SliderHandle, q); 0272 painter->setClipRect(clip); 0273 #endif 0274 painter->drawComplexControl(QStyle::CC_Slider, option); 0275 } 0276 0277 //--------------------------------------------------------------------------- 0278 // Draw slider at the top end of the range 0279 void ctkRangeSliderPrivate::drawMaximumSlider( QStylePainter* painter ) const 0280 { 0281 Q_Q(const ctkRangeSlider); 0282 QStyleOptionSlider option; 0283 q->initMaximumSliderStyleOption( &option ); 0284 0285 option.subControls = QStyle::SC_SliderHandle; 0286 option.sliderValue = m_MaximumValue; 0287 option.sliderPosition = m_MaximumPosition; 0288 if (q->isMaximumSliderDown()) 0289 { 0290 option.activeSubControls = QStyle::SC_SliderHandle; 0291 option.state |= QStyle::State_Sunken; 0292 } 0293 #ifdef Q_OS_MAC 0294 // On mac style, drawing just the handle actually draws also the groove. 0295 QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option, 0296 QStyle::SC_SliderHandle, q); 0297 painter->setClipRect(clip); 0298 #endif 0299 painter->drawComplexControl(QStyle::CC_Slider, option); 0300 } 0301 0302 // -------------------------------------------------------------------------- 0303 ctkRangeSlider::ctkRangeSlider(QWidget* _parent) 0304 : QSlider(_parent) 0305 , d_ptr(new ctkRangeSliderPrivate(*this)) 0306 { 0307 Q_D(ctkRangeSlider); 0308 d->init(); 0309 } 0310 0311 // -------------------------------------------------------------------------- 0312 ctkRangeSlider::ctkRangeSlider( Qt::Orientation o, 0313 QWidget* parentObject ) 0314 :QSlider(o, parentObject) 0315 , d_ptr(new ctkRangeSliderPrivate(*this)) 0316 { 0317 Q_D(ctkRangeSlider); 0318 d->init(); 0319 } 0320 0321 // -------------------------------------------------------------------------- 0322 ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate* impl, QWidget* _parent) 0323 : QSlider(_parent) 0324 , d_ptr(impl) 0325 { 0326 Q_D(ctkRangeSlider); 0327 d->init(); 0328 } 0329 0330 // -------------------------------------------------------------------------- 0331 ctkRangeSlider::ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o, 0332 QWidget* parentObject ) 0333 :QSlider(o, parentObject) 0334 , d_ptr(impl) 0335 { 0336 Q_D(ctkRangeSlider); 0337 d->init(); 0338 } 0339 0340 // -------------------------------------------------------------------------- 0341 ctkRangeSlider::~ctkRangeSlider() 0342 { 0343 } 0344 0345 // -------------------------------------------------------------------------- 0346 int ctkRangeSlider::minimumValue() const 0347 { 0348 Q_D(const ctkRangeSlider); 0349 return d->m_MinimumValue; 0350 } 0351 0352 // -------------------------------------------------------------------------- 0353 void ctkRangeSlider::setMinimumValue( int min ) 0354 { 0355 Q_D(ctkRangeSlider); 0356 this->setValues( min, qMax(d->m_MaximumValue,min) ); 0357 } 0358 0359 // -------------------------------------------------------------------------- 0360 int ctkRangeSlider::maximumValue() const 0361 { 0362 Q_D(const ctkRangeSlider); 0363 return d->m_MaximumValue; 0364 } 0365 0366 // -------------------------------------------------------------------------- 0367 void ctkRangeSlider::setMaximumValue( int max ) 0368 { 0369 Q_D(ctkRangeSlider); 0370 this->setValues( qMin(d->m_MinimumValue, max), max ); 0371 } 0372 0373 // -------------------------------------------------------------------------- 0374 void ctkRangeSlider::setValues(int l, int u) 0375 { 0376 Q_D(ctkRangeSlider); 0377 const int minValue = 0378 qBound(this->minimum(), qMin(l,u), this->maximum()); 0379 const int maxValue = 0380 qBound(this->minimum(), qMax(l,u), this->maximum()); 0381 bool emitMinValChanged = (minValue != d->m_MinimumValue); 0382 bool emitMaxValChanged = (maxValue != d->m_MaximumValue); 0383 0384 d->m_MinimumValue = minValue; 0385 d->m_MaximumValue = maxValue; 0386 0387 bool emitMinPosChanged = 0388 (minValue != d->m_MinimumPosition); 0389 bool emitMaxPosChanged = 0390 (maxValue != d->m_MaximumPosition); 0391 d->m_MinimumPosition = minValue; 0392 d->m_MaximumPosition = maxValue; 0393 0394 if (isSliderDown()) 0395 { 0396 if (emitMinPosChanged || emitMaxPosChanged) 0397 { 0398 emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition); 0399 } 0400 if (emitMinPosChanged) 0401 { 0402 emit minimumPositionChanged(d->m_MinimumPosition); 0403 } 0404 if (emitMaxPosChanged) 0405 { 0406 emit maximumPositionChanged(d->m_MaximumPosition); 0407 } 0408 } 0409 if (emitMinValChanged || emitMaxValChanged) 0410 { 0411 emit valuesChanged(d->m_MinimumValue, 0412 d->m_MaximumValue); 0413 } 0414 if (emitMinValChanged) 0415 { 0416 emit minimumValueChanged(d->m_MinimumValue); 0417 } 0418 if (emitMaxValChanged) 0419 { 0420 emit maximumValueChanged(d->m_MaximumValue); 0421 } 0422 if (emitMinPosChanged || emitMaxPosChanged || 0423 emitMinValChanged || emitMaxValChanged) 0424 { 0425 this->update(); 0426 } 0427 } 0428 0429 // -------------------------------------------------------------------------- 0430 int ctkRangeSlider::minimumPosition() const 0431 { 0432 Q_D(const ctkRangeSlider); 0433 return d->m_MinimumPosition; 0434 } 0435 0436 // -------------------------------------------------------------------------- 0437 int ctkRangeSlider::maximumPosition() const 0438 { 0439 Q_D(const ctkRangeSlider); 0440 return d->m_MaximumPosition; 0441 } 0442 0443 // -------------------------------------------------------------------------- 0444 void ctkRangeSlider::setMinimumPosition(int l) 0445 { 0446 Q_D(const ctkRangeSlider); 0447 this->setPositions(l, qMax(l, d->m_MaximumPosition)); 0448 } 0449 0450 // -------------------------------------------------------------------------- 0451 void ctkRangeSlider::setMaximumPosition(int u) 0452 { 0453 Q_D(const ctkRangeSlider); 0454 this->setPositions(qMin(d->m_MinimumPosition, u), u); 0455 } 0456 0457 // -------------------------------------------------------------------------- 0458 void ctkRangeSlider::setPositions(int min, int max) 0459 { 0460 Q_D(ctkRangeSlider); 0461 const int minPosition = 0462 qBound(this->minimum(), qMin(min, max), this->maximum()); 0463 const int maxPosition = 0464 qBound(this->minimum(), qMax(min, max), this->maximum()); 0465 0466 bool emitMinPosChanged = (minPosition != d->m_MinimumPosition); 0467 bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition); 0468 0469 if (!emitMinPosChanged && !emitMaxPosChanged) 0470 { 0471 return; 0472 } 0473 0474 d->m_MinimumPosition = minPosition; 0475 d->m_MaximumPosition = maxPosition; 0476 0477 if (!this->hasTracking()) 0478 { 0479 this->update(); 0480 } 0481 if (isSliderDown()) 0482 { 0483 if (emitMinPosChanged) 0484 { 0485 emit minimumPositionChanged(d->m_MinimumPosition); 0486 } 0487 if (emitMaxPosChanged) 0488 { 0489 emit maximumPositionChanged(d->m_MaximumPosition); 0490 } 0491 if (emitMinPosChanged || emitMaxPosChanged) 0492 { 0493 emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition); 0494 } 0495 } 0496 if (this->hasTracking()) 0497 { 0498 this->triggerAction(SliderMove); 0499 this->setValues(d->m_MinimumPosition, d->m_MaximumPosition); 0500 } 0501 } 0502 0503 // -------------------------------------------------------------------------- 0504 void ctkRangeSlider::setSymmetricMoves(bool symmetry) 0505 { 0506 Q_D(ctkRangeSlider); 0507 d->m_SymmetricMoves = symmetry; 0508 } 0509 0510 // -------------------------------------------------------------------------- 0511 bool ctkRangeSlider::symmetricMoves()const 0512 { 0513 Q_D(const ctkRangeSlider); 0514 return d->m_SymmetricMoves; 0515 } 0516 0517 // -------------------------------------------------------------------------- 0518 void ctkRangeSlider::onRangeChanged(int _minimum, int _maximum) 0519 { 0520 Q_UNUSED(_minimum); 0521 Q_UNUSED(_maximum); 0522 Q_D(ctkRangeSlider); 0523 this->setValues(d->m_MinimumValue, d->m_MaximumValue); 0524 } 0525 0526 // -------------------------------------------------------------------------- 0527 // Render 0528 void ctkRangeSlider::paintEvent( QPaintEvent* ) 0529 { 0530 Q_D(ctkRangeSlider); 0531 QStyleOptionSlider option; 0532 this->initStyleOption(&option); 0533 0534 QStylePainter painter(this); 0535 option.subControls = QStyle::SC_SliderGroove; 0536 // Move to minimum to not highlight the SliderGroove. 0537 // On mac style, drawing just the slider groove also draws the handles, 0538 // therefore we give a negative (outside of view) position. 0539 option.sliderValue = this->minimum() - this->maximum(); 0540 option.sliderPosition = this->minimum() - this->maximum(); 0541 painter.drawComplexControl(QStyle::CC_Slider, option); 0542 0543 option.sliderPosition = d->m_MinimumPosition; 0544 const QRect lr = style()->subControlRect( QStyle::CC_Slider, 0545 &option, 0546 QStyle::SC_SliderHandle, 0547 this); 0548 option.sliderPosition = d->m_MaximumPosition; 0549 0550 const QRect ur = style()->subControlRect( QStyle::CC_Slider, 0551 &option, 0552 QStyle::SC_SliderHandle, 0553 this); 0554 0555 QRect sr = style()->subControlRect( QStyle::CC_Slider, 0556 &option, 0557 QStyle::SC_SliderGroove, 0558 this); 0559 QRect rangeBox; 0560 if (option.orientation == Qt::Horizontal) 0561 { 0562 rangeBox = QRect( 0563 QPoint(qMin( lr.center().x(), ur.center().x() ), sr.center().y() - 2), 0564 QPoint(qMax( lr.center().x(), ur.center().x() ), sr.center().y() + 1)); 0565 } 0566 else 0567 { 0568 rangeBox = QRect( 0569 QPoint(sr.center().x() - 2, qMin( lr.center().y(), ur.center().y() )), 0570 QPoint(sr.center().x() + 1, qMax( lr.center().y(), ur.center().y() ))); 0571 } 0572 0573 // ----------------------------- 0574 // Render the range 0575 // 0576 QRect groove = this->style()->subControlRect( QStyle::CC_Slider, 0577 &option, 0578 QStyle::SC_SliderGroove, 0579 this ); 0580 groove.adjust(0, 0, -1, 0); 0581 0582 // Create default colors based on the transfer function. 0583 // 0584 QColor highlight = this->palette().color(QPalette::Normal, QPalette::Highlight); 0585 QLinearGradient gradient; 0586 if (option.orientation == Qt::Horizontal) 0587 { 0588 gradient = QLinearGradient( groove.center().x(), groove.top(), 0589 groove.center().x(), groove.bottom()); 0590 } 0591 else 0592 { 0593 gradient = QLinearGradient( groove.left(), groove.center().y(), 0594 groove.right(), groove.center().y()); 0595 } 0596 0597 // TODO: Set this based on the supplied transfer function 0598 //QColor l = Qt::darkGray; 0599 //QColor u = Qt::black; 0600 0601 gradient.setColorAt(0, highlight.darker(120)); 0602 gradient.setColorAt(1, highlight.lighter(160)); 0603 0604 painter.setPen(QPen(highlight.darker(150), 0)); 0605 painter.setBrush(gradient); 0606 painter.drawRect( rangeBox.intersected(groove) ); 0607 0608 // ----------------------------------- 0609 // Render the sliders 0610 // 0611 if (this->isMinimumSliderDown()) 0612 { 0613 d->drawMaximumSlider( &painter ); 0614 d->drawMinimumSlider( &painter ); 0615 } 0616 else 0617 { 0618 d->drawMinimumSlider( &painter ); 0619 d->drawMaximumSlider( &painter ); 0620 } 0621 } 0622 0623 // -------------------------------------------------------------------------- 0624 // Standard Qt UI events 0625 void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent) 0626 { 0627 Q_D(ctkRangeSlider); 0628 if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button())) 0629 { 0630 mouseEvent->ignore(); 0631 return; 0632 } 0633 int mepos = this->orientation() == Qt::Horizontal ? 0634 mouseEvent->pos().x() : mouseEvent->pos().y(); 0635 0636 QStyleOptionSlider option; 0637 this->initStyleOption( &option ); 0638 0639 QRect handleRect; 0640 ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect); 0641 0642 if (handle_ != ctkRangeSliderPrivate::NoHandle) 0643 { 0644 d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle)? 0645 d->m_MinimumPosition : d->m_MaximumPosition; 0646 0647 // save the position of the mouse inside the handle for later 0648 d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ? 0649 handleRect.left() : handleRect.top()); 0650 0651 this->setSliderDown(true); 0652 0653 if (d->m_SelectedHandles != handle_) 0654 { 0655 d->m_SelectedHandles = handle_; 0656 this->update(handleRect); 0657 } 0658 // Accept the mouseEvent 0659 mouseEvent->accept(); 0660 return; 0661 } 0662 0663 // if we are here, no handles have been pressed 0664 // Check if we pressed on the groove between the 2 handles 0665 0666 QStyle::SubControl control = this->style()->hitTestComplexControl( 0667 QStyle::CC_Slider, &option, mouseEvent->pos(), this); 0668 QRect sr = style()->subControlRect( 0669 QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this); 0670 int minCenter = (this->orientation() == Qt::Horizontal ? 0671 handleRect.left() : handleRect.top()); 0672 int maxCenter = (this->orientation() == Qt::Horizontal ? 0673 handleRect.right() : handleRect.bottom()); 0674 if (control == QStyle::SC_SliderGroove && 0675 mepos > minCenter && mepos < maxCenter) 0676 { 0677 // warning lost of precision it might be fatal 0678 d->m_SubclassPosition = (d->m_MinimumPosition + d->m_MaximumPosition) / 2.; 0679 d->m_SubclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_SubclassPosition); 0680 d->m_SubclassWidth = (d->m_MaximumPosition - d->m_MinimumPosition) / 2; 0681 qMax(d->m_SubclassPosition - d->m_MinimumPosition, d->m_MaximumPosition - d->m_SubclassPosition); 0682 this->setSliderDown(true); 0683 if (!this->isMinimumSliderDown() || !this->isMaximumSliderDown()) 0684 { 0685 d->m_SelectedHandles = 0686 QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MinimumHandle) | 0687 QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MaximumHandle); 0688 this->update(handleRect.united(sr)); 0689 } 0690 mouseEvent->accept(); 0691 return; 0692 } 0693 mouseEvent->ignore(); 0694 } 0695 0696 // -------------------------------------------------------------------------- 0697 // Standard Qt UI events 0698 void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent) 0699 { 0700 Q_D(ctkRangeSlider); 0701 if (!d->m_SelectedHandles) 0702 { 0703 mouseEvent->ignore(); 0704 return; 0705 } 0706 int mepos = this->orientation() == Qt::Horizontal ? 0707 mouseEvent->pos().x() : mouseEvent->pos().y(); 0708 0709 QStyleOptionSlider option; 0710 this->initStyleOption(&option); 0711 0712 const int m = style()->pixelMetric( QStyle::PM_MaximumDragDistance, &option, this ); 0713 0714 int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset); 0715 0716 if (m >= 0) 0717 { 0718 const QRect r = rect().adjusted(-m, -m, m, m); 0719 if (!r.contains(mouseEvent->pos())) 0720 { 0721 newPosition = d->m_SubclassPosition; 0722 } 0723 } 0724 0725 // Only the lower/left slider is down 0726 if (this->isMinimumSliderDown() && !this->isMaximumSliderDown()) 0727 { 0728 double newMinPos = qMin(newPosition,d->m_MaximumPosition); 0729 this->setPositions(newMinPos, d->m_MaximumPosition + 0730 (d->m_SymmetricMoves ? d->m_MinimumPosition - newMinPos : 0)); 0731 } 0732 // Only the upper/right slider is down 0733 else if (this->isMaximumSliderDown() && !this->isMinimumSliderDown()) 0734 { 0735 double newMaxPos = qMax(d->m_MinimumPosition, newPosition); 0736 this->setPositions(d->m_MinimumPosition - 0737 (d->m_SymmetricMoves ? newMaxPos - d->m_MaximumPosition: 0), 0738 newMaxPos); 0739 } 0740 // Both handles are down (the user clicked in between the handles) 0741 else if (this->isMinimumSliderDown() && this->isMaximumSliderDown()) 0742 { 0743 this->setPositions(newPosition - d->m_SubclassWidth, 0744 newPosition + d->m_SubclassWidth ); 0745 } 0746 mouseEvent->accept(); 0747 } 0748 0749 // -------------------------------------------------------------------------- 0750 // Standard Qt UI mouseEvents 0751 void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent) 0752 { 0753 Q_D(ctkRangeSlider); 0754 this->QSlider::mouseReleaseEvent(mouseEvent); 0755 0756 setSliderDown(false); 0757 d->m_SelectedHandles = ctkRangeSliderPrivate::NoHandle; 0758 0759 this->update(); 0760 } 0761 0762 // -------------------------------------------------------------------------- 0763 bool ctkRangeSlider::isMinimumSliderDown()const 0764 { 0765 Q_D(const ctkRangeSlider); 0766 return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle; 0767 } 0768 0769 // -------------------------------------------------------------------------- 0770 bool ctkRangeSlider::isMaximumSliderDown()const 0771 { 0772 Q_D(const ctkRangeSlider); 0773 return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle; 0774 } 0775 0776 // -------------------------------------------------------------------------- 0777 void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const 0778 { 0779 this->initStyleOption(option); 0780 } 0781 0782 // -------------------------------------------------------------------------- 0783 void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const 0784 { 0785 this->initStyleOption(option); 0786 } 0787 0788 // -------------------------------------------------------------------------- 0789 QString ctkRangeSlider::handleToolTip()const 0790 { 0791 Q_D(const ctkRangeSlider); 0792 return d->m_HandleToolTip; 0793 } 0794 0795 // -------------------------------------------------------------------------- 0796 void ctkRangeSlider::setHandleToolTip(const QString& _toolTip) 0797 { 0798 Q_D(ctkRangeSlider); 0799 d->m_HandleToolTip = _toolTip; 0800 } 0801 0802 // -------------------------------------------------------------------------- 0803 bool ctkRangeSlider::event(QEvent* _event) 0804 { 0805 Q_D(ctkRangeSlider); 0806 switch(_event->type()) 0807 { 0808 case QEvent::ToolTip: 0809 { 0810 QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event); 0811 QStyleOptionSlider opt; 0812 // Test the MinimumHandle 0813 opt.sliderPosition = d->m_MinimumPosition; 0814 opt.sliderValue = d->m_MinimumValue; 0815 this->initStyleOption(&opt); 0816 QStyle::SubControl hoveredControl = 0817 this->style()->hitTestComplexControl( 0818 QStyle::CC_Slider, &opt, helpEvent->pos(), this); 0819 if (!d->m_HandleToolTip.isEmpty() && 0820 hoveredControl == QStyle::SC_SliderHandle) 0821 { 0822 QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue())); 0823 _event->accept(); 0824 return true; 0825 } 0826 // Test the MaximumHandle 0827 opt.sliderPosition = d->m_MaximumPosition; 0828 opt.sliderValue = d->m_MaximumValue; 0829 this->initStyleOption(&opt); 0830 hoveredControl = this->style()->hitTestComplexControl( 0831 QStyle::CC_Slider, &opt, helpEvent->pos(), this); 0832 if (!d->m_HandleToolTip.isEmpty() && 0833 hoveredControl == QStyle::SC_SliderHandle) 0834 { 0835 QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue())); 0836 _event->accept(); 0837 return true; 0838 } 0839 } 0840 default: 0841 break; 0842 } 0843 return this->Superclass::event(_event); 0844 }