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
19class ctkRangeSliderPrivate
20{
21 Q_DECLARE_PUBLIC(ctkRangeSlider)
22protected:
23 ctkRangeSlider* const q_ptr;
24public:
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
82private:
83 Q_DISABLE_COPY(ctkRangeSliderPrivate)
84};
85
86// --------------------------------------------------------------------------
87ctkRangeSliderPrivate::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// --------------------------------------------------------------------------
104void 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// --------------------------------------------------------------------------
115ctkRangeSliderPrivate::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//
181int 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//---------------------------------------------------------------------------
217int 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
254void 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
279void 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// --------------------------------------------------------------------------
322ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate* impl, QWidget* _parent)
323 : QSlider(_parent)
324 , d_ptr(impl)
325{
327 d->init();
328}
329
330// --------------------------------------------------------------------------
331ctkRangeSlider::ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o,
332 QWidget* parentObject )
333 :QSlider(o, parentObject)
334 , d_ptr(impl)
335{
337 d->init();
338}
339
340// --------------------------------------------------------------------------
341ctkRangeSlider::~ctkRangeSlider()
342{
343}
344
345// --------------------------------------------------------------------------
346int 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// --------------------------------------------------------------------------
360int 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// --------------------------------------------------------------------------
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// --------------------------------------------------------------------------
430int ctkRangeSlider::minimumPosition() const
431{
432 Q_D(const ctkRangeSlider);
433 return d->m_MinimumPosition;
434}
435
436// --------------------------------------------------------------------------
437int ctkRangeSlider::maximumPosition() const
438{
439 Q_D(const ctkRangeSlider);
440 return d->m_MaximumPosition;
441}
442
443// --------------------------------------------------------------------------
444void ctkRangeSlider::setMinimumPosition(int l)
445{
446 Q_D(const ctkRangeSlider);
447 this->setPositions(l, qMax(l, d->m_MaximumPosition));
448}
449
450// --------------------------------------------------------------------------
451void ctkRangeSlider::setMaximumPosition(int u)
452{
453 Q_D(const ctkRangeSlider);
454 this->setPositions(qMin(d->m_MinimumPosition, u), u);
455}
456
457// --------------------------------------------------------------------------
458void 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 {
499 this->setValues(d->m_MinimumPosition, d->m_MaximumPosition);
500 }
501}
502
503// --------------------------------------------------------------------------
504void ctkRangeSlider::setSymmetricMoves(bool symmetry)
505{
507 d->m_SymmetricMoves = symmetry;
508}
509
510// --------------------------------------------------------------------------
511bool ctkRangeSlider::symmetricMoves()const
512{
513 Q_D(const ctkRangeSlider);
514 return d->m_SymmetricMoves;
515}
516
517// --------------------------------------------------------------------------
518void 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
528void 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
625void 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
698void 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
751void 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// --------------------------------------------------------------------------
777void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const
778{
779 this->initStyleOption(option);
780}
781
782// --------------------------------------------------------------------------
783void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const
784{
785 this->initStyleOption(option);
786}
787
788// --------------------------------------------------------------------------
789QString ctkRangeSlider::handleToolTip()const
790{
791 Q_D(const ctkRangeSlider);
792 return d->m_HandleToolTip;
793}
794
795// --------------------------------------------------------------------------
796void ctkRangeSlider::setHandleToolTip(const QString& _toolTip)
797{
799 d->m_HandleToolTip = _toolTip;
800}
801
802// --------------------------------------------------------------------------
803bool ctkRangeSlider::event(QEvent* _event)
804{
806 switch(_event->type())
807 {
808 case QEvent::ToolTip:
809 {
810 QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event);
812 // Test the MinimumHandle
813 opt.sliderPosition = d->m_MinimumPosition;
814 opt.sliderValue = d->m_MinimumValue;
815 this->initStyleOption(&opt);
816 QStyle::SubControl hoveredControl =
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}
A ctkRangeSlider is a slider that lets you input 2 values instead of one (see QSlider).
void setPositions(int min, int max)
Utility function that set the minimum position and maximum position at once.
void minimumPositionChanged(int min)
This signal is emitted when sliderDown is true and the slider moves.
void setMaximumValue(int max)
This property holds the slider's current maximum value.
void minimumValueChanged(int min)
This signal is emitted when the slider minimum value has changed, with the new slider value as argume...
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 ...
bool isMinimumSliderDown() const
Returns true if the minimum value handle is down, false if it is up.
void maximumValueChanged(int max)
This signal is emitted when the slider maximum value has changed, with the new slider value as argume...
void maximumPositionChanged(int max)
This signal is emitted when sliderDown is true and the slider moves.
void positionsChanged(int min, int max)
Utility signal that is fired when minimum or maximum positions have changed.
void setValues(int min, int max)
Utility function that set the minimum value and maximum value at once.
bool isMaximumSliderDown() const
Returns true if the maximum value handle is down, false if it is up.
void valuesChanged(int min, int max)
Utility signal that is fired when minimum or maximum values have changed.
void setMinimumValue(int min)
This property holds the slider's current minimum value.
bool isSliderDown() const const
bool hasTracking() const const
void triggerAction(SliderAction action)
QColor darker(int factor) const const
QColor lighter(int factor) const const
void accept()
void ignore()
Type type() const const
void setColorAt(qreal position, const QColor &color)
const QPoint & globalPos() const const
const QPoint & pos() const const
QPoint pos() const const
void drawRect(const QRect &rectangle)
void setBrush(Qt::BrushStyle style)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setPen(Qt::PenStyle style)
int x() const const
int y() const const
void adjust(int dx1, int dy1, int dx2, int dy2)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
int bottom() const const
QPoint center() const const
bool contains(const QPoint &point, bool proper) const const
int height() const const
QRect intersected(const QRect &rectangle) const const
int left() const const
int right() const const
int top() const const
QRect united(const QRect &rectangle) const const
int width() const const
int x() const const
int y() const const
Qt::MouseButton button() const const
Qt::MouseButtons buttons() const const
virtual bool event(QEvent *event) override
virtual void initStyleOption(QStyleOptionSlider *option) const const
virtual void mouseReleaseEvent(QMouseEvent *ev) override
PM_MaximumDragDistance
virtual SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const const=0
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
int sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown)
int sliderValueFromPosition(int min, int max, int position, int span, bool upsideDown)
virtual QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const const=0
void drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex &option)
Horizontal
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
QStyle * style() const const
void update()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.