00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <QDebug>
00023 #include <QMouseEvent>
00024 #include <QKeyEvent>
00025 #include <QStyleOptionSlider>
00026 #include <QApplication>
00027 #include <QStylePainter>
00028 #include <QStyle>
00029
00030
00031 #include "ctkRangeSlider.h"
00032
00033 class ctkRangeSliderPrivate:public ctkPrivate<ctkRangeSlider>
00034 {
00035 public:
00036 ctkRangeSliderPrivate();
00037 void init();
00038
00039
00040
00041 int pixelPosToRangeValue(int pos) const;
00042
00043
00044
00045 void drawMinimumSlider( QStylePainter* painter ) const;
00046 void drawMaximumSlider( QStylePainter* painter ) const;
00047
00048
00049
00050 int m_MaximumValue;
00051 int m_MinimumValue;
00052
00053
00054
00055 int m_MaximumPosition;
00056 int m_MinimumPosition;
00057
00058
00059
00060 QStyle::SubControl m_MinimumSliderSelected;
00061 QStyle::SubControl m_MaximumSliderSelected;
00062
00063
00064
00065
00066 int m_SubclassClickOffset;
00067
00068
00069
00070
00071 int m_SubclassPosition;
00072
00073
00074
00075
00076 bool m_SelectedSlider;
00077 };
00078
00079
00080 ctkRangeSliderPrivate::ctkRangeSliderPrivate()
00081 {
00082 this->m_MinimumValue = 0;
00083 this->m_MaximumValue = 100;
00084 this->m_MinimumPosition = 0;
00085 this->m_MaximumPosition = 100;
00086 this->m_MinimumSliderSelected = QStyle::SC_None;
00087 this->m_MaximumSliderSelected = QStyle::SC_None;
00088 this->m_SubclassClickOffset = 0;
00089 this->m_SubclassPosition = 0;
00090 }
00091
00092
00093 void ctkRangeSliderPrivate::init()
00094 {
00095 CTK_P(ctkRangeSlider);
00096 this->m_MinimumValue = p->minimum();
00097 this->m_MaximumValue = p->maximum();
00098 this->m_MinimumPosition = p->minimum();
00099 this->m_MaximumPosition = p->maximum();
00100 p->connect(p, SIGNAL(rangeChanged(int, int)), p, SLOT(onRangeChanged(int, int)));
00101 }
00102
00103
00104
00105
00106 int ctkRangeSliderPrivate::pixelPosToRangeValue( int pos ) const
00107 {
00108 CTK_P(const ctkRangeSlider);
00109 QStyleOptionSlider option;
00110 p->initStyleOption( &option );
00111
00112 QRect gr = p->style()->subControlRect( QStyle::CC_Slider,
00113 &option,
00114 QStyle::SC_SliderGroove,
00115 p );
00116 QRect sr = p->style()->subControlRect( QStyle::CC_Slider,
00117 &option,
00118 QStyle::SC_SliderHandle,
00119 p );
00120
00121 int sliderLength = sr.width();
00122 int sliderMin = gr.x();
00123 int sliderMax = gr.right() - sliderLength + 1;
00124
00125 return QStyle::sliderValueFromPosition( p->minimum(),
00126 p->maximum(),
00127 pos - sliderMin,
00128 sliderMax - sliderMin,
00129 option.upsideDown );
00130 }
00131
00132
00133
00134 void ctkRangeSliderPrivate::drawMinimumSlider( QStylePainter* painter ) const
00135 {
00136 CTK_P(const ctkRangeSlider);
00137 QStyleOptionSlider option;
00138 p->initStyleOption( &option );
00139
00140 option.subControls = QStyle::SC_SliderHandle;
00141 option.sliderValue = m_MinimumValue;
00142 option.sliderPosition = m_MinimumPosition;
00143 if (m_MinimumSliderSelected == QStyle::SC_SliderHandle)
00144 {
00145 option.activeSubControls = m_MinimumSliderSelected;
00146 option.state |= QStyle::State_Sunken;
00147 }
00148
00149 painter->drawComplexControl(QStyle::CC_Slider, option);
00150 }
00151
00152
00153
00154 void ctkRangeSliderPrivate::drawMaximumSlider( QStylePainter* painter ) const
00155 {
00156 CTK_P(const ctkRangeSlider);
00157 QStyleOptionSlider option;
00158 p->Superclass::initStyleOption( &option );
00159
00160 option.subControls = QStyle::SC_SliderHandle;
00161 option.sliderValue = m_MaximumValue;
00162 option.sliderPosition = m_MaximumPosition;
00163 if (m_MaximumSliderSelected == QStyle::SC_SliderHandle)
00164 {
00165 option.activeSubControls = m_MaximumSliderSelected;
00166 option.state |= QStyle::State_Sunken;
00167 }
00168
00169 painter->drawComplexControl(QStyle::CC_Slider, option);
00170 }
00171
00172
00173 ctkRangeSlider::ctkRangeSlider(QWidget* parent)
00174 : QSlider(parent)
00175 {
00176 CTK_INIT_PRIVATE(ctkRangeSlider);
00177 ctk_d()->init();
00178 }
00179
00180
00181 ctkRangeSlider::ctkRangeSlider( Qt::Orientation o,
00182 QWidget* parentObject )
00183 :QSlider(o, parentObject)
00184 {
00185 CTK_INIT_PRIVATE(ctkRangeSlider);
00186 ctk_d()->init();
00187 }
00188
00189
00190 ctkRangeSlider::~ctkRangeSlider()
00191 {
00192 }
00193
00194
00195 int ctkRangeSlider::minimumValue() const
00196 {
00197 CTK_D(const ctkRangeSlider);
00198 return d->m_MinimumValue;
00199 }
00200
00201
00202 void ctkRangeSlider::setMinimumValue( int min )
00203 {
00204 CTK_D(ctkRangeSlider);
00205 this->setValues( min, qMax(d->m_MaximumValue,min) );
00206 }
00207
00208
00209 int ctkRangeSlider::maximumValue() const
00210 {
00211 CTK_D(const ctkRangeSlider);
00212 return d->m_MaximumValue;
00213 }
00214
00215
00216 void ctkRangeSlider::setMaximumValue( int max )
00217 {
00218 CTK_D(ctkRangeSlider);
00219 this->setValues( qMin(d->m_MinimumValue, max), max );
00220 }
00221
00222
00223 void ctkRangeSlider::setValues(int l, int u)
00224 {
00225 CTK_D(ctkRangeSlider);
00226 const int minimumValue =
00227 qBound(this->minimum(), qMin(l,u), this->maximum());
00228 const int maximumValue =
00229 qBound(this->minimum(), qMax(l,u), this->maximum());
00230 bool emitMinValChanged = (minimumValue != d->m_MinimumValue);
00231 bool emitMaxValChanged = (maximumValue != d->m_MaximumValue);
00232
00233 d->m_MinimumValue = minimumValue;
00234 d->m_MaximumValue = maximumValue;
00235
00236 bool emitMinPosChanged =
00237 (minimumValue != d->m_MinimumPosition);
00238 bool emitMaxPosChanged =
00239 (maximumValue != d->m_MaximumPosition);
00240 d->m_MinimumPosition = minimumValue;
00241 d->m_MaximumPosition = maximumValue;
00242
00243 if (isSliderDown())
00244 {
00245 if (emitMinPosChanged)
00246 {
00247 emit minimumPositionChanged(minimumValue);
00248 }
00249 if (emitMaxPosChanged)
00250 {
00251 emit maximumPositionChanged(maximumValue);
00252 }
00253 if (emitMinPosChanged || emitMaxPosChanged)
00254 {
00255 emit positionsChanged(minimumValue, maximumValue);
00256 }
00257 }
00258 if (emitMinValChanged)
00259 {
00260 emit minimumValueChanged(minimumValue);
00261 }
00262 if (emitMaxValChanged)
00263 {
00264 emit maximumValueChanged(maximumValue);
00265 }
00266 if (emitMinValChanged || emitMaxValChanged)
00267 {
00268 emit valuesChanged(d->m_MinimumValue,
00269 d->m_MaximumValue);
00270 }
00271 if (emitMinPosChanged || emitMaxPosChanged ||
00272 emitMinValChanged || emitMaxValChanged)
00273 {
00274 this->update();
00275 }
00276 }
00277
00278
00279 int ctkRangeSlider::minimumPosition() const
00280 {
00281 CTK_D(const ctkRangeSlider);
00282 return d->m_MinimumPosition;
00283 }
00284
00285
00286 int ctkRangeSlider::maximumPosition() const
00287 {
00288 CTK_D(const ctkRangeSlider);
00289 return d->m_MaximumPosition;
00290 }
00291
00292
00293 void ctkRangeSlider::setMinimumPosition(int l)
00294 {
00295 CTK_D(const ctkRangeSlider);
00296 this->setPositions(l, qMax(l, d->m_MaximumPosition));
00297 }
00298
00299
00300 void ctkRangeSlider::setMaximumPosition(int u)
00301 {
00302 CTK_D(const ctkRangeSlider);
00303 this->setPositions(qMin(d->m_MinimumPosition, u), u);
00304 }
00305
00306
00307 void ctkRangeSlider::setPositions(int min, int max)
00308 {
00309 CTK_D(ctkRangeSlider);
00310 const int minPosition =
00311 qBound(this->minimum(), qMin(min, max), this->maximum());
00312 const int maxPosition =
00313 qBound(this->minimum(), qMax(min, max), this->maximum());
00314
00315 bool emitMinPosChanged = (minPosition != d->m_MinimumPosition);
00316 bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition);
00317
00318 if (!emitMinPosChanged && !emitMaxPosChanged)
00319 {
00320 return;
00321 }
00322
00323 d->m_MinimumPosition = minPosition;
00324 d->m_MaximumPosition = maxPosition;
00325
00326 if (!this->hasTracking())
00327 {
00328 this->update();
00329 }
00330 if (isSliderDown())
00331 {
00332 if (emitMinPosChanged)
00333 {
00334 emit minimumPositionChanged(d->m_MinimumPosition);
00335 }
00336 if (emitMaxPosChanged)
00337 {
00338 emit maximumPositionChanged(d->m_MaximumPosition);
00339 }
00340 if (emitMinPosChanged || emitMaxPosChanged)
00341 {
00342 emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
00343 }
00344 }
00345 if (this->hasTracking())
00346 {
00347 this->triggerAction(SliderMove);
00348 this->setValues(d->m_MinimumPosition, d->m_MaximumPosition);
00349 }
00350 }
00351
00352
00353 void ctkRangeSlider::onRangeChanged(int minimum, int maximum)
00354 {
00355 CTK_D(ctkRangeSlider);
00356 this->setValues(d->m_MinimumValue, d->m_MaximumValue);
00357 }
00358
00359
00360
00361 void ctkRangeSlider::paintEvent( QPaintEvent* )
00362 {
00363 CTK_D(ctkRangeSlider);
00364 QStyleOptionSlider option;
00365 this->initStyleOption(&option);
00366
00367 QStylePainter painter(this);
00368 option.subControls = QStyle::SC_SliderGroove;
00369 painter.drawComplexControl(QStyle::CC_Slider, option);
00370
00371 option.sliderPosition = d->m_MinimumPosition;
00372 const QRect lr = style()->subControlRect( QStyle::CC_Slider,
00373 &option,
00374 QStyle::SC_SliderHandle,
00375 this);
00376 option.sliderPosition = d->m_MaximumPosition;
00377
00378 const QRect ur = style()->subControlRect( QStyle::CC_Slider,
00379 &option,
00380 QStyle::SC_SliderHandle,
00381 this);
00382
00383 QRect sr = style()->subControlRect( QStyle::CC_Slider,
00384 &option,
00385 QStyle::SC_SliderGroove,
00386 this);
00387
00388 QRect rangeBox = QRect(
00389 QPoint( qMin( lr.center().x(), ur.center().x() ), sr.center().y() - 2),
00390 QPoint(qMax( lr.center().x(), ur.center().x() ), sr.center().y() + 1));
00391
00392
00393
00394
00395
00396 QRect groove = this->style()->subControlRect( QStyle::CC_Slider,
00397 &option,
00398 QStyle::SC_SliderGroove,
00399 this );
00400 groove.adjust(0, 0, -1, 0);
00401
00402 painter.setPen( QPen( this->palette().color(QPalette::Dark).light(90), 0));
00403
00404
00405
00406 QColor highlight = this->palette().color(QPalette::Highlight);
00407 QLinearGradient gradient( groove.center().x(), groove.top(),
00408 groove.center().x(), groove.bottom());
00409
00410
00411 QColor l = Qt::darkGray;
00412 QColor u = Qt::black;
00413
00414 gradient.setColorAt(0, l);
00415 gradient.setColorAt(1, u);
00416
00417 painter.setBrush(gradient);
00418 painter.setPen(QPen(highlight.dark(140), 0));
00419
00420 painter.drawRect( rangeBox.intersected(groove) );
00421
00422
00423
00424
00425 if (d->m_SelectedSlider)
00426 {
00427 d->drawMaximumSlider( &painter );
00428 d->drawMinimumSlider( &painter );
00429 }
00430 else
00431 {
00432 d->drawMinimumSlider( &painter );
00433 d->drawMaximumSlider( &painter );
00434 }
00435 }
00436
00437
00438
00439 void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent)
00440 {
00441 CTK_D(ctkRangeSlider);
00442 if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button()))
00443 {
00444 mouseEvent->ignore();
00445 return;
00446 }
00447
00448 QStyleOptionSlider option;
00449 this->initStyleOption( &option );
00450
00451
00452
00453 if (!this->isSliderDown())
00454 {
00455 option.sliderPosition = d->m_MinimumPosition;
00456 option.sliderValue = d->m_MinimumValue;
00457
00458 QStyle::SubControl& control = d->m_MinimumSliderSelected;
00459
00460 control = this->style()->hitTestComplexControl( QStyle::CC_Slider,
00461 &option,
00462 mouseEvent->pos(),
00463 this);
00464
00465 if (control == QStyle::SC_SliderHandle)
00466 {
00467 d->m_SelectedSlider = true;
00468 d->m_SubclassPosition = d->m_MinimumValue;
00469
00470 const QRect sr = this->style()->subControlRect( QStyle::CC_Slider,
00471 &option,
00472 QStyle::SC_SliderHandle,
00473 this);
00474
00475 d->m_SubclassClickOffset = mouseEvent->pos().x() - sr.topLeft().x();
00476
00477 this->setSliderDown(true);
00478
00479 if (control != d->m_MinimumSliderSelected)
00480 {
00481 this->update(sr);
00482 }
00483 }
00484 }
00485
00486
00487
00488
00489 if (!this->isSliderDown())
00490 {
00491 option.sliderPosition = d->m_MaximumPosition;
00492 option.sliderValue = d->m_MaximumValue;
00493
00494 QStyle::SubControl& control = d->m_MaximumSliderSelected;
00495
00496 control = this->style()->hitTestComplexControl( QStyle::CC_Slider,
00497 &option,
00498 mouseEvent->pos(),
00499 this);
00500
00501 if (control == QStyle::SC_SliderHandle)
00502 {
00503 d->m_SelectedSlider = false;
00504 d->m_SubclassPosition = d->m_MaximumValue;
00505
00506 const QRect sr = this->style()->subControlRect( QStyle::CC_Slider,
00507 &option,
00508 QStyle::SC_SliderHandle,
00509 this);
00510
00511 d->m_SubclassClickOffset = mouseEvent->pos().x() - sr.topLeft().x();
00512
00513 this->setSliderDown(true);
00514
00515 if (d->m_MaximumSliderSelected != control)
00516 {
00517 this->update(sr);
00518 }
00519 }
00520 }
00521
00522
00523
00524 mouseEvent->accept();
00525 }
00526
00527
00528
00529 void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent)
00530 {
00531 CTK_D(ctkRangeSlider);
00532 if (d->m_MinimumSliderSelected == QStyle::SC_SliderHandle ||
00533 d->m_MaximumSliderSelected == QStyle::SC_SliderHandle)
00534 {
00535
00536 QStyleOptionSlider option;
00537 this->initStyleOption(&option);
00538
00539 const int m = style()->pixelMetric( QStyle::PM_MaximumDragDistance, &option, this );
00540
00541 int newPosition = d->pixelPosToRangeValue(
00542 mouseEvent->pos().x() - d->m_SubclassClickOffset);
00543
00544 if (m >= 0)
00545 {
00546 const QRect r = rect().adjusted(-m, -m, m, m);
00547 if (!r.contains(mouseEvent->pos()))
00548 {
00549 newPosition = d->m_SubclassPosition;
00550 }
00551 }
00552
00553 if (d->m_MinimumSliderSelected == QStyle::SC_SliderHandle)
00554 {
00555 this->setMinimumPosition(qMin(newPosition,d->m_MaximumPosition));
00556 }
00557 else if (d->m_MaximumSliderSelected == QStyle::SC_SliderHandle)
00558 {
00559 this->setMaximumPosition(qMax(d->m_MinimumPosition, newPosition));
00560 }
00561 mouseEvent->accept();
00562 }
00563
00564 mouseEvent->ignore();
00565 }
00566
00567
00568
00569 void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent)
00570 {
00571 CTK_D(ctkRangeSlider);
00572 QSlider::mouseReleaseEvent(mouseEvent);
00573 setSliderDown(false);
00574
00575 d->m_MinimumSliderSelected = QStyle::SC_None;
00576 d->m_MaximumSliderSelected = QStyle::SC_None;
00577
00578 this->update();
00579 }
00580