ctkRangeWidget.cpp

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Library:   CTK
00004  
00005   Copyright (c) 2010  Kitware Inc.
00006 
00007   Licensed under the Apache License, Version 2.0 (the "License");
00008   you may not use this file except in compliance with the License.
00009   You may obtain a copy of the License at
00010 
00011       http://www.commontk.org/LICENSE
00012 
00013   Unless required by applicable law or agreed to in writing, software
00014   distributed under the License is distributed on an "AS IS" BASIS,
00015   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016   See the License for the specific language governing permissions and
00017   limitations under the License.
00018  
00019 =========================================================================*/
00020 
00021 // Qt includes
00022 #include <QDebug>
00023 #include <QMouseEvent>
00024 
00025 // CTK includes
00026 #include "ctkRangeWidget.h"
00027 #include "ui_ctkRangeWidget.h"
00028 
00029 //-----------------------------------------------------------------------------
00030 class ctkRangeWidgetPrivate: public ctkPrivate<ctkRangeWidget>,
00031                               public Ui_ctkRangeWidget
00032 {
00033 public:
00034   ctkRangeWidgetPrivate();
00035   void updateSpinBoxWidth();
00036   int synchronizedSpinBoxWidth()const;
00037   void synchronizeSiblingSpinBox(int newWidth);
00038   static bool equal(double v1, double v2);
00039 
00040 
00041   bool   Tracking;
00042   bool   Changing;
00043   double MinimumValueBeforeChange;
00044   double MaximumValueBeforeChange;
00045   bool   AutoSpinBoxWidth;
00046 };
00047 
00048 // --------------------------------------------------------------------------
00049 bool ctkRangeWidgetPrivate::equal(double v1, double v2)
00050 {
00051   return qAbs(v1 - v2) < 0.0001;
00052 }
00053 
00054 // --------------------------------------------------------------------------
00055 ctkRangeWidgetPrivate::ctkRangeWidgetPrivate()
00056 {
00057   this->Tracking = true;
00058   this->Changing = false;
00059   this->MinimumValueBeforeChange = 0.;
00060   this->MaximumValueBeforeChange = 0.;
00061   this->AutoSpinBoxWidth = true;
00062 }
00063 
00064 // --------------------------------------------------------------------------
00065 void ctkRangeWidgetPrivate::updateSpinBoxWidth()
00066 {
00067   int spinBoxWidth = this->synchronizedSpinBoxWidth();
00068   if (this->AutoSpinBoxWidth)
00069     {
00070     this->MinimumSpinBox->setMinimumWidth(spinBoxWidth);
00071     this->MaximumSpinBox->setMinimumWidth(spinBoxWidth);
00072     }
00073   else
00074     {
00075     this->MinimumSpinBox->setMinimumWidth(0);
00076     this->MaximumSpinBox->setMinimumWidth(0);
00077     }
00078   this->synchronizeSiblingSpinBox(spinBoxWidth);
00079 }
00080 
00081 // --------------------------------------------------------------------------
00082 int ctkRangeWidgetPrivate::synchronizedSpinBoxWidth()const
00083 {
00084   CTK_P(const ctkRangeWidget);
00085   //Q_ASSERT(this->MinimumSpinBox->sizeHint() == this->MaximumSpinBox->sizeHint());
00086   int maxWidth = qMax(this->MinimumSpinBox->sizeHint().width(),
00087                       this->MaximumSpinBox->sizeHint().width());
00088   if (!p->parent())
00089     {
00090     return maxWidth;
00091     }
00092   QList<ctkRangeWidget*> siblings =
00093     p->parent()->findChildren<ctkRangeWidget*>();
00094   foreach(ctkRangeWidget* sibling, siblings)
00095     {
00096     maxWidth = qMax(maxWidth, qMax(sibling->ctk_d()->MaximumSpinBox->sizeHint().width(),
00097                                    sibling->ctk_d()->MaximumSpinBox->sizeHint().width()));
00098     }
00099   return maxWidth;
00100 }
00101 
00102 // --------------------------------------------------------------------------
00103 void ctkRangeWidgetPrivate::synchronizeSiblingSpinBox(int width)
00104 {
00105   CTK_P(const ctkRangeWidget);
00106   QList<ctkRangeWidget*> siblings =
00107     p->parent()->findChildren<ctkRangeWidget*>();
00108   foreach(ctkRangeWidget* sibling, siblings)
00109     {
00110     if (sibling != p && sibling->isAutoSpinBoxWidth())
00111       {
00112       sibling->ctk_d()->MinimumSpinBox->setMinimumWidth(width);
00113       sibling->ctk_d()->MaximumSpinBox->setMinimumWidth(width);
00114       }
00115     }
00116 }
00117 
00118 // --------------------------------------------------------------------------
00119 ctkRangeWidget::ctkRangeWidget(QWidget* _parent) : Superclass(_parent)
00120 {
00121   CTK_INIT_PRIVATE(ctkRangeWidget);
00122   CTK_D(ctkRangeWidget);
00123   
00124   d->setupUi(this);
00125 
00126   d->MinimumSpinBox->setMinimum(d->Slider->minimum());
00127   d->MinimumSpinBox->setMaximum(d->Slider->maximum());
00128   d->MaximumSpinBox->setMinimum(d->Slider->minimum());
00129   d->MaximumSpinBox->setMaximum(d->Slider->maximum());
00130   d->MinimumSpinBox->setValue(d->Slider->minimumValue());
00131   d->MaximumSpinBox->setValue(d->Slider->maximumValue());
00132   this->connect(d->Slider, SIGNAL(minimumValueChanged(double)), d->MinimumSpinBox, SLOT(setValue(double)));
00133   this->connect(d->MinimumSpinBox, SIGNAL(valueChanged(double)), d->Slider, SLOT(setMinimumValue(double)));
00134   this->connect(d->Slider, SIGNAL(maximumValueChanged(double)), d->MaximumSpinBox, SLOT(setValue(double)));
00135   this->connect(d->MaximumSpinBox, SIGNAL(valueChanged(double)), d->Slider, SLOT(setMaximumValue(double)));
00136   this->connect(d->MinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setMinimumToMaximumSpinBox(double)));
00137   this->connect(d->MaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setMaximumToMinimumSpinBox(double)));
00138 
00139   this->connect(d->Slider, SIGNAL(sliderPressed()), this, SLOT(startChanging()));
00140   this->connect(d->Slider, SIGNAL(sliderReleased()), this, SLOT(stopChanging()));
00141   this->connect(d->Slider, SIGNAL(minimumValueChanged(double)), this, SLOT(changeMinimumValue(double)));
00142   this->connect(d->Slider, SIGNAL(maximumValueChanged(double)), this, SLOT(changeMaximumValue(double)));
00143   d->MinimumSpinBox->installEventFilter(this);
00144   d->MaximumSpinBox->installEventFilter(this);
00145 }
00146 
00147 // --------------------------------------------------------------------------
00148 double ctkRangeWidget::minimum()const
00149 {
00150   CTK_D(const ctkRangeWidget);
00151   Q_ASSERT(d->equal(d->MinimumSpinBox->minimum(),d->Slider->minimum()));
00152   return d->Slider->minimum();
00153 }
00154 
00155 // --------------------------------------------------------------------------
00156 double ctkRangeWidget::maximum()const
00157 {
00158   CTK_D(const ctkRangeWidget);
00159   Q_ASSERT(d->equal(d->MaximumSpinBox->maximum(), d->Slider->maximum()));
00160   return d->Slider->maximum();
00161 }
00162 
00163 // --------------------------------------------------------------------------
00164 void ctkRangeWidget::setMinimum(double min)
00165 {
00166   CTK_D(ctkRangeWidget);
00167   d->MinimumSpinBox->setMinimum(min);
00168   // SpinBox can truncate min (depending on decimals).
00169   // use Spinbox's min to set Slider's min
00170   d->Slider->setMinimum(d->MinimumSpinBox->minimum());
00171   Q_ASSERT(d->equal(d->MinimumSpinBox->minimum(),d->Slider->minimum()));
00172   d->updateSpinBoxWidth();
00173 }
00174 
00175 // --------------------------------------------------------------------------
00176 void ctkRangeWidget::setMaximum(double max)
00177 {
00178   CTK_D(ctkRangeWidget);
00179   d->MaximumSpinBox->setMaximum(max);
00180   // SpinBox can truncate max (depending on decimals).
00181   // use Spinbox's max to set Slider's max
00182   d->Slider->setMaximum(d->MaximumSpinBox->maximum());
00183   Q_ASSERT(d->equal(d->MaximumSpinBox->maximum(), d->Slider->maximum()));
00184   d->updateSpinBoxWidth();
00185 }
00186 
00187 // --------------------------------------------------------------------------
00188 void ctkRangeWidget::setRange(double min, double max)
00189 {
00190   CTK_D(ctkRangeWidget);
00191   
00192   d->MinimumSpinBox->setMinimum(qMin(min,max));
00193   d->MaximumSpinBox->setMaximum(qMax(min,max));
00194   // SpinBox can truncate the range (depending on decimals).
00195   // use Spinbox's range to set Slider's range
00196   d->Slider->setRange(d->MinimumSpinBox->minimum(), d->MaximumSpinBox->maximum());
00197   Q_ASSERT(d->equal(d->MinimumSpinBox->minimum(), d->Slider->minimum()));
00198   Q_ASSERT(d->equal(d->MaximumSpinBox->maximum(), d->Slider->maximum()));
00199   d->updateSpinBoxWidth();
00200 }
00201 /*
00202 // --------------------------------------------------------------------------
00203 double ctkRangeWidget::sliderPosition()const
00204 {
00205   return ctk_d()->Slider->sliderPosition();
00206 }
00207 
00208 // --------------------------------------------------------------------------
00209 void ctkRangeWidget::setSliderPosition(double position)
00210 {
00211   ctk_d()->Slider->setSliderPosition(position);
00212 }
00213 */
00214 /*
00215 // --------------------------------------------------------------------------
00216 double ctkRangeWidget::previousSliderPosition()
00217 {
00218   return ctk_d()->Slider->previousSliderPosition();
00219 }
00220 */
00221 
00222 // --------------------------------------------------------------------------
00223 double ctkRangeWidget::minimumValue()const
00224 {
00225   CTK_D(const ctkRangeWidget);
00226   Q_ASSERT(d->equal(d->Slider->minimumValue(), d->MinimumSpinBox->value()));
00227   return d->Changing ? d->MinimumValueBeforeChange : d->Slider->minimumValue();
00228 }
00229 
00230 // --------------------------------------------------------------------------
00231 double ctkRangeWidget::maximumValue()const
00232 {
00233   CTK_D(const ctkRangeWidget);
00234   Q_ASSERT(d->equal(d->Slider->maximumValue(), d->MaximumSpinBox->value()));
00235   return d->Changing ? d->MaximumValueBeforeChange : d->Slider->maximumValue();
00236 }
00237 
00238 // --------------------------------------------------------------------------
00239 void ctkRangeWidget::setMinimumValue(double _value)
00240 {
00241   CTK_D(ctkRangeWidget);
00242   // disable the tracking temporally to emit the
00243   // signal valueChanged if changeValue() is called
00244   bool isChanging = d->Changing;
00245   d->Changing = false;
00246   d->MinimumSpinBox->setValue(_value);
00247   // Why do we need to set the value to the slider ?
00248   //d->Slider->setValue(d->SpinBox->value());
00249   Q_ASSERT(d->equal(d->Slider->minimumValue(), d->MinimumSpinBox->value()));
00250   // restore the prop
00251   d->Changing = isChanging;
00252 }
00253 
00254 // --------------------------------------------------------------------------
00255 void ctkRangeWidget::setMaximumValue(double _value)
00256 {
00257   CTK_D(ctkRangeWidget);
00258   // disable the tracking temporally to emit the
00259   // signal valueChanged if changeValue() is called
00260   bool isChanging = d->Changing;
00261   d->Changing = false;
00262   d->MaximumSpinBox->setValue(_value);
00263   // Why do we need to set the value to the slider ?
00264   //d->Slider->setValue(d->SpinBox->value());
00265   Q_ASSERT(d->equal(d->Slider->maximumValue(), d->MaximumSpinBox->value()));
00266   // restore the prop
00267   d->Changing = isChanging;
00268 }
00269 
00270 // --------------------------------------------------------------------------
00271 void ctkRangeWidget::setValues(double newMinimumValue, double newMaximumValue)
00272 {
00273   CTK_D(ctkRangeWidget);
00274   // disable the tracking temporally to emit the
00275   // signal valueChanged if changeValue() is called
00276   bool isChanging = d->Changing;
00277   d->Changing = false;
00278   d->MinimumSpinBox->setValue(newMinimumValue);
00279   d->MaximumSpinBox->setValue(newMaximumValue);
00280   // Why do we need to set the value to the slider ?
00281   //d->Slider->setValue(d->SpinBox->value());
00282   Q_ASSERT(d->equal(d->Slider->minimumValue(), d->MinimumSpinBox->value()));
00283   Q_ASSERT(d->equal(d->Slider->maximumValue(), d->MaximumSpinBox->value()));
00284   // restore the prop
00285   d->Changing = isChanging;
00286 }
00287 
00288 // --------------------------------------------------------------------------
00289 void ctkRangeWidget::setMinimumToMaximumSpinBox(double minimum)
00290 {
00291   ctk_d()->MaximumSpinBox->setMinimum(minimum);
00292 }
00293 
00294 // --------------------------------------------------------------------------
00295 void ctkRangeWidget::setMaximumToMinimumSpinBox(double maximum)
00296 {
00297   ctk_d()->MinimumSpinBox->setMaximum(maximum);
00298 }
00299 
00300 // --------------------------------------------------------------------------
00301 void ctkRangeWidget::startChanging()
00302 {
00303   CTK_D(ctkRangeWidget);
00304   if (d->Tracking)
00305     {
00306     return;
00307     }
00308   d->Changing = true;
00309   d->MinimumValueBeforeChange = this->minimumValue();
00310   d->MaximumValueBeforeChange = this->maximumValue();
00311 }
00312 
00313 // --------------------------------------------------------------------------
00314 void ctkRangeWidget::stopChanging()
00315 {
00316   CTK_D(ctkRangeWidget);
00317   if (d->Tracking)
00318     {
00319     return;
00320     }
00321   d->Changing = false;
00322   if (qAbs(this->minimumValue() - d->MinimumValueBeforeChange) > (this->singleStep() * 0.000000001))
00323     {
00324     emit this->minimumValueChanged(this->minimumValue());
00325     }
00326   if (qAbs(this->maximumValue() - d->MaximumValueBeforeChange) > (this->singleStep() * 0.000000001))
00327     {
00328     emit this->maximumValueChanged(this->maximumValue());
00329     }
00330 }
00331 
00332 // --------------------------------------------------------------------------
00333 void ctkRangeWidget::changeMinimumValue(double newValue)
00334 {
00335   CTK_D(ctkRangeWidget);
00336   //if (d->Tracking)
00337     {
00338     emit this->minimumValueIsChanging(newValue);
00339     }
00340   if (!d->Changing)
00341     {
00342     emit this->minimumValueChanged(newValue);
00343     }
00344 }
00345 
00346 // --------------------------------------------------------------------------
00347 void ctkRangeWidget::changeMaximumValue(double newValue)
00348 {
00349   CTK_D(ctkRangeWidget);
00350   //if (d->Tracking)
00351     {
00352     emit this->maximumValueIsChanging(newValue);
00353     }
00354   if (!d->Changing)
00355     {
00356     emit this->maximumValueChanged(newValue);
00357     }
00358 }
00359 
00360 // --------------------------------------------------------------------------
00361 bool ctkRangeWidget::eventFilter(QObject *obj, QEvent *event)
00362  {
00363    if (event->type() == QEvent::MouseButtonPress)
00364      {
00365      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
00366      if (mouseEvent->button() & Qt::LeftButton)
00367        {
00368        this->startChanging();
00369        }
00370      }
00371    else if (event->type() == QEvent::MouseButtonRelease) 
00372      {
00373      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
00374      if (mouseEvent->button() & Qt::LeftButton)
00375        {
00376        // here we might prevent ctkRangeWidget::stopChanging
00377        // from sending a valueChanged() event as the spinbox might
00378        // send a valueChanged() after eventFilter() is done.
00379        this->stopChanging();
00380        }
00381      } 
00382    // standard event processing
00383    return this->Superclass::eventFilter(obj, event);
00384  }
00385 
00386 // --------------------------------------------------------------------------
00387 double ctkRangeWidget::singleStep()const
00388 {
00389   CTK_D(const ctkRangeWidget);
00390   Q_ASSERT(d->equal(d->Slider->singleStep(), d->MinimumSpinBox->singleStep()) &&
00391            d->equal(d->Slider->singleStep(), d->MaximumSpinBox->singleStep()));
00392   return d->Slider->singleStep();
00393 }
00394 
00395 // --------------------------------------------------------------------------
00396 void ctkRangeWidget::setSingleStep(double step)
00397 {
00398   CTK_D(ctkRangeWidget);
00399   d->MinimumSpinBox->setSingleStep(step);
00400   d->MaximumSpinBox->setSingleStep(step);
00401   d->Slider->setSingleStep(d->MinimumSpinBox->singleStep());
00402   Q_ASSERT(d->equal(d->Slider->singleStep(), d->MinimumSpinBox->singleStep()) &&
00403            d->equal(d->Slider->singleStep(), d->MaximumSpinBox->singleStep()));
00404 }
00405 
00406 // --------------------------------------------------------------------------
00407 int ctkRangeWidget::decimals()const
00408 {
00409   CTK_D(const ctkRangeWidget);
00410   Q_ASSERT(d->MinimumSpinBox->decimals() == d->MaximumSpinBox->decimals());
00411   return d->MinimumSpinBox->decimals();
00412 }
00413 
00414 // --------------------------------------------------------------------------
00415 void ctkRangeWidget::setDecimals(int newDecimals)
00416 {
00417   CTK_D(ctkRangeWidget);
00418   d->MinimumSpinBox->setDecimals(newDecimals);
00419   d->MaximumSpinBox->setDecimals(newDecimals);
00420   // The number of decimals can change the range values
00421   // i.e. 50.55 with 2 decimals -> 51 with 0 decimals
00422   // As the SpinBox range change doesn't fire signals, 
00423   // we have to do the synchronization manually here
00424   d->Slider->setMinimum(d->MinimumSpinBox->minimum());
00425   d->Slider->setMaximum(d->MaximumSpinBox->maximum());
00426 }
00427 
00428 // --------------------------------------------------------------------------
00429 QString ctkRangeWidget::prefix()const
00430 {
00431   CTK_D(const ctkRangeWidget);
00432   Q_ASSERT(d->MinimumSpinBox->prefix() == d->MaximumSpinBox->prefix());
00433   return d->MinimumSpinBox->prefix();
00434 }
00435 
00436 // --------------------------------------------------------------------------
00437 void ctkRangeWidget::setPrefix(const QString& newPrefix)
00438 {
00439   CTK_D(ctkRangeWidget);
00440   d->MinimumSpinBox->setPrefix(newPrefix);
00441   d->MaximumSpinBox->setPrefix(newPrefix);
00442 }
00443 
00444 // --------------------------------------------------------------------------
00445 QString ctkRangeWidget::suffix()const
00446 {
00447   CTK_D(const ctkRangeWidget);
00448  Q_ASSERT(d->MinimumSpinBox->suffix() == d->MaximumSpinBox->suffix());
00449   return d->MinimumSpinBox->suffix();
00450 }
00451 
00452 // --------------------------------------------------------------------------
00453 void ctkRangeWidget::setSuffix(const QString& newSuffix)
00454 {
00455   CTK_D(ctkRangeWidget);
00456   d->MinimumSpinBox->setSuffix(newSuffix);
00457   d->MaximumSpinBox->setSuffix(newSuffix);
00458 }
00459 
00460 // --------------------------------------------------------------------------
00461 double ctkRangeWidget::tickInterval()const
00462 {
00463   CTK_D(const ctkRangeWidget);
00464   return d->Slider->tickInterval();
00465 }
00466 
00467 // --------------------------------------------------------------------------
00468 void ctkRangeWidget::setTickInterval(double ti)
00469 { 
00470   CTK_D(ctkRangeWidget);
00471   d->Slider->setTickInterval(ti);
00472 }
00473 
00474 // -------------------------------------------------------------------------
00475 void ctkRangeWidget::reset()
00476 {
00477   this->setMinimumValue(this->minimum());
00478   this->setMaximumValue(this->maximum());
00479 }
00480 
00481 // -------------------------------------------------------------------------
00482 void ctkRangeWidget::setSpinBoxAlignment(Qt::Alignment alignment)
00483 {
00484   CTK_D(ctkRangeWidget);
00485   d->MinimumSpinBox->setAlignment(alignment);
00486   d->MaximumSpinBox->setAlignment(alignment);
00487 }
00488 
00489 // -------------------------------------------------------------------------
00490 Qt::Alignment ctkRangeWidget::spinBoxAlignment()const
00491 {
00492   CTK_D(const ctkRangeWidget);
00493   Q_ASSERT(d->MinimumSpinBox->alignment() == d->MaximumSpinBox->alignment());
00494   return d->MinimumSpinBox->alignment();
00495 }
00496 
00497 // -------------------------------------------------------------------------
00498 void ctkRangeWidget::setTracking(bool enable)
00499 {
00500   CTK_D(ctkRangeWidget);
00501   d->Tracking = enable;
00502 }
00503 
00504 // -------------------------------------------------------------------------
00505 bool ctkRangeWidget::hasTracking()const
00506 {
00507   CTK_D(const ctkRangeWidget);
00508   return d->Tracking;
00509 }
00510 
00511 // -------------------------------------------------------------------------
00512 bool ctkRangeWidget::isAutoSpinBoxWidth()const
00513 {
00514   CTK_D(const ctkRangeWidget);
00515   return d->AutoSpinBoxWidth;
00516 }
00517 
00518 // -------------------------------------------------------------------------
00519 void ctkRangeWidget::setAutoSpinBoxWidth(bool autoWidth)
00520 {
00521   CTK_D(ctkRangeWidget);
00522   d->AutoSpinBoxWidth = autoWidth;
00523   d->updateSpinBoxWidth();
00524 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines