Browse Source

Merge pull request #323 from vovythevov/ctkSpinBox

Add ctkSpinBox DecimalsStyle::UseShortcut
Julien Finet 12 years ago
parent
commit
4f6fe07cd1

+ 3 - 0
Libs/Widgets/Resources/UI/ctkScreenshotDialog.ui

@@ -155,6 +155,9 @@
         <property name="toolTip">
          <string>Select an integer scale factor (between 0.5 and 5) for the image file, e.g. a value of &quot;2&quot; will save an image twice the size.</string>
         </property>
+        <property name="decimalsOption">
+         <enum>ctkSpinBox::Fixed</enum>
+        </property>
         <property name="decimals">
          <number>1</number>
         </property>

+ 6 - 6
Libs/Widgets/Testing/Cpp/ctkRangeWidgetEventTranslatorPlayerTest1.xml

@@ -59,11 +59,11 @@
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/Slider" command="set_min_double" arguments="35"/>
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/Slider" command="set_min_double" arguments="36"/>
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/Slider" command="set_min_double" arguments="37"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox" command="spin" arguments="down"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox" command="spin" arguments="down"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox" command="spin" arguments="down"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox" command="spin" arguments="down"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox" command="spin" arguments="down"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox" command="spin" arguments="down"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="70"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="71"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MaximumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="72"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="32"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="33"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget1/MinimumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="34"/>
     </events>
 </QtTesting>

+ 2 - 2
Libs/Widgets/Testing/Cpp/ctkRangeWidgetEventTranslatorPlayerTest2.xml

@@ -17,7 +17,7 @@
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/Slider" command="set_max_double" arguments="0.4"/>
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/Slider" command="set_max_double" arguments="-4.6"/>
         <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/Slider" command="set_max_double" arguments="-9.6"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/MinimumSpinBox" command="spin" arguments="up"/>
-        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/MinimumSpinBox" command="spin" arguments="up"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/MinimumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="-36"/>
+        <event widget="ctkEventTranslatorPlayerWidget/centralwidget/stackedWidget/RangeWidget2/MinimumSpinBox/1QDoubleSpinBox0" command="set_double" arguments="-35"/>
     </events>
 </QtTesting>

+ 4 - 3
Libs/Widgets/Testing/Cpp/ctkSliderWidgetTest1.cpp

@@ -152,13 +152,14 @@ int ctkSliderWidgetTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  sliderSpinBox.setAutoSpinBoxWidth(false);
+  sliderSpinBox.setSynchronizeSiblings(ctkSliderWidget::NoSynchronize);
 
-  if (sliderSpinBox.isAutoSpinBoxWidth() != false || 
+  if (sliderSpinBox.synchronizeSiblings().testFlag(
+      ctkSliderWidget::SynchronizeWidth) != false ||
       !qFuzzyCompare(sliderSpinBox.value(), 80.6))
     {
     std::cerr << "ctkSliderWidget::setAutoSpinBoxWidth failed."
-              << sliderSpinBox.isAutoSpinBoxWidth() << " "
+              << sliderSpinBox.synchronizeSiblings() << " "
               << sliderSpinBox.value() << std::endl;
     return EXIT_FAILURE;
     }

+ 3 - 0
Libs/Widgets/ctkCoordinatesWidget.cpp

@@ -63,6 +63,9 @@ void ctkCoordinatesWidget::addSpinBox()
   spinBox->setMaximum(this->Maximum);
   connect( spinBox, SIGNAL(valueChanged(double)),
            this, SLOT(updateCoordinate(double)));
+  // Same number of decimals within the spinboxes.
+  connect( spinBox, SIGNAL(decimalsChanged(int)),
+           this, SLOT(setDecimals(int)));
   this->layout()->addWidget(spinBox);
 }
 

+ 4 - 2
Libs/Widgets/ctkCoordinatesWidget.h

@@ -59,9 +59,8 @@ public:
   void setDimension(int dim);
   int dimension() const;
 
-  /// Set/Get the number of decimals of each coordinate spin box
+  /// Get the number of decimals of each coordinate spin box
   /// The default number of decimals is 3.
-  void setDecimals(int decimals);
   int decimals() const;
 
   /// Set/Get the single step of each coordinate spin box
@@ -106,6 +105,9 @@ public:
 public Q_SLOTS:
   void normalize();
 
+  /// Set the number of decimals of each coordinate spin box.
+  void setDecimals(int decimals);
+
 Q_SIGNALS:
   ///
   /// valueChanged is fired anytime a coordinate is modified, the returned

+ 3 - 0
Libs/Widgets/ctkMatrixWidget.cpp

@@ -56,6 +56,9 @@ namespace
       this->setMaximum(matrixWidget->maximum());
       this->setDecimals(matrixWidget->decimals());
       this->setSingleStep(matrixWidget->singleStep());
+
+      this->connect(this, SIGNAL(decimalsChanged(int)),
+        matrixWidget, SLOT(setDecimals(int)));
     }
   };
 }

+ 5 - 1
Libs/Widgets/ctkMatrixWidget.h

@@ -122,7 +122,6 @@ public:
   /// Dictates how many decimals will be used for displaying and interpreting doubles by the spinbox
   /// used to adjust the value of a matrix element.
   int decimals()const;
-  void setDecimals(int decimals);
 
   ///
   /// Reimplemented from QAbstractScrollArea
@@ -135,6 +134,11 @@ public Q_SLOTS:
   /// Reset the matrix to identity
   void identity();
 
+  ///
+  /// Set how many decimals will be used for displaying and interpreting
+  /// doubles by the spinbox used to adjust the value of a matrix element.
+  void setDecimals(int decimals);
+
 Q_SIGNALS:
   void matrixChanged();
 

+ 4 - 0
Libs/Widgets/ctkRangeWidget.cpp

@@ -92,6 +92,10 @@ void ctkRangeWidgetPrivate::connectSlider()
                    q, SLOT(setMinimumToMaximumSpinBox(double)));
   QObject::connect(this->MaximumSpinBox, SIGNAL(valueChanged(double)),
                    q, SLOT(setMaximumToMinimumSpinBox(double)));
+  QObject::connect(this->MinimumSpinBox, SIGNAL(decimalsChanged(int)),
+                   q, SLOT(setDecimals(int)));
+  QObject::connect(this->MaximumSpinBox, SIGNAL(decimalsChanged(int)),
+                   q, SLOT(setDecimals(int)));
 
   QObject::connect(this->Slider, SIGNAL(sliderPressed()),
                    q, SLOT(startChanging()));

+ 4 - 3
Libs/Widgets/ctkRangeWidget.h

@@ -118,10 +118,7 @@ public:
 
   ///
   /// This property holds the precision of the spin box, in decimals.
-  /// Sets how many decimals the spinbox will use for displaying and
-  /// interpreting doubles.
   int decimals()const;
-  void setDecimals(int decimals);
 
   ///
   /// This property holds the spin box's prefix.
@@ -192,6 +189,10 @@ public Q_SLOTS:
   /// Utility function that set the min and max values at once
   void setValues(double minValue, double maxValue);
 
+  /// Sets how many decimals the spinbox will use for displaying and
+  /// interpreting doubles.
+  void setDecimals(int decimals);
+
 Q_SIGNALS:
   /// Use with care:
   /// sliderMoved is emitted only when the user moves the slider

+ 53 - 14
Libs/Widgets/ctkSliderWidget.cpp

@@ -42,8 +42,12 @@ public:
   virtual ~ctkSliderWidgetPrivate();
 
   void updateSpinBoxWidth();
-  int synchronizedSpinBoxWidth()const;
-  void synchronizeSiblingSpinBox(int newWidth);
+  void updateSpinBoxDecimals();
+
+  int synchronizedSpinBoxWidth() const;
+
+  void synchronizeSiblingWidth(int width);
+  void synchronizeSiblingDecimals(int decimals);
   bool equal(double spinBoxValue, double sliderValue)const
   {
     return qAbs(sliderValue - spinBoxValue) < std::pow(10., -this->SpinBox->decimals());
@@ -52,7 +56,7 @@ public:
   bool   Tracking;
   bool   Changing;
   double ValueBeforeChange;
-  bool   AutoSpinBoxWidth;
+  ctkSliderWidget::SynchronizeSiblings SynchronizeMode;
   ctkPopupWidget* SliderPopup;
 };
 
@@ -60,14 +64,16 @@ public:
 ctkSliderWidgetPrivate::ctkSliderWidgetPrivate(ctkSliderWidget& object)
   :q_ptr(&object)
 {
+  qRegisterMetaType<ctkSliderWidget::SynchronizeSiblings>(
+    "ctkSliderWidget::SynchronizeSiblings");
   this->Tracking = true;
   this->Changing = false;
   this->ValueBeforeChange = 0.;
-  this->AutoSpinBoxWidth = true;
+  this->SynchronizeMode =
+    ctkSliderWidget::SynchronizeWidth | ctkSliderWidget::SynchronizeDecimals;
   this->SliderPopup = 0;
 }
 
-
 // --------------------------------------------------------------------------
 ctkSliderWidgetPrivate::~ctkSliderWidgetPrivate()
 {
@@ -77,7 +83,7 @@ ctkSliderWidgetPrivate::~ctkSliderWidgetPrivate()
 void ctkSliderWidgetPrivate::updateSpinBoxWidth()
 {
   int spinBoxWidth = this->synchronizedSpinBoxWidth();
-  if (this->AutoSpinBoxWidth)
+  if (this->SynchronizeMode.testFlag(ctkSliderWidget::SynchronizeWidth))
     {
     this->SpinBox->setMinimumWidth(spinBoxWidth);
     }
@@ -85,7 +91,17 @@ void ctkSliderWidgetPrivate::updateSpinBoxWidth()
     {
     this->SpinBox->setMinimumWidth(0);
     }
-  this->synchronizeSiblingSpinBox(spinBoxWidth);
+
+  this->synchronizeSiblingWidth(spinBoxWidth);
+}
+
+// --------------------------------------------------------------------------
+void ctkSliderWidgetPrivate::updateSpinBoxDecimals()
+{
+  if (this->SynchronizeMode.testFlag(ctkSliderWidget::SynchronizeDecimals))
+    {
+    this->synchronizeSiblingDecimals(this->SpinBox->decimals());
+    }
 }
 
 // --------------------------------------------------------------------------
@@ -107,16 +123,34 @@ int ctkSliderWidgetPrivate::synchronizedSpinBoxWidth()const
 }
 
 // --------------------------------------------------------------------------
-void ctkSliderWidgetPrivate::synchronizeSiblingSpinBox(int width)
+void ctkSliderWidgetPrivate::synchronizeSiblingWidth(int width)
+{
+  Q_Q(const ctkSliderWidget);
+  QList<ctkSliderWidget*> siblings =
+    q->parent()->findChildren<ctkSliderWidget*>();
+  foreach(ctkSliderWidget* sibling, siblings)
+    {
+    if (sibling != q
+      && sibling->synchronizeSiblings().testFlag(ctkSliderWidget::SynchronizeWidth))
+      {
+      sibling->d_func()->SpinBox->setMinimumWidth(
+        this->SpinBox->minimumWidth());
+      }
+    }
+}
+
+// --------------------------------------------------------------------------
+void ctkSliderWidgetPrivate::synchronizeSiblingDecimals(int decimals)
 {
   Q_Q(const ctkSliderWidget);
   QList<ctkSliderWidget*> siblings =
     q->parent()->findChildren<ctkSliderWidget*>();
   foreach(ctkSliderWidget* sibling, siblings)
     {
-    if (sibling != q && sibling->isAutoSpinBoxWidth())
+    if (sibling != q
+      && sibling->synchronizeSiblings().testFlag(ctkSliderWidget::SynchronizeDecimals))
       {
-      sibling->d_func()->SpinBox->setMinimumWidth(width);
+      sibling->d_func()->SpinBox->setDecimals(this->SpinBox->decimals());
       }
     }
 }
@@ -133,6 +167,7 @@ ctkSliderWidget::ctkSliderWidget(QWidget* _parent) : Superclass(_parent)
   d->Slider->setMinimum(d->SpinBox->minimum());
 
   this->connect(d->SpinBox, SIGNAL(valueChanged(double)), d->Slider, SLOT(setValue(double)));
+  this->connect(d->SpinBox, SIGNAL(decimalsChanged(int)), this, SLOT(setDecimals(int)));
 
   //this->connect(d->Slider, SIGNAL(valueChanged(double)), SIGNAL(valueChanged(double)));
   this->connect(d->Slider, SIGNAL(sliderPressed()), this, SLOT(startChanging()));
@@ -387,6 +422,7 @@ void ctkSliderWidget::setDecimals(int newDecimals)
   Q_ASSERT(d->equal(d->SpinBox->minimum(),d->Slider->minimum()));
   Q_ASSERT(d->equal(d->SpinBox->value(),d->Slider->value()));
   Q_ASSERT(d->equal(d->SpinBox->maximum(),d->Slider->maximum()));
+  d->updateSpinBoxDecimals();
 }
 
 // --------------------------------------------------------------------------
@@ -482,18 +518,21 @@ bool ctkSliderWidget::hasTracking()const
 }
 
 // -------------------------------------------------------------------------
-bool ctkSliderWidget::isAutoSpinBoxWidth()const
+ctkSliderWidget::SynchronizeSiblings
+ctkSliderWidget::synchronizeSiblings() const
 {
   Q_D(const ctkSliderWidget);
-  return d->AutoSpinBoxWidth;
+  return d->SynchronizeMode;
 }
 
 // -------------------------------------------------------------------------
-void ctkSliderWidget::setAutoSpinBoxWidth(bool autoWidth)
+void ctkSliderWidget
+::setSynchronizeSiblings(ctkSliderWidget::SynchronizeSiblings flag)
 {
   Q_D(ctkSliderWidget);
-  d->AutoSpinBoxWidth = autoWidth;
+  d->SynchronizeMode = flag;
   d->updateSpinBoxWidth();
+  d->updateSpinBoxDecimals();
 }
 
 // -------------------------------------------------------------------------

+ 38 - 11
Libs/Widgets/ctkSliderWidget.h

@@ -52,13 +52,36 @@ class CTK_WIDGETS_EXPORT ctkSliderWidget : public QWidget
   Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
   Q_PROPERTY(double tickInterval READ tickInterval WRITE setTickInterval)
   Q_PROPERTY(QSlider::TickPosition tickPosition READ tickPosition WRITE setTickPosition)
-  Q_PROPERTY(bool autoSpinBoxWidth READ isAutoSpinBoxWidth WRITE setAutoSpinBoxWidth)
+  Q_FLAGS(SynchronizeSiblings)
+  Q_PROPERTY(SynchronizeSiblings SynchronizeSibling READ synchronizeSiblings WRITE setSynchronizeSiblings)
   Q_PROPERTY(Qt::Alignment spinBoxAlignment READ spinBoxAlignment WRITE setSpinBoxAlignment)
   Q_PROPERTY(bool tracking READ hasTracking WRITE setTracking)
   Q_PROPERTY(bool spinBoxVisible READ isSpinBoxVisible WRITE setSpinBoxVisible);
   Q_PROPERTY(bool popupSlider READ hasPopupSlider WRITE setPopupSlider);
 
 public:
+
+  /// Synchronize properties of the slider siblings:
+  /// NoSynchronize:
+  /// The slider widget siblings aren't updated and this widget does not update
+  /// from its siblings.
+  /// SynchronizeWidth:
+  /// The width of the SpinBox is set to the same width of the largest QSpinBox
+  /// of its ctkSliderWidget siblings.
+  /// SynchronizeDecimals:
+  /// Whenever one of the siblings changes its number of decimals, all its
+  /// siblings Synchronize to the new number of decimals.
+  ///
+  /// Default is SynchronizeWidth |SynchronizeDecimals.
+  /// \sa SynchronizeSiblings(), setSynchronizeSiblings()
+  enum SynchronizeSibling
+    {
+    NoSynchronize = 0x000,
+    SynchronizeWidth = 0x001,
+    SynchronizeDecimals = 0x002,
+    };
+  Q_DECLARE_FLAGS(SynchronizeSiblings, SynchronizeSibling)
+
   /// Superclass typedef
   typedef QWidget Superclass;
 
@@ -116,9 +139,7 @@ public:
 
   /// 
   /// This property holds the precision of the spin box, in decimals.
-  /// Sets how many decimals the spinbox will use for displaying and interpreting doubles.
   int decimals()const;
-  void setDecimals(int decimals);
 
   ///
   /// This property holds the spin box's prefix.
@@ -140,7 +161,7 @@ public:
   /// If it is 0, the slider will choose between lineStep() and pageStep().
   /// The default value is 0.
   double tickInterval()const;
-  void setTickInterval(double ti);
+  void setTickInterval(double tick);
 
   /// 
   /// This property holds the tickmark position for the slider.
@@ -166,12 +187,12 @@ public:
   bool hasTracking()const;
 
   /// 
-  /// Set/Get the auto spinbox width
-  /// When the autoSpinBoxWidth property is on, the width of the SpinBox is
-  /// set to the same width of the largest QSpinBox of its
-  // ctkSliderWidget siblings.
-  bool isAutoSpinBoxWidth()const;
-  void setAutoSpinBoxWidth(bool autoWidth);
+  /// Set/Get the synchronize siblings mode. This helps when having multiple
+  /// ctkSliderWidget stacked upon each other.
+  /// Default flag is SynchronizeWidth | SynchronizeDecimals.
+  /// \sa SynchronizeSiblingsModes
+  ctkSliderWidget::SynchronizeSiblings synchronizeSiblings() const;
+  void setSynchronizeSiblings(ctkSliderWidget::SynchronizeSiblings options);
 
   ///
   /// The Spinbox visibility can be controlled using setSpinBoxVisible() and
@@ -212,6 +233,10 @@ public Q_SLOTS:
   void setValue(double value);
   void setSpinBoxVisible(bool);
 
+  /// Sets how many decimals the spinbox uses for displaying and
+  /// interpreting doubles.
+  void setDecimals(int decimals);
+
 Q_SIGNALS:
   /// When tracking is on (default), valueChanged is emitted when the
   /// user drags the slider.
@@ -231,7 +256,7 @@ protected Q_SLOTS:
   void startChanging();
   void stopChanging();
   void changeValue(double value);
-  
+
 protected:
   virtual bool eventFilter(QObject *obj, QEvent *event);
   
@@ -244,4 +269,6 @@ private:
 
 };
 
+Q_DECLARE_OPERATORS_FOR_FLAGS(ctkSliderWidget::SynchronizeSiblings);
+
 #endif

+ 82 - 6
Libs/Widgets/ctkSpinBox.cpp

@@ -29,7 +29,7 @@
 #include <QDoubleSpinBox>
 #include <QEvent>
 #include <QHBoxLayout>
-#include <QKeySequence>
+#include <QKeyEvent>
 #include <QShortcut>
 #include <QSizePolicy>
 #include <QVariant>
@@ -45,18 +45,27 @@ public:
 
   QDoubleSpinBox* SpinBox;
   ctkSpinBox::SetMode Mode;
+  int DefaultDecimals;
+  ctkSpinBox::DecimalsOptions DOption;
 
   void init();
   // Compare two double previously rounded according to the number of decimals
   bool compare(double x1, double x2) const;
+
+  // Set the number of decimals of the spinbox and emit the signal
+  // No check if they are the same.
+  void setDecimals(int dec);
 };
 
 //-----------------------------------------------------------------------------
 ctkSpinBoxPrivate::ctkSpinBoxPrivate(ctkSpinBox& object) : q_ptr(&object)
 {
   qRegisterMetaType<ctkSpinBox::SetMode>("ctkSpinBox::SetMode");
+  qRegisterMetaType<ctkSpinBox::DecimalsOptions>("ctkSpinBox::DecimalsOption");
   this->SpinBox = 0;
   this->Mode = ctkSpinBox::SetIfDifferent;
+  this->DefaultDecimals = 2;
+  this->DOption = ctkSpinBox::UseShortcuts;
 }
 
 //-----------------------------------------------------------------------------
@@ -77,6 +86,8 @@ void ctkSpinBoxPrivate::init()
   q->setLayout(l);
   q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,
     QSizePolicy::Fixed, QSizePolicy::ButtonBox));
+
+  this->SpinBox->installEventFilter(q);
 }
 
 //-----------------------------------------------------------------------------
@@ -87,6 +98,14 @@ bool ctkSpinBoxPrivate::compare(double x1, double x2) const
 }
 
 //-----------------------------------------------------------------------------
+void ctkSpinBoxPrivate::setDecimals(int dec)
+{
+  Q_Q(ctkSpinBox);
+  this->SpinBox->setDecimals(dec);
+  emit q->decimalsChanged(dec);
+}
+
+//-----------------------------------------------------------------------------
 ctkSpinBox::ctkSpinBox(QWidget* newParent)
   : QWidget(newParent)
   , d_ptr(new ctkSpinBoxPrivate(*this))
@@ -115,7 +134,6 @@ double ctkSpinBox::value() const
 //-----------------------------------------------------------------------------
 double ctkSpinBox::displayedValue() const
 {
-  Q_D(const ctkSpinBox);
   return this->round(this->value());
 }
 
@@ -304,13 +322,15 @@ int ctkSpinBox::decimals() const
 //-----------------------------------------------------------------------------
 void ctkSpinBox::setDecimals(int dec)
 {
-  Q_D(const ctkSpinBox);
-  if (d->Mode == ctkSpinBox::SetIfDifferent && dec == d->SpinBox->decimals())
+  Q_D(ctkSpinBox);
+  dec = qMax(0, dec);
+  if (d->Mode == ctkSpinBox::SetIfDifferent && dec == this->decimals())
     {
     return;
     }
 
-  d->SpinBox->setDecimals(dec);
+  d->DefaultDecimals = dec;
+  d->setDecimals(d->DefaultDecimals);
 }
 
 //-----------------------------------------------------------------------------
@@ -330,7 +350,7 @@ QDoubleSpinBox* ctkSpinBox::spinBox() const
 //-----------------------------------------------------------------------------
 void ctkSpinBox::setValue(double value)
 {
-  Q_D(const ctkSpinBox);
+  Q_D(ctkSpinBox);
   if (d->Mode == ctkSpinBox::SetIfDifferent)
     {
     this->setValueIfDifferent(value);
@@ -386,3 +406,59 @@ void ctkSpinBox::setSetMode(ctkSpinBox::SetMode newMode)
   d->Mode = newMode;
 }
 
+//-----------------------------------------------------------------------------
+ctkSpinBox::DecimalsOptions ctkSpinBox::decimalsOption()
+{
+  Q_D(const ctkSpinBox);
+  return d->DOption;
+}
+
+//-----------------------------------------------------------------------------
+void ctkSpinBox::setDecimalsOption(ctkSpinBox::DecimalsOptions option)
+{
+  Q_D(ctkSpinBox);
+  if (d->Mode == ctkSpinBox::SetIfDifferent && option == d->DOption)
+    {
+    return;
+    }
+
+  d->DOption = option;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkSpinBox::eventFilter(QObject* obj, QEvent* event)
+{
+  Q_D(ctkSpinBox);
+  if (d->DOption & ctkSpinBox::UseShortcuts &&
+    obj == d->SpinBox && event->type() == QEvent::KeyPress)
+    {
+    QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+    Q_ASSERT(keyEvent);
+    if (keyEvent->modifiers() & Qt::ControlModifier)
+      {
+      if (keyEvent->key() == Qt::Key_Plus
+        || keyEvent->key() == Qt::Key_Equal)
+        {
+        d->setDecimals(this->decimals() + 1);
+        return true;
+        }
+      else if (keyEvent->key() == Qt::Key_Minus)
+        {
+        d->setDecimals(this->decimals() - 1);
+        return true;
+        }
+      else if (keyEvent->key() == Qt::Key_0)
+        {
+        d->setDecimals(d->DefaultDecimals);
+        return true;
+        }
+      }
+
+    return QWidget::eventFilter(obj, event);
+    }
+  else
+    {
+    // pass the event on to the parent class
+    return QWidget::eventFilter(obj, event);
+    }
+}

+ 40 - 3
Libs/Widgets/ctkSpinBox.h

@@ -27,6 +27,9 @@
 #include <QWidget>
 
 class QDoubleSpinBox;
+class QEvent;
+class QKeyEvent;
+class QObject;
 
 // CTK includes
 #include "ctkWidgetsExport.h"
@@ -42,6 +45,10 @@ class CTK_WIDGETS_EXPORT ctkSpinBox : public QWidget
   Q_OBJECT
   Q_ENUMS(SetMode)
   Q_PROPERTY(SetMode setMode READ setMode WRITE setSetMode)
+
+  Q_FLAGS(DecimalsOption DecimalsOptions)
+  Q_PROPERTY(DecimalsOptions decimalsOption READ decimalsOption WRITE setDecimalsOption)
+
   Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
   Q_PROPERTY(bool frame READ hasFrame WRITE setFrame)
   Q_PROPERTY(QString prefix READ prefix WRITE setPrefix)
@@ -71,6 +78,25 @@ public:
     SetIfDifferent,
     };
 
+  /// DecimalsOption enums the input style of the spinbox decimals.
+  /// Fixed:
+  /// Behaves just like a QDoubleSpinBox. The maximum number of decimals
+  /// allowed is given by decimals().
+  /// UseShortcuts:
+  /// When the spinbox has focus, entering the shortcut "CTRL +"
+  /// adds decimals to the current number of decimals. "CTRL -" decreases the
+  /// number of decimals and "CTRL 0" returns it to its original decimals()
+  /// value.
+  ///
+  /// Default option is UseShortcuts.
+  /// \sa decimals(), currentDecimals()
+  enum DecimalsOption
+    {
+    Fixed =         0x0,
+    UseShortcuts =  0x01,
+    };
+  Q_DECLARE_FLAGS(DecimalsOptions, DecimalsOption)
+
   typedef QWidget Superclass;
 
   /// Constructor, creates a ctkSpinBox. The look and feel
@@ -128,9 +154,9 @@ public:
   void setMaximum(double max);
   void setRange(double min, double max);
 
-  /// Set/Get number of decimals displayed. For a spinbox dealing only with
-  /// integers, set this to 0.
-  /// \sa addOneDecimal(), removeOneDecimal()
+  /// Set/Get number of displayed decimals.
+  /// For a spinbox dealing only with integers, set this to 0.
+  /// \sa ctkSpinBox::DecimalsOption
   int decimals() const;
   void setDecimals(int decimal);
 
@@ -149,6 +175,11 @@ public:
   ctkSpinBox::SetMode setMode() const;
   void setSetMode(SetMode mode);
 
+  /// Set/Get the option used to input the decimals.
+  /// \sa ctkSpinBox::DecimalsOption
+  ctkSpinBox::DecimalsOptions decimalsOption();
+  void setDecimalsOption(ctkSpinBox::DecimalsOptions option);
+
 public Q_SLOTS:
   /// Set the value of the spinbox following the current mode.
   /// \sa setMode(), value(), setValueIfDifferent(), setValueAlways()
@@ -177,14 +208,20 @@ Q_SIGNALS:
   /// \sa QAbstractSpinbox::editingFinished
   void editingFinished();
 
+  /// Signal emitted when the decimals of the displayed are changed.
+  void decimalsChanged(int);
+
 protected:
   ctkSpinBoxPrivate* const d_ptr;
 
+  bool eventFilter(QObject *obj, QEvent *event);
+
 private:
   Q_DECLARE_PRIVATE(ctkSpinBox);
   Q_DISABLE_COPY(ctkSpinBox);
 };
 
 Q_DECLARE_METATYPE(ctkSpinBox::SetMode)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ctkSpinBox::DecimalsOptions)
 
 #endif //__ctkSpinBox_h