fw4spl
QRangeSlider.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2015.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include <cassert>
8 #include <QPainter>
9 #include <QApplication>
10 #include <QMouseEvent>
11 
12 
13 #include "fwGuiQt/widget/QRangeSlider.hpp"
14 
15 
16 namespace fwGuiQt
17 {
18 
19 namespace widget
20 {
21 
22 template <typename T>
23 struct Castable
24 {
25  template <typename U>
26  static T* safeCast(U *p)
27  {
28  T* casted = dynamic_cast<T*>(p);
29  return casted;
30  }
31 };
32 
33 
34 
36  public Castable<Handle>
37 {
38 public:
39  Handle(QWidget *w)
40  : Paintable(w),
41  m_pen(Qt::gray),
42  m_brush(Qt::lightGray)
43  {
44  m_pos = 0;
45  m_width = 13;
46  m_verticalPadding = 0.2;
47  m_tolerance = std::max(0, 10 - m_width);
48  }
49 
50  virtual void draw(QPainter &painter, bool /*enabled*/)
51  {
52  int height = drawingArea().height()-1;
53  int top = height * m_verticalPadding;
54  int handleHeight = height - 2*top;
55  painter.setRenderHint(QPainter::Antialiasing);
56  painter.setPen(m_pen);
57  painter.setBrush(m_brush);
58  painter.drawRect(m_pos - halfWidth(), top, m_width, handleHeight);
59  }
60 
61  virtual bool pick(const QPoint &point) const
62  {
63  bool picked = false;
64 
65  int height = drawingArea().height()-1;
66  int top = height * m_verticalPadding;
67  int handleHeight = height - 2*top;
68 
69  if ( abs(point.x() - m_pos) <= (halfWidth() + m_tolerance)
70  && (top+handleHeight) >= point.y() && point.y() >= top )
71  {
72  picked = true;
73  }
74  return picked;
75  }
76 
77  int setHandleSize(int size)
78  {
79  //handle size should be odd
80  m_width = size + ((size+1)%2);
81  return m_width;
82  }
83 
84  int halfWidth() const
85  {
86  return m_width/2;
87  }
88 
89  int setPos(const int &pos)
90  {
91  int p = pos;
92 
93  p = std::max(p, xPosMin());
94  p = std::min(p, xPosMax());
95 
96  m_pos = p;
97 
98  return p;
99  }
100 
101  int pos()
102  {
103  return m_pos;
104  }
105 
106  int xPosMin()
107  {
108  return halfWidth();
109  }
110 
111  int xPosMax()
112  {
113  return drawingArea().width() - halfWidth() - 1;
114  }
115 
116  double toFloatingPos(int p)
117  {
118  int posMin = xPosMin();
119  int posMax = xPosMax();
120  return ( (double) (p - posMin) / (double)(posMax - posMin) );
121  }
122 
123  int fromFloatingPos(double p)
124  {
125  assert( 0. <= p && p <= 1.);
126  int posMin = xPosMin();
127  int extend = (xPosMax()) - posMin;
128 
129  return posMin + (int) (p*extend);
130  }
131 
132 
133  double floatingPos()
134  {
135  return toFloatingPos( pos() );
136  }
137 
138  void setFloatingPos(double pos)
139  {
140  setPos(fromFloatingPos(pos));
141  }
142 
143 protected:
144  int m_pos;
145  int m_tolerance;
146  int m_width;
147  double m_verticalPadding;
148 
149  QPen m_pen;
150  QBrush m_brush;
151 };
152 
153 
155  public Castable<Window>
156 {
157 public:
158  Window(QWidget *w)
159  : Paintable(w),
160  m_pen(Qt::darkBlue),
161  m_brush(Qt::cyan),
162  m_reversePen(Qt::darkYellow),
163  m_reverseBrush(Qt::yellow)
164  {
165  m_left = 0;
166  m_right = 0;
167  }
168 
169  int width() const
170  {
171  return m_right-m_left;
172  }
173 
174  virtual void draw(QPainter &painter, bool enabled)
175  {
176  int w = this->width();
177  QPen pen;
178  QBrush brush;
179 
180  if(enabled)
181  {
182  if ( w < 0 )
183  {
184  pen = m_reversePen;
185  brush = m_reverseBrush;
186  }
187  else
188  {
189  pen = m_pen;
190  brush = m_brush;
191  }
192  }
193  else
194  {
195  pen = QPen(Qt::lightGray);
196  brush = QBrush(Qt::lightGray);
197  }
198 
199  painter.setPen(pen);
200  painter.setBrush(brush);
201  painter.setRenderHint(QPainter::Antialiasing);
202  painter.drawRect(m_left, 0, w, drawingArea().height()-1);
203  }
204 
205  virtual bool pick(const QPoint &point) const
206  {
207  bool picked = false;
208  int min = std::min(m_left, m_right);
209  int max = std::max(m_left, m_right);
210  picked = min <= point.x() && point.x() <= max;
211  return picked;
212  }
213 
214  void setPos(const int &left, const int &right)
215  {
216  m_left = left;
217  m_right = right;
218  }
219 
220 protected:
221  int m_left;
222  int m_right;
223 
224  QPen m_pen;
225  QBrush m_brush;
226  QPen m_reversePen;
227  QBrush m_reverseBrush;
228 
229 };
230 
231 
232 
233 //-----------------------------------------------------------------------------
234 
235 QRangeSlider::QRangeSlider(QWidget *parent)
236  : QWidget(parent)
237 {
238  m_minValue = 0.;
239  m_maxValue = 1.;
240  m_allowMinGreaterThanMax = true;
241  m_minimumMinMaxDelta = 0.;
242  m_handleSize = 11;
243 
244  m_current = NULL;
245 
246  Handle *minh = new Handle(this);
247  Handle *maxh = new Handle(this);
248  minh->setHandleSize(m_handleSize);
249  maxh->setHandleSize(m_handleSize);
250 
251  m_minHandle = minh;
252  m_maxHandle = maxh;
253  m_window = new Window(this);
254 
255  this->setPos(m_minValue, m_maxValue);
256  this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
257 }
258 
259 
260 QRangeSlider::~QRangeSlider()
261 {
262  delete m_minHandle;
263  delete m_maxHandle;
264  delete m_window;
265 }
266 
267 void QRangeSlider::setPos(double _min, double _max)
268 {
269  Handle *minHandle = Handle::safeCast(m_minHandle);
270  Handle *maxHandle = Handle::safeCast(m_maxHandle);
271  Window *window = Window::safeCast(m_window);
272 
273  assert(minHandle && maxHandle && window);
274 
275  minHandle->setFloatingPos(_min);
276  maxHandle->setFloatingPos(_max);
277 
278  int min, max;
279  min = minHandle->pos();
280  max = maxHandle->pos();
281  window->setPos(min, max);
282 
283  this->movedTo(_min, _max);
284  this->update();
285 }
286 
287 void QRangeSlider::move(int delta)
288 {
289  Handle *minHandle = Handle::safeCast(m_minHandle);
290  Handle *maxHandle = Handle::safeCast(m_maxHandle);
291  Window *window = Window::safeCast(m_window);
292 
293  assert(minHandle && maxHandle && window);
294 
295  int low, high, width, dir;
296  dir = ((minHandle->pos() < maxHandle->pos()) ? 1 : -1);
297  bool movingRight = (delta < 0);
298 
299  low = minHandle->pos();
300  high = maxHandle->pos();
301  width = high - low;
302 
303  if( (movingRight && dir < 0)
304  || (!movingRight && dir > 0 ) )
305  {
306  low = minHandle->setPos(low-delta);
307  high = low + width;
308  maxHandle->setPos(high);
309  }
310  else
311  {
312  high = maxHandle->setPos(high-delta);
313  low = high - width;
314  minHandle->setPos(low);
315  }
316 
317  window->setPos(low, high);
318 }
319 
320 bool QRangeSlider::movedTo(double _min, double _max)
321 {
322  bool changed = m_minValue != _min || m_maxValue != _max;
323  if (changed)
324  {
325  m_minValue = _min;
326  m_maxValue = _max;
327  Q_EMIT sliderRangeChanged( m_minValue, m_maxValue );
328  }
329  return changed;
330 }
331 
332 void QRangeSlider::paintEvent ( QPaintEvent * /*event*/ )
333 {
334  bool enabled = this->isEnabled();
335  QPainter painter(this);
336  painter.setRenderHint(QPainter::Antialiasing);
337 
338  QRect rect = this->rect();
339  rect.setLeft(rect.left() + m_handleSize/2);
340  rect.setRight(rect.right() - m_handleSize/2);
341  painter.fillRect(rect, QApplication::palette().base());
342 
343  painter.setBrush(Qt::cyan);
344  m_window->draw(painter, enabled);
345 
346  painter.setBrush(Qt::gray);
347  painter.setPen(Qt::darkGreen);
348  m_minHandle->draw(painter, enabled);
349 
350  painter.setPen(Qt::darkRed);
351  m_maxHandle->draw(painter, enabled);
352 
353 }
354 
355 void QRangeSlider::mouseMoveEvent ( QMouseEvent * event )
356 {
357  if (m_current)
358  {
359 
360  Handle *minHandle = Handle::safeCast(m_minHandle);
361  Handle *maxHandle = Handle::safeCast(m_maxHandle);
362  Window *window = Window::safeCast(m_window);
363  Handle *currentHandle;
364 
365 
366  if( (currentHandle = Handle::safeCast(m_current)) )
367  {
368  int oldPos = currentHandle->pos();
369  int newPos = event->pos().x();
370  currentHandle->setPos(newPos);
371 
372  if(!m_allowMinGreaterThanMax &&
373  minHandle->floatingPos() + m_minimumMinMaxDelta >= maxHandle->floatingPos() )
374  {
375  currentHandle->setPos(oldPos);
376  }
377  window->setPos(minHandle->pos(), maxHandle->pos());
378  }
379  else if( Window::safeCast(m_current) )
380  {
381  QPoint delta = m_pressPos - event->pos();
382 
383  minHandle->setPos(m_pressMin);
384  maxHandle->setPos(m_pressMax);
385  window->setPos(minHandle->pos(), maxHandle->pos());
386  this->move(delta.x());
387  }
388 
389  double min = minHandle->floatingPos();
390  double max = maxHandle->floatingPos();
391  if( this->movedTo(min, max) )
392  {
393  Q_EMIT sliderRangeEdited ( min, max );
394  }
395  this->update();
396  }
397 }
398 
399 void QRangeSlider::mousePressEvent ( QMouseEvent * event )
400 {
401  Handle *minHandle = Handle::safeCast(m_minHandle);
402  Handle *maxHandle = Handle::safeCast(m_maxHandle);
403 // Window *window = Window::safeCast(m_window);
404 
405  m_pressPos = event->pos();
406  m_pressMin = minHandle->pos();
407  m_pressMax = maxHandle->pos();
408 
409  if(m_maxHandle->pick(m_pressPos))
410  {
411  m_current = m_maxHandle;
412  }
413  else if(m_minHandle->pick(m_pressPos))
414  {
415  m_current = m_minHandle;
416  }
417  else if(m_window->pick(m_pressPos))
418  {
419  m_current = m_window;
420  }
421 }
422 
423 void QRangeSlider::mouseReleaseEvent ( QMouseEvent * /*event*/)
424 {
425  m_current = NULL;
426 }
427 
428 
429 void QRangeSlider::wheelEvent ( QWheelEvent * event )
430 {
431  Handle *minHandle = Handle::safeCast(m_minHandle);
432  Handle *maxHandle = Handle::safeCast(m_maxHandle);
433  Window *window = Window::safeCast(m_window);
434 
435  int delta = this->size().width()/( ((double) event->delta())/4. );
436  int low = minHandle->pos();
437  int high = maxHandle->pos();
438 
439  if(event->orientation() == Qt::Vertical)
440  {
441  if(!m_allowMinGreaterThanMax)
442  {
443  int diff = (high - low);
444  int minDiff = minHandle->fromFloatingPos(m_minimumMinMaxDelta);
445  delta = std::max(delta, -(diff - minDiff)/2);
446  }
447 
448  low = minHandle->setPos(low - delta);
449  high = maxHandle->setPos(high + delta);
450  window->setPos(low, high);
451  }
452  else
453  {
454  this->move(delta);
455  }
456 
457  double min = minHandle->floatingPos();
458  double max = maxHandle->floatingPos();
459  if( this->movedTo(min, max) )
460  {
461  Q_EMIT sliderRangeEdited ( min, max );
462  }
463  this->update();
464 }
465 
466 void QRangeSlider::resizeEvent ( QResizeEvent * event )
467 {
468  this->setPos(m_minValue, m_maxValue);
469 }
470 
471 } // namespace widget
472 } // namespace fwGuiQt
The namespace fwGuiQt contains classes which provide the implementation of the Gui using Qt library...
Definition: WindowLevel.hpp:32