Kstars

ctkrangeslider.cpp
1 /*
2  SPDX-FileCopyrightText: Kitware Inc.
3  SPDX-License-Identifier: Apache-2.0
4 */
5 
6 // Qt includes
7 #include <QDebug>
8 #include <QMouseEvent>
9 #include <QKeyEvent>
10 #include <QStyleOptionSlider>
11 #include <QApplication>
12 #include <QStylePainter>
13 #include <QStyle>
14 #include <QToolTip>
15 
16 // CTK includes
17 #include "ctkrangeslider.h"
18 
19 class ctkRangeSliderPrivate
20 {
21  Q_DECLARE_PUBLIC(ctkRangeSlider)
22 protected:
23  ctkRangeSlider* const q_ptr;
24 public:
25  /// Boolean indicates the selected handle
26  /// True for the minimum range handle, false for the maximum range handle
27  enum Handle {
28  NoHandle = 0x0,
29  MinimumHandle = 0x1,
30  MaximumHandle = 0x2
31  };
32  Q_DECLARE_FLAGS(Handles, Handle)
33 
34  ctkRangeSliderPrivate(ctkRangeSlider& object);
35  void init();
36 
37  /// Return the handle at the given pos, or none if no handle is at the pos.
38  /// If a handle is selected, handleRect is set to the handle rect.
39  /// otherwise return NoHandle and handleRect is set to the combined rect of
40  /// the min and max handles
41  Handle handleAtPos(const QPoint& pos, QRect& handleRect)const;
42 
43  /// Copied verbatim from QSliderPrivate class (see QSlider.cpp)
44  int pixelPosToRangeValue(int pos) const;
45  int pixelPosFromRangeValue(int val) const;
46 
47  /// Draw the bottom and top sliders.
48  void drawMinimumSlider( QStylePainter* painter ) const;
49  void drawMaximumSlider( QStylePainter* painter ) const;
50 
51  /// End points of the range on the Model
52  int m_MaximumValue;
53  int m_MinimumValue;
54 
55  /// End points of the range on the GUI. This is synced with the model.
56  int m_MaximumPosition;
57  int m_MinimumPosition;
58 
59  /// Controls selected ?
60  QStyle::SubControl m_MinimumSliderSelected;
61  QStyle::SubControl m_MaximumSliderSelected;
62 
63  /// See QSliderPrivate::clickOffset.
64  /// Overrides this ivar
65  int m_SubclassClickOffset;
66 
67  /// See QSliderPrivate::position
68  /// Overrides this ivar.
69  int m_SubclassPosition;
70 
71  /// Original width between the 2 bounds before any moves
72  int m_SubclassWidth;
73 
74  ctkRangeSliderPrivate::Handles m_SelectedHandles;
75 
76  /// When symmetricMoves is true, moving a handle will move the other handle
77  /// symmetrically, otherwise the handles are independent.
78  bool m_SymmetricMoves;
79 
80  QString m_HandleToolTip;
81 
82 private:
83  Q_DISABLE_COPY(ctkRangeSliderPrivate)
84 };
85 
86 // --------------------------------------------------------------------------
87 ctkRangeSliderPrivate::ctkRangeSliderPrivate(ctkRangeSlider& object)
88  :q_ptr(&object)
89 {
90  this->m_MinimumValue = 0;
91  this->m_MaximumValue = 100;
92  this->m_MinimumPosition = 0;
93  this->m_MaximumPosition = 100;
94  this->m_MinimumSliderSelected = QStyle::SC_None;
95  this->m_MaximumSliderSelected = QStyle::SC_None;
96  this->m_SubclassClickOffset = 0;
97  this->m_SubclassPosition = 0;
98  this->m_SubclassWidth = 0;
99  this->m_SelectedHandles = ctkRangeSliderPrivate::NoHandle;
100  this->m_SymmetricMoves = false;
101 }
102 
103 // --------------------------------------------------------------------------
104 void ctkRangeSliderPrivate::init()
105 {
106  Q_Q(ctkRangeSlider);
107  this->m_MinimumValue = q->minimum();
108  this->m_MaximumValue = q->maximum();
109  this->m_MinimumPosition = q->minimum();
110  this->m_MaximumPosition = q->maximum();
111  q->connect(q, SIGNAL(rangeChanged(int,int)), q, SLOT(onRangeChanged(int,int)));
112 }
113 
114 // --------------------------------------------------------------------------
115 ctkRangeSliderPrivate::Handle ctkRangeSliderPrivate::handleAtPos(const QPoint& pos, QRect& handleRect)const
116 {
117  Q_Q(const ctkRangeSlider);
118 
119  QStyleOptionSlider option;
120  q->initStyleOption( &option );
121 
122  // The functions hitTestComplexControl only know about 1 handle. As we have
123  // 2, we change the position of the handle and test if the pos correspond to
124  // any of the 2 positions.
125 
126  // Test the MinimumHandle
127  option.sliderPosition = this->m_MinimumPosition;
128  option.sliderValue = this->m_MinimumValue;
129 
130  QStyle::SubControl minimumControl = q->style()->hitTestComplexControl(
131  QStyle::CC_Slider, &option, pos, q);
132  QRect minimumHandleRect = q->style()->subControlRect(
134 
135  // Test if the pos is under the Maximum handle
136  option.sliderPosition = this->m_MaximumPosition;
137  option.sliderValue = this->m_MaximumValue;
138 
139  QStyle::SubControl maximumControl = q->style()->hitTestComplexControl(
140  QStyle::CC_Slider, &option, pos, q);
141  QRect maximumHandleRect = q->style()->subControlRect(
143 
144  // The pos is above both handles, select the closest handle
145  if (minimumControl == QStyle::SC_SliderHandle &&
146  maximumControl == QStyle::SC_SliderHandle)
147  {
148  int minDist = 0;
149  int maxDist = 0;
150  if (q->orientation() == Qt::Horizontal)
151  {
152  minDist = pos.x() - minimumHandleRect.left();
153  maxDist = maximumHandleRect.right() - pos.x();
154  }
155  else //if (q->orientation() == Qt::Vertical)
156  {
157  minDist = minimumHandleRect.bottom() - pos.y();
158  maxDist = pos.y() - maximumHandleRect.top();
159  }
160  Q_ASSERT( minDist >= 0 && maxDist >= 0);
161  minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None;
162  }
163 
164  if (minimumControl == QStyle::SC_SliderHandle)
165  {
166  handleRect = minimumHandleRect;
167  return MinimumHandle;
168  }
169  else if (maximumControl == QStyle::SC_SliderHandle)
170  {
171  handleRect = maximumHandleRect;
172  return MaximumHandle;
173  }
174  handleRect = minimumHandleRect.united(maximumHandleRect);
175  return NoHandle;
176 }
177 
178 // --------------------------------------------------------------------------
179 // Copied verbatim from QSliderPrivate::pixelPosToRangeValue. See QSlider.cpp
180 //
181 int ctkRangeSliderPrivate::pixelPosToRangeValue( int pos ) const
182 {
183  Q_Q(const ctkRangeSlider);
184  QStyleOptionSlider option;
185  q->initStyleOption( &option );
186 
187  QRect gr = q->style()->subControlRect( QStyle::CC_Slider,
188  &option,
190  q );
191  QRect sr = q->style()->subControlRect( QStyle::CC_Slider,
192  &option,
194  q );
195  int sliderMin, sliderMax, sliderLength;
196  if (option.orientation == Qt::Horizontal)
197  {
198  sliderLength = sr.width();
199  sliderMin = gr.x();
200  sliderMax = gr.right() - sliderLength + 1;
201  }
202  else
203  {
204  sliderLength = sr.height();
205  sliderMin = gr.y();
206  sliderMax = gr.bottom() - sliderLength + 1;
207  }
208 
209  return QStyle::sliderValueFromPosition( q->minimum(),
210  q->maximum(),
211  pos - sliderMin,
212  sliderMax - sliderMin,
213  option.upsideDown );
214 }
215 
216 //---------------------------------------------------------------------------
217 int ctkRangeSliderPrivate::pixelPosFromRangeValue( int val ) const
218 {
219  Q_Q(const ctkRangeSlider);
220  QStyleOptionSlider option;
221  q->initStyleOption( &option );
222 
223  QRect gr = q->style()->subControlRect( QStyle::CC_Slider,
224  &option,
226  q );
227  QRect sr = q->style()->subControlRect( QStyle::CC_Slider,
228  &option,
230  q );
231  int sliderMin, sliderMax, sliderLength;
232  if (option.orientation == Qt::Horizontal)
233  {
234  sliderLength = sr.width();
235  sliderMin = gr.x();
236  sliderMax = gr.right() - sliderLength + 1;
237  }
238  else
239  {
240  sliderLength = sr.height();
241  sliderMin = gr.y();
242  sliderMax = gr.bottom() - sliderLength + 1;
243  }
244 
245  return QStyle::sliderPositionFromValue( q->minimum(),
246  q->maximum(),
247  val,
248  sliderMax - sliderMin,
249  option.upsideDown ) + sliderMin;
250 }
251 
252 //---------------------------------------------------------------------------
253 // Draw slider at the bottom end of the range
254 void ctkRangeSliderPrivate::drawMinimumSlider( QStylePainter* painter ) const
255 {
256  Q_Q(const ctkRangeSlider);
257  QStyleOptionSlider option;
258  q->initMinimumSliderStyleOption( &option );
259 
260  option.subControls = QStyle::SC_SliderHandle;
261  option.sliderValue = m_MinimumValue;
262  option.sliderPosition = m_MinimumPosition;
263  if (q->isMinimumSliderDown())
264  {
265  option.activeSubControls = QStyle::SC_SliderHandle;
266  option.state |= QStyle::State_Sunken;
267  }
268 #ifdef Q_OS_MAC
269  // On mac style, drawing just the handle actually draws also the groove.
270  QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
272  painter->setClipRect(clip);
273 #endif
274  painter->drawComplexControl(QStyle::CC_Slider, option);
275 }
276 
277 //---------------------------------------------------------------------------
278 // Draw slider at the top end of the range
279 void ctkRangeSliderPrivate::drawMaximumSlider( QStylePainter* painter ) const
280 {
281  Q_Q(const ctkRangeSlider);
282  QStyleOptionSlider option;
283  q->initMaximumSliderStyleOption( &option );
284 
285  option.subControls = QStyle::SC_SliderHandle;
286  option.sliderValue = m_MaximumValue;
287  option.sliderPosition = m_MaximumPosition;
288  if (q->isMaximumSliderDown())
289  {
290  option.activeSubControls = QStyle::SC_SliderHandle;
291  option.state |= QStyle::State_Sunken;
292  }
293 #ifdef Q_OS_MAC
294  // On mac style, drawing just the handle actually draws also the groove.
295  QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
297  painter->setClipRect(clip);
298 #endif
299  painter->drawComplexControl(QStyle::CC_Slider, option);
300 }
301 
302 // --------------------------------------------------------------------------
304  : QSlider(_parent)
305  , d_ptr(new ctkRangeSliderPrivate(*this))
306 {
308  d->init();
309 }
310 
311 // --------------------------------------------------------------------------
313  QWidget* parentObject )
314  :QSlider(o, parentObject)
315  , d_ptr(new ctkRangeSliderPrivate(*this))
316 {
318  d->init();
319 }
320 
321 // --------------------------------------------------------------------------
322 ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate* impl, QWidget* _parent)
323  : QSlider(_parent)
324  , d_ptr(impl)
325 {
327  d->init();
328 }
329 
330 // --------------------------------------------------------------------------
331 ctkRangeSlider::ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o,
332  QWidget* parentObject )
333  :QSlider(o, parentObject)
334  , d_ptr(impl)
335 {
337  d->init();
338 }
339 
340 // --------------------------------------------------------------------------
341 ctkRangeSlider::~ctkRangeSlider()
342 {
343 }
344 
345 // --------------------------------------------------------------------------
346 int ctkRangeSlider::minimumValue() const
347 {
348  Q_D(const ctkRangeSlider);
349  return d->m_MinimumValue;
350 }
351 
352 // --------------------------------------------------------------------------
354 {
356  this->setValues( min, qMax(d->m_MaximumValue,min) );
357 }
358 
359 // --------------------------------------------------------------------------
360 int ctkRangeSlider::maximumValue() const
361 {
362  Q_D(const ctkRangeSlider);
363  return d->m_MaximumValue;
364 }
365 
366 // --------------------------------------------------------------------------
368 {
370  this->setValues( qMin(d->m_MinimumValue, max), max );
371 }
372 
373 // --------------------------------------------------------------------------
374 void ctkRangeSlider::setValues(int l, int u)
375 {
377  const int minValue =
378  qBound(this->minimum(), qMin(l,u), this->maximum());
379  const int maxValue =
380  qBound(this->minimum(), qMax(l,u), this->maximum());
381  bool emitMinValChanged = (minValue != d->m_MinimumValue);
382  bool emitMaxValChanged = (maxValue != d->m_MaximumValue);
383 
384  d->m_MinimumValue = minValue;
385  d->m_MaximumValue = maxValue;
386 
387  bool emitMinPosChanged =
388  (minValue != d->m_MinimumPosition);
389  bool emitMaxPosChanged =
390  (maxValue != d->m_MaximumPosition);
391  d->m_MinimumPosition = minValue;
392  d->m_MaximumPosition = maxValue;
393 
394  if (isSliderDown())
395  {
396  if (emitMinPosChanged || emitMaxPosChanged)
397  {
398  emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
399  }
400  if (emitMinPosChanged)
401  {
402  emit minimumPositionChanged(d->m_MinimumPosition);
403  }
404  if (emitMaxPosChanged)
405  {
406  emit maximumPositionChanged(d->m_MaximumPosition);
407  }
408  }
409  if (emitMinValChanged || emitMaxValChanged)
410  {
411  emit valuesChanged(d->m_MinimumValue,
412  d->m_MaximumValue);
413  }
414  if (emitMinValChanged)
415  {
416  emit minimumValueChanged(d->m_MinimumValue);
417  }
418  if (emitMaxValChanged)
419  {
420  emit maximumValueChanged(d->m_MaximumValue);
421  }
422  if (emitMinPosChanged || emitMaxPosChanged ||
423  emitMinValChanged || emitMaxValChanged)
424  {
425  this->update();
426  }
427 }
428 
429 // --------------------------------------------------------------------------
430 int ctkRangeSlider::minimumPosition() const
431 {
432  Q_D(const ctkRangeSlider);
433  return d->m_MinimumPosition;
434 }
435 
436 // --------------------------------------------------------------------------
437 int ctkRangeSlider::maximumPosition() const
438 {
439  Q_D(const ctkRangeSlider);
440  return d->m_MaximumPosition;
441 }
442 
443 // --------------------------------------------------------------------------
444 void ctkRangeSlider::setMinimumPosition(int l)
445 {
446  Q_D(const ctkRangeSlider);
447  this->setPositions(l, qMax(l, d->m_MaximumPosition));
448 }
449 
450 // --------------------------------------------------------------------------
451 void ctkRangeSlider::setMaximumPosition(int u)
452 {
453  Q_D(const ctkRangeSlider);
454  this->setPositions(qMin(d->m_MinimumPosition, u), u);
455 }
456 
457 // --------------------------------------------------------------------------
458 void ctkRangeSlider::setPositions(int min, int max)
459 {
461  const int minPosition =
462  qBound(this->minimum(), qMin(min, max), this->maximum());
463  const int maxPosition =
464  qBound(this->minimum(), qMax(min, max), this->maximum());
465 
466  bool emitMinPosChanged = (minPosition != d->m_MinimumPosition);
467  bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition);
468 
469  if (!emitMinPosChanged && !emitMaxPosChanged)
470  {
471  return;
472  }
473 
474  d->m_MinimumPosition = minPosition;
475  d->m_MaximumPosition = maxPosition;
476 
477  if (!this->hasTracking())
478  {
479  this->update();
480  }
481  if (isSliderDown())
482  {
483  if (emitMinPosChanged)
484  {
485  emit minimumPositionChanged(d->m_MinimumPosition);
486  }
487  if (emitMaxPosChanged)
488  {
489  emit maximumPositionChanged(d->m_MaximumPosition);
490  }
491  if (emitMinPosChanged || emitMaxPosChanged)
492  {
493  emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
494  }
495  }
496  if (this->hasTracking())
497  {
498  this->triggerAction(SliderMove);
499  this->setValues(d->m_MinimumPosition, d->m_MaximumPosition);
500  }
501 }
502 
503 // --------------------------------------------------------------------------
504 void ctkRangeSlider::setSymmetricMoves(bool symmetry)
505 {
507  d->m_SymmetricMoves = symmetry;
508 }
509 
510 // --------------------------------------------------------------------------
511 bool ctkRangeSlider::symmetricMoves()const
512 {
513  Q_D(const ctkRangeSlider);
514  return d->m_SymmetricMoves;
515 }
516 
517 // --------------------------------------------------------------------------
518 void ctkRangeSlider::onRangeChanged(int _minimum, int _maximum)
519 {
520  Q_UNUSED(_minimum);
521  Q_UNUSED(_maximum);
523  this->setValues(d->m_MinimumValue, d->m_MaximumValue);
524 }
525 
526 // --------------------------------------------------------------------------
527 // Render
528 void ctkRangeSlider::paintEvent( QPaintEvent* )
529 {
531  QStyleOptionSlider option;
532  this->initStyleOption(&option);
533 
534  QStylePainter painter(this);
535  option.subControls = QStyle::SC_SliderGroove;
536  // Move to minimum to not highlight the SliderGroove.
537  // On mac style, drawing just the slider groove also draws the handles,
538  // therefore we give a negative (outside of view) position.
539  option.sliderValue = this->minimum() - this->maximum();
540  option.sliderPosition = this->minimum() - this->maximum();
541  painter.drawComplexControl(QStyle::CC_Slider, option);
542 
543  option.sliderPosition = d->m_MinimumPosition;
545  &option,
547  this);
548  option.sliderPosition = d->m_MaximumPosition;
549 
551  &option,
553  this);
554 
556  &option,
558  this);
559  QRect rangeBox;
560  if (option.orientation == Qt::Horizontal)
561  {
562  rangeBox = QRect(
563  QPoint(qMin( lr.center().x(), ur.center().x() ), sr.center().y() - 2),
564  QPoint(qMax( lr.center().x(), ur.center().x() ), sr.center().y() + 1));
565  }
566  else
567  {
568  rangeBox = QRect(
569  QPoint(sr.center().x() - 2, qMin( lr.center().y(), ur.center().y() )),
570  QPoint(sr.center().x() + 1, qMax( lr.center().y(), ur.center().y() )));
571  }
572 
573  // -----------------------------
574  // Render the range
575  //
576  QRect groove = this->style()->subControlRect( QStyle::CC_Slider,
577  &option,
579  this );
580  groove.adjust(0, 0, -1, 0);
581 
582  // Create default colors based on the transfer function.
583  //
584  QColor highlight = this->palette().color(QPalette::Normal, QPalette::Highlight);
585  QLinearGradient gradient;
586  if (option.orientation == Qt::Horizontal)
587  {
588  gradient = QLinearGradient( groove.center().x(), groove.top(),
589  groove.center().x(), groove.bottom());
590  }
591  else
592  {
593  gradient = QLinearGradient( groove.left(), groove.center().y(),
594  groove.right(), groove.center().y());
595  }
596 
597  // TODO: Set this based on the supplied transfer function
598  //QColor l = Qt::darkGray;
599  //QColor u = Qt::black;
600 
601  gradient.setColorAt(0, highlight.darker(120));
602  gradient.setColorAt(1, highlight.lighter(160));
603 
604  painter.setPen(QPen(highlight.darker(150), 0));
605  painter.setBrush(gradient);
606  painter.drawRect( rangeBox.intersected(groove) );
607 
608  // -----------------------------------
609  // Render the sliders
610  //
611  if (this->isMinimumSliderDown())
612  {
613  d->drawMaximumSlider( &painter );
614  d->drawMinimumSlider( &painter );
615  }
616  else
617  {
618  d->drawMinimumSlider( &painter );
619  d->drawMaximumSlider( &painter );
620  }
621 }
622 
623 // --------------------------------------------------------------------------
624 // Standard Qt UI events
625 void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent)
626 {
628  if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button()))
629  {
630  mouseEvent->ignore();
631  return;
632  }
633  int mepos = this->orientation() == Qt::Horizontal ?
634  mouseEvent->pos().x() : mouseEvent->pos().y();
635 
636  QStyleOptionSlider option;
637  this->initStyleOption( &option );
638 
639  QRect handleRect;
640  ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect);
641 
642  if (handle_ != ctkRangeSliderPrivate::NoHandle)
643  {
644  d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle)?
645  d->m_MinimumPosition : d->m_MaximumPosition;
646 
647  // save the position of the mouse inside the handle for later
648  d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ?
649  handleRect.left() : handleRect.top());
650 
651  this->setSliderDown(true);
652 
653  if (d->m_SelectedHandles != handle_)
654  {
655  d->m_SelectedHandles = handle_;
656  this->update(handleRect);
657  }
658  // Accept the mouseEvent
659  mouseEvent->accept();
660  return;
661  }
662 
663  // if we are here, no handles have been pressed
664  // Check if we pressed on the groove between the 2 handles
665 
667  QStyle::CC_Slider, &option, mouseEvent->pos(), this);
668  QRect sr = style()->subControlRect(
670  int minCenter = (this->orientation() == Qt::Horizontal ?
671  handleRect.left() : handleRect.top());
672  int maxCenter = (this->orientation() == Qt::Horizontal ?
673  handleRect.right() : handleRect.bottom());
674  if (control == QStyle::SC_SliderGroove &&
675  mepos > minCenter && mepos < maxCenter)
676  {
677  // warning lost of precision it might be fatal
678  d->m_SubclassPosition = (d->m_MinimumPosition + d->m_MaximumPosition) / 2.;
679  d->m_SubclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_SubclassPosition);
680  d->m_SubclassWidth = (d->m_MaximumPosition - d->m_MinimumPosition) / 2;
681  qMax(d->m_SubclassPosition - d->m_MinimumPosition, d->m_MaximumPosition - d->m_SubclassPosition);
682  this->setSliderDown(true);
683  if (!this->isMinimumSliderDown() || !this->isMaximumSliderDown())
684  {
685  d->m_SelectedHandles =
686  QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MinimumHandle) |
687  QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MaximumHandle);
688  this->update(handleRect.united(sr));
689  }
690  mouseEvent->accept();
691  return;
692  }
693  mouseEvent->ignore();
694 }
695 
696 // --------------------------------------------------------------------------
697 // Standard Qt UI events
698 void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent)
699 {
701  if (!d->m_SelectedHandles)
702  {
703  mouseEvent->ignore();
704  return;
705  }
706  int mepos = this->orientation() == Qt::Horizontal ?
707  mouseEvent->pos().x() : mouseEvent->pos().y();
708 
709  QStyleOptionSlider option;
710  this->initStyleOption(&option);
711 
712  const int m = style()->pixelMetric( QStyle::PM_MaximumDragDistance, &option, this );
713 
714  int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset);
715 
716  if (m >= 0)
717  {
718  const QRect r = rect().adjusted(-m, -m, m, m);
719  if (!r.contains(mouseEvent->pos()))
720  {
721  newPosition = d->m_SubclassPosition;
722  }
723  }
724 
725  // Only the lower/left slider is down
726  if (this->isMinimumSliderDown() && !this->isMaximumSliderDown())
727  {
728  double newMinPos = qMin(newPosition,d->m_MaximumPosition);
729  this->setPositions(newMinPos, d->m_MaximumPosition +
730  (d->m_SymmetricMoves ? d->m_MinimumPosition - newMinPos : 0));
731  }
732  // Only the upper/right slider is down
733  else if (this->isMaximumSliderDown() && !this->isMinimumSliderDown())
734  {
735  double newMaxPos = qMax(d->m_MinimumPosition, newPosition);
736  this->setPositions(d->m_MinimumPosition -
737  (d->m_SymmetricMoves ? newMaxPos - d->m_MaximumPosition: 0),
738  newMaxPos);
739  }
740  // Both handles are down (the user clicked in between the handles)
741  else if (this->isMinimumSliderDown() && this->isMaximumSliderDown())
742  {
743  this->setPositions(newPosition - d->m_SubclassWidth,
744  newPosition + d->m_SubclassWidth );
745  }
746  mouseEvent->accept();
747 }
748 
749 // --------------------------------------------------------------------------
750 // Standard Qt UI mouseEvents
751 void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent)
752 {
754  this->QSlider::mouseReleaseEvent(mouseEvent);
755 
756  setSliderDown(false);
757  d->m_SelectedHandles = ctkRangeSliderPrivate::NoHandle;
758 
759  this->update();
760 }
761 
762 // --------------------------------------------------------------------------
764 {
765  Q_D(const ctkRangeSlider);
766  return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle;
767 }
768 
769 // --------------------------------------------------------------------------
771 {
772  Q_D(const ctkRangeSlider);
773  return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle;
774 }
775 
776 // --------------------------------------------------------------------------
777 void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const
778 {
779  this->initStyleOption(option);
780 }
781 
782 // --------------------------------------------------------------------------
783 void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const
784 {
785  this->initStyleOption(option);
786 }
787 
788 // --------------------------------------------------------------------------
789 QString ctkRangeSlider::handleToolTip()const
790 {
791  Q_D(const ctkRangeSlider);
792  return d->m_HandleToolTip;
793 }
794 
795 // --------------------------------------------------------------------------
796 void ctkRangeSlider::setHandleToolTip(const QString& _toolTip)
797 {
799  d->m_HandleToolTip = _toolTip;
800 }
801 
802 // --------------------------------------------------------------------------
803 bool ctkRangeSlider::event(QEvent* _event)
804 {
806  switch(_event->type())
807  {
808  case QEvent::ToolTip:
809  {
810  QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event);
811  QStyleOptionSlider opt;
812  // Test the MinimumHandle
813  opt.sliderPosition = d->m_MinimumPosition;
814  opt.sliderValue = d->m_MinimumValue;
815  this->initStyleOption(&opt);
816  QStyle::SubControl hoveredControl =
817  this->style()->hitTestComplexControl(
818  QStyle::CC_Slider, &opt, helpEvent->pos(), this);
819  if (!d->m_HandleToolTip.isEmpty() &&
820  hoveredControl == QStyle::SC_SliderHandle)
821  {
822  QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue()));
823  _event->accept();
824  return true;
825  }
826  // Test the MaximumHandle
827  opt.sliderPosition = d->m_MaximumPosition;
828  opt.sliderValue = d->m_MaximumValue;
829  this->initStyleOption(&opt);
830  hoveredControl = this->style()->hitTestComplexControl(
831  QStyle::CC_Slider, &opt, helpEvent->pos(), this);
832  if (!d->m_HandleToolTip.isEmpty() &&
833  hoveredControl == QStyle::SC_SliderHandle)
834  {
835  QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue()));
836  _event->accept();
837  return true;
838  }
839  }
840  default:
841  break;
842  }
843  return this->Superclass::event(_event);
844 }
void setColorAt(qreal position, const QColor &color)
QPoint pos() const const
void showText(const QPoint &pos, const QString &text, QWidget *w)
void maximumValueChanged(int max)
This signal is emitted when the slider maximum value has changed, with the new slider value as argume...
bool isMaximumSliderDown() const
Returns true if the maximum value handle is down, false if it is up.
void positionsChanged(int min, int max)
Utility signal that is fired when minimum or maximum positions have changed.
void setPen(const QColor &color)
virtual bool event(QEvent *event) override
void initStyleOption(QStyleOptionSlider *option) const const
int right() const const
Qt::MouseButton button() const const
void drawRect(const QRectF &rectangle)
void maximumPositionChanged(int max)
This signal is emitted when sliderDown is true and the slider moves.
void setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
void update()
virtual void mouseReleaseEvent(QMouseEvent *ev) override
const QPoint & pos() const const
virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const const=0
bool isSliderDown() const const
void adjust(int dx1, int dy1, int dx2, int dy2)
int width() const const
int x() const const
int y() const const
void setMaximumValue(int max)
This property holds the slider's current maximum value.
int x() const const
int y() const const
QRect intersected(const QRect &rectangle) const const
QRect united(const QRect &rectangle) const const
bool contains(const QRect &rectangle, bool proper) const const
int left() const const
void minimumPositionChanged(int min)
This signal is emitted when sliderDown is true and the slider moves.
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
int bottom() const const
int top() const const
void triggerAction(QAbstractSlider::SliderAction action)
QStyle * style() const const
bool hasTracking() const const
Horizontal
Qt::MouseButtons buttons() const const
virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const const=0
void init(KXmlGuiWindow *window, KgDifficulty *difficulty=nullptr)
QPoint center() const const
void setMinimumValue(int min)
This property holds the slider's current minimum value.
bool isMinimumSliderDown() const
Returns true if the minimum value handle is down, false if it is up.
void setBrush(const QBrush &brush)
const QPoint & globalPos() const const
PM_MaximumDragDistance
QColor darker(int factor) const const
void setPositions(int min, int max)
Utility function that set the minimum position and maximum position at once.
int sliderValueFromPosition(int min, int max, int position, int span, bool upsideDown)
int height() const const
ctkRangeSlider(Qt::Orientation o, QWidget *par=0)
Constructor, builds a ctkRangeSlider that ranges from 0 to 100 and has a lower and upper values of 0 ...
QEvent::Type type() const const
void setValues(int min, int max)
Utility function that set the minimum value and maximum value at once.
int sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown)
void ignore()
void drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex &option)
void valuesChanged(int min, int max)
Utility signal that is fired when minimum or maximum values have changed.
void minimumValueChanged(int min)
This signal is emitted when the slider minimum value has changed, with the new slider value as argume...
QColor lighter(int factor) const const
Q_D(Todo)
void accept()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 04:00:53 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.