From bd7e9ae655c83fb9d79576063eeaffb6d7c1a99b Mon Sep 17 00:00:00 2001
From: Mikhail Svechnikov <m.svechnikov@fz-juelich.de>
Date: Mon, 23 Sep 2024 12:42:18 +0200
Subject: [PATCH] add fixed step and rework adaptive step

---
 GUI/View/Numeric/DSpinBox.cpp | 45 +++++++++++++++++++----------------
 GUI/View/Numeric/DSpinBox.h   |  2 --
 2 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/GUI/View/Numeric/DSpinBox.cpp b/GUI/View/Numeric/DSpinBox.cpp
index 64948d998db..4d227946daa 100644
--- a/GUI/View/Numeric/DSpinBox.cpp
+++ b/GUI/View/Numeric/DSpinBox.cpp
@@ -40,21 +40,25 @@ QString toString(double val, int decimal_points = 6)
                           "\\3\\5\\7");
 }
 
+int orderOfMagnitude(double x)
+{
+    if (x == 0)
+        return 0;
+
+    return std::floor(std::log10(std::abs(x)));
+}
+
 } // namespace
 
 
 DSpinBox::DSpinBox(DoubleProperty* d)
-    : m_step(::step0)
 {
     replaceProperty(d);
 
     connect(this, &QAbstractSpinBox::editingFinished, [this] {
         ASSERT(m_property);
         setValue(fromDisplay());
-        m_old_dir = 0;
-        m_step = ::step0;
     });
-    // setSingleStep(m_property->step());
 }
 
 void DSpinBox::replaceProperty(DoubleProperty* d)
@@ -68,7 +72,6 @@ void DSpinBox::replaceProperty(DoubleProperty* d)
         setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
         lineEdit()->setText(toString(m_property->dVal()));
         connect(d, &DoubleProperty::setAndNotifyCalled, this, &DSpinBox::updateValue);
-        //		[this] { updateValue(); });
     }
     setReadOnly(!m_property);
     updateValue();
@@ -118,22 +121,22 @@ void DSpinBox::wheelEvent(QWheelEvent* event)
 void DSpinBox::stepBy(int steps)
 {
     ASSERT(m_property);
+    const double val = m_property->dVal();
 
-    const int new_dir = steps > 0 ? +1 : -1;
-    if (m_old_dir == new_dir)
-        m_step = std::min(m_step * (std::abs(steps) == 1 ? 1.2 : 2.) * (1 + m_step), 9.);
-    else if (m_old_dir == -new_dir)
-        m_step = std::abs(steps) == 1 ? std::max(m_step / 9, 1e-6) : m_step;
-
-    const double fac = (steps > 0) ^ (m_property->dVal() < 0) ? 1 + m_step : 1 / (1 + m_step);
-    const int decimals = std::min(6, std::max(2, (int)(2 - std::log10(m_step))));
-
-    // std::cout << "DEBUG steps=" << steps << " m_s=" << m_step << " fac=" << fac
-    //	      << " dec=" << decimals << " old=" << m_property->dVal()
-    //	      << " new=" << m_property->dVal() * fac
-    //	      << " rnd=" << Numeric::round_decimal(m_property->dVal() * fac, decimals)
-    //	      << std::endl;
-    setValue(Numeric::round_decimal(m_property->dVal() * fac, decimals));
+    if (m_property->limits().isLimited()) {
+        setValue(val + m_property->step() * steps);
+        return;
+    }
 
-    m_old_dir = new_dir;
+    // "step digit" is the orger of magnitude of the step.
+    // If it is "1", then we increment/decrement the first digit of the value.
+    // If it is "2", then we increment/decrement the second digit of the value and so on.
+    const int step_digit = 2;
+    const int order_of_mag = ::orderOfMagnitude(val);
+    // special cases: if the current value is 100 and step digit is 2, then the diminished value
+    // should be not 90, but 99.
+    const int correction = (val == std::pow(10, order_of_mag) && steps < 0) ? 1 : 0;
+    const double adaptive_step = std::pow(10, order_of_mag - step_digit - correction + 1);
+    const double step = (val == 0) ? ::step0 : adaptive_step;
+    setValue(val + step * steps);
 }
diff --git a/GUI/View/Numeric/DSpinBox.h b/GUI/View/Numeric/DSpinBox.h
index 4817d840291..e365c10184a 100644
--- a/GUI/View/Numeric/DSpinBox.h
+++ b/GUI/View/Numeric/DSpinBox.h
@@ -50,8 +50,6 @@ private:
     void stepBy(int steps) override;
 
     DoubleProperty* m_property;
-    int m_old_dir = 0;
-    double m_step;
 };
 
 #endif // BORNAGAIN_GUI_VIEW_NUMERIC_DSPINBOX_H
-- 
GitLab