Skip to content

Commit

Permalink
Port hover/pressed state handling from QSlider
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 26, 2020
1 parent 580ab84 commit f0cbbae
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 20 deletions.
5 changes: 5 additions & 0 deletions python/gui/auto_generated/qgsrangeslider.sip.in
Expand Up @@ -131,6 +131,8 @@ position for the widget. If the value is ``True``, the minimum and maximum appea

virtual void mouseMoveEvent( QMouseEvent *event );

virtual void mouseReleaseEvent( QMouseEvent *event );

virtual QSize sizeHint() const;


Expand Down Expand Up @@ -194,6 +196,9 @@ Sets the current range selected in the widget.
.. seealso:: :py:func:`setUpperValue`
%End

virtual bool event( QEvent *event );


signals:

void rangeChanged( int minimum, int maximum );
Expand Down
167 changes: 149 additions & 18 deletions src/gui/qgsrangeslider.cpp
Expand Up @@ -22,6 +22,15 @@ QgsRangeSlider::QgsRangeSlider( QWidget *parent )
{
mStyleOption.minimum = 0;
mStyleOption.maximum = 100;

setFocusPolicy( Qt::FocusPolicy( style()->styleHint( QStyle::SH_Button_FocusPolicy ) ) );
QSizePolicy sp( QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::Slider );
if ( mStyleOption.orientation == Qt::Vertical )
sp.transpose();
setSizePolicy( sp );
setAttribute( Qt::WA_WState_OwnSizePolicy, false );

installEventFilter( this );
}

int QgsRangeSlider::maximum() const
Expand Down Expand Up @@ -106,6 +115,82 @@ void QgsRangeSlider::setRange( int lower, int upper )
update();
}

bool QgsRangeSlider::event( QEvent *event )
{
switch ( event->type() )
{
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove:
if ( const QHoverEvent *he = static_cast<const QHoverEvent *>( event ) )
updateHoverControl( he->pos() );
break;
default:
break;
}
return QWidget::event( event );
}

bool QgsRangeSlider::updateHoverControl( const QPoint &pos )
{
const QRect lastHoverRect = mHoverRect;
const bool doesHover = testAttribute( Qt::WA_Hover );
if ( doesHover && newHoverControl( pos ) )
{
update( lastHoverRect );
update( mHoverRect );
return true;
}
return !doesHover;
}

bool QgsRangeSlider::newHoverControl( const QPoint &pos )
{
const Control lastHoverControl = mHoverControl;
const QStyle::SubControl lastHoverSubControl = mHoverSubControl;

mStyleOption.subControls = QStyle::SC_All;

mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mLowerValue : mLowerValue;
QRect lowerHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle, this );
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mUpperValue : mUpperValue;
QRect upperHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle, this );

QRect grooveRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderGroove, this );
QRect tickmarksRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderTickmarks, this );
if ( lowerHandleRect.contains( pos ) )
{
mHoverRect = lowerHandleRect;
mHoverControl = Lower;
mHoverSubControl = QStyle::SC_SliderHandle;
}
else if ( upperHandleRect.contains( pos ) )
{
mHoverRect = upperHandleRect;
mHoverControl = Upper;
mHoverSubControl = QStyle::SC_SliderHandle;
}
else if ( grooveRect.contains( pos ) )
{
mHoverRect = grooveRect;
mHoverControl = None;
mHoverSubControl = QStyle::SC_SliderGroove;
}
else if ( tickmarksRect.contains( pos ) )
{
mHoverRect = tickmarksRect;
mHoverControl = None;
mHoverSubControl = QStyle::SC_SliderTickmarks;
}
else
{
mHoverRect = QRect();
mHoverControl = None;
mHoverSubControl = QStyle::SC_None;
}
return mHoverSubControl != lastHoverSubControl || mHoverControl != lastHoverControl;
}

void QgsRangeSlider::setTickPosition( QSlider::TickPosition position )
{
mStyleOption.tickPosition = position;
Expand Down Expand Up @@ -159,6 +244,7 @@ void QgsRangeSlider::paintEvent( QPaintEvent * )
mStyleOption.sliderPosition = 0;
mStyleOption.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderTickmarks;

mStyleOption.activeSubControls = mHoverSubControl;
// draw groove
style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );

Expand All @@ -167,9 +253,11 @@ void QgsRangeSlider::paintEvent( QPaintEvent * )
painter.setBrush( QBrush( color ) );
painter.setPen( Qt::NoPen );

mStyleOption.activeSubControls = mHoverControl == Lower || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mLowerValue : mLowerValue;
const QRect lowerHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle, nullptr );

mStyleOption.activeSubControls = mHoverControl == Upper || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mUpperValue : mUpperValue;
const QRect upperHandleRect = style()->subControlRect( QStyle::CC_Slider, &mStyleOption, QStyle::SC_SliderHandle, nullptr );

Expand Down Expand Up @@ -209,21 +297,45 @@ void QgsRangeSlider::paintEvent( QPaintEvent * )

// draw first handle
mStyleOption.subControls = QStyle::SC_SliderHandle;
mStyleOption.activeSubControls = mHoverControl == Lower || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mLowerValue : mLowerValue;
if ( mActiveControl == Lower )
mStyleOption.state |= QStyle::State_Sunken;
else
mStyleOption.state &= ~QStyle::State_Sunken;
style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );

// draw second handle
mStyleOption.activeSubControls = mHoverControl == Upper || mActiveControl == Lower ? QStyle::SC_SliderHandle : QStyle::SC_None;
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mUpperValue : mUpperValue;
if ( mActiveControl == Upper )
mStyleOption.state |= QStyle::State_Sunken;
else
mStyleOption.state &= ~QStyle::State_Sunken;
style()->drawComplexControl( QStyle::CC_Slider, &mStyleOption, &painter );
}

void QgsRangeSlider::mousePressEvent( QMouseEvent *event )
{
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mLowerValue : mLowerValue;
mLowerControl = style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption, event->pos(), this );
if ( mStyleOption.maximum == mStyleOption.minimum || ( event->buttons() ^ event->button() ) )
{
event->ignore();
return;
}

mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mUpperValue : mUpperValue;
mUpperControl = style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption, event->pos(), this );
event->accept();

mActiveControl = None;

mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mLowerValue : mLowerValue;
if ( style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption, event->pos(), this ) == QStyle::SC_SliderHandle )
mActiveControl = Lower;
else
{
mStyleOption.sliderPosition = mInverted ? mStyleOption.maximum - mUpperValue : mUpperValue;
if ( style()->hitTestComplexControl( QStyle::CC_Slider, &mStyleOption, event->pos(), this ) )
mActiveControl = Upper;
}
}

void QgsRangeSlider::mouseMoveEvent( QMouseEvent *event )
Expand All @@ -238,29 +350,35 @@ void QgsRangeSlider::mouseMoveEvent( QMouseEvent *event )
pos = mStyleOption.maximum - pos;

bool changed = false;
bool overLowerHandle = false;
if ( mLowerControl == QStyle::SC_SliderHandle )
switch ( mActiveControl )
{
if ( pos <= mUpperValue )
case None:
return;

case Lower:
{
overLowerHandle = true;
if ( mLowerValue != pos )
if ( pos <= mUpperValue )
{
mLowerValue = pos;
changed = true;
if ( mLowerValue != pos )
{
mLowerValue = pos;
changed = true;
}
}
break;
}
}

if ( !overLowerHandle && mUpperControl == QStyle::SC_SliderHandle )
{
if ( pos >= mLowerValue )
case Upper:
{
if ( mUpperValue != pos )
if ( pos >= mLowerValue )
{
mUpperValue = pos;
changed = true;
if ( mUpperValue != pos )
{
mUpperValue = pos;
changed = true;
}
}
break;
}
}

Expand All @@ -271,6 +389,19 @@ void QgsRangeSlider::mouseMoveEvent( QMouseEvent *event )
}
}

void QgsRangeSlider::mouseReleaseEvent( QMouseEvent *event )
{
if ( mActiveControl == None || event->buttons() )
{
event->ignore();
return;
}

event->accept();
mActiveControl = None;
update();
}

QSize QgsRangeSlider::sizeHint() const
{
static constexpr int sliderLength = 84;
Expand Down
19 changes: 17 additions & 2 deletions src/gui/qgsrangeslider.h
Expand Up @@ -136,6 +136,7 @@ class GUI_EXPORT QgsRangeSlider : public QWidget
void paintEvent( QPaintEvent *event ) override;
void mousePressEvent( QMouseEvent *event ) override;
void mouseMoveEvent( QMouseEvent *event ) override;
void mouseReleaseEvent( QMouseEvent *event ) override;
QSize sizeHint() const override;

public slots:
Expand Down Expand Up @@ -190,6 +191,8 @@ class GUI_EXPORT QgsRangeSlider : public QWidget
*/
void setRange( int lower, int upper );

bool event( QEvent *event ) override;

signals:

/**
Expand All @@ -204,12 +207,24 @@ class GUI_EXPORT QgsRangeSlider : public QWidget

private:

bool updateHoverControl( const QPoint &pos );
bool newHoverControl( const QPoint &pos );

int mLowerValue = 0;
int mUpperValue = 0;

QStyleOptionSlider mStyleOption;
QStyle::SubControl mLowerControl = QStyle::SC_None;
QStyle::SubControl mUpperControl = QStyle::SC_None;
enum Control
{
None,
Lower,
Upper
};
Control mActiveControl = None;
Control mHoverControl = None;
QStyle::SubControl mHoverSubControl = QStyle::SC_None;
QRect mHoverRect;

bool mInverted = false;
};

Expand Down

0 comments on commit f0cbbae

Please sign in to comment.