Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkSliderLevelWindowWidget.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 // mitk core
16 #include <mitkRenderingManager.h>
17 
18 // mitk qt widgets
20 
21 // qt
22 #include <QCursor>
23 #include <QMouseEvent>
24 #include <QPainter>
25 #include <QToolTip>
26 
27 // itk
28 #include <itkCommand.h>
29 
30 // c++
31 #include <cmath>
32 
34  : QWidget(parent, f)
35 {
37 
38  itk::ReceptorMemberCommand<QmitkSliderLevelWindowWidget>::Pointer command =
39  itk::ReceptorMemberCommand<QmitkSliderLevelWindowWidget>::New();
40  command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified);
41  m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command);
42  m_IsObserverTagSet = true;
43 
44  setMouseTracking(true);
45  m_Resize = false;
46  m_Bottom = false;
47  m_CtrlPressed = false;
48  m_MouseDown = false;
49 
50  m_Font.setPointSize(6);
51 
52  m_MoveHeight = height() - 25;
53  m_ScaleVisible = true;
55 
56  this->hide();
57  Update();
58 }
59 
61 {
63  {
64  m_Manager->RemoveObserver(m_ObserverTag);
65  m_IsObserverTagSet = false;
66  }
67 }
68 
70 {
72  {
73  m_Manager->RemoveObserver(m_ObserverTag);
74  m_IsObserverTagSet = false;
75  }
76  m_Manager = levelWindowManager;
77  if (m_Manager.IsNotNull())
78  {
79  itk::ReceptorMemberCommand<QmitkSliderLevelWindowWidget>::Pointer command =
80  itk::ReceptorMemberCommand<QmitkSliderLevelWindowWidget>::New();
81  command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified);
82  m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command);
83  m_IsObserverTagSet = true;
84  }
85 }
86 
87 void QmitkSliderLevelWindowWidget::OnPropertyModified(const itk::EventObject &)
88 {
89  try
90  {
91  m_LevelWindow = m_Manager->GetLevelWindow();
92  this->show();
93  Update();
94  }
95  catch (...)
96  {
97  try
98  {
99  this->hide();
100  }
101  catch (...)
102  {
103  }
104  }
105 }
106 
107 void QmitkSliderLevelWindowWidget::paintEvent(QPaintEvent *itkNotUsed(e))
108 {
109  QPixmap pm(width(), height());
110  pm.fill(this->palette().color(this->backgroundRole()));
111  QPainter painter(&pm);
112 
113  painter.setFont(m_Font);
114  painter.setPen(this->palette().color(this->foregroundRole()));
115 
116  QColor c(51, 153, 204);
117  QColor cl = c.light();
118  QColor cd = c.dark();
119 
120  painter.setBrush(c);
121  painter.drawRect(m_Rect);
122 
123  float mr = m_LevelWindow.GetRange();
124  float smallestLevelableValue = 1e-9;
125 
126  //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges
127  //from images, but old scene serialization may contain infinite ranges that overwrite the new
128  //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962.
129  //Until LevelWindow and this widget is refactored the check was the minimal invasive fix.
130  if (!std::isfinite(mr))
131  {
132  mr = m_LevelWindow.GetWindow();
133  }
134 
135 
136  // avoiding a division by 0 while still enabling small level windows
137  if (mr < smallestLevelableValue)
138  mr = smallestLevelableValue;
139 
140  float fact = (float)m_MoveHeight / mr;
141 
142  // begin draw scale
143  if (m_ScaleVisible)
144  {
145  double minRange = (double)m_LevelWindow.GetRangeMin();
146  double maxRange = (double)m_LevelWindow.GetRangeMax();
147 
148  //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges
149  //from images, but old scene serialization may contain infinite ranges that overwrite the new
150  //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962.
151  //Until LevelWindow and this widget is refactored the check was the minimal invasive fix.
152  if (!std::isfinite(minRange))
153  {
154  minRange = m_LevelWindow.GetLowerWindowBound();
155  }
156  //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges
157  //from images, but old scene serialization may contain infinite ranges that overwrite the new
158  //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962.
159  //Until LevelWindow and this widget is refactored the check was the minimal invasive fix.
160  if (!std::isfinite(maxRange))
161  {
162  maxRange = m_LevelWindow.GetUpperWindowBound();
163  }
164 
165  int yValue = m_MoveHeight + (int)(minRange * fact);
166  QString s = " 0";
167  if (minRange < 0 && maxRange > 0)
168  {
169  painter.drawLine(5, yValue, 15, yValue);
170  painter.drawText(21, yValue + 3, s);
171  }
172 
173  int count = 1;
174  int k = 5;
175  bool enoughSpace = false;
176  bool enoughSpace2 = false;
177 
178  double dStepSize = pow(10, floor(log10(mr / 100)) + 1);
179 
180  for (int i = m_MoveHeight + (int)(minRange * fact); i < m_MoveHeight;) // negative
181  {
182 
183  if (-count * dStepSize < minRange)
184  {
185  break;
186  }
187 
188  yValue = m_MoveHeight + (int)((minRange + count * dStepSize) * fact);
189 
190  s = QString::number(-count * dStepSize);
191  if (count % k && ((dStepSize * fact) > 2.5))
192  {
193  painter.drawLine(8, yValue, 12, yValue);
194  enoughSpace = true;
195  }
196  else if (!(count % k))
197  {
198  if ((k * dStepSize * fact) > 7)
199  {
200  painter.drawLine(5, yValue, 15, yValue);
201  painter.drawText(21, yValue + 3, s);
202  enoughSpace2 = true;
203  }
204  else
205  {
206  k += 5;
207  }
208  }
209  if (enoughSpace)
210  {
211  i = yValue;
212  count++;
213  }
214  else if (enoughSpace2)
215  {
216  i = yValue;
217  count += k;
218  }
219  else
220  {
221  i = yValue;
222  count = k;
223  }
224  }
225 
226  count = 1;
227  k = 5;
228  enoughSpace = false;
229  enoughSpace2 = false;
230  for (int i = m_MoveHeight + (int)(minRange * fact); i >= 0;)
231  {
232  if (count * dStepSize > maxRange)
233  {
234  break;
235  }
236  yValue = m_MoveHeight + (int)((minRange - count * dStepSize) * fact);
237  s = QString::number(count * dStepSize);
238  if (count % k && ((dStepSize * fact) > 2.5))
239  {
240  if (!(minRange > 0 && (count * dStepSize) < minRange))
241  painter.drawLine(8, yValue, 12, yValue);
242  enoughSpace = true;
243  }
244  else if (!(count % k))
245  {
246  if ((k * dStepSize * fact) > 7)
247  {
248  if (!(minRange > 0 && (count * dStepSize) < minRange))
249  {
250  painter.drawLine(5, yValue, 15, yValue);
251  painter.drawText(21, yValue + 3, s);
252  }
253  enoughSpace2 = true;
254  }
255  else
256  {
257  k += 5;
258  }
259  }
260  if (enoughSpace)
261  {
262  i = yValue;
263  count++;
264  }
265  else if (enoughSpace2)
266  {
267  i = yValue;
268  count += k;
269  }
270  else
271  {
272  i = yValue;
273  count = k;
274  }
275  }
276  }
277  // end draw scale
278  painter.setPen(cl);
279  painter.drawLine(m_Rect.topLeft(), m_Rect.topRight());
280  painter.drawLine(m_Rect.topLeft(), m_Rect.bottomLeft());
281 
282  painter.setPen(cd);
283  painter.drawLine(m_Rect.topRight(), m_Rect.bottomRight());
284  painter.drawLine(m_Rect.bottomRight(), m_Rect.bottomLeft());
285  painter.end();
286 
287  QPainter p(this);
288  p.drawPixmap(0, 0, pm);
289 }
290 
291 void QmitkSliderLevelWindowWidget::mouseMoveEvent(QMouseEvent *mouseEvent)
292 {
293  if (!mouseEvent)
294  return;
295  if (m_LevelWindow.IsFixed())
296  return;
297  if (!m_MouseDown)
298  {
299  if (mouseEvent->pos().y() >= 0 && mouseEvent->pos().y() <= (m_Rect.topLeft().y() + 3))
300  {
301  setCursor(Qt::SizeVerCursor);
302  m_UpperBound.setRect(m_Rect.topLeft().x(), m_Rect.topLeft().y() - 3, 17, 7);
303  this->setToolTip("Ctrl + left click to change only upper bound");
304  m_Resize = true;
305  }
306  else if (mouseEvent->pos().y() >= (m_Rect.bottomLeft().y() - 3))
307  {
308  setCursor(Qt::SizeVerCursor);
309  m_LowerBound.setRect(m_Rect.bottomLeft().x(), m_Rect.bottomLeft().y() - 3, 17, 7);
310  this->setToolTip("Ctrl + left click to change only lower bound");
311  m_Resize = true;
312  m_Bottom = true;
313  }
314  else
315  {
316  setCursor(Qt::ArrowCursor);
317  this->setToolTip("Left click and mouse move to adjust the slider");
318  m_Resize = false;
319  m_Bottom = false;
320  }
321  }
322 
323  else
324  {
325  float fact = (float)m_MoveHeight / m_LevelWindow.GetRange();
326 
327  if (m_Leftbutton)
328  {
329  if (m_Resize && !m_CtrlPressed)
330  {
331  double diff = (mouseEvent->pos().y()) / fact;
332  diff -= (m_StartPos.y()) / fact;
333  m_StartPos = mouseEvent->pos();
334 
335  if (diff == 0)
336  return;
337  float value;
338  if (m_Bottom)
339  value = m_LevelWindow.GetWindow() + ((2 * diff));
340  else
341  value = m_LevelWindow.GetWindow() - ((2 * diff));
342 
343  if (value < 0)
344  value = 0;
345 
347  }
348  else if (m_Resize && m_CtrlPressed)
349  {
350  if (!m_Bottom)
351  {
352  double diff = (mouseEvent->pos().y()) / fact;
353  diff -= (m_StartPos.y()) / fact;
354  m_StartPos = mouseEvent->pos();
355 
356  if (diff == 0)
357  return;
358  float value;
359 
360  value = m_LevelWindow.GetWindow() - ((diff));
361 
362  if (value < 0)
363  value = 0;
364  float oldWindow;
365  float oldLevel;
366  float newLevel;
367  oldWindow = m_LevelWindow.GetWindow();
368  oldLevel = m_LevelWindow.GetLevel();
369  newLevel = oldLevel + (value - oldWindow) / 2;
370  if (!((newLevel + value / 2) > m_LevelWindow.GetRangeMax()))
371  m_LevelWindow.SetLevelWindow(newLevel, value);
372  }
373  else
374  {
375  double diff = (mouseEvent->pos().y()) / fact;
376  diff -= (m_StartPos.y()) / fact;
377  m_StartPos = mouseEvent->pos();
378 
379  if (diff == 0)
380  return;
381  float value;
382 
383  value = m_LevelWindow.GetWindow() + ((diff));
384 
385  if (value < 0)
386  value = 0;
387  float oldWindow;
388  float oldLevel;
389  float newLevel;
390  oldWindow = m_LevelWindow.GetWindow();
391  oldLevel = m_LevelWindow.GetLevel();
392  newLevel = oldLevel - (value - oldWindow) / 2;
393  if (!((newLevel - value / 2) < m_LevelWindow.GetRangeMin()))
394  m_LevelWindow.SetLevelWindow(newLevel, value);
395  }
396  }
397  else
398  {
399  const float minv = m_LevelWindow.GetRangeMin();
400 
401  const float level = (m_MoveHeight - mouseEvent->pos().y()) / fact + minv;
402 
403  double diff = (mouseEvent->pos().x()) / fact;
404  diff -= (m_StartPos.x()) / fact;
405  m_StartPos = mouseEvent->pos();
406 
407  float window;
408  if (m_Bottom)
409  window = m_LevelWindow.GetWindow() + ((2 * diff));
410  else
411  window = m_LevelWindow.GetWindow() - ((2 * diff));
412 
413  if (window < 0)
414  window = 0;
415 
416  m_LevelWindow.SetLevelWindow(level, window);
417  }
418  m_Manager->SetLevelWindow(m_LevelWindow);
420  }
421  }
422 }
423 
425 {
426  QPoint p = QCursor::pos();
427  p = this->mapFromGlobal(p);
428  QMouseEvent ev(QEvent::MouseMove, p, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
429  this->mouseMoveEvent(&ev);
430 }
431 
433 {
434  if (m_LevelWindow.IsFixed())
435  return;
436  m_MouseDown = true;
437  m_StartPos = mouseEvent->pos();
438 
439  if (mouseEvent->button() == Qt::LeftButton)
440  {
441  if (mouseEvent->modifiers() == Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier)
442  {
443  m_CtrlPressed = true;
444  }
445  else
446  {
447  m_CtrlPressed = false;
448  }
449  m_Leftbutton = true;
450  }
451  else
452  m_Leftbutton = false;
453 
454  mouseMoveEvent(mouseEvent);
455 }
456 
458 {
459  m_MoveHeight = event->size().height() - 25;
460  Update();
461 }
462 
464 {
465  if (m_LevelWindow.IsFixed())
466  return;
467  m_MouseDown = false;
468 }
469 
471 {
472  int rectWidth;
473  if (m_ScaleVisible)
474  {
475  rectWidth = 17;
476  setMinimumSize(QSize(50, 50));
477  setMaximumSize(QSize(50, 2000));
478  setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
479  }
480  else
481  {
482  rectWidth = 26;
483  setMinimumSize(QSize(40, 50));
484  setMaximumSize(QSize(50, 2000));
485  setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding));
486  }
487  float mr = m_LevelWindow.GetRange();
488 
489  if (mr < 1e-9)
490  mr = 1e-9;
491 
492  float fact = (float)m_MoveHeight / mr;
493 
494  float rectHeight = m_LevelWindow.GetWindow() * fact;
495 
496  if (rectHeight < 15)
497  rectHeight = 15;
498 
500  m_Rect.setRect(2,
502  rectWidth,
503  (int)rectHeight);
504  else
505  m_Rect.setRect(2,
507  rectWidth,
508  (int)rectHeight);
509 
510  QWidget::repaint();
511 }
512 
513 void QmitkSliderLevelWindowWidget::contextMenuEvent(QContextMenuEvent *)
514 {
516  auto contextMenu = new QMenu(this);
517  Q_CHECK_PTR(contextMenu);
518  if (m_ScaleVisible)
519  contextMenu->addAction(tr("Hide Scale"), this, SLOT(HideScale()));
520  else
521  contextMenu->addAction(tr("Show Scale"), this, SLOT(ShowScale()));
522  contextMenu->addSeparator();
523  m_Contextmenu->GetContextMenu(contextMenu);
524 
525  // Fix: Bug #13327 we need to reset the m_MouseDown value
526  // otherwise the cursor is not correctly restored afterwards
527  m_MouseDown = false;
528 }
529 
531 {
532  m_ScaleVisible = false;
533  Update();
534 }
535 
537 {
538  m_ScaleVisible = true;
539  Update();
540 }
541 
543 {
544  m_Manager->SetDataStorage(ds);
545 }
546 
548 {
549  return m_Manager.GetPointer();
550 }
ScalarType GetLevel() const
method that returns the level value, i.e. the center of the current grey value interval ...
float k(1.0)
Data management class that handles &#39;was created by&#39; relations.
mitk::LevelWindowManager * GetManager()
returns the manager who is responsible to collect and deliver changes on Level/Window ...
void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager)
lets this object know about the LevelWindowManager to get all images and tell about changes ...
virtual void Update()
recalculate the size and position of the slider bar
QmitkSliderLevelWindowWidget(QWidget *parent=nullptr, Qt::WindowFlags f=nullptr)
constructor
void mousePressEvent(QMouseEvent *mouseEvent) override
void SetDataStorage(mitk::DataStorage *ds)
sets the DataStorage which holds all image-nodes
void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager)
sets the manager who is responsible to collect and deliver changes on Level/Window ...
void enterEvent(QEvent *event) override
Provides a contextmenu for Level/Window functionality.
void ShowScale()
Shows the scale if "Show Scale" is selected in the context menu.
QmitkLevelWindowWidgetContextMenu * m_Contextmenu
void HideScale()
Hide the scale if "Hide Scale" is selected in the context menu.
ScalarType GetUpperWindowBound() const
static RenderingManager * GetInstance()
ScalarType GetRange() const
returns the size of the grey value range
void resizeEvent(QResizeEvent *event) override
void mouseReleaseEvent(QMouseEvent *mouseEvent) override
ScalarType GetRangeMax() const
void paintEvent(QPaintEvent *e) override
ScalarType GetWindow() const
returns the current window size, i.e the range size of the current grey value interval ...
mitk::LevelWindowManager::Pointer m_Manager
manager who is responsible to collect and deliver changes on Level/Window
~QmitkSliderLevelWindowWidget() override
destructor
void mouseMoveEvent(QMouseEvent *mouseEvent) override
ScalarType GetRangeMin() const
void SetLevelWindow(ScalarType level, ScalarType window, bool expandRangesIfNecessary=true)
static Pointer New()
Provides access to the LevelWindowProperty object and LevelWindow of the "current" image...
ScalarType GetLowerWindowBound() const
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)