18 #include <QMouseEvent>
28 mStyleOption.minimum = 0;
29 mStyleOption.maximum = 100;
32 setFocusPolicy( Qt::FocusPolicy( style()->styleHint( QStyle::SH_Button_FocusPolicy ) ) );
33 QSizePolicy sp( QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::Slider );
34 if ( mStyleOption.orientation == Qt::Vertical )
37 setAttribute( Qt::WA_WState_OwnSizePolicy,
false );
39 setAttribute( Qt::WA_Hover );
40 setMouseTracking(
true );
45 return mStyleOption.maximum;
50 if ( mStyleOption.maximum ==
maximum )
54 mStyleOption.minimum = std::min(
maximum, mStyleOption.minimum );
59 mUpperValue = std::min( mUpperValue,
maximum );
60 mLowerValue = std::min( mLowerValue,
maximum );
69 return mStyleOption.minimum;
74 if ( mStyleOption.minimum ==
minimum )
77 mStyleOption.maximum = std::max(
minimum, mStyleOption.maximum );
82 mUpperValue = std::max( mUpperValue,
minimum );
83 mLowerValue = std::max( mLowerValue,
minimum );
95 if ( mStyleOption.minimum ==
minimum && mStyleOption.maximum ==
maximum )
102 if ( mUpperValue <
minimum || mLowerValue < minimum || mUpperValue >
maximum || mLowerValue >
maximum )
104 mUpperValue = std::min(
maximum, std::max( mUpperValue,
minimum ) );
105 mLowerValue = std::min(
maximum, std::max( mLowerValue,
minimum ) );
122 mLowerValue = std::min( mStyleOption.maximum, std::max( mStyleOption.minimum,
lowerValue ) );
123 mUpperValue = std::max( mLowerValue, mUpperValue );
139 mUpperValue = std::max( mStyleOption.minimum, std::min( mStyleOption.maximum,
upperValue ) );
140 mLowerValue = std::min( mLowerValue, mUpperValue );
147 if (
lower == mLowerValue && upper == mUpperValue )
151 std::swap(
lower, upper );
153 mLowerValue = std::min( mStyleOption.maximum, std::max( mStyleOption.minimum,
lower ) );
154 mUpperValue = std::min( mStyleOption.maximum, std::max( mStyleOption.minimum, upper ) );
161 switch (
event->type() )
163 case QEvent::HoverEnter:
164 case QEvent::HoverLeave:
165 case QEvent::HoverMove:
166 if (
const QHoverEvent *he =
static_cast<const QHoverEvent *
>(
event ) )
167 updateHoverControl( he->pos() );
172 return QWidget::event(
event );
175 int QgsRangeSlider::pick(
const QPoint &pt )
const
177 return mStyleOption.orientation == Qt::Horizontal ? pt.x() : pt.y();
180 int QgsRangeSlider::pixelPosToRangeValue(
int pos )
const
182 const QRect gr = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderGroove,
this );
183 const QRect sr = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
184 int sliderMin, sliderMax, sliderLength;
185 if ( mStyleOption.orientation == Qt::Horizontal )
187 sliderLength = sr.width();
189 sliderMax = gr.right() - sliderLength + 1;
193 sliderLength = sr.height();
195 sliderMax = gr.bottom() - sliderLength + 1;
198 int value = QStyle::sliderValueFromPosition( mStyleOption.minimum, mStyleOption.maximum, pos - sliderMin,
199 sliderMax - sliderMin );
201 value = mStyleOption.maximum + mStyleOption.minimum - value;
205 bool QgsRangeSlider::updateHoverControl(
const QPoint &pos )
207 const QRect lastHoverRect = mHoverRect;
208 const bool doesHover = testAttribute( Qt::WA_Hover );
209 if ( doesHover && newHoverControl( pos ) )
211 update( lastHoverRect );
212 update( mHoverRect );
218 bool QgsRangeSlider::newHoverControl(
const QPoint &pos )
220 const Control lastHoverControl = mHoverControl;
221 const QStyle::SubControl lastHoverSubControl = mHoverSubControl;
223 mStyleOption.subControls = QStyle::SC_All;
225 mStyleOption.sliderPosition = unFlippedSliderPosition( mLowerValue );
226 const QRect lowerHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
227 mStyleOption.sliderPosition = unFlippedSliderPosition( mUpperValue );
228 const QRect upperHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
230 const QRect grooveRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderGroove,
this );
231 const QRect tickmarksRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderTickmarks,
this );
232 if ( lowerHandleRect.contains( pos ) )
234 mHoverRect = lowerHandleRect;
235 mHoverControl = Lower;
236 mHoverSubControl = QStyle::SC_SliderHandle;
237 setCursor( Qt::OpenHandCursor );
239 else if ( upperHandleRect.contains( pos ) )
241 mHoverRect = upperHandleRect;
242 mHoverControl = Upper;
243 mHoverSubControl = QStyle::SC_SliderHandle;
244 setCursor( Qt::OpenHandCursor );
246 else if ( grooveRect.contains( pos ) )
248 mHoverRect = grooveRect;
249 mHoverControl = None;
250 mHoverSubControl = QStyle::SC_SliderGroove;
252 if ( selectedRangeRect().contains( pos ) )
253 setCursor( Qt::OpenHandCursor );
257 else if ( tickmarksRect.contains( pos ) )
259 mHoverRect = tickmarksRect;
260 mHoverControl = None;
261 mHoverSubControl = QStyle::SC_SliderTickmarks;
266 mHoverRect = QRect();
267 mHoverControl = None;
268 mHoverSubControl = QStyle::SC_None;
271 return mHoverSubControl != lastHoverSubControl || mHoverControl != lastHoverControl;
274 QRect QgsRangeSlider::selectedRangeRect()
278 mStyleOption.activeSubControls = mHoverControl == Lower || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
279 mStyleOption.sliderPosition = unFlippedSliderPosition( mLowerValue );
280 const QRect lowerHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
nullptr );
282 mStyleOption.activeSubControls = mHoverControl == Upper || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
283 mStyleOption.sliderPosition = unFlippedSliderPosition( mUpperValue );
284 const QRect upperHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
nullptr );
286 const QRect grooveRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderGroove,
nullptr );
288 switch ( mStyleOption.orientation )
291 selectionRect = mFlipped ? QRect( upperHandleRect.right(),
293 lowerHandleRect.left() - upperHandleRect.right(),
296 : QRect( lowerHandleRect.right(),
298 upperHandleRect.left() - lowerHandleRect.right(),
304 selectionRect = mFlipped ? QRect( grooveRect.x(),
305 lowerHandleRect.top(),
307 upperHandleRect.bottom() - lowerHandleRect.top()
309 : QRect( grooveRect.x(),
310 upperHandleRect.top(),
312 lowerHandleRect.bottom() - upperHandleRect.top()
317 return selectionRect.adjusted( -1, 1, 1, -1 );
320 void QgsRangeSlider::applyStep(
int step )
322 switch ( mFocusControl )
326 const int newLowerValue = std::min( mUpperValue, std::min( mStyleOption.maximum, std::max( mStyleOption.minimum, mLowerValue + step ) ) );
327 if ( newLowerValue != mLowerValue )
329 mLowerValue = newLowerValue;
338 const int newUpperValue = std::max( mLowerValue, std::min( mStyleOption.maximum, std::max( mStyleOption.minimum, mUpperValue + step ) ) );
339 if ( newUpperValue != mUpperValue )
341 mUpperValue = newUpperValue;
352 const int previousWidth = mUpperValue - mLowerValue;
353 const int newLowerValue = std::min( mUpperValue, std::min( mStyleOption.maximum, std::max( mStyleOption.minimum, mLowerValue + step ) ) );
354 if ( newLowerValue != mLowerValue )
356 mLowerValue = newLowerValue;
357 mUpperValue = std::min( mStyleOption.maximum, mLowerValue + previousWidth );
364 const int previousWidth = mUpperValue - mLowerValue;
365 const int newUpperValue = std::max( mLowerValue, std::min( mStyleOption.maximum, std::max( mStyleOption.minimum, mUpperValue + step ) ) );
366 if ( newUpperValue != mUpperValue )
368 mUpperValue = newUpperValue;
369 mLowerValue = std::max( mStyleOption.minimum, mUpperValue - previousWidth );
383 int QgsRangeSlider::unFlippedSliderPosition(
int value )
const
385 return mFlipped ? mStyleOption.maximum + mStyleOption.minimum - value : value;
410 mStyleOption.tickPosition = position;
416 return mStyleOption.tickPosition;
421 mStyleOption.tickInterval = interval;
427 return mStyleOption.tickInterval;
433 if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
435 setSizePolicy( sizePolicy().transposed() );
436 setAttribute( Qt::WA_WState_OwnSizePolicy,
false );
444 return mStyleOption.orientation;
460 QPainter painter(
this );
462 mStyleOption.initFrom(
this );
463 mStyleOption.rect = rect();
464 mStyleOption.sliderPosition = mStyleOption.minimum;
465 mStyleOption.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderTickmarks;
467 mStyleOption.activeSubControls = mHoverSubControl;
469 style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );
471 QColor color = palette().color( QPalette::Highlight );
472 color.setAlpha( 160 );
473 painter.setBrush( QBrush( color ) );
474 painter.setPen( Qt::NoPen );
475 painter.drawRect( selectedRangeRect() );
478 mStyleOption.subControls = QStyle::SC_SliderHandle;
479 mStyleOption.activeSubControls = mHoverControl == Lower || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
480 mStyleOption.sliderPosition = unFlippedSliderPosition( mLowerValue );
481 if ( mActiveControl == Lower )
482 mStyleOption.state |= QStyle::State_Sunken;
484 mStyleOption.state &= ~QStyle::State_Sunken;
485 style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );
488 mStyleOption.activeSubControls = mHoverControl == Upper || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
489 mStyleOption.sliderPosition = unFlippedSliderPosition( mUpperValue );
490 if ( mActiveControl == Upper )
491 mStyleOption.state |= QStyle::State_Sunken;
493 mStyleOption.state &= ~QStyle::State_Sunken;
494 style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );
496 if ( hasFocus() && mFocusControl != None )
499 QStyleOptionFocusRect option;
500 option.initFrom(
this );
501 option.state = QStyle::State_KeyboardFocusChange;
502 if ( mFocusControl == Lower )
504 mStyleOption.sliderPosition = unFlippedSliderPosition( mLowerValue );
505 option.rect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
507 else if ( mFocusControl == Upper )
509 mStyleOption.sliderPosition = unFlippedSliderPosition( mUpperValue );
510 option.rect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
512 else if ( mFocusControl == Range )
514 option.rect = selectedRangeRect();
515 if ( mStyleOption.orientation == Qt::Horizontal )
516 option.rect = option.rect.adjusted( 0, -1, 0, 1 );
518 option.rect = option.rect.adjusted( -1, 0, 1, 0 );
520 style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, &painter );
526 if ( mStyleOption.maximum == mStyleOption.minimum || (
event->buttons() ^
event->button() ) )
534 mStyleOption.sliderPosition = unFlippedSliderPosition( mLowerValue );
535 const bool overLowerControl = style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption,
event->pos(),
this ) == QStyle::SC_SliderHandle;
536 const QRect lowerSliderRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
537 mStyleOption.sliderPosition = unFlippedSliderPosition( mUpperValue );
538 const bool overUpperControl = style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption,
event->pos(),
this ) == QStyle::SC_SliderHandle;
539 const QRect upperSliderRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle,
this );
541 const bool overSelectedRange = selectedRangeRect().contains(
event->pos() );
543 mLowerClickOffset = pick(
event->pos() - lowerSliderRect.topLeft() );
544 mUpperClickOffset = pick(
event->pos() - upperSliderRect.topLeft() );
546 mPreDragLowerValue = mLowerValue;
547 mPreDragUpperValue = mUpperValue;
548 mRangeDragOffset = 0;
550 if ( ( overLowerControl || overUpperControl ) &&
event->modifiers() & Qt::ShiftModifier )
552 mActiveControl = Range;
553 mRangeDragOffset = overUpperControl ? mUpperClickOffset : mLowerClickOffset;
554 mFocusControl = overUpperControl ? Upper : Lower;
556 else if ( overLowerControl && overUpperControl )
557 mActiveControl = Both;
558 else if ( overLowerControl )
560 mActiveControl = Lower;
561 mFocusControl = Lower;
563 else if ( overUpperControl )
565 mActiveControl = Upper;
566 mFocusControl = Upper;
568 else if ( overSelectedRange )
570 mActiveControl = Range;
571 mFocusControl = Range;
574 mActiveControl = None;
576 if ( mActiveControl != None )
578 mStartDragPos = pixelPosToRangeValue( pick(
event->pos() ) - mRangeDragOffset );
584 if ( mActiveControl == None )
592 int newPosition = pixelPosToRangeValue( pick(
event->pos() ) );
594 bool changed =
false;
595 Control destControl = mActiveControl;
596 if ( destControl == Both )
599 if ( newPosition < mStartDragPos )
602 mFocusControl = Lower;
603 if ( mUpperValue != mPreDragUpperValue )
606 mUpperValue = mPreDragUpperValue;
609 else if ( newPosition > mStartDragPos )
612 mFocusControl = Upper;
613 if ( mLowerValue != mPreDragLowerValue )
616 mLowerValue = mPreDragLowerValue;
622 if ( mUpperValue != mPreDragUpperValue )
625 mUpperValue = mPreDragUpperValue;
627 if ( mLowerValue != mPreDragLowerValue )
630 mLowerValue = mPreDragLowerValue;
635 switch ( destControl )
644 newPosition = std::min( mUpperValue, pixelPosToRangeValue( pick(
event->pos() ) - mLowerClickOffset ) );
645 if ( mLowerValue != newPosition )
647 mLowerValue = newPosition;
656 newPosition = std::max( mLowerValue, pixelPosToRangeValue( pick(
event->pos() ) - mUpperClickOffset ) );
657 if ( mUpperValue != newPosition )
659 mUpperValue = newPosition;
667 newPosition = pixelPosToRangeValue( pick(
event->pos() ) - mRangeDragOffset ) ;
668 int delta = newPosition - mStartDragPos;
673 const int maxDelta = mStyleOption.maximum - mPreDragUpperValue;
674 delta = std::min( maxDelta, delta );
675 mLowerValue = mPreDragLowerValue + delta;
676 mUpperValue = mPreDragUpperValue + delta;
679 else if ( delta < 0 )
683 const int maxDelta = mPreDragLowerValue - mStyleOption.minimum ;
684 delta = std::min( maxDelta, delta );
685 mLowerValue = mPreDragLowerValue - delta;
686 mUpperValue = mPreDragUpperValue - delta;
703 if ( mActiveControl == None ||
event->buttons() )
710 mActiveControl = None;
716 Control destControl = mFocusControl;
717 if ( ( destControl == Lower || destControl == Upper ) && mLowerValue == mUpperValue )
720 switch (
event->key() )
724 switch ( mStyleOption.orientation )
727 if ( destControl == Both )
728 mFocusControl = mFlipped ? Upper : Lower;
730 applyStep( mFlipped ? mSingleStep : -mSingleStep );
736 switch ( mFocusControl )
739 mFocusControl = Range;
742 mFocusControl = Upper;
747 mFocusControl = Lower;
753 switch ( mFocusControl )
758 mFocusControl = Upper;
761 mFocusControl = Lower;
764 mFocusControl = Range;
776 switch ( mStyleOption.orientation )
779 if ( destControl == Both )
780 mFocusControl = mFlipped ? Lower : Upper;
781 applyStep( mFlipped ? -mSingleStep : mSingleStep );
787 switch ( mFocusControl )
792 mFocusControl = Upper;
795 mFocusControl = Lower;
798 mFocusControl = Range;
804 switch ( mFocusControl )
807 mFocusControl = Range;
810 mFocusControl = Upper;
815 mFocusControl = Lower;
827 switch ( mStyleOption.orientation )
832 switch ( mFocusControl )
835 mFocusControl = Range;
838 mFocusControl = Upper;
843 mFocusControl = Lower;
849 switch ( mFocusControl )
852 mFocusControl = Upper;
857 mFocusControl = Lower;
860 mFocusControl = Range;
868 if ( destControl == Both )
869 mFocusControl = mFlipped ? Upper : Lower;
871 applyStep( mFlipped ? mSingleStep : -mSingleStep );
879 switch ( mStyleOption.orientation )
884 switch ( mFocusControl )
887 mFocusControl = Upper;
892 mFocusControl = Lower;
895 mFocusControl = Range;
901 switch ( mFocusControl )
904 mFocusControl = Range;
907 mFocusControl = Upper;
912 mFocusControl = Lower;
920 if ( destControl == Both )
921 mFocusControl = mFlipped ? Lower : Upper;
923 applyStep( mFlipped ? -mSingleStep : mSingleStep );
931 switch ( mStyleOption.orientation )
934 if ( destControl == Both )
935 mFocusControl = mFlipped ? Lower : Upper;
937 applyStep( mFlipped ? -mPageStep : mPageStep );
941 if ( destControl == Both )
942 mFocusControl = mFlipped ? Upper : Lower;
944 applyStep( mFlipped ? mPageStep : -mPageStep );
950 case Qt::Key_PageDown:
952 switch ( mStyleOption.orientation )
955 if ( destControl == Both )
956 mFocusControl = mFlipped ? Upper : Lower;
958 applyStep( mFlipped ? mPageStep : -mPageStep );
962 if ( destControl == Both )
963 mFocusControl = mFlipped ? Lower : Upper;
965 applyStep( mFlipped ? -mPageStep : mPageStep );
972 switch ( destControl )
975 applyStep( mFlipped ? mUpperValue - mLowerValue : mStyleOption.minimum - mLowerValue );
979 applyStep( mFlipped ? mStyleOption.maximum - mUpperValue : mLowerValue - mUpperValue );
983 applyStep( mFlipped ? mStyleOption.maximum - mUpperValue : mStyleOption.minimum - mLowerValue );
987 if ( destControl == Both )
988 mFocusControl = mFlipped ? Upper : Lower;
990 applyStep( mFlipped ? mStyleOption.maximum - mUpperValue : mStyleOption.minimum - mLowerValue );
1000 switch ( destControl )
1003 applyStep( mFlipped ? mStyleOption.minimum - mLowerValue : mUpperValue - mLowerValue );
1007 applyStep( mFlipped ? mLowerValue - mUpperValue : mStyleOption.maximum - mUpperValue );
1011 applyStep( mFlipped ? mStyleOption.minimum - mLowerValue : mStyleOption.maximum - mUpperValue );
1015 if ( destControl == Both )
1016 mFocusControl = mFlipped ? Lower : Upper;
1018 applyStep( mFlipped ? mStyleOption.minimum - mLowerValue : mStyleOption.maximum - mUpperValue );
1037 static constexpr
int SLIDER_LENGTH = 84;
1038 static constexpr
int TICK_SPACE = 5;
1040 int thick = style()->pixelMetric( QStyle::PM_SliderThickness, &mStyleOption,
this );
1041 if ( mStyleOption.tickPosition & QSlider::TicksAbove )
1042 thick += TICK_SPACE;
1043 if ( mStyleOption.tickPosition & QSlider::TicksBelow )
1044 thick += TICK_SPACE;
1045 int w = thick, h = SLIDER_LENGTH;
1046 if ( mStyleOption.orientation == Qt::Horizontal )
1050 return style()->sizeFromContents( QStyle::CT_Slider, &mStyleOption, QSize( w, h ),
this );
1056 const int length = style()->pixelMetric( QStyle::PM_SliderLength, &mStyleOption,
this );
1057 if ( mStyleOption.orientation == Qt::Horizontal )
1058 s.setWidth( length );
1060 s.setHeight( length );
A slider control with two interactive endpoints, for interactive selection of a range of values.
void setUpperValue(int value)
Sets the upper value for the range currently selected in the widget.
void setRangeLimits(int minimum, int maximum)
Sets the minimum and maximum range limits for values allowed in the widget.
QgsRangeSlider(QWidget *parent=nullptr)
Constructor for QgsRangeSlider, with the specified parent widget.
void setOrientation(Qt::Orientation orientation)
Sets the orientation of the slider.
void setTickInterval(int interval)
Sets the interval for tick marks shown in the widget.
int upperValue() const
Returns the upper value for the range selected in the widget.
int tickInterval() const
Returns the interval for tick marks shown in the widget.
void paintEvent(QPaintEvent *event) override
void rangeLimitsChanged(int minimum, int maximum)
Emitted when the limits of values allowed in the widget is changed.
QSize sizeHint() const override
void keyPressEvent(QKeyEvent *event) override
void mouseMoveEvent(QMouseEvent *event) override
void rangeChanged(int minimum, int maximum)
Emitted when the range selected in the widget is changed.
int maximum() const
Returns the maximum value allowed by the widget.
void mousePressEvent(QMouseEvent *event) override
bool event(QEvent *event) override
void setSingleStep(int step)
Sets the single step value for the widget.
void setMinimum(int minimum)
Sets the minimum value allowed in the widget.
void setPageStep(int step)
Sets the page step value for the widget.
Qt::Orientation orientation() const
Returns the orientation of the slider.
void setMaximum(int maximum)
Sets the maximum value allowed in the widget.
int pageStep() const
Returns the page step value for the widget.
void setFlippedDirection(bool flipped)
Sets whether the slider has its values flipped.
int minimum() const
Returns the minimum value allowed by the widget.
QSize minimumSizeHint() const override
void setRange(int lower, int upper)
Sets the current range selected in the widget.
void setLowerValue(int value)
Sets the lower value for the range currently selected in the widget.
int lowerValue() const
Returns the lower value for the range selected in the widget.
void setTickPosition(QSlider::TickPosition position)
Sets the position of the tick marks shown in the widget.
void mouseReleaseEvent(QMouseEvent *event) override
bool flippedDirection() const
Returns true if the slider has its values flipped.
QSlider::TickPosition tickPosition() const
Returns the position of the tick marks shown in the widget.
int singleStep() const
Returns the single step value for the widget.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.