BornAgain  1.19.0
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/coregui/Views/JobWidgets/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 
22 #include <QAbstractItemModel>
23 #include <QApplication>
24 #include <QHBoxLayout>
25 #include <QItemSelectionModel>
26 #include <QMouseEvent>
27 #include <QPaintDevice>
28 #include <QPainter>
29 #include <QRect>
30 #include <QStyleOptionSlider>
31 #include <QWidget>
32 #include <cmath>
33 #include <iostream>
34 #include <limits>
35 
36 namespace {
37 const double maximum_doublespin_value = std::numeric_limits<double>::max();
38 const double minimum_doublespin_value = std::numeric_limits<double>::lowest();
39 } // namespace
40 
42  : m_smin(0), m_smax(100), m_rmin(0.0), m_rmax(0.0), m_range_factor(100.0)
43 {
44 }
45 
47 {
48  m_range_factor = range_factor;
49 }
50 
52 {
53  m_item_limits = item_limits;
54 }
55 
57 {
58  double dr(0);
59  if (value == 0.0) {
60  dr = 1.0 * m_range_factor / 100.;
61  } else {
62  dr = std::abs(value) * m_range_factor / 100.;
63  }
64  m_rmin = value - dr;
65  m_rmax = value + dr;
66 
67  if (m_item_limits.hasLowerLimit() && m_rmin < m_item_limits.lowerLimit())
68  m_rmin = m_item_limits.lowerLimit();
69 
70  if (m_item_limits.hasUpperLimit() && m_rmax > m_item_limits.upperLimit())
71  m_rmax = m_item_limits.upperLimit();
72 
73  double result = m_smin + (value - m_rmin) * (m_smax - m_smin) / (m_rmax - m_rmin);
74  return static_cast<int>(result);
75 }
76 
78 {
79  return m_rmin + (slider - m_smin) * (m_rmax - m_rmin) / (m_smax - m_smin);
80 }
81 
83 {
84  return (m_rmax - m_rmin) / (m_smax - m_smin);
85 }
86 
88  : QItemDelegate(parent)
89  , m_valueColumn(1)
90  , m_slider(nullptr)
91  , m_valueBox(nullptr)
92  , m_contentWidget(nullptr)
93  , m_contentLayout(nullptr)
94  , m_currentItem(nullptr)
95  , m_isReadOnly(false)
96 {
97 }
98 
100 
101 void ParameterTuningDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
102  const QModelIndex& index) const
103 {
104  if (index.column() == m_valueColumn) {
105 
106  if (!index.parent().isValid())
107  return;
108 
109  QVariant prop_value = index.model()->data(index, Qt::EditRole);
110  if (prop_value.isValid()) {
111  int type = SessionItemUtils::VariantType(prop_value);
112  if (type == QVariant::Double) {
113  double value = prop_value.toDouble();
114  QString text = ScientificSpinBox::toString(value, 3);
115 
116  QStyleOptionViewItem myOption = option;
117  myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
118 
119  drawDisplay(painter, myOption, myOption.rect, text);
120  drawFocus(painter, myOption, myOption.rect);
121  return;
122  }
123  }
124  }
125  QItemDelegate::paint(painter, option, index);
126 }
127 
128 QWidget* ParameterTuningDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
129  const QModelIndex& index) const
130 {
131  if (m_isReadOnly)
132  return nullptr;
133 
134  if (index.column() == m_valueColumn) {
135  if (index.parent().isValid() == false)
136  return nullptr;
137 
138  QVariant data = index.model()->data(index, Qt::EditRole);
139  if (!data.isValid())
140  return nullptr;
141 
142  m_currentItem = static_cast<ParameterItem*>(
143  ParameterTuningModel::toSourceIndex(index).internalPointer());
144  if (!m_currentItem)
145  return nullptr;
146 
147  double value = data.toDouble();
148  RealLimits limits = m_currentItem->linkedItem()->limits();
151 
152  // initializing value box
154  m_valueBox->setKeyboardTracking(false);
155  m_valueBox->setFixedWidth(105);
158 
159  if (limits.hasLowerLimit()) {
160  m_valueBox->setMinimum(limits.lowerLimit());
161  } else {
162  m_valueBox->setMinimum(minimum_doublespin_value);
163  }
164 
165  if (limits.hasUpperLimit()) {
166  m_valueBox->setMaximum(limits.upperLimit());
167  } else {
168  m_valueBox->setMaximum(maximum_doublespin_value);
169  }
170 
171  m_valueBox->setValue(value);
174 
175  // initializing slider
176  m_slider = new QSlider(Qt::Horizontal);
177  m_slider->setFocusPolicy(Qt::StrongFocus);
178  m_slider->setTickPosition(QSlider::NoTicks);
179  m_slider->setTickInterval(1);
180  m_slider->setSingleStep(1);
182 
183  updateSlider(value);
184 
185  m_contentWidget = new QWidget(parent);
186  m_contentLayout = new QHBoxLayout(parent);
187  m_contentLayout->setMargin(0);
188  m_contentLayout->setSpacing(0);
189  m_contentLayout->addWidget(m_valueBox);
190  m_contentLayout->addWidget(m_slider);
191 
192  // FIXME there is an issue with time of life of editor .vs. item
193  // m_currentItem->mapper()->setOnValueChange(
194  // [this](){
195  // if(m_valueBox && m_currentItem)
196  // m_valueBox->setValue(m_currentItem->value().toDouble());
197  // }, this);
198 
199  // m_currentItem->mapper()->setOnItemDestroy(
200  // [this](SessionItem *) {
201  // m_currentItem = 0;
202  // }, this);
203 
204  m_contentWidget->setLayout(m_contentLayout);
205 
206  return m_contentWidget;
207  } else {
208  return QItemDelegate::createEditor(parent, option, index);
209  }
210 }
211 
213 {
214  disconnect(m_slider, &QSlider::valueChanged, this,
216 
217  m_slider->setValue(m_tuning_info.value_to_slider(value));
218 
219  connect(m_slider, &QSlider::valueChanged, this, &ParameterTuningDelegate::sliderValueChanged);
220 }
221 
223 {
224  disconnect(m_valueBox, &ScientificSpinBox::valueChanged, this,
226 
227  double value = m_tuning_info.slider_to_value(position);
228  m_valueBox->setValue(value);
229 
232  emitSignals(value);
233 }
234 
236 {
237  disconnect(m_slider, &QSlider::valueChanged, this,
239 
240  updateSlider(value);
241 
242  connect(m_slider, &QSlider::valueChanged, this, &ParameterTuningDelegate::sliderValueChanged);
243  emitSignals(value);
244 }
245 
246 void ParameterTuningDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
247 {
248  if (index.column() == m_valueColumn) {
249  // as using custom widget, doing nothing here
250  } else {
251  QItemDelegate::setEditorData(editor, index);
252  }
253 }
254 
255 void ParameterTuningDelegate::setModelData(QWidget* editor, QAbstractItemModel* model,
256  const QModelIndex& index) const
257 {
258  if (index.column() == m_valueColumn) {
259 
260  model->setData(index, m_valueBox->value());
261 
262  } else {
263  QItemDelegate::setModelData(editor, model, index);
264  }
265 }
266 
268 {
269  if (m_currentItem) {
272  }
273 }
274 
276 {
278 }
279 
281 {
282  m_isReadOnly = isReadOnly;
283 }
Defines ModelPath namespace.
Defines classes for ParameterTreeItems.
Defines class ParameterTuningDelegate.
Defines class ParameterTuningModel.
Defines class ScientificSpinBox.
Defines namespace SessionItemUtils.
Defines class SessionModel.
static QModelIndex toSourceIndex(QModelIndex index)
The ParameterItem class represent a tuning value in a parameter tuning tree.
SessionItem * linkedItem()
Returns corresponding linked item in MultiLayerItem/IsntrumentItem.
void propagateValueToLink(double newValue)
Sets current value to the original PropertyItem of MultiLayerItem/InstrumentItem.
void setItemLimits(const RealLimits &item_limits)
void setReadOnly(bool isReadOnly)
void setEditorData(QWidget *editor, const QModelIndex &index) const
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
void setSliderRangeFactor(double value)
void updateSlider(double value) const
ScientificSpinBox * m_valueBox
ParameterTuningDelegate(QObject *parent=0)
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
void currentLinkChanged(SessionItem *item)
Limits for a real fit parameter.
Definition: RealLimits.h:24
bool hasUpperLimit() const
if has upper limit
Definition: RealLimits.cpp:57
double upperLimit() const
Returns upper limit.
Definition: RealLimits.cpp:62
double lowerLimit() const
Returns lower limit.
Definition: RealLimits.cpp:40
bool hasLowerLimit() const
if has lower limit
Definition: RealLimits.cpp:35
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)
int decimals() const
RealLimits limits() const
int VariantType(const QVariant &variant)
Returns type of variant (additionally checks for user type).