diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 3bb258e6..f3afbcb6 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -1012,9 +1012,13 @@ void Editor::setupScrollView() // scroll bars for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } ) { - setMetric( subControl | A::Size, 12_dp ); - setPadding( subControl, 0 ); + setMetric( subControl | A::Size, 14 ); + setPadding( subControl, 2 ); setMargin( subControl, 0 ); + + setPanel( subControl, Sunken ); + setBoxShape( subControl, 100, Qt::RelativeSize ); + setBoxBorderMetrics( subControl, 1 ); } // scrollbar handles @@ -1024,6 +1028,8 @@ void Editor::setupScrollView() setButton( subControl, Raised, bw ); setButton( subControl | Q::Pressed, Sunken, bw ); + setBoxShape( subControl, 100, Qt::RelativeSize ); + setBoxShape( subControl | Q::Pressed, 100, Qt::RelativeSize ); const auto extent = 40_dp; diff --git a/src/controls/QskScrollView.cpp b/src/controls/QskScrollView.cpp index 828b2d40..34622005 100644 --- a/src/controls/QskScrollView.cpp +++ b/src/controls/QskScrollView.cpp @@ -17,60 +17,132 @@ QSK_SUBCONTROL( QskScrollView, VerticalScrollHandle ) QSK_SYSTEM_STATE( QskScrollView, Pressed, QskAspect::FirstSystemState << 1 ) +static inline QskAspect::Subcontrol qskSubControlAt( + const QskScrollView* scrollView, const QPointF& pos ) +{ + using Q = QskScrollView; + + const auto rect = scrollView->contentsRect(); + + // order is important as the handles are inside the bars ! + + for ( auto subControl : { Q::VerticalScrollHandle, Q::VerticalScrollBar, + Q::HorizontalScrollHandle, Q::HorizontalScrollBar } ) + { + if ( scrollView->subControlRect( rect, subControl ).contains( pos ) ) + return subControl; + } + + return QskAspect::NoSubcontrol; +} + class QskScrollView::PrivateData { public: inline void resetScrolling( QskScrollView* scrollView ) { - setScrolling( scrollView, 0, 0.0 ); + setScrolling( scrollView, QskAspect::NoSubcontrol, 0.0 ); } - inline void setScrolling( QskScrollView* scrollView, int scrolling, qreal pos ) + inline void setScrolling( QskScrollView* scrollView, + QskAspect::Subcontrol subControl, qreal pos ) { - if ( isScrolling == scrolling ) + if ( subControl == pressedSubControl ) return; - Qt::Orientation orientation; - - if ( ( isScrolling == Qt::Horizontal ) || ( scrolling == Qt::Horizontal ) ) - orientation = Qt::Horizontal; + QskAspect::Subcontrol subControls[2]; + if ( subControl == VerticalScrollHandle || pressedSubControl == VerticalScrollHandle ) + { + subControls[0] = VerticalScrollHandle; + subControls[1] = VerticalScrollBar; + } else - orientation = Qt::Vertical; + { + subControls[0] = HorizontalScrollHandle;; + subControls[1] = HorizontalScrollBar; + } - this->isScrolling = scrolling; - this->scrollPressPos = pos; + pressedSubControl = subControl; + scrollPressPos = pos; scrollView->update(); - auto oldStates = scrollView->skinStates(); + auto oldStates = scrollView->skinStates() | scrollView->scrollBarStates( subControl ); auto newStates = oldStates | QskScrollView::Pressed; - if ( scrolling == 0 ) + if ( pressedSubControl == QskAspect::NoSubcontrol ) qSwap( oldStates, newStates ); - if ( orientation == Qt::Horizontal ) + scrollView->startHintTransitions( { subControls[0] }, oldStates, newStates ); + scrollView->startHintTransitions( { subControls[1] }, oldStates, newStates ); + } + + void setHovered( QskScrollView* scrollView, QskAspect::Subcontrol subControl ) + { + if ( subControl == this->hoveredSubControl ) + return; + + QskAspect::Subcontrol subControls[2]; + if ( subControl == VerticalScrollHandle + || hoveredSubControl == VerticalScrollHandle + || subControl == VerticalScrollBar + || hoveredSubControl == VerticalScrollBar ) { - scrollView->startHintTransitions( { HorizontalScrollHandle }, oldStates, newStates ); - scrollView->startHintTransitions( { HorizontalScrollBar }, oldStates, newStates ); + subControls[0] = VerticalScrollHandle; + subControls[1] = VerticalScrollBar; } else { - scrollView->startHintTransitions( { VerticalScrollHandle }, oldStates, newStates ); - scrollView->startHintTransitions( { VerticalScrollBar }, oldStates, newStates ); + subControls[0] = HorizontalScrollHandle;; + subControls[1] = HorizontalScrollBar; } + + hoveredSubControl = subControl; + + auto oldStates = scrollView->skinStates(); + auto newStates = oldStates | QskScrollView::Hovered; + + if ( hoveredSubControl == QskAspect::NoSubcontrol ) + qSwap( oldStates, newStates ); + + scrollView->startHintTransitions( { subControls[0] }, oldStates, newStates ); + scrollView->startHintTransitions( { subControls[1] }, oldStates, newStates ); + } + + bool hasState( QskAspect::Subcontrol subControl, QskAspect::State state ) const + { + if ( subControl == QskAspect::NoSubcontrol ) + return false; + + const auto stateSubcontrol = + ( state == QskControl::Hovered ) ? hoveredSubControl : pressedSubControl; + + if ( subControl == stateSubcontrol ) + return true; + + if ( subControl == VerticalScrollBar ) + return stateSubcontrol == VerticalScrollHandle; + + if ( subControl == HorizontalScrollBar ) + return stateSubcontrol == HorizontalScrollHandle; + + return false; } Qt::ScrollBarPolicy horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded; Qt::ScrollBarPolicy verticalScrollBarPolicy = Qt::ScrollBarAsNeeded; - qreal scrollPressPos; - int isScrolling = 0; + qreal scrollPressPos = 0.0; + + QskAspect::Subcontrol pressedSubControl = QskAspect::NoSubcontrol; + QskAspect::Subcontrol hoveredSubControl = QskAspect::NoSubcontrol; }; QskScrollView::QskScrollView( QQuickItem* parent ) : Inherited( parent ) , m_data( new PrivateData() ) { + setAcceptHoverEvents( true ); } QskScrollView::~QskScrollView() @@ -117,15 +189,23 @@ Qt::ScrollBarPolicy QskScrollView::horizontalScrollBarPolicy() const bool QskScrollView::isScrolling( Qt::Orientation orientation ) const { - return m_data->isScrolling == orientation; + if ( orientation == Qt::Vertical ) + return m_data->pressedSubControl == VerticalScrollHandle; + else + return m_data->pressedSubControl == HorizontalScrollHandle; } -QskAspect::States QskScrollView::scrollHandleStates( Qt::Orientation orientation ) const +QskAspect::States QskScrollView::scrollBarStates( + QskAspect::Subcontrol subControl ) const { auto states = skinStates(); - if ( m_data->isScrolling == orientation ) + + if ( m_data->hasState( subControl, Pressed ) ) states |= Pressed; + if ( m_data->hasState( subControl, Hovered ) ) + states |= Hovered; + return states; } @@ -143,11 +223,11 @@ void QskScrollView::mousePressEvent( QMouseEvent* event ) if ( subControlRect( VerticalScrollBar ).contains( mousePos ) ) { - const QRectF handleRect = subControlRect( VerticalScrollHandle ); + const auto handleRect = subControlRect( VerticalScrollHandle ); if ( handleRect.contains( mousePos ) ) { - m_data->setScrolling( this, Qt::Vertical, mousePos.y() ); + m_data->setScrolling( this, VerticalScrollHandle, mousePos.y() ); } else { @@ -172,7 +252,7 @@ void QskScrollView::mousePressEvent( QMouseEvent* event ) if ( handleRect.contains( mousePos ) ) { - m_data->setScrolling( this, Qt::Horizontal, mousePos.x() ); + m_data->setScrolling( this, HorizontalScrollHandle, mousePos.x() ); } else { @@ -196,7 +276,7 @@ void QskScrollView::mousePressEvent( QMouseEvent* event ) void QskScrollView::mouseMoveEvent( QMouseEvent* event ) { - if ( !m_data->isScrolling ) + if ( m_data->pressedSubControl == QskAspect::NoSubcontrol ) { Inherited::mouseMoveEvent( event ); return; @@ -205,7 +285,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event ) const auto mousePos = qskMousePosition( event ); QPointF pos = scrollPos(); - if ( m_data->isScrolling == Qt::Horizontal ) + if ( m_data->pressedSubControl == HorizontalScrollHandle ) { const qreal dx = mousePos.x() - m_data->scrollPressPos; const qreal w = subControlRect( HorizontalScrollBar ).width(); @@ -213,7 +293,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event ) pos.rx() += dx / w * scrollableSize().width(); m_data->scrollPressPos = mousePos.x(); } - else if ( m_data->isScrolling == Qt::Vertical ) + else { const qreal dy = mousePos.y() - m_data->scrollPressPos; const qreal h = subControlRect( VerticalScrollBar ).height(); @@ -228,7 +308,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event ) void QskScrollView::mouseReleaseEvent( QMouseEvent* event ) { - if ( !m_data->isScrolling ) + if ( m_data->pressedSubControl == QskAspect::NoSubcontrol ) { Inherited::mouseReleaseEvent( event ); return; @@ -242,6 +322,23 @@ void QskScrollView::mouseUngrabEvent() m_data->resetScrolling( this ); } +void QskScrollView::hoverEnterEvent( QHoverEvent* event ) +{ + const auto subControl = qskSubControlAt( this, qskHoverPosition( event ) ); + m_data->setHovered( this, subControl ); +} + +void QskScrollView::hoverMoveEvent( QHoverEvent* event ) +{ + const auto subControl = qskSubControlAt( this, qskHoverPosition( event ) ); + m_data->setHovered( this, subControl ); +} + +void QskScrollView::hoverLeaveEvent( QHoverEvent* ) +{ + m_data->setHovered( this, QskAspect::NoSubcontrol ); +} + #ifndef QT_NO_WHEELEVENT QPointF QskScrollView::scrollOffset( const QWheelEvent* event ) const diff --git a/src/controls/QskScrollView.h b/src/controls/QskScrollView.h index fe0dfa38..4771b394 100644 --- a/src/controls/QskScrollView.h +++ b/src/controls/QskScrollView.h @@ -39,7 +39,7 @@ class QSK_EXPORT QskScrollView : public QskScrollBox Qt::Orientations scrollableOrientations() const; bool isScrolling( Qt::Orientation ) const; - QskAspect::States scrollHandleStates( Qt::Orientation ) const; + QskAspect::States scrollBarStates( QskAspect::Subcontrol ) const; QRectF viewContentsRect() const override; QskAnimationHint flickHint() const override; @@ -54,6 +54,10 @@ class QSK_EXPORT QskScrollView : public QskScrollBox void mouseReleaseEvent( QMouseEvent* ) override; void mouseUngrabEvent() override; + void hoverEnterEvent( QHoverEvent* ) override; + void hoverMoveEvent( QHoverEvent* ) override; + void hoverLeaveEvent( QHoverEvent* ) override; + #ifndef QT_NO_WHEELEVENT QPointF scrollOffset( const QWheelEvent* ) const override; #endif diff --git a/src/controls/QskScrollViewSkinlet.cpp b/src/controls/QskScrollViewSkinlet.cpp index 70d2ba40..3bc10a11 100644 --- a/src/controls/QskScrollViewSkinlet.cpp +++ b/src/controls/QskScrollViewSkinlet.cpp @@ -39,14 +39,16 @@ static void qskAlignedHandle( qreal start, qreal end, } } -static inline Qt::Orientation qskSubcontrolOrientation( QskAspect::Subcontrol subControl ) +static qreal qskScrollBarExtent( + const QskScrollView* scrollView, Qt::Orientation orientation ) { - using Q = QskScrollView; + const auto subControl = ( orientation == Qt::Horizontal ) + ? QskScrollView::HorizontalScrollBar : QskScrollView::VerticalScrollBar; - if ( subControl == Q::HorizontalScrollBar || subControl == Q::HorizontalScrollHandle ) - return Qt::Horizontal; - else - return Qt::Vertical; + QskSkinStateChanger stateChanger( scrollView ); + stateChanger.setStates( scrollView->scrollBarStates( subControl ) ); + + return scrollView->metric( subControl | QskAspect::Size ); } QskScrollViewSkinlet::QskScrollViewSkinlet( QskSkin* skin ) @@ -128,10 +130,8 @@ QSGNode* QskScrollViewSkinlet::updateScrollBarNode( const QskScrollView* scrollV const auto rect = subControlRect( scrollView, scrollView->contentsRect(), subControl ); - const auto orientation = qskSubcontrolOrientation( subControl ); - QskSkinStateChanger stateChanger( scrollView ); - stateChanger.setStates( scrollView->scrollHandleStates( orientation ) ); + stateChanger.setStates( scrollView->scrollBarStates( subControl ) ); return updateBoxNode( scrollView, node, rect, subControl ); } @@ -254,7 +254,7 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView, const auto sbRect = subControlRect( scrollView, contentsRect, Q::VerticalScrollBar ); QskSkinStateChanger stateChanger( scrollView ); - stateChanger.setStates( scrollView->scrollHandleStates( orientation ) ); + stateChanger.setStates( scrollView->scrollBarStates( Q::VerticalScrollBar ) ); const auto padding = scrollView->paddingHint( Q::VerticalScrollBar ); const auto strut = scrollView->strutSizeHint( Q::VerticalScrollHandle ); @@ -275,7 +275,7 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView, const auto sbRect = subControlRect( scrollView, contentsRect, Q::HorizontalScrollBar ); QskSkinStateChanger stateChanger( scrollView ); - stateChanger.setStates( scrollView->scrollHandleStates( orientation ) ); + stateChanger.setStates( scrollView->scrollBarStates( Q::HorizontalScrollBar ) ); const auto padding = scrollView->paddingHint( Q::HorizontalScrollBar ); @@ -299,7 +299,6 @@ QRectF QskScrollViewSkinlet::scrollHandleRect( const QskScrollView* scrollView, QRectF QskScrollViewSkinlet::scrollBarRect( const QskScrollView* scrollView, const QRectF& contentsRect, Qt::Orientation orientation ) const { - using A = QskAspect; using Q = QskScrollView; const auto scrollOrientations = scrollView->scrollableOrientations(); @@ -308,28 +307,25 @@ QRectF QskScrollViewSkinlet::scrollBarRect( const QskScrollView* scrollView, auto r = subControlRect( scrollView, contentsRect, Q::Panel ); - QskSkinStateChanger stateChanger( scrollView ); - stateChanger.setStates( scrollView->scrollHandleStates( orientation ) ); - if ( orientation == Qt::Horizontal ) { - const qreal h = scrollView->metric( Q::HorizontalScrollBar | A::Size ); + const qreal h = qskScrollBarExtent( scrollView, Qt::Horizontal ); r.setTop( r.bottom() - h ); if ( scrollOrientations & Qt::Vertical ) { - const qreal w = scrollView->metric( Q::VerticalScrollBar | A::Size ); + const qreal w = qskScrollBarExtent( scrollView, Qt::Vertical ); r.setRight( r.right() - w ); } } else { - const qreal w = scrollView->metric( Q::VerticalScrollBar | A::Size ); + const qreal w = qskScrollBarExtent( scrollView, Qt::Vertical ); r.setLeft( r.right() - w ); if ( scrollOrientations & Qt::Horizontal ) { - const qreal h = scrollView->metric( Q::HorizontalScrollBar | A::Size ); + const qreal h = qskScrollBarExtent( scrollView, Qt::Horizontal ); r.setBottom( r.bottom() - h ); } }