From 2a7a68e91506855f5f06ee7f8d04c54e326ae36a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 12 May 2023 14:58:40 +0200 Subject: [PATCH] wip --- src/controls/QskMenu.cpp | 74 +++++++++++++++++++++++---------- src/controls/QskMenu.h | 8 ++-- src/controls/QskMenuSkinlet.cpp | 63 ++++++++++++---------------- 3 files changed, 82 insertions(+), 63 deletions(-) diff --git a/src/controls/QskMenu.cpp b/src/controls/QskMenu.cpp index 4d2395fe..63b62abb 100644 --- a/src/controls/QskMenu.cpp +++ b/src/controls/QskMenu.cpp @@ -28,13 +28,25 @@ QSK_SUBCONTROL( QskMenu, Separator ) QSK_SYSTEM_STATE( QskMenu, Selected, QskAspect::FirstSystemState << 2 ) +QVector< int > qskSeparators( const QVector< QskLabelData >& options ) +{ + QVector< int > separators; + + for ( int i = 0; i < options.count(); i++ ) + { + if ( options[i].isEmpty() ) + separators += i; + } + + return separators; +} + class QskMenu::PrivateData { public: QPointF origin; QVector< QskLabelData > options; - // QVector< bool > enabled; QVector< int > separators; int triggeredIndex = -1; @@ -128,13 +140,16 @@ int QskMenu::addOption( const QskLabelData& option ) { m_data->options += option; + if ( option.isEmpty() ) + m_data->separators += m_data->options.count() - 1; + resetImplicitSize(); update(); if ( isComponentComplete() ) Q_EMIT optionsChanged(); - return count() - 1; + return m_data->options.count() - 1; } void QskMenu::setOptions( const QStringList& options ) @@ -145,6 +160,7 @@ void QskMenu::setOptions( const QStringList& options ) void QskMenu::setOptions( const QVector< QskLabelData >& options ) { m_data->options = options; + m_data->separators = qskSeparators( options ); if ( m_data->currentIndex >= 0 ) { @@ -163,7 +179,6 @@ void QskMenu::setOptions( const QVector< QskLabelData >& options ) void QskMenu::clear() { - m_data->separators.clear(); setOptions( QVector< QskLabelData >() ); } @@ -177,27 +192,19 @@ QskLabelData QskMenu::optionAt( int index ) const return m_data->options.value( index ); } -int QskMenu::count() const +int QskMenu::optionsCount() const { return m_data->options.count(); } void QskMenu::addSeparator() { - m_data->separators += m_data->options.count(); - - resetImplicitSize(); - update(); + addOption( QskLabelData() ); } -int QskMenu::separatorPosition( int index ) const +QVector< int > QskMenu::separators() const { - return m_data->separators.value( index, -1 ); -} - -int QskMenu::separatorCount() const -{ - return m_data->separators.count(); + return m_data->separators; } int QskMenu::currentIndex() const @@ -207,8 +214,15 @@ int QskMenu::currentIndex() const void QskMenu::setCurrentIndex( int index ) { - if( index < 0 || index >= count() ) + if( index < 0 || index >= m_data->options.count() ) + { index = -1; + } + else + { + if ( m_data->options[index].isEmpty() ) // a seperator + index = -1; + } if( index != m_data->currentIndex ) { @@ -308,22 +322,38 @@ void QskMenu::wheelEvent( QWheelEvent* event ) void QskMenu::traverse( int steps ) { - if ( count() == 0 || ( steps % count() == 0 ) ) + const auto count = m_data->options.count(); + + const auto n = count - m_data->separators.count(); + if ( ( n <= 0 ) || ( steps % n == 0 ) ) return; - auto index = m_data->currentIndex + steps; + auto index = m_data->currentIndex; + for ( auto i : m_data->separators ) + { + if ( i < index ) + index--; + } - auto newIndex = index % count(); + index += steps; + + auto newIndex = index % n; if ( newIndex < 0 ) - newIndex += count(); + newIndex += n; + + for ( int i = 0; i < newIndex; i++) + { + if ( m_data->options[i].isEmpty() ) + newIndex++; + } // when cycling we want slide in int startIndex = m_data->currentIndex; if ( index < 0 ) - startIndex = count(); - else if ( index >= count() ) + startIndex = count; + else if ( index >= n ) startIndex = -1; movePositionHint( Cursor, startIndex, newIndex ); diff --git a/src/controls/QskMenu.h b/src/controls/QskMenu.h index 5d46223a..fb51ed8e 100644 --- a/src/controls/QskMenu.h +++ b/src/controls/QskMenu.h @@ -26,7 +26,7 @@ class QSK_EXPORT QskMenu : public QskPopup Q_PROPERTY( QVector< QskLabelData > options READ options WRITE setOptions NOTIFY optionsChanged ) - Q_PROPERTY( int count READ count ) + Q_PROPERTY( int optionsCount READ optionsCount ) Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged ) @@ -65,12 +65,10 @@ class QSK_EXPORT QskMenu : public QskPopup QVector< QskLabelData > options() const; QskLabelData optionAt( int ) const; - int count() const; + int optionsCount() const; void addSeparator(); - - int separatorPosition( int ) const; - int separatorCount() const; + QVector< int > separators() const; void clear(); diff --git a/src/controls/QskMenuSkinlet.cpp b/src/controls/QskMenuSkinlet.cpp index 9198a955..cc5c39c5 100644 --- a/src/controls/QskMenuSkinlet.cpp +++ b/src/controls/QskMenuSkinlet.cpp @@ -47,10 +47,12 @@ class QskMenuSkinlet::PrivateData inline int separatorsBefore( const QskMenu* menu, int index ) const { + const auto separators = menu->separators(); + int i = 0; - for ( ; i < menu->separatorCount(); i++ ) + for ( ; i < separators.count(); i++ ) { - if ( menu->separatorPosition( i ) > index ) + if ( separators[i] >= index ) break; } @@ -112,26 +114,22 @@ class QskMenuSkinlet::PrivateData private: qreal graphicWidthInternal( const QskMenu* menu ) const { - const auto skinlet = menu->effectiveSkinlet(); - const auto hint = menu->strutSizeHint( QskMenu::Icon ); const qreal textHeight = menu->effectiveFontHeight( QskMenu::Text ); const auto h = qMax( hint.height(), textHeight ); qreal maxW = 0.0; - for ( int i = 0; i < menu->count(); i++ ) + + const auto options = menu->options(); + for ( auto& option : options ) { - const auto sample = skinlet->sampleAt( menu, QskMenu::Icon, i ); - if ( sample.canConvert< QskGraphic >() ) + const auto graphic = option.icon().graphic(); + if ( !graphic.isNull() ) { - const auto graphic = sample.value< QskGraphic >(); - if ( !graphic.isNull() ) - { - const auto w = graphic.widthForHeight( h ); - if( w > maxW ) - maxW = w; - } + const auto w = graphic.widthForHeight( h ); + if( w > maxW ) + maxW = w; } } @@ -140,24 +138,18 @@ class QskMenuSkinlet::PrivateData qreal textWidthInternal( const QskMenu* menu ) const { - const auto skinlet = menu->effectiveSkinlet(); - const QFontMetricsF fm( menu->effectiveFont( QskMenu::Text ) ); auto maxWidth = 0.0; - for ( int i = 0; i < menu->count(); i++ ) + const auto options = menu->options(); + for ( auto& option : options ) { - const auto sample = skinlet->sampleAt( menu, QskMenu::Text, i ); - if ( sample.canConvert< QString >() ) + if( !option.text().isEmpty() ) { - const auto text = sample.toString(); - if( !text.isEmpty() ) - { - const auto w = qskHorizontalAdvance( fm, text ); - if( w > maxWidth ) - maxWidth = w; - } + const auto w = qskHorizontalAdvance( fm, option.text() ); + if( w > maxWidth ) + maxWidth = w; } } @@ -324,17 +316,16 @@ QRectF QskMenuSkinlet::sampleRect( if ( subControl == QskMenu::Separator ) { - const int pos = menu->separatorPosition( index ); - if ( pos < 0 ) + const auto separators = menu->separators(); + if ( index >= separators.count() ) return QRectF(); - QRectF r = menu->subControlContentsRect( Q::Panel ); + const int pos = separators[ index ]; - if ( pos < menu->count() ) - { - const auto segmentRect = sampleRect( skinnable, contentsRect, Q::Segment, pos ); - r.setBottom( segmentRect.top() ); // spacing ??? - } + auto r = menu->subControlContentsRect( Q::Panel ); + + const auto segmentRect = sampleRect( skinnable, contentsRect, Q::Segment, pos ); + r.setBottom( segmentRect.top() ); // spacing ??? const qreal h = menu->metric( Q::Separator | QskAspect::Size ); r.setTop( r.bottom() - h ); @@ -362,13 +353,13 @@ int QskMenuSkinlet::sampleCount( if ( subControl == Q::Segment || subControl == Q::Icon || subControl == Q::Text ) { const auto menu = static_cast< const QskMenu* >( skinnable ); - return menu->count(); + return menu->optionsCount() - menu->separators().count(); } if ( subControl == Q::Separator ) { const auto menu = static_cast< const QskMenu* >( skinnable ); - return menu->separatorCount(); + return menu->separators().count(); } return Inherited::sampleCount( skinnable, subControl );