Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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