瀏覽代碼

Add support for inf and nan in ctkRangeWidget

Issue #348
Julien Finet 11 年之前
父節點
當前提交
49b9f5ba95

+ 33 - 0
Libs/Testing/ctkTest.h

@@ -21,6 +21,12 @@
 // Qt includes
 #include <QtTest/QtTest>
 
+// STD includes
+#include <limits>
+
+#ifndef __ctkTest_h
+#define __ctkTest_h
+
 #define CTK_TEST_NOOP_MAIN(TestObject) \
 int TestObject(int argc, char *argv[]) \
 { \
@@ -95,4 +101,31 @@ inline void mouseMove(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModif
                       QPoint pos = QPoint(), int delay=-1)
   { ctkTest::mouseEvent(QTest::MouseMove, widget, button, stateKey, pos, delay); }
 
+
+// ----------------------------------------------------------------------------
+static void COMPARE(double v1, double v2)
+{
+  // QCOMPARE fails to compare NaN numbers
+  if (v2 != v2)
+    {
+    QVERIFY(v1 != v1);
+    }
+  // QCOMPARE fails to compare - infinity
+  else if (v2 == -std::numeric_limits<double>::infinity())
+    {
+    QVERIFY(v1 == -std::numeric_limits<double>::infinity());
+    }
+  // QCOMPARE fails to compare infinity
+  else if (v2 == std::numeric_limits<double>::infinity())
+    {
+    QVERIFY(v1 == std::numeric_limits<double>::infinity());
+    }
+  else
+    {
+    QCOMPARE(v1, v2);
+    }
 }
+
+}; // end ctkTest namespace
+
+#endif

+ 3 - 2
Libs/Widgets/Testing/Cpp/CMakeLists.txt

@@ -61,8 +61,8 @@ set(TEST_SOURCES
   ctkProxyStyleTest1.cpp
   ctkRangeSliderTest.cpp
   ctkRangeSliderTest1.cpp
+  ctkRangeWidgetTest.cpp
   ctkRangeWidgetTest1.cpp
-  ctkRangeWidgetTest2.cpp
   ctkDateRangeWidgetTest1.cpp
   ctkScreenshotDialogTest1.cpp
   ctkSearchBoxTest1.cpp
@@ -190,6 +190,7 @@ QT4_GENERATE_MOCS(
   ctkPathListWidgetTest.cpp
   ctkPathListWidgetWithButtonsTest.cpp
   ctkRangeSliderTest.cpp
+  ctkRangeWidgetTest.cpp
   ctkSettingsPanelTest.cpp
   ctkSliderWidgetTest.cpp
   )
@@ -271,8 +272,8 @@ SIMPLE_TEST( ctkPopupWidgetTest1 )
 SIMPLE_TEST( ctkProxyStyleTest1 )
 SIMPLE_TEST( ctkRangeSliderTest )
 SIMPLE_TEST( ctkRangeSliderTest1 )
+SIMPLE_TEST( ctkRangeWidgetTest )
 SIMPLE_TEST( ctkRangeWidgetTest1 )
-SIMPLE_TEST( ctkRangeWidgetTest2 )
 SIMPLE_TEST( ctkResizableFrameTest1 )
 SIMPLE_TEST( ctkScreenshotDialogTest1 )
 SIMPLE_TEST( ctkSearchBoxTest1 )

+ 121 - 0
Libs/Widgets/Testing/Cpp/ctkDoubleSpinBoxTest.cpp

@@ -31,6 +31,9 @@
 #include "ctkDoubleSpinBox.h"
 #include "ctkTest.h"
 
+// STD includes
+#include <limits>
+
 // ----------------------------------------------------------------------------
 class ctkDoubleSpinBoxTester: public QObject
 {
@@ -40,6 +43,12 @@ private slots:
 
   void testToLocals();
 
+  void testSetValue();
+  void testSetValue_data();
+
+  void testSetRange();
+  void testSetRange_data();
+
   void testDecimalsByKey();
   void testDecimalsByKey_data();
 
@@ -88,6 +97,118 @@ void ctkDoubleSpinBoxTester::testToLocals()
   qDebug() << "0.0 1" << ok;
 }
 
+//-----------------------------------------------------------------------------
+void ctkDoubleSpinBoxTester::testSetValue()
+{
+  ctkDoubleSpinBox spinBox;
+  spinBox.setValue(25.);
+  // Compare with a QDoubleSpinBox as we are supposed to have the same behavior.
+  QDoubleSpinBox compareSpinBox;
+  compareSpinBox.setValue(25.);
+
+  QFETCH(double, value);
+
+  QSignalSpy valueChangedSpy(&spinBox,
+                             SIGNAL(valueChanged(double)));
+  spinBox.setValue(value);
+  QSignalSpy compareValueChangedSpy(&compareSpinBox,
+                                    SIGNAL(valueChanged(double)));
+  compareSpinBox.setValue(value);
+
+  QCOMPARE(spinBox.value(), compareSpinBox.value());
+  QCOMPARE(valueChangedSpy.count(), compareValueChangedSpy.count());
+
+  QFETCH(double, expectedValue);
+  QCOMPARE(spinBox.value(), expectedValue);
+
+  const bool valueChanged = expectedValue != 25.;
+  QCOMPARE(valueChangedSpy.count(), valueChanged ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkDoubleSpinBoxTester::testSetValue_data()
+{
+  QTest::addColumn<double>("value");
+  QTest::addColumn<double>("expectedValue");
+
+  QTest::newRow("1. -> 1.]") << 1. << 1.;
+  QTest::newRow("100. -> 99.99]") << 100. << 99.99;
+  QTest::newRow("-1. -> 0.]") << -1. << 0.;
+
+  QTest::newRow("min -> 0.") << std::numeric_limits<double>::min() << 0.;
+  QTest::newRow("max -> 99.99") << std::numeric_limits<double>::max() << 99.99;
+  QTest::newRow("-inf -> 0.") << -std::numeric_limits<double>::infinity() << 0.;
+  QTest::newRow("inf -> 99.99") << std::numeric_limits<double>::infinity() << 99.99;
+  QTest::newRow("NaN -> 99.99") << std::numeric_limits<double>::quiet_NaN() << 99.99;
+}
+
+//-----------------------------------------------------------------------------
+void ctkDoubleSpinBoxTester::testSetRange()
+{
+  ctkDoubleSpinBox spinBox;
+  spinBox.setValue(25.);
+  QDoubleSpinBox compareSpinBox;
+  compareSpinBox.setValue(25.);
+
+  QSignalSpy valueChangedSpy(&spinBox,
+                             SIGNAL(valueChanged(double)));
+  QSignalSpy compareValueChangedSpy(&compareSpinBox,
+                             SIGNAL(valueChanged(double)));
+
+  QFETCH(double, minimum);
+  QFETCH(double, maximum);
+  spinBox.setRange(minimum, maximum);
+  compareSpinBox.setRange(minimum, maximum);
+
+  ctkTest::COMPARE(spinBox.minimum(), compareSpinBox.minimum());
+  ctkTest::COMPARE(spinBox.maximum(), compareSpinBox.maximum());
+  ctkTest::COMPARE(spinBox.value(), compareSpinBox.value());
+
+  QFETCH(double, expectedMinimum);
+  QFETCH(double, expectedMaximum);
+  ctkTest::COMPARE(spinBox.minimum(), expectedMinimum);
+  ctkTest::COMPARE(spinBox.maximum(), expectedMaximum);
+
+  QFETCH(double, expectedValue);
+  ctkTest::COMPARE(spinBox.value(), expectedValue);
+
+  const bool valueChanged = expectedValue != 25.;
+  ctkTest::COMPARE(valueChangedSpy.count(), valueChanged ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkDoubleSpinBoxTester::testSetRange_data()
+{
+  QTest::addColumn<double>("minimum");
+  QTest::addColumn<double>("maximum");
+  QTest::addColumn<double>("expectedMinimum");
+  QTest::addColumn<double>("expectedMaximum");
+  QTest::addColumn<double>("expectedValue");
+
+  QTest::newRow("[1.,98.]") << 1. << 98. << 1. << 98. << 25.;
+  QTest::newRow("[-1.,101.]") << -1. << 101. << -1. << 101. << 25.;
+  QTest::newRow("[1.,10.]") << 1. << 10. << 1. << 10. << 10.;
+  QTest::newRow("[90.,99.]") << 90. << 99. << 90. << 99. << 90.;
+  QTest::newRow("[min,max]")
+    << std::numeric_limits<double>::min()
+    << std::numeric_limits<double>::max()
+    << 0. // \tbd Qt bug ?
+    << std::numeric_limits<double>::max()
+    << 25.;
+  QTest::newRow("[-inf,inf]")
+    << -std::numeric_limits<double>::infinity()
+    << std::numeric_limits<double>::infinity()
+    << -std::numeric_limits<double>::infinity()
+    << std::numeric_limits<double>::infinity()
+    << 25.;
+  QTest::newRow("[NaN,NaN]")
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN();
+}
+
 // ----------------------------------------------------------------------------
 void ctkDoubleSpinBoxTester::testDecimalsByKey()
 {

+ 272 - 0
Libs/Widgets/Testing/Cpp/ctkRangeWidgetTest.cpp

@@ -0,0 +1,272 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+
+// Qt includes
+#include <QApplication>
+
+// CTK includes
+#include "ctkRangeWidget.h"
+#include "ctkTest.h"
+
+// STD includes
+#include <limits>
+
+// ----------------------------------------------------------------------------
+class ctkRangeWidgetTester: public QObject
+{
+  Q_OBJECT
+private slots:
+  void testUI();
+
+  void testSetMinimumValue();
+  void testSetMinimumValue_data();
+
+  void testSetMaximumValue();
+  void testSetMaximumValue_data();
+
+  void testSetValues();
+  void testSetValues_data();
+
+  void testSetRange();
+  void testSetRange_data();
+};
+
+// ----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testUI()
+{
+  ctkRangeWidget rangeWidget;
+  rangeWidget.show();
+  QTest::qWaitForWindowShown(&rangeWidget);
+  //qApp->exec();
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetMinimumValue()
+{
+  ctkRangeWidget rangeWidget;
+  rangeWidget.setValues(25., 75.);
+
+  QSignalSpy lowerValueChangedSpy(&rangeWidget,
+                                  SIGNAL(minimumValueChanged(double)));
+  QSignalSpy valuesChangedSpy(&rangeWidget,
+                              SIGNAL(valuesChanged(double,double)));
+  QFETCH(double, lowerValue);
+  rangeWidget.setMinimumValue(lowerValue);
+
+  QFETCH(double, expectedLowerValue);
+  QCOMPARE(rangeWidget.minimumValue(), expectedLowerValue);
+
+  const bool lowerValueChanged = expectedLowerValue != 25.;
+  QCOMPARE(lowerValueChangedSpy.count(), lowerValueChanged ? 1 : 0);
+  QCOMPARE(valuesChangedSpy.count(), lowerValueChanged ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetMinimumValue_data()
+{
+  QTest::addColumn<double>("lowerValue");
+  QTest::addColumn<double>("expectedLowerValue");
+
+  QTest::newRow("1. -> 1.]") << 1. << 1.;
+  QTest::newRow("100. -> 75.]") << 100. << 75.;
+  QTest::newRow("-1. -> 0.]") << -1. << 0.;
+
+  QTest::newRow("min -> 0.") << std::numeric_limits<double>::min() << 0.;
+  QTest::newRow("max -> 75.") << std::numeric_limits<double>::max() << 75.;
+  QTest::newRow("-inf -> 0.") << -std::numeric_limits<double>::infinity() << 0.;
+  QTest::newRow("inf -> 75.") << std::numeric_limits<double>::infinity() << 75.;
+  QTest::newRow("NaN -> 75.") << std::numeric_limits<double>::quiet_NaN() << 75.;
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetMaximumValue()
+{
+  ctkRangeWidget rangeWidget;
+  rangeWidget.setValues(25., 75.);
+
+  QSignalSpy upperValueChangedSpy(&rangeWidget,
+                                  SIGNAL(maximumValueChanged(double)));
+  QSignalSpy valuesChangedSpy(&rangeWidget,
+                              SIGNAL(valuesChanged(double,double)));
+
+  QFETCH(double, upperValue);
+  rangeWidget.setMaximumValue(upperValue);
+
+  QFETCH(double, expectedUpperValue);
+  QCOMPARE(rangeWidget.maximumValue(), expectedUpperValue);
+
+  const bool upperValueChanged = expectedUpperValue != 75.;
+  QCOMPARE(upperValueChangedSpy.count(), upperValueChanged ? 1 : 0);
+  QCOMPARE(valuesChangedSpy.count(), upperValueChanged ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetMaximumValue_data()
+{
+  QTest::addColumn<double>("upperValue");
+  QTest::addColumn<double>("expectedUpperValue");
+
+  QTest::newRow("99. -> 99.]") << 99. << 99.;
+  QTest::newRow("0. -> 25.]") << 0. << 25.;
+  QTest::newRow("100. -> 99.]") << 100. << 99.;
+
+  QTest::newRow("min -> 25.") << std::numeric_limits<double>::min() << 25.;
+  QTest::newRow("max -> 99.") << std::numeric_limits<double>::max() << 99.;
+  QTest::newRow("-inf -> 25.") << -std::numeric_limits<double>::infinity() << 25.;
+  QTest::newRow("inf -> 99.") << std::numeric_limits<double>::infinity() << 99.;
+  QTest::newRow("NaN -> 99.") << std::numeric_limits<double>::quiet_NaN() << 99.;
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetValues()
+{
+  ctkRangeWidget rangeWidget;
+  rangeWidget.setValues(25., 75.);
+
+  QSignalSpy lowerValueChangedSpy(&rangeWidget,
+                                  SIGNAL(minimumValueChanged(double)));
+  QSignalSpy upperValueChangedSpy(&rangeWidget,
+                                  SIGNAL(maximumValueChanged(double)));
+  QSignalSpy valuesChangedSpy(&rangeWidget,
+                              SIGNAL(valuesChanged(double,double)));
+
+  QFETCH(double, lowerValue);
+  QFETCH(double, upperValue);
+  rangeWidget.setValues(lowerValue, upperValue);
+
+  QFETCH(double, expectedLowerValue);
+  QFETCH(double, expectedUpperValue);
+  QCOMPARE(rangeWidget.minimumValue(), expectedLowerValue);
+  QCOMPARE(rangeWidget.maximumValue(), expectedUpperValue);
+
+  const bool lowerValueChanged = expectedLowerValue != 25.;
+  const bool upperValueChanged = expectedUpperValue != 75.;
+  QCOMPARE(lowerValueChangedSpy.count(), lowerValueChanged ? 1 : 0);
+  QCOMPARE(upperValueChangedSpy.count(), upperValueChanged ? 1 : 0);
+  // \todo fix the valuesChanged signal count.
+  //QCOMPARE(valuesChangedSpy.count(),
+  //         (lowerValueChanged || upperValueChanged) ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetValues_data()
+{
+  QTest::addColumn<double>("lowerValue");
+  QTest::addColumn<double>("upperValue");
+  QTest::addColumn<double>("expectedLowerValue");
+  QTest::addColumn<double>("expectedUpperValue");
+
+  QTest::newRow("[1.,10.] -> [1., 10.]") << 1. << 10. << 1. << 10.;
+  QTest::newRow("[98.,99.] -> [98., 99.]") << 98. << 99. << 98. << 99.;
+  QTest::newRow("[1.,1.] -> [1., 1.]") << 1. << 1. << 1. << 1.;
+  QTest::newRow("[10.,1.] -> [1., 10.]") << 10. << 1. << 1. << 10.;
+  QTest::newRow("[-1.,100.] -> [0., 99.]") << -1. << 100. << 0. << 99.;
+
+  QTest::newRow("[min,max] -> [0., 99.]")
+    << std::numeric_limits<double>::min()
+    << std::numeric_limits<double>::max() << 0. << 99.;
+  QTest::newRow("[-inf,inf] -> [0., 99.]")
+    << -std::numeric_limits<double>::infinity()
+    << std::numeric_limits<double>::infinity() << 0. << 99.;
+  QTest::newRow("[NaN,NaN] -> [99., 99.]")
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN() << 99. << 99.;
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetRange()
+{
+  ctkRangeWidget rangeWidget;
+  rangeWidget.setValues(25., 75.);
+
+  QSignalSpy lowerValueChangedSpy(&rangeWidget,
+                                  SIGNAL(minimumValueChanged(double)));
+  QSignalSpy upperValueChangedSpy(&rangeWidget,
+                                  SIGNAL(maximumValueChanged(double)));
+  QSignalSpy rangeChangedSpy(&rangeWidget,
+                              SIGNAL(rangeChanged(double,double)));
+
+  QFETCH(double, minimum);
+  QFETCH(double, maximum);
+  rangeWidget.setRange(minimum, maximum);
+
+  QFETCH(double, expectedMinimum);
+  QFETCH(double, expectedMaximum);
+  ctkTest::COMPARE(rangeWidget.minimum(), expectedMinimum);
+  ctkTest::COMPARE(rangeWidget.maximum(), expectedMaximum);
+
+  const bool minimumChanged = expectedMinimum != 0.;
+  const bool maximumChanged = expectedMaximum != 99.;
+  QCOMPARE(rangeChangedSpy.count(),(minimumChanged || maximumChanged) ? 1 : 0);
+
+  QFETCH(double, expectedLowerValue);
+  QFETCH(double, expectedUpperValue);
+  ctkTest::COMPARE(rangeWidget.minimumValue(), expectedLowerValue);
+  ctkTest::COMPARE(rangeWidget.maximumValue(), expectedUpperValue);
+
+  const bool lowerValueChanged = expectedLowerValue != 25.;
+  const bool upperValueChanged = expectedUpperValue != 75.;
+  QCOMPARE(lowerValueChangedSpy.count(), lowerValueChanged ? 1 : 0);
+  QCOMPARE(upperValueChangedSpy.count(), upperValueChanged ? 1 : 0);
+}
+
+//-----------------------------------------------------------------------------
+void ctkRangeWidgetTester::testSetRange_data()
+{
+  QTest::addColumn<double>("minimum");
+  QTest::addColumn<double>("maximum");
+  QTest::addColumn<double>("expectedMinimum");
+  QTest::addColumn<double>("expectedMaximum");
+  QTest::addColumn<double>("expectedLowerValue");
+  QTest::addColumn<double>("expectedUpperValue");
+
+  QTest::newRow("[1.,98.]") << 1. << 98. << 1. << 98. << 25. << 75.;
+  QTest::newRow("[-1.,101.]") << -1. << 101. << -1. << 101. << 25. << 75.;
+  QTest::newRow("[1.,50.]") << 1. << 50. << 1. << 50. << 25. << 50.;
+  QTest::newRow("[50.,99.]") << 50. << 99. << 50. << 99. << 50. << 75. ;
+  QTest::newRow("[1.,10.]") << 1. << 10. << 1. << 10. << 10. << 10.;
+  QTest::newRow("[90.,99.]") << 90. << 99. << 90. << 99. << 90. << 90.;
+  QTest::newRow("[min,max]")
+    << std::numeric_limits<double>::min()
+    << std::numeric_limits<double>::max()
+    << 0.
+    << std::numeric_limits<double>::max()
+    << 25. << 75.;
+  QTest::newRow("[-inf,inf]")
+    << -std::numeric_limits<double>::infinity()
+    << std::numeric_limits<double>::infinity()
+    << -std::numeric_limits<double>::infinity()
+    << std::numeric_limits<double>::infinity()
+    << 25. << 75.;
+  QTest::newRow("[NaN,NaN]")
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN()
+    << std::numeric_limits<double>::quiet_NaN();
+}
+
+// ----------------------------------------------------------------------------
+CTK_TEST_MAIN(ctkRangeWidgetTest)
+#include "moc_ctkRangeWidgetTest.cpp"

+ 0 - 62
Libs/Widgets/Testing/Cpp/ctkRangeWidgetTest2.cpp

@@ -1,62 +0,0 @@
-/*=========================================================================
-
-  Library:   CTK
-
-  Copyright (c) Kitware Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-=========================================================================*/
-
-// Qt includes
-#include <QApplication>
-#include <QTimer>
-
-// CTK includes
-#include "ctkRangeWidget.h"
-
-// STD includes
-#include <cstdlib>
-#include <iostream>
-
-//-----------------------------------------------------------------------------
-int ctkRangeWidgetTest2(int argc, char * argv [] )
-{
-  QApplication app(argc, argv);
-
-  ctkRangeWidget sliderSpinBox;
-  sliderSpinBox.setDecimals(2);
-  sliderSpinBox.setRange(0, 99);
-  
-  sliderSpinBox.setValues(1., 10.);
-  sliderSpinBox.setRange(-10., -0.10);
-
-  sliderSpinBox.setMaximum(-11.);
-  
-  sliderSpinBox.setMinimum(101.);
-  
-  sliderSpinBox.setValues(0., 1000.);
-  
-  sliderSpinBox.setRange(-2002, 2002);
-
-  sliderSpinBox.show();
-
-  if (argc < 2 || QString(argv[1]) != "-I" )
-    {
-    QTimer::singleShot(200, &app, SLOT(quit()));
-    }
-
-  return app.exec();
-
-}
-

+ 35 - 4
Libs/Widgets/ctkRangeWidget.cpp

@@ -57,6 +57,15 @@ public:
 // --------------------------------------------------------------------------
 bool ctkRangeWidgetPrivate::equal(double v1, double v2)const
 {
+  if (v1 == v2)
+    {// don't bother computing difference as it could fail for infinity numbers
+    return true;
+    }
+  if (v1 != v1 && v2 != v2)
+    {// NaN check
+    return true;
+    }
+  qDebug() << "equal: " << v1 << v2 << qAbs(v1 - v2) << pow(10., -this->MinimumSpinBox->decimals());
   return qAbs(v1 - v2) < pow(10., -this->MinimumSpinBox->decimals());
 }
 
@@ -406,14 +415,28 @@ void ctkRangeWidget::setMaximumValue(double _value)
 void ctkRangeWidget::setValues(double newMinimumValue, double newMaximumValue)
 {
   Q_D(ctkRangeWidget);
+  if (newMinimumValue > newMaximumValue)
+    {
+    qSwap(newMinimumValue, newMaximumValue);
+    }
+  const bool minimumFirst = (newMinimumValue <= this->maximumValue());
+
   // disable the tracking temporally to emit the
   // signal valueChanged if changeValue() is called
   bool isChanging = d->Changing;
   d->Changing = false;
-  // the pb here is that setting the spinbox separately will fired 2 signals and
-  // between the state will be inconsistent
-  d->MinimumSpinBox->setValue(newMinimumValue);
-  d->MaximumSpinBox->setValue(newMaximumValue);
+  // \todo: setting the spinbox separately is currently firing 2 signals and
+  // between the signals, the state of the widget is inconsistent.
+  if (minimumFirst)
+    {
+    d->MinimumSpinBox->setValue(newMinimumValue);
+    d->MaximumSpinBox->setValue(newMaximumValue);
+    }
+  else
+    {
+    d->MaximumSpinBox->setValue(newMaximumValue);
+    d->MinimumSpinBox->setValue(newMinimumValue);
+    }
 
   Q_ASSERT(d->equal(d->Slider->minimumValue(), d->MinimumSpinBox->value()));
   Q_ASSERT(d->equal(d->Slider->maximumValue(), d->MaximumSpinBox->value()));
@@ -425,6 +448,10 @@ void ctkRangeWidget::setValues(double newMinimumValue, double newMaximumValue)
 void ctkRangeWidget::setMinimumToMaximumSpinBox(double minimum)
 {
   Q_D(ctkRangeWidget);
+  if (minimum != minimum) // NaN check
+    {
+    return;
+    }
   d->MaximumSpinBox->setMinimum(minimum);
 }
 
@@ -432,6 +459,10 @@ void ctkRangeWidget::setMinimumToMaximumSpinBox(double minimum)
 void ctkRangeWidget::setMaximumToMinimumSpinBox(double maximum)
 {
   Q_D(ctkRangeWidget);
+  if (maximum != maximum) // NaN check
+    {
+    return;
+    }
   d->MinimumSpinBox->setMaximum(maximum);
 }