瀏覽代碼

Fix decimals in ctkCoordinatesWidget with DecimalsByKey

Issue http://www.na-mic.org/Bug/view.php?id=2973
Julien Finet 11 年之前
父節點
當前提交
1526abf7b8

+ 90 - 0
Libs/Widgets/Testing/Cpp/ctkCoordinatesWidgetTest.cpp

@@ -21,6 +21,7 @@
 // Qt includes
 #include <QApplication>
 #include <QDoubleSpinBox>
+#include <QLineEdit>
 #include <QString>
 #include <QStyle>
 #include <QStyleOptionSlider>
@@ -43,6 +44,9 @@ private slots:
 
   void testDecimalsByValue();
   void testDecimalsByValue_data();
+
+  void testDecimalsByKey();
+  void testDecimalsByKey_data();
 private:
   void testDecimals(ctkCoordinatesWidget* coordinatesWidget, int decimals);
 };
@@ -140,6 +144,92 @@ void ctkCoordinatesWidgetTester::testDecimalsByValue_data()
   QTest::newRow("same value more digits") << QVector3D(0.001, 0.002, 0.0004) << 4;
 }
 
+
+// ----------------------------------------------------------------------------
+void ctkCoordinatesWidgetTester::testDecimalsByKey()
+{
+  ctkCoordinatesWidget coordinatesWidget;
+  coordinatesWidget.setDecimalsOption(
+    ctkDoubleSpinBox::DecimalsByValue | ctkDoubleSpinBox::DecimalsByKey);
+  coordinatesWidget.setDecimals(3);
+  coordinatesWidget.setCoordinates(1.,1.,1.3);
+
+  QFETCH(QVector3D, coordinates);
+  coordinatesWidget.setCoordinates(coordinates.x(), coordinates.y(), coordinates.z());
+
+  QFETCH(int, expectedDecimals);
+  testDecimals(&coordinatesWidget, expectedDecimals);
+
+  // Simulate decimals by key
+  QFETCH(int, decimalsOffset);
+  QList<QDoubleSpinBox*> spinBoxes =
+    coordinatesWidget.findChildren<QDoubleSpinBox*>();
+  QList<QLineEdit*> lineEdits =
+    spinBoxes[0]->findChildren<QLineEdit*>();
+  QString text = lineEdits[0]->text();
+  switch (decimalsOffset)
+    {
+    case 1:
+      if (!text.contains('.'))
+        {
+        text += '.';
+        }
+      text += '7';
+      break;
+    case 0:
+      text = QString("7") + text;
+      break;
+    case -1:
+      text.chop(1);
+      break;
+    default:
+      break;
+    }
+  lineEdits[0]->setText(text);
+
+  QFETCH(QVector3D, finalDecimals);
+  QCOMPARE(spinBoxes[0]->decimals(), static_cast<int>(finalDecimals.x()));
+  QCOMPARE(spinBoxes[1]->decimals(), static_cast<int>(finalDecimals.y()));
+  QCOMPARE(spinBoxes[2]->decimals(), static_cast<int>(finalDecimals.z()));
+}
+
+// ----------------------------------------------------------------------------
+void ctkCoordinatesWidgetTester::testDecimalsByKey_data()
+{
+  QTest::addColumn<QVector3D>("coordinates");
+  QTest::addColumn<int>("expectedDecimals");
+  QTest::addColumn<int>("decimalsOffset");
+  QTest::addColumn<QVector3D>("finalDecimals");
+
+  QTest::newRow("(1, 1, 1) +1") << QVector3D(1., 1., 1.) << 0 << 1 << QVector3D(1,1,1);
+  QTest::newRow("(1, 1, 1) +0") << QVector3D(1., 1., 1.) << 0 << 0 << QVector3D(0,0,0);
+  QTest::newRow("(1, 1, 1) -1") << QVector3D(1., 1., 1.) << 0 << -1 << QVector3D(0,0,0);
+
+  QTest::newRow("(1, 1, 1.3) +1") << QVector3D(1., 1., 1.3) << 1 << 1 << QVector3D(2,2,2);
+  QTest::newRow("(1, 1, 1.3) +0") << QVector3D(1., 1., 1.3) << 1 << 0 << QVector3D(1,1,1);
+  QTest::newRow("(1, 1, 1.3) -1") << QVector3D(1., 1., 1.3) << 1 << -1 << QVector3D(0,1,1);
+
+  QTest::newRow("(1.3, 1, 1) +1") << QVector3D(1.3, 1., 1.) << 1 << 1 << QVector3D(2,2,2);
+  QTest::newRow("(1.3, 1, 1) +0") << QVector3D(1.3, 1., 1.) << 1 << 0 << QVector3D(1,1,1);
+  QTest::newRow("(1.3, 1, 1) -1") << QVector3D(1.3, 1., 1.) << 1 << -1 << QVector3D(0,0,0);
+
+  QTest::newRow("(1.3, 1, 1.3) +1") << QVector3D(1.3, 1., 1.3) << 1 << 1 << QVector3D(2,2,2);
+  QTest::newRow("(1.3, 1, 1.3) +0") << QVector3D(1.3, 1., 1.3) << 1 << 0 << QVector3D(1,1,1);
+  QTest::newRow("(1.3, 1, 1.3) -1") << QVector3D(1.3, 1., 1.3) << 1 << -1 << QVector3D(0,1,1);
+
+  QTest::newRow("(1.*, 1, 1.3) +1") << QVector3D(1.12345678910121416, 1., 1.3) << 3 << 1 << QVector3D(4,4,4);
+  QTest::newRow("(1.*, 1, 1.3) +0") << QVector3D(1.12345678910121416, 1., 1.3) << 3 << 0 << QVector3D(3,3,3);
+  QTest::newRow("(1.*, 1, 1.3) -1") << QVector3D(1.12345678910121416, 1., 1.3) << 3 << -1 << QVector3D(2,2,2);
+
+  QTest::newRow("(1, 1.*, 1.3) +1") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << 1 << QVector3D(4,4,4);
+  QTest::newRow("(1, 1.*, 1.3) +0") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << 0 << QVector3D(3,3,3);
+  QTest::newRow("(1, 1.*, 1.3) -1") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << -1 << QVector3D(2,3,3);
+
+  QTest::newRow("(1.*, 1.*, 1.3) +1") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << 1 << QVector3D(4,4,4);
+  QTest::newRow("(1.*, 1.*, 1.3) +0") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << 0 << QVector3D(3,3,3);
+  QTest::newRow("(1.*, 1.*, 1.3) -1") << QVector3D(1., 1.12345678910121416, 1.3) << 3 << -1 << QVector3D(2,3,3);
+}
+
 // ----------------------------------------------------------------------------
 CTK_TEST_MAIN(ctkCoordinatesWidgetTest)
 #include "moc_ctkCoordinatesWidgetTest.cpp"

+ 48 - 9
Libs/Widgets/ctkCoordinatesWidget.cpp

@@ -26,6 +26,7 @@
 // CTK includes
 #include "ctkCoordinatesWidget.h"
 #include "ctkDoubleSpinBox.h"
+#include "ctkUtils.h"
 #include "ctkValueProxy.h"
 
 // STD includes
@@ -43,6 +44,7 @@ ctkCoordinatesWidget::ctkCoordinatesWidget(QWidget* _parent) :QWidget(_parent)
   this->Normalized = false;
   this->Dimension = 0;
   this->Coordinates = 0;
+  this->ChangingDecimals = false;
 
   QHBoxLayout* hboxLayout = new QHBoxLayout(this);
   hboxLayout->setContentsMargins(0, 0, 0, 0);
@@ -71,7 +73,7 @@ void ctkCoordinatesWidget::addSpinBox()
            this, SLOT(updateCoordinate(double)));
   // Same number of decimals within the spinboxes.
   connect( spinBox, SIGNAL(decimalsChanged(int)),
-           this, SLOT(setTemporaryDecimals(int)));
+           this, SLOT(updateOtherDecimals(int)));
   this->layout()->addWidget(spinBox);
 }
 
@@ -123,7 +125,7 @@ int ctkCoordinatesWidget::dimension() const
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::setMinimum(double min)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setMinimum(min);
     }
@@ -139,7 +141,7 @@ double ctkCoordinatesWidget::minimum() const
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::setMaximum(double max)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setMaximum(max);
     }
@@ -155,7 +157,7 @@ double ctkCoordinatesWidget::maximum() const
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::setRange(double min, double max)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setRange(min, max);
     }
@@ -191,7 +193,7 @@ bool ctkCoordinatesWidget::isNormalized() const
 void ctkCoordinatesWidget::setDecimals(int newDecimals)
 {
   this->Decimals = newDecimals;
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setDecimals(newDecimals);
     }
@@ -200,19 +202,56 @@ void ctkCoordinatesWidget::setDecimals(int newDecimals)
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::updateDecimals()
 {
+  if (this->ChangingDecimals)
+    {
+    return;
+    }
   int maxDecimals = 0;
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     maxDecimals = qMax(maxDecimals, this->spinBox(i)->decimals());
     }
+  this->ChangingDecimals = true;
+  this->setTemporaryDecimals(maxDecimals);
+  this->ChangingDecimals = false;
+}
+
+//------------------------------------------------------------------------------
+void ctkCoordinatesWidget::updateOtherDecimals(int decimals)
+{
+  if (this->ChangingDecimals)
+    {
+    return;
+    }
+  int maxDecimals = decimals;
+  for (int i = 0; i < this->Dimension; ++i)
+    {
+    if (this->sender() == this->spinBox(i))
+      {
+      continue;
+      }
+    int spinBoxDecimals = this->spinBox(i)->decimals();
+    if (this->decimalsOption() & ctkDoubleSpinBox::DecimalsByValue)
+      {
+      spinBoxDecimals = ctk::significantDecimals(
+        this->spinBox(i)->displayedValue(), maxDecimals);
+      }
+    maxDecimals = qMax(maxDecimals, spinBoxDecimals);
+    }
+  this->ChangingDecimals = true;
   this->setTemporaryDecimals(maxDecimals);
+  this->ChangingDecimals = false;
 }
 
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::setTemporaryDecimals(int newDecimals)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
+    if (this->sender() == this->spinBox(i))
+      {
+      continue;
+      }
     this->spinBox(i)->spinBox()->setDecimals(newDecimals);
     }
 }
@@ -233,7 +272,7 @@ ctkDoubleSpinBox::DecimalsOptions ctkCoordinatesWidget::decimalsOption()const
 void ctkCoordinatesWidget
 ::setDecimalsOption(ctkDoubleSpinBox::DecimalsOptions newDecimalsOption)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setDecimalsOption(newDecimalsOption);
     }
@@ -243,7 +282,7 @@ void ctkCoordinatesWidget
 //------------------------------------------------------------------------------
 void ctkCoordinatesWidget::setSingleStep(double step)
 {
-  for (int i = 0; this->layout()->itemAt(i); ++i)
+  for (int i = 0; i < this->Dimension; ++i)
     {
     this->spinBox(i)->setSingleStep(step);
     }

+ 2 - 0
Libs/Widgets/ctkCoordinatesWidget.h

@@ -143,6 +143,7 @@ protected Q_SLOTS:
   void updateCoordinate(double);
   void updateCoordinates();
   void updateDecimals();
+  void updateOtherDecimals(int);
   void setTemporaryDecimals(int);
   void onValueProxyAboutToBeModified();
   void onValueProxyModified();
@@ -166,6 +167,7 @@ protected:
   int     Dimension;
   double* Coordinates;
   QList<int> LastUserEditedCoordinates;
+  bool    ChangingDecimals;
   QWeakPointer<ctkValueProxy> Proxy;
 };