diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 3ea2406f..bbf79f31 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -303,6 +303,7 @@ void Editor::setupPopup() void Editor::setupMenu() { + using A = QskAspect; using Q = QskMenu; const QColor c1( 78, 158, 38 ); @@ -312,7 +313,7 @@ void Editor::setupMenu() setVGradient( Q::Panel, c1, c2 ); const bool isCascading = qskMaybeDesktopPlatform(); - setFlagHint( Q::Panel | QskAspect::Style, isCascading ); + setFlagHint( Q::Panel | A::Style, isCascading ); #if 0 setPadding( Q::Separator, QMarginsF( 10, 0, 10, 0 ) ); @@ -329,10 +330,11 @@ void Editor::setupMenu() setColor( Q::Text, QColor( 255, 255, 255 ) ); setFontRole( Q::Text, QskSkin::SmallFont ); - setMetric( Q::Panel | QskAspect::Position, 0 ); - setMetric( Q::Panel | QskAspect::Position | QskPopup::Closed, 1 ); + setMetric( Q::Panel | A::Position, 0 ); + setMetric( Q::Panel | A::Position | QskPopup::Closed, 1 ); - setAnimation( Q::Panel | QskAspect::Metric, 200 ); + setAnimation( Q::Panel | A::Metric, 150 ); + setAnimation( Q::Cursor | A::Metric, 50, QEasingCurve::OutCubic ); } void Editor::setupTextLabel() diff --git a/src/controls/QskMenu.cpp b/src/controls/QskMenu.cpp index c013e646..f73c1a06 100644 --- a/src/controls/QskMenu.cpp +++ b/src/controls/QskMenu.cpp @@ -36,7 +36,7 @@ class QskMenu::PrivateData QskTextOptions textOptions; QPointF origin; - int currentIndex = 0; + int currentIndex = -1; bool isPressed = false; }; @@ -157,9 +157,13 @@ QskTextOptions QskMenu::textOptions() const void QskMenu::setCurrentIndex( int index ) { - if( index >= 0 && index < count() - && ( index != m_data->currentIndex ) ) + if( index < 0 || index >= count() ) + index = -1; + + if( index != m_data->currentIndex ) { + setPositionHint( Cursor, index ); + m_data->currentIndex = index; update(); @@ -239,14 +243,29 @@ void QskMenu::wheelEvent( QWheelEvent* event ) void QskMenu::traverse( int steps ) { - auto& index = m_data->currentIndex; + if ( count() == 0 || ( steps % count() == 0 ) ) + return; - index = ( index + steps ) % count(); - if ( index < 0 ) - index += count(); + auto index = m_data->currentIndex + steps; - update(); - Q_EMIT currentIndexChanged( index ); + auto newIndex = index % count(); + if ( newIndex < 0 ) + newIndex += count(); + + if ( hasAnimationHint( Cursor | QskAspect::Metric ) ) + { + // when cycling we want slide in + + if ( index < 0 ) + setPositionHint( Cursor, count() ); + + if ( index >= count() ) + setPositionHint( Cursor, -1 ); + + movePositionHint( Cursor, newIndex ); + } + + setCurrentIndex( newIndex ); } QskColorFilter QskMenu::graphicFilterAt( int index ) const @@ -288,6 +307,10 @@ void QskMenu::mouseReleaseEvent( QMouseEvent* event ) void QskMenu::aboutToShow() { setGeometry( QRectF( m_data->origin, sizeConstraint() ) ); + + if ( m_data->currentIndex < 0 ) + setCurrentIndex( 0 ); + Inherited::aboutToShow(); } diff --git a/src/controls/QskMenuSkinlet.cpp b/src/controls/QskMenuSkinlet.cpp index c66a8dfb..90e945ba 100644 --- a/src/controls/QskMenuSkinlet.cpp +++ b/src/controls/QskMenuSkinlet.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -222,20 +223,57 @@ QskMenuSkinlet::QskMenuSkinlet( QskSkin* skin ) appendNodeRoles( { PanelRole } ); } +QRectF QskMenuSkinlet::cursorRect( + const QskSkinnable* skinnable, const QRectF& contentsRect, int index ) const +{ + const auto count = sampleCount( skinnable, QskMenu::Cell ); + + auto rect = sampleRect( skinnable, contentsRect, + QskMenu::Cell, qBound( 0, index, count ) ); + + if ( index < 0 ) + rect.setBottom( rect.top() ); + + if ( index >= count ) + rect.setTop( rect.bottom() ); + + return rect; +} + QRectF QskMenuSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { + using Q = QskMenu; + const auto menu = static_cast< const QskMenu* >( skinnable ); - if( subControl == QskMenu::Panel ) + if( subControl == Q::Panel ) { return contentsRect; } - if( subControl == QskMenu::Cursor ) + if( subControl == Q::Cursor ) { - return menu->cellRect( menu->currentIndex() ); + if ( menu->currentIndex() < 0 ) + return QRectF(); + + const qreal pos = menu->positionHint( Q::Cursor ); + + const int pos1 = qFloor( pos ); + const int pos2 = qCeil( pos ); + + auto rect = cursorRect( skinnable, contentsRect, pos1 ); + + if ( pos1 != pos2 ) + { + const auto r = cursorRect( skinnable, contentsRect, pos2 ); + + const qreal ratio = ( pos - pos1 ) / ( pos2 - pos1 ); + rect = qskInterpolatedRect( rect, r, ratio ); + } + + return rect; } return Inherited::subControlRect( skinnable, contentsRect, subControl ); diff --git a/src/controls/QskMenuSkinlet.h b/src/controls/QskMenuSkinlet.h index 500f93a1..2738654a 100644 --- a/src/controls/QskMenuSkinlet.h +++ b/src/controls/QskMenuSkinlet.h @@ -49,6 +49,8 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet QskAspect::Subcontrol, int index, QSGNode* ) const override; private: + QRectF cursorRect( const QskSkinnable*, const QRectF&, int index ) const; + class PrivateData; std::unique_ptr< PrivateData > m_data; };