Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkNumberPropertySlider.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include <mitkProperties.h>
16 #include <mitkPropertyObserver.h>
17 
18 #include <mitkRenderingManager.h>
19 
20 #define DT_SHORT 1
21 #define DT_INT 2
22 #define DT_FLOAT 3
23 #define DT_DOUBLE 4
24 
25 #define ROUND(x) (((x) > 0) ? int((x) + 0.5) : int((x)-0.5))
26 #define ROUND_SHORT(x) (((x) > 0) ? short((x) + 0.5) : short((x)-0.5))
27 
28 class QmitkNumberPropertySlider::Impl
29 {
30 public:
32 
33  void DisplayNumber();
34  void adjustFactors(short, bool);
35 
36  class Editor : public mitk::PropertyEditor
37  {
38  public:
39  Editor(mitk::IntProperty *, Impl *impl);
40  Editor(mitk::FloatProperty *, Impl *impl);
41  Editor(mitk::DoubleProperty *, Impl *impl);
42 
43  void PropertyChanged() override;
44  void PropertyRemoved() override;
45 
46  void BeginModifyProperty() { mitk::PropertyEditor::BeginModifyProperty(); }
47  void EndModifyProperty() { mitk::PropertyEditor::EndModifyProperty(); }
48  union {
49  mitk::GenericProperty<int> *m_IntProperty;
50  mitk::GenericProperty<float> *m_FloatProperty;
51  mitk::GenericProperty<double> *m_DoubleProperty;
52  };
53 
54  const int m_DataType;
55 
56  private:
57  Impl *m_Impl;
58  };
59 
60  std::unique_ptr<Editor> m_PropEditor;
61 
62  short m_DecimalPlaces; // how many decimal places are shown
63  double m_FactorPropertyToSlider; // internal conversion factor. neccessary because slider ranges work only with ints
64  double m_FactorSliderToDisplay; // internal conversion factor. neccessary because slider ranges work only with ints
65  bool m_ShowPercents; // whether values are given in percent (0.5 -> 50%)
66 
67  bool m_SelfChangeLock;
68 
69 private:
70  void initialize();
71 
73 };
74 
75 QmitkNumberPropertySlider::Impl::Editor::Editor(mitk::IntProperty *property, Impl *impl)
76  : mitk::PropertyEditor(property), m_IntProperty(property), m_DataType(DT_INT), m_Impl(impl)
77 {
78 }
79 
80 QmitkNumberPropertySlider::Impl::Editor::Editor(mitk::FloatProperty *property, Impl *impl)
81  : mitk::PropertyEditor(property), m_FloatProperty(property), m_DataType(DT_FLOAT), m_Impl(impl)
82 {
83 }
84 
85 QmitkNumberPropertySlider::Impl::Editor::Editor(mitk::DoubleProperty *property, Impl *impl)
86  : mitk::PropertyEditor(property), m_DoubleProperty(property), m_DataType(DT_DOUBLE), m_Impl(impl)
87 {
88 }
89 
91 {
92 }
93 
95 {
96  if (property == nullptr)
97  {
98  d->m_PropEditor.reset();
99  this->setEnabled(false);
100  }
101  else
102  {
103  d->m_PropEditor.reset(new Impl::Editor(property, d.get()));
104  d->m_PropEditor->PropertyChanged();
105  this->setEnabled(true);
106  }
107 }
108 
110 {
111  if (property == nullptr)
112  {
113  d->m_PropEditor.reset();
114  this->setEnabled(false);
115  }
116  else
117  {
118  d->m_PropEditor.reset(new Impl::Editor(property, d.get()));
119  d->m_PropEditor->PropertyChanged();
120  this->setEnabled(true);
121  }
122 }
123 
125 {
126  if (property == nullptr)
127  {
128  d->m_PropEditor.reset();
129  this->setEnabled(false);
130  }
131  else
132  {
133  d->m_PropEditor.reset(new Impl::Editor(property, d.get()));
134  d->m_PropEditor->PropertyChanged();
135  this->setEnabled(true);
136  }
137 }
138 
139 QmitkNumberPropertySlider::Impl::Impl(QmitkNumberPropertySlider *q)
140  : m_DecimalPlaces(0),
141  m_FactorPropertyToSlider(1.0),
142  m_FactorSliderToDisplay(1.0),
143  m_ShowPercents(false),
144  m_SelfChangeLock(false),
145  q(q)
146 {
147 }
148 
149 QmitkNumberPropertySlider::QmitkNumberPropertySlider(QWidget *parent) : QSlider(parent), d(new Impl(this))
150 {
151  connect(this, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
152  this->setEnabled(false);
153 }
154 
155 void QmitkNumberPropertySlider::Impl::adjustFactors(short newDecimalPlaces, bool newShowPercents)
156 {
157  int oldMax = q->maxValue();
158  int oldMin = q->minValue();
159 
160  m_DecimalPlaces = newDecimalPlaces;
161  m_ShowPercents = newShowPercents;
162 
163  m_FactorPropertyToSlider = pow(10.0, m_DecimalPlaces);
164  m_FactorSliderToDisplay = 1.0 / m_FactorPropertyToSlider;
165 
166  if (m_ShowPercents)
167  m_FactorPropertyToSlider *= 100.0;
168 
169  q->setMinimum(oldMin);
170  q->setMaximum(oldMax);
171 }
172 
174 {
175  return d->m_DecimalPlaces;
176 }
177 
179 {
180  if (d->m_PropEditor.get() == nullptr)
181  return;
182 
183  switch (d->m_PropEditor->m_DataType)
184  {
185  case DT_FLOAT:
186  case DT_DOUBLE:
187  {
188  d->adjustFactors(places, d->m_ShowPercents);
189  d->DisplayNumber();
190  break;
191  }
192  default:
193  break;
194  }
195 }
196 
198 {
199  return d->m_ShowPercents;
200 }
201 
203 {
204  if (showPercent == d->m_ShowPercents)
205  return; // nothing to change
206 
207  if (d->m_PropEditor.get() == nullptr)
208  return;
209 
210  switch (d->m_PropEditor->m_DataType)
211  {
212  case DT_FLOAT:
213  case DT_DOUBLE:
214  {
215  d->adjustFactors(d->m_DecimalPlaces, showPercent);
216  break;
217  }
218  default:
219  {
220  break;
221  }
222  }
223 
224  d->DisplayNumber();
225 }
226 
228 {
229  return ROUND(QSlider::minimum() / d->m_FactorPropertyToSlider);
230 }
231 
233 {
234  QSlider::setMinimum(ROUND(value * d->m_FactorPropertyToSlider));
235 }
236 
238 {
239  return ROUND(QSlider::maximum() / d->m_FactorPropertyToSlider);
240 }
241 
243 {
244  QSlider::setMaximum(ROUND(value * d->m_FactorPropertyToSlider));
245 }
246 
248 {
249  return static_cast<double>((QSlider::value()) / d->m_FactorPropertyToSlider);
250 }
251 
253 {
254  QSlider::setValue(ROUND(value * d->m_FactorPropertyToSlider));
255 }
256 
258 {
259  if (d->m_PropEditor.get() == nullptr)
260  return;
261 
262  if (d->m_SelfChangeLock)
263  return; // valueChanged is even emitted, when this widget initiates a change to its value
264  // this may be useful some times, but in this use, it would be wrong:
265  // (A) is an editor with 3 decimal places
266  // (B) is an editor with 2 decimal places
267  // User changes A's displayed value to 4.002
268  // A's onValueChanged gets called, sets the associated Property to 4.002
269  // B's onPropertyChanged gets called, sets its display to 4.00
270  // B's onValueChanged gets called and sets the associated Property to 4.00
271  // A's onPropertyChanged gets called, sets its display to 4.000
272 
273  d->m_PropEditor->BeginModifyProperty();
274 
275  double newValue(value / d->m_FactorPropertyToSlider);
276 
277  switch (d->m_PropEditor->m_DataType)
278  {
279  case DT_INT:
280  {
281  d->m_PropEditor->m_IntProperty->SetValue(ROUND(newValue));
282  break;
283  }
284  case DT_FLOAT:
285  {
286  d->m_PropEditor->m_FloatProperty->SetValue(newValue);
287  break;
288  }
289  case DT_DOUBLE:
290  {
291  d->m_PropEditor->m_DoubleProperty->SetValue(newValue);
292  break;
293  }
294  }
296 
297  d->m_PropEditor->EndModifyProperty();
298 }
299 
300 void QmitkNumberPropertySlider::Impl::Editor::PropertyChanged()
301 {
302  m_Impl->DisplayNumber();
304 }
305 
306 void QmitkNumberPropertySlider::Impl::Editor::PropertyRemoved()
307 {
308  this->m_Property = nullptr;
309 }
310 
311 void QmitkNumberPropertySlider::Impl::DisplayNumber()
312 {
313  if (m_PropEditor.get() == nullptr)
314  return;
315 
316  m_SelfChangeLock = true;
317  switch (m_PropEditor->m_DataType)
318  {
319  case DT_INT:
320  {
321  int i = m_PropEditor->m_IntProperty->GetValue();
322  q->setValue(i);
323  break;
324  }
325  case DT_FLOAT:
326  {
327  float f = m_PropEditor->m_FloatProperty->GetValue();
328  q->setDoubleValue(f);
329  break;
330  }
331  case DT_DOUBLE:
332  {
333  double d = m_PropEditor->m_DoubleProperty->GetValue();
334  q->setDoubleValue(d);
335  break;
336  }
337  default:
338  break;
339  }
340  m_SelfChangeLock = false;
341 }
#define DT_FLOAT
void SetProperty(mitk::IntProperty *property)
QmitkNumberPropertySlider(QWidget *parent=nullptr)
static RenderingManager * GetInstance()
#define DT_DOUBLE
#define ROUND(x)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
#define DT_INT