BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
ScientificSpinBox.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Common/ScientificSpinBox.cpp
6 //! @brief Implements class ScientificSpinBox
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include <QLineEdit>
17 #include <cmath>
18 
19 namespace {
20 
21 const double upper_switch = 100;
22 const double lower_switch = 0.1;
23 const double min_val = std::numeric_limits<double>::min();
24 const double max_val = std::numeric_limits<double>::max();
25 
26 bool useExponentialNotation(double val);
27 
28 } // namespace
29 
31  : QDoubleSpinBox(parent)
32  , m_value(0.0)
33  , m_min(-max_val)
34  , m_max(max_val)
35  , m_step(1.0)
36  , m_decimals(3)
37 {
38  QLocale locale;
39  locale.setNumberOptions(QLocale::RejectGroupSeparator);
40  m_validator.setLocale(locale);
41  m_validator.setNotation(QDoubleValidator::ScientificNotation);
42 
43  connect(this, &QAbstractSpinBox::editingFinished, this, &ScientificSpinBox::updateValue);
44 }
45 
47 
49 {
50  // The following is somehow a hack to get a reasonable sizeHint. Implementation could/should be
51  // re-thought
52  QDoubleSpinBox d;
53  d.setRange(m_min, m_max);
54  d.setDecimals(m_decimals);
55  return d.sizeHint();
56 }
57 
59 {
60  return m_value;
61 }
62 
64 {
65  double old_val = m_value;
66  m_value = round(val, m_decimals);
67  updateText();
68  if (std::abs(old_val - m_value) > min_val)
69  emit valueChanged(m_value);
70 }
71 
73 {
74  double new_val = toDouble(text(), m_validator, m_min, m_max, m_value);
75  setValue(new_val);
76 }
77 
79 {
80  return m_step;
81 }
82 
84 {
85  m_step = step;
86 }
87 
89 {
90  return m_min;
91 }
92 
94 {
95  m_min = min;
96  if (m_value < m_min)
97  setValue(m_min);
98 }
99 
101 {
102  return m_max;
103 }
104 
106 {
107  m_max = max;
108  if (m_value > m_max)
109  setValue(m_max);
110 }
111 
113 {
114  if (val <= 0)
115  return;
116  m_decimals = val;
117  setValue(m_value);
118 }
119 
121 {
122  return m_decimals;
123 }
124 
126 {
127  double new_val = round(m_value + m_step * steps, m_decimals);
128  if (inRange(new_val))
129  setValue(new_val);
130 }
131 
132 QString ScientificSpinBox::toString(double val, int decimal_points)
133 {
134  QString result = useExponentialNotation(val) ? QString::number(val, 'e', decimal_points)
135  : QString::number(val, 'f', decimal_points);
136 
137  return result.replace(QRegExp("(\\.?0+)?((e{1}[\\+|-]{1})(0+)?([1-9]{1}.*))?$"), "\\3\\5");
138 }
139 
140 double ScientificSpinBox::toDouble(QString text, const QDoubleValidator& validator, double min,
141  double max, double default_value)
142 {
143  int pos = 0;
144  if (validator.validate(text, pos) == QValidator::Acceptable) {
145  double new_val = validator.locale().toDouble(text);
146  if (std::abs(new_val) < min_val)
147  new_val = 0.0;
148  return new_val >= min && new_val <= max ? new_val : default_value;
149  }
150  return default_value;
151 }
152 
153 double ScientificSpinBox::round(double val, int decimals)
154 {
155  return QString::number(val, 'e', decimals).toDouble();
156 }
157 
158 QAbstractSpinBox::StepEnabled ScientificSpinBox::stepEnabled() const
159 {
160  return isReadOnly() ? StepNone : StepUpEnabled | StepDownEnabled;
161 }
162 
164 {
165  QString new_text = toString(m_value, m_decimals);
166  if (new_text != text())
167  lineEdit()->setText(new_text);
168 }
169 
170 bool ScientificSpinBox::inRange(double val) const
171 {
172  return val >= m_min && val <= m_max;
173 }
174 
175 namespace {
176 
177 bool useExponentialNotation(double val)
178 {
179  const double abs_val = std::abs(val);
180 
181  if (abs_val <= min_val)
182  return false;
183 
184  return abs_val >= upper_switch || abs_val < lower_switch;
185 }
186 
187 } // namespace
Defines class ScientificSpinBox.
double minimum() const
ScientificSpinBox(QWidget *parent=nullptr)
void stepBy(int steps) override
static double toDouble(QString text, const QDoubleValidator &validator, double min, double max, double default_value)
void setMaximum(double max)
QSize sizeHint() const override
void setMinimum(double min)
~ScientificSpinBox() override
double maximum() const
void setValue(double val)
void setSingleStep(double step)
QDoubleValidator m_validator
static double round(double val, int decimals)
bool inRange(double val) const
QAbstractSpinBox::StepEnabled stepEnabled() const override
static QString toString(double val, int decimal_points)
void valueChanged(double value)
double singleStep() const