BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
scientificspinbox.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // qt-mvvm: Model-view-view-model framework for large GUI applications
4 //
5 //! @file mvvm/viewmodel/mvvm/editors/scientificspinbox.cpp
6 //! @brief Implements class CLASS?
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2020
11 //! @authors Gennady Pospelov et al, Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
17 #include <QLineEdit>
18 #include <cmath>
19 #include <limits>
20 
21 namespace {
22 const double upper_switch = 1000;
23 const double lower_switch = 0.1;
24 const double min_val = std::numeric_limits<double>::min();
25 const double max_val = std::numeric_limits<double>::max();
26 
27 bool useExponentialNotation(double val);
28 } // namespace
29 
30 using namespace ModelView;
31 
33  : QAbstractSpinBox(parent)
34  , m_value(0.0)
35  , m_min(-max_val)
36  , m_max(max_val)
37  , m_step(1.0)
38  , m_decimals(Constants::default_double_decimals)
39 {
40  QLocale locale;
41  locale.setNumberOptions(QLocale::RejectGroupSeparator);
42  m_validator.setLocale(locale);
43  m_validator.setNotation(QDoubleValidator::ScientificNotation);
44 
45  connect(this, &QAbstractSpinBox::editingFinished, this, &ScientificSpinBox::updateValue);
46 }
47 
49 
51 {
52  // return last acceptable input (required for the proper focus-out behaviour)
53  double val = toDouble(text(), m_validator, m_min, m_max, m_value);
54  return round(val, m_decimals);
55 }
56 
58 {
59  double old_val = m_value;
60  m_value = round(val, m_decimals);
61  updateText();
62  if (std::abs(old_val - m_value) > min_val)
63  emit valueChanged(m_value);
64 }
65 
67 {
68  double new_val = toDouble(text(), m_validator, m_min, m_max, m_value);
69  setValue(new_val);
70 }
71 
73 {
74  return m_step;
75 }
76 
78 {
79  m_step = step;
80 }
81 
83 {
84  return m_min;
85 }
86 
88 {
89  m_min = min;
90  if (m_value < m_min)
91  setValue(m_min);
92 }
93 
95 {
96  return m_max;
97 }
98 
100 {
101  m_max = max;
102  if (m_value > m_max)
103  setValue(m_max);
104 }
105 
107 {
108  if (val <= 0)
109  return;
110  m_decimals = val;
111  setValue(m_value);
112 }
113 
115 {
116  return m_decimals;
117 }
118 
120 {
121  double new_val = round(m_value + m_step * steps, m_decimals);
122  if (inRange(new_val))
123  setValue(new_val);
124 }
125 
126 QString ScientificSpinBox::toString(double val, int decimal_points)
127 {
128  QString result = useExponentialNotation(val) ? QString::number(val, 'e', decimal_points)
129  : QString::number(val, 'f', decimal_points);
130 
131  return result.replace(QRegExp("(\\.?0+)?((e{1}[\\+|-]{1})(0+)?([1-9]{1}.*))?$"), "\\3\\5");
132 }
133 
134 double ScientificSpinBox::toDouble(QString text, const QDoubleValidator& validator, double min,
135  double max, double default_value)
136 {
137  int pos = 0;
138  if (validator.validate(text, pos) == QValidator::Acceptable) {
139  double new_val = validator.locale().toDouble(text);
140  if (std::abs(new_val) < min_val)
141  new_val = 0.0;
142  return new_val >= min && new_val <= max ? new_val : default_value;
143  }
144  return default_value;
145 }
146 
147 double ScientificSpinBox::round(double val, int decimals)
148 {
149  char notation = useExponentialNotation(val) ? 'e' : 'f';
150  return QString::number(val, notation, decimals).toDouble();
151 }
152 
153 QAbstractSpinBox::StepEnabled ScientificSpinBox::stepEnabled() const
154 {
155  return isReadOnly() ? StepNone : StepUpEnabled | StepDownEnabled;
156 }
157 
159 {
160  QString new_text = toString(m_value, m_decimals);
161  if (new_text != text())
162  lineEdit()->setText(new_text);
163 }
164 
165 bool ScientificSpinBox::inRange(double val) const
166 {
167  return val >= m_min && val <= m_max;
168 }
169 
170 namespace {
171 bool useExponentialNotation(double val)
172 {
173  const double abs_val = std::abs(val);
174 
175  if (abs_val <= min_val)
176  return false;
177 
178  return abs_val >= upper_switch || abs_val < lower_switch;
179 }
180 } // namespace
ScientificSpinBox(QWidget *parent=nullptr)
void stepBy(int steps) override
static double toDouble(QString text, const QDoubleValidator &validator, double min, double max, double default_value)
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)
Defines class CLASS?
const int default_double_decimals
materialitems.h Collection of materials to populate MaterialModel.
Defines class CLASS?