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