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