ctkSliderSpinBoxWidget.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 "ctkSliderSpinBoxWidget.h"
00027 #include "ui_ctkSliderSpinBoxWidget.h"
00028 
00029 //-----------------------------------------------------------------------------
00030 namespace
00031 {
00032 bool equal(double v1, double v2)
00033 {
00034   return qAbs(v1 - v2) < 0.0001;
00035 }
00036 }
00037 
00038 //-----------------------------------------------------------------------------
00039 class ctkSliderSpinBoxWidgetPrivate: public ctkPrivate<ctkSliderSpinBoxWidget>,
00040                                      public Ui_ctkSliderSpinBoxWidget
00041 {
00042 public:
00043   ctkSliderSpinBoxWidgetPrivate();
00044   void updateSpinBoxWidth();
00045   int synchronizedSpinBoxWidth()const;
00046   void synchronizeSiblingSpinBox(int newWidth);
00047 
00048   bool   Tracking;
00049   bool   Changing;
00050   double ValueBeforeChange;
00051   bool   AutoSpinBoxWidth;
00052 };
00053 
00054 // --------------------------------------------------------------------------
00055 ctkSliderSpinBoxWidgetPrivate::ctkSliderSpinBoxWidgetPrivate()
00056 {
00057   this->Tracking = true;
00058   this->Changing = false;
00059   this->ValueBeforeChange = 0.;
00060   this->AutoSpinBoxWidth = true;
00061 }
00062 
00063 // --------------------------------------------------------------------------
00064 void ctkSliderSpinBoxWidgetPrivate::updateSpinBoxWidth()
00065 {
00066   int spinBoxWidth = this->synchronizedSpinBoxWidth();
00067   if (this->AutoSpinBoxWidth)
00068     {
00069     this->SpinBox->setMinimumWidth(spinBoxWidth);
00070     }
00071   else
00072     {
00073     this->SpinBox->setMinimumWidth(0);
00074     }
00075   this->synchronizeSiblingSpinBox(spinBoxWidth);
00076 }
00077 
00078 // --------------------------------------------------------------------------
00079 int ctkSliderSpinBoxWidgetPrivate::synchronizedSpinBoxWidth()const
00080 {
00081   CTK_P(const ctkSliderSpinBoxWidget);
00082   int maxWidth = this->SpinBox->sizeHint().width();
00083   if (!p->parent())
00084     {
00085     return maxWidth;
00086     }
00087   QList<ctkSliderSpinBoxWidget*> siblings =
00088     p->parent()->findChildren<ctkSliderSpinBoxWidget*>();
00089   foreach(ctkSliderSpinBoxWidget* sibling, siblings)
00090     {
00091     maxWidth = qMax(maxWidth, sibling->ctk_d()->SpinBox->sizeHint().width());
00092     }
00093   return maxWidth;
00094 }
00095 
00096 // --------------------------------------------------------------------------
00097 void ctkSliderSpinBoxWidgetPrivate::synchronizeSiblingSpinBox(int width)
00098 {
00099   CTK_P(const ctkSliderSpinBoxWidget);
00100   QList<ctkSliderSpinBoxWidget*> siblings =
00101     p->parent()->findChildren<ctkSliderSpinBoxWidget*>();
00102   foreach(ctkSliderSpinBoxWidget* sibling, siblings)
00103     {
00104     if (sibling != p && sibling->isAutoSpinBoxWidth())
00105       {
00106       sibling->ctk_d()->SpinBox->setMinimumWidth(width);
00107       }
00108     }
00109 }
00110 
00111 // --------------------------------------------------------------------------
00112 ctkSliderSpinBoxWidget::ctkSliderSpinBoxWidget(QWidget* _parent) : Superclass(_parent)
00113 {
00114   CTK_INIT_PRIVATE(ctkSliderSpinBoxWidget);
00115   CTK_D(ctkSliderSpinBoxWidget);
00116   
00117   d->setupUi(this);
00118 
00119   d->Slider->setMaximum(d->SpinBox->maximum());
00120   d->Slider->setMinimum(d->SpinBox->minimum());
00121 
00122   this->connect(d->Slider, SIGNAL(valueChanged(double)), d->SpinBox, SLOT(setValue(double)));
00123   this->connect(d->SpinBox, SIGNAL(valueChanged(double)), d->Slider, SLOT(setValue(double)));
00124 
00125   //this->connect(d->Slider, SIGNAL(valueChanged(double)), SIGNAL(valueChanged(double)));
00126   this->connect(d->Slider, SIGNAL(sliderPressed()), this, SLOT(startChanging()));
00127   this->connect(d->Slider, SIGNAL(sliderReleased()), this, SLOT(stopChanging()));
00128   this->connect(d->Slider, SIGNAL(valueChanged(double)), this, SLOT(changeValue(double)));
00129   d->SpinBox->installEventFilter(this);
00130 }
00131 
00132 // --------------------------------------------------------------------------
00133 double ctkSliderSpinBoxWidget::minimum()const
00134 {
00135   CTK_D(const ctkSliderSpinBoxWidget);
00136   Q_ASSERT(equal(d->SpinBox->minimum(),d->Slider->minimum()));
00137   return d->Slider->minimum();
00138 }
00139 
00140 // --------------------------------------------------------------------------
00141 double ctkSliderSpinBoxWidget::maximum()const
00142 {
00143   CTK_D(const ctkSliderSpinBoxWidget);
00144   Q_ASSERT(equal(d->SpinBox->maximum(),d->Slider->maximum()));
00145   return d->Slider->maximum();
00146 }
00147 
00148 // --------------------------------------------------------------------------
00149 void ctkSliderSpinBoxWidget::setMinimum(double min)
00150 {
00151   CTK_D(ctkSliderSpinBoxWidget);
00152   d->SpinBox->setMinimum(min);
00153   // SpinBox can truncate min (depending on decimals).
00154   // use Spinbox's min to set Slider's min
00155   d->Slider->setMinimum(d->SpinBox->minimum());
00156   Q_ASSERT(equal(d->SpinBox->minimum(),d->Slider->minimum()));
00157   d->updateSpinBoxWidth();
00158 }
00159 
00160 // --------------------------------------------------------------------------
00161 void ctkSliderSpinBoxWidget::setMaximum(double max)
00162 {
00163   CTK_D(ctkSliderSpinBoxWidget);
00164   d->SpinBox->setMaximum(max);
00165   // SpinBox can truncate max (depending on decimals).
00166   // use Spinbox's max to set Slider's max
00167   d->Slider->setMaximum(d->SpinBox->maximum());
00168   Q_ASSERT(equal(d->SpinBox->maximum(), d->Slider->maximum()));
00169   d->updateSpinBoxWidth();
00170 }
00171 
00172 // --------------------------------------------------------------------------
00173 void ctkSliderSpinBoxWidget::setRange(double min, double max)
00174 {
00175   CTK_D(ctkSliderSpinBoxWidget);
00176   
00177   d->SpinBox->setRange(min, max);
00178   // SpinBox can truncate the range (depending on decimals).
00179   // use Spinbox's range to set Slider's range
00180   d->Slider->setRange(d->SpinBox->minimum(), d->SpinBox->maximum());
00181   Q_ASSERT(equal(d->SpinBox->minimum(), d->Slider->minimum()));
00182   Q_ASSERT(equal(d->SpinBox->maximum(), d->Slider->maximum()));
00183   d->updateSpinBoxWidth();
00184 }
00185 /*
00186 // --------------------------------------------------------------------------
00187 double ctkSliderSpinBoxWidget::sliderPosition()const
00188 {
00189   return ctk_d()->Slider->sliderPosition();
00190 }
00191 
00192 // --------------------------------------------------------------------------
00193 void ctkSliderSpinBoxWidget::setSliderPosition(double position)
00194 {
00195   ctk_d()->Slider->setSliderPosition(position);
00196 }
00197 */
00198 /*
00199 // --------------------------------------------------------------------------
00200 double ctkSliderSpinBoxWidget::previousSliderPosition()
00201 {
00202   return ctk_d()->Slider->previousSliderPosition();
00203 }
00204 */
00205 
00206 // --------------------------------------------------------------------------
00207 double ctkSliderSpinBoxWidget::value()const
00208 {
00209   CTK_D(const ctkSliderSpinBoxWidget);
00210   Q_ASSERT(equal(d->Slider->value(), d->SpinBox->value()));
00211   return d->Changing ? d->ValueBeforeChange : d->Slider->value();
00212 }
00213 
00214 // --------------------------------------------------------------------------
00215 void ctkSliderSpinBoxWidget::setValue(double _value)
00216 {
00217   CTK_D(ctkSliderSpinBoxWidget);
00218   // disable the tracking temporally to emit the
00219   // signal valueChanged if changeValue() is called
00220   bool isChanging = d->Changing;
00221   d->Changing = false;
00222   d->SpinBox->setValue(_value);
00223   // Why do we need to set the value to the slider ?
00224   //d->Slider->setValue(d->SpinBox->value());
00225   Q_ASSERT(equal(d->Slider->value(), d->SpinBox->value()));
00226   // restore the prop
00227   d->Changing = isChanging;
00228 }
00229 
00230 // --------------------------------------------------------------------------
00231 void ctkSliderSpinBoxWidget::startChanging()
00232 {
00233   CTK_D(ctkSliderSpinBoxWidget);
00234   if (d->Tracking)
00235     {
00236     return;
00237     }
00238   d->Changing = true;
00239   d->ValueBeforeChange = this->value();
00240 }
00241 
00242 // --------------------------------------------------------------------------
00243 void ctkSliderSpinBoxWidget::stopChanging()
00244 {
00245   CTK_D(ctkSliderSpinBoxWidget);
00246   if (d->Tracking)
00247     {
00248     return;
00249     }
00250   d->Changing = false;
00251   if (qAbs(this->value() - d->ValueBeforeChange) > (this->singleStep() * 0.000000001))
00252     {
00253     emit this->valueChanged(this->value());
00254     }
00255 }
00256 
00257 // --------------------------------------------------------------------------
00258 void ctkSliderSpinBoxWidget::changeValue(double newValue)
00259 {
00260   CTK_D(ctkSliderSpinBoxWidget);
00261   //if (d->Tracking)
00262     {
00263     emit this->valueIsChanging(newValue);
00264     }
00265   if (!d->Changing)
00266     {
00267     emit this->valueChanged(newValue);
00268     }
00269 }
00270 
00271 // --------------------------------------------------------------------------
00272 bool ctkSliderSpinBoxWidget::eventFilter(QObject *obj, QEvent *event)
00273  {
00274    if (event->type() == QEvent::MouseButtonPress)
00275      {
00276      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
00277      if (mouseEvent->button() & Qt::LeftButton)
00278        {
00279        this->startChanging();
00280        }
00281      }
00282    else if (event->type() == QEvent::MouseButtonRelease) 
00283      {
00284      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
00285      if (mouseEvent->button() & Qt::LeftButton)
00286        {
00287        // here we might prevent ctkSliderSpinBoxWidget::stopChanging
00288        // from sending a valueChanged() event as the spinbox might
00289        // send a valueChanged() after eventFilter() is done.
00290        this->stopChanging();
00291        }
00292      } 
00293    // standard event processing
00294    return this->Superclass::eventFilter(obj, event);
00295  }
00296 
00297 // --------------------------------------------------------------------------
00298 double ctkSliderSpinBoxWidget::singleStep()const
00299 {
00300   CTK_D(const ctkSliderSpinBoxWidget);
00301   Q_ASSERT(equal(d->Slider->singleStep(), d->SpinBox->singleStep()));
00302   return d->Slider->singleStep();
00303 }
00304 
00305 // --------------------------------------------------------------------------
00306 void ctkSliderSpinBoxWidget::setSingleStep(double step)
00307 {
00308   CTK_D(ctkSliderSpinBoxWidget);
00309   d->SpinBox->setSingleStep(step);
00310   d->Slider->setSingleStep(d->SpinBox->singleStep());
00311   Q_ASSERT(equal(d->Slider->singleStep(), d->SpinBox->singleStep()));
00312 }
00313 
00314 // --------------------------------------------------------------------------
00315 int ctkSliderSpinBoxWidget::decimals()const
00316 {
00317   CTK_D(const ctkSliderSpinBoxWidget);
00318   return d->SpinBox->decimals();
00319 }
00320 
00321 // --------------------------------------------------------------------------
00322 void ctkSliderSpinBoxWidget::setDecimals(int newDecimals)
00323 {
00324   CTK_D(ctkSliderSpinBoxWidget);
00325   d->SpinBox->setDecimals(newDecimals);
00326   // The number of decimals can change the range values
00327   // i.e. 50.55 with 2 decimals -> 51 with 0 decimals
00328   // As the SpinBox range change doesn't fire signals, 
00329   // we have to do the synchronization manually here
00330   d->Slider->setMinimum(d->SpinBox->minimum());
00331   d->Slider->setMaximum(d->SpinBox->maximum());
00332 }
00333 
00334 // --------------------------------------------------------------------------
00335 QString ctkSliderSpinBoxWidget::prefix()const
00336 {
00337   CTK_D(const ctkSliderSpinBoxWidget);
00338   return d->SpinBox->prefix();
00339 }
00340 
00341 // --------------------------------------------------------------------------
00342 void ctkSliderSpinBoxWidget::setPrefix(const QString& newPrefix)
00343 {
00344   CTK_D(ctkSliderSpinBoxWidget);
00345   d->SpinBox->setPrefix(newPrefix);
00346 }
00347 
00348 // --------------------------------------------------------------------------
00349 QString ctkSliderSpinBoxWidget::suffix()const
00350 {
00351   CTK_D(const ctkSliderSpinBoxWidget);
00352   return d->SpinBox->suffix();
00353 }
00354 
00355 // --------------------------------------------------------------------------
00356 void ctkSliderSpinBoxWidget::setSuffix(const QString& newSuffix)
00357 {
00358   CTK_D(ctkSliderSpinBoxWidget);
00359   d->SpinBox->setSuffix(newSuffix);
00360 }
00361 
00362 // --------------------------------------------------------------------------
00363 double ctkSliderSpinBoxWidget::tickInterval()const
00364 {
00365   CTK_D(const ctkSliderSpinBoxWidget);
00366   return d->Slider->tickInterval();
00367 }
00368 
00369 // --------------------------------------------------------------------------
00370 void ctkSliderSpinBoxWidget::setTickInterval(double ti)
00371 { 
00372   CTK_D(ctkSliderSpinBoxWidget);
00373   d->Slider->setTickInterval(ti);
00374 }
00375 
00376 // -------------------------------------------------------------------------
00377 void ctkSliderSpinBoxWidget::reset()
00378 {
00379   this->setValue(0.);
00380 }
00381 
00382 // -------------------------------------------------------------------------
00383 void ctkSliderSpinBoxWidget::setSpinBoxAlignment(Qt::Alignment alignment)
00384 {
00385   return ctk_d()->SpinBox->setAlignment(alignment);
00386 }
00387 
00388 // -------------------------------------------------------------------------
00389 Qt::Alignment ctkSliderSpinBoxWidget::spinBoxAlignment()const
00390 {
00391   return ctk_d()->SpinBox->alignment();
00392 }
00393 
00394 // -------------------------------------------------------------------------
00395 void ctkSliderSpinBoxWidget::setTracking(bool enable)
00396 {
00397   CTK_D(ctkSliderSpinBoxWidget);
00398   d->Tracking = enable;
00399 }
00400 
00401 // -------------------------------------------------------------------------
00402 bool ctkSliderSpinBoxWidget::hasTracking()const
00403 {
00404   CTK_D(const ctkSliderSpinBoxWidget);
00405   return d->Tracking;
00406 }
00407 
00408 // -------------------------------------------------------------------------
00409 bool ctkSliderSpinBoxWidget::isAutoSpinBoxWidth()const
00410 {
00411   CTK_D(const ctkSliderSpinBoxWidget);
00412   return d->AutoSpinBoxWidth;
00413 }
00414 
00415 // -------------------------------------------------------------------------
00416 void ctkSliderSpinBoxWidget::setAutoSpinBoxWidth(bool autoWidth)
00417 {
00418   CTK_D(ctkSliderSpinBoxWidget);
00419   d->AutoSpinBoxWidth = autoWidth;
00420   d->updateSpinBoxWidth();
00421 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines