BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
ParameterTuningDelegate.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Fit/ParameterTuningDelegate.cpp
6 //! @brief Implements class ParameterTuningDelegate
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 
19 #include <QAbstractItemModel>
20 #include <QApplication>
21 #include <QHBoxLayout>
22 #include <QItemSelectionModel>
23 #include <QMouseEvent>
24 #include <QPaintDevice>
25 #include <QPainter>
26 #include <QRect>
27 #include <QStyleOptionSlider>
28 #include <QWidget>
29 #include <cmath>
30 #include <iostream>
31 #include <limits>
32 
33 namespace {
34 
35 const double maximum_doublespin_value = std::numeric_limits<double>::max();
36 const double minimum_doublespin_value = std::numeric_limits<double>::lowest();
37 
38 } // namespace
39 
41  : m_smin(0)
42  , m_smax(100)
43  , m_rmin(0.0)
44  , m_rmax(0.0)
45  , m_range_factor(100.0)
46 {
47 }
48 
50 {
51  m_range_factor = range_factor;
52 }
53 
54 void ParameterTuningDelegate::TuningData::setItemLimits(const RealLimits& item_limits)
55 {
56  m_item_limits = item_limits;
57 }
58 
60 {
61  double dr(0);
62  if (value == 0.0)
63  dr = 1.0 * m_range_factor / 100.;
64  else
65  dr = std::abs(value) * m_range_factor / 100.;
66  m_rmin = value - dr;
67  m_rmax = value + dr;
68 
69  if (m_item_limits.hasLowerLimit() && m_rmin < m_item_limits.lowerLimit())
70  m_rmin = m_item_limits.lowerLimit();
71 
72  if (m_item_limits.hasUpperLimit() && m_rmax > m_item_limits.upperLimit())
73  m_rmax = m_item_limits.upperLimit();
74 
75  double result = m_smin + (value - m_rmin) * (m_smax - m_smin) / (m_rmax - m_rmin);
76  return static_cast<int>(result);
77 }
78 
80 {
81  return m_rmin + (slider - m_smin) * (m_rmax - m_rmin) / (m_smax - m_smin);
82 }
83 
85 {
86  return (m_rmax - m_rmin) / (m_smax - m_smin);
87 }
88 
90  : QItemDelegate(parent)
91  , m_valueColumn(1)
92  , m_slider(nullptr)
93  , m_valueBox(nullptr)
94  , m_contentWidget(nullptr)
95  , m_contentLayout(nullptr)
96  , m_currentItem(nullptr)
97  , m_isReadOnly(false)
98 {
99 }
100 
102 
103 void ParameterTuningDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
104  const QModelIndex& index) const
105 {
106  if (index.column() == m_valueColumn) {
107  if (!index.parent().isValid())
108  return;
109 
110  QVariant valueAsVariant = index.model()->data(index, Qt::EditRole);
111  if (valueAsVariant.isValid() && valueAsVariant.type() == QVariant::Double) {
112  double value = valueAsVariant.toDouble();
113  QString text = ScientificSpinBox::toString(value, 3);
114 
115  QStyleOptionViewItem myOption = option;
116  myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
117 
118  drawDisplay(painter, myOption, myOption.rect, text);
119  drawFocus(painter, myOption, myOption.rect);
120  return;
121  }
122  }
123  QItemDelegate::paint(painter, option, index);
124 }
125 
126 QWidget* ParameterTuningDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
127  const QModelIndex& index) const
128 {
129  if (m_isReadOnly)
130  return nullptr;
131 
132  if (index.column() != m_valueColumn)
133  return QItemDelegate::createEditor(parent, option, index);
134 
135  if (!index.parent().isValid())
136  return nullptr;
137 
138  QVariant data = index.model()->data(index, Qt::EditRole);
139  if (!data.isValid())
140  return nullptr;
141 
143  if (!m_currentItem)
144  return nullptr;
145 
146  double value = data.toDouble();
147  RealLimits limits = m_currentItem->limitsOfLink();
150 
151  // initializing value box
153  m_valueBox->setKeyboardTracking(false);
154  m_valueBox->setFixedWidth(105);
157 
158  if (limits.hasLowerLimit())
159  m_valueBox->setMinimum(limits.lowerLimit());
160  else
161  m_valueBox->setMinimum(minimum_doublespin_value);
162 
163  if (limits.hasUpperLimit())
164  m_valueBox->setMaximum(limits.upperLimit());
165  else
166  m_valueBox->setMaximum(maximum_doublespin_value);
167 
168  m_valueBox->setValue(value);
171 
172  // initializing slider
173  m_slider = new QSlider(Qt::Horizontal);
174  m_slider->setFocusPolicy(Qt::StrongFocus);
175  m_slider->setTickPosition(QSlider::NoTicks);
176  m_slider->setTickInterval(1);
177  m_slider->setSingleStep(1);
179 
180  updateSlider(value);
181 
182  m_contentWidget = new QWidget(parent);
183  m_contentLayout = new QHBoxLayout(parent);
184  m_contentLayout->setMargin(0);
185  m_contentLayout->setSpacing(0);
186  m_contentLayout->addWidget(m_valueBox);
187  m_contentLayout->addWidget(m_slider);
188 
189  // FIXME there is an issue with time of life of editor .vs. item
190  // m_currentItem->mapper()->setOnValueChange(
191  // [this](){
192  // if(m_valueBox && m_currentItem)
193  // m_valueBox->setValue(m_currentItem->value().toDouble());
194  // }, this);
195 
196  // m_currentItem->mapper()->setOnItemDestroy(
197  // [this](SessionItem *) {
198  // m_currentItem = 0;
199  // }, this);
200 
201  m_contentWidget->setLayout(m_contentLayout);
202 
203  return m_contentWidget;
204 }
205 
207 {
208  disconnect(m_slider, &QSlider::valueChanged, this,
210 
211  m_slider->setValue(m_tuning_info.value_to_slider(value));
212 
213  connect(m_slider, &QSlider::valueChanged, this, &ParameterTuningDelegate::sliderValueChanged);
214 }
215 
217 {
218  disconnect(m_valueBox, &ScientificSpinBox::valueChanged, this,
220 
221  double value = m_tuning_info.slider_to_value(position);
222  m_valueBox->setValue(value);
223 
226  emitSignals(value);
227 }
228 
230 {
231  disconnect(m_slider, &QSlider::valueChanged, this,
233 
234  updateSlider(value);
235 
236  connect(m_slider, &QSlider::valueChanged, this, &ParameterTuningDelegate::sliderValueChanged);
237  emitSignals(value);
238 }
239 
240 void ParameterTuningDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
241 {
242  if (index.column() == m_valueColumn) {
243  // as using custom widget, doing nothing here
244  } else {
245  QItemDelegate::setEditorData(editor, index);
246  }
247 }
248 
249 void ParameterTuningDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,
250  const QModelIndex& index) const
251 {
252  if (index.column() == m_valueColumn)
253  model->setData(index, m_valueBox->value());
254  else
255  QItemDelegate::setModelData(editor, model, index);
256 }
257 
259 {
260  if (m_currentItem) {
263  }
264 }
265 
267 {
269 }
270 
272 {
273  m_isReadOnly = isReadOnly;
274 }
Defines classes for ParameterTreeItems.
Defines class ParameterTuningDelegate.
Defines class ParameterTuningModel.
Defines class ScientificSpinBox.
void propagateValueToLink(double newValue)
Sets current value to the original PropertyItem of MultiLayerItem/InstrumentItem.
int decimalsOfLink() const
RealLimits limitsOfLink() const
void setItemLimits(const RealLimits &item_limits)
void setReadOnly(bool isReadOnly)
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
~ParameterTuningDelegate() override
void setSliderRangeFactor(double value)
void updateSlider(double value) const
ScientificSpinBox * m_valueBox
ParameterTuningDelegate(QObject *parent=nullptr)
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
void currentLinkChanged(ParameterItem *item)
void setEditorData(QWidget *editor, const QModelIndex &index) const override
static ParameterItem * toParameterItem(const QModelIndex &index)
void setMaximum(double max)
void setMinimum(double min)
void setValue(double val)
void setSingleStep(double step)
static QString toString(double val, int decimal_points)
void valueChanged(double value)