From f1a324b21676aa0db1d0c7dd111a9abdb3efb03e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 28 Dec 2021 10:08:21 +0100 Subject: [PATCH] QskSkinlet improved for subControls with multible instances --- src/controls/QskListViewSkinlet.cpp | 6 +-- src/controls/QskMenu.cpp | 4 +- src/controls/QskMenuSkinlet.cpp | 82 ++++++++++++++++------------- src/controls/QskMenuSkinlet.h | 8 +-- src/controls/QskSkinStateChanger.h | 27 +++------- src/controls/QskSkinlet.cpp | 26 ++++++--- src/controls/QskSkinlet.h | 22 +++++++- 7 files changed, 99 insertions(+), 76 deletions(-) diff --git a/src/controls/QskListViewSkinlet.cpp b/src/controls/QskListViewSkinlet.cpp index d7534798..8ac0575f 100644 --- a/src/controls/QskListViewSkinlet.cpp +++ b/src/controls/QskListViewSkinlet.cpp @@ -162,7 +162,7 @@ void QskListViewSkinlet::updateBackgroundNodes( if ( rowSelected >= rowMin && rowSelected <= rowMax ) { QskSkinStateChanger stateChanger( listView ); - stateChanger.addStates( QskListView::Selected ); + stateChanger.setStates( listView->skinStates() | QskListView::Selected ); const QColor color = listView->color( QskListView::Cell ); @@ -436,12 +436,12 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView, { using namespace QskSGNode; - QskAspect::States rowStates; + auto rowStates = listView->skinStates(); if ( row == listView->selectedRow() ) rowStates |= QskListView::Selected; QskSkinStateChanger stateChanger( listView ); - stateChanger.addStates( rowStates ); + stateChanger.setStates( rowStates ); QSGNode* newNode = nullptr; diff --git a/src/controls/QskMenu.cpp b/src/controls/QskMenu.cpp index aa215d99..7c914024 100644 --- a/src/controls/QskMenu.cpp +++ b/src/controls/QskMenu.cpp @@ -308,13 +308,13 @@ void QskMenu::setSelectedIndex( int index ) QRectF QskMenu::cellRect( int index ) const { - return effectiveSkinlet()->itemRect( + return effectiveSkinlet()->subControlCell( this, contentsRect(), QskMenu::Cell, index ); } int QskMenu::indexAtPosition( const QPointF& pos ) const { - return effectiveSkinlet()->itemIndexAt( + return effectiveSkinlet()->subControlCellIndexAt( this, contentsRect(), QskMenu::Cell, pos ); } diff --git a/src/controls/QskMenuSkinlet.cpp b/src/controls/QskMenuSkinlet.cpp index d8dc1f92..3e9a4c96 100644 --- a/src/controls/QskMenuSkinlet.cpp +++ b/src/controls/QskMenuSkinlet.cpp @@ -44,7 +44,7 @@ static qreal qskMaxTextWidth( const QskMenu* menu ) for ( int i = 0; i < menu->count(); i++ ) { const auto value = menu->itemAt( i ); - + const auto text = qskValueAt< QString >( menu, i ); if( !text.isEmpty() ) { @@ -131,6 +131,10 @@ static QSGNode* qskUpdateTextNode( const QskMenu* menu, static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode ) { + using Q = QskMenu; + + const auto skinlet = menu->effectiveSkinlet(); + auto node = rootNode ? rootNode->firstChild() : nullptr; QSGNode* lastNode = nullptr; @@ -140,11 +144,11 @@ static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode { QskSkinStateChanger stateChanger( menu ); - if ( menu->currentIndex() == i ) - stateChanger.addStates( QskMenu::Selected ); + stateChanger.setStates( + skinlet->subControlCellStates( menu, Q::Cell, i ) ); newNode = QskSkinlet::updateBoxNode( - menu, node, menu->cellRect( i ), QskMenu::Cell ); + menu, node, menu->cellRect( i ), Q::Cell ); } if ( newNode ) @@ -196,15 +200,21 @@ static void qskUpdateItemNode( static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode ) { - const auto spacing = menu->spacingHint( QskMenu::Cell ); + using Q = QskMenu; + + const auto skinlet = menu->effectiveSkinlet(); + + const auto spacing = menu->spacingHint( Q::Cell ); const auto graphicWidth = qskGraphicWidth( menu ); + const auto contentsRect = menu->contentsRect(); if ( rootNode == nullptr ) rootNode = new QSGNode(); QSGNode* node = nullptr; - for( int i = 0; i < menu->count(); i++ ) + const auto count = skinlet->subControlCellCount( menu, Q::Cell ); + for( int i = 0; i < count; i++ ) { if ( node == nullptr ) node = rootNode->firstChild(); @@ -219,10 +229,11 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode ) { QskSkinStateChanger stateChanger( menu ); - if ( menu->currentIndex() == i ) - stateChanger.addStates( QskMenu::Selected ); + stateChanger.setStates( + skinlet->subControlCellStates( menu, Q::Cell, i ) ); - const auto cellRect = menu->cellRect( i ); + const auto cellRect = skinlet->subControlCell( + menu, contentsRect, Q::Cell, i ); auto graphicRect = cellRect; graphicRect.setWidth( graphicWidth ); @@ -268,10 +279,11 @@ QRectF QskMenuSkinlet::subControlRect( return Inherited::subControlRect( skinnable, contentsRect, subControl ); } -QRectF QskMenuSkinlet::itemRect( +QRectF QskMenuSkinlet::subControlCell( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const { + // QskMenu::Text, QskMenu::Graphic ??? if ( subControl == QskMenu::Cell ) { const auto menu = static_cast< const QskMenu* >( skinnable ); @@ -285,43 +297,37 @@ QRectF QskMenuSkinlet::itemRect( return QRectF( r.x(), r.y() + index * h, r.width(), h ); } - return Inherited::itemRect( + return Inherited::subControlCell( skinnable, contentsRect, subControl, index ); } -int QskMenuSkinlet::itemIndexAt( const QskSkinnable* skinnable, - const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const +int QskMenuSkinlet::subControlCellCount( + const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const { + // QskMenu::Text, QskMenu::Graphic ??? if ( subControl == QskMenu::Cell ) { const auto menu = static_cast< const QskMenu* >( skinnable ); - - const auto panelRect = menu->subControlContentsRect( QskMenu::Panel ); - if ( !panelRect.contains( pos ) ) - return -1; - - /* - A menu never has many items and we can simply iterate - without being concerned about performance issues - */ - - const auto h = qskCellHeight( menu ); - - auto r = panelRect; - r.setHeight( h ); - - for ( int i = 0; i < menu->count(); i++ ) - { - if ( r.contains( pos ) ) - return i; - - r.moveTop( r.bottom() ); - } - - return -1; + return menu->count(); } - return Inherited::itemIndexAt( skinnable, rect, subControl, pos ); + return Inherited::subControlCellCount( skinnable, subControl ); +} + +QskAspect::States QskMenuSkinlet::subControlCellStates( + const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const +{ + auto states = Inherited::subControlCellStates( skinnable, subControl, index ); + + // QskMenu::Text, QskMenu::Graphic ??? + if ( subControl == QskMenu::Cell ) + { + const auto menu = static_cast< const QskMenu* >( skinnable ); + if ( menu->currentIndex() == index ) + states |= QskMenu::Selected; + } + + return states; } QSGNode* QskMenuSkinlet::updateContentsNode( diff --git a/src/controls/QskMenuSkinlet.h b/src/controls/QskMenuSkinlet.h index 1d6cf444..fd0df36a 100644 --- a/src/controls/QskMenuSkinlet.h +++ b/src/controls/QskMenuSkinlet.h @@ -23,11 +23,13 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet QRectF subControlRect( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol ) const override; - QRectF itemRect( const QskSkinnable*, + QRectF subControlCell( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol, int index ) const override; - int itemIndexAt( const QskSkinnable*, - const QRectF&, QskAspect::Subcontrol, const QPointF& ) const override; + int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const override; + + QskAspect::States subControlCellStates( const QskSkinnable*, + QskAspect::Subcontrol, int index ) const override; QSizeF sizeHint( const QskSkinnable*, Qt::SizeHint, const QSizeF& ) const override; diff --git a/src/controls/QskSkinStateChanger.h b/src/controls/QskSkinStateChanger.h index 454fd8f7..8fe85325 100644 --- a/src/controls/QskSkinStateChanger.h +++ b/src/controls/QskSkinStateChanger.h @@ -12,25 +12,20 @@ class QskSkinStateChanger { public: - QskSkinStateChanger( const QskSkinnable*, - QskAspect::States = QskAspect::States() ); - + QskSkinStateChanger( const QskSkinnable* ); ~QskSkinStateChanger(); - void addStates( QskAspect::States ); - void clearStates( QskAspect::States ); + void setStates( QskAspect::States ); private: QskSkinnable* m_skinnable; const QskAspect::States m_oldStates; }; -inline QskSkinStateChanger::QskSkinStateChanger( - const QskSkinnable* skinnable, QskAspect::States states ) +inline QskSkinStateChanger::QskSkinStateChanger( const QskSkinnable* skinnable ) : m_skinnable( const_cast< QskSkinnable* >( skinnable ) ) , m_oldStates( skinnable->skinStates() ) { - addStates( states ); } inline QskSkinStateChanger::~QskSkinStateChanger() @@ -39,20 +34,10 @@ inline QskSkinStateChanger::~QskSkinStateChanger() m_skinnable->replaceSkinStates( m_oldStates ); } -inline void QskSkinStateChanger::addStates( QskAspect::States states ) +inline void QskSkinStateChanger::setStates( QskAspect::States states ) { - const auto newStates = m_oldStates | states; - - if ( newStates != m_skinnable->skinStates() ) - m_skinnable->replaceSkinStates( newStates ); -} - -inline void QskSkinStateChanger::clearStates( QskAspect::States states ) -{ - const auto newStates = m_oldStates & ~states; - - if ( newStates != m_skinnable->skinStates() ) - m_skinnable->replaceSkinStates( newStates ); + if ( states != m_skinnable->skinStates() ) + m_skinnable->replaceSkinStates( states ); } #endif diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index a4bd9033..229b56eb 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -581,19 +581,31 @@ QSizeF QskSkinlet::hintWithoutConstraint( return h; } -int QskSkinlet::itemIndexAt( const QskSkinnable*, - const QRectF&, QskAspect::Subcontrol, const QPointF& ) const +int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable, + const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const { + /* + slow default implementation to be overloaded when + having many cells + */ + + const auto cellCount = subControlCellCount( skinnable, subControl ); + + for ( int i = 0; i < cellCount; i++ ) + { + const auto cellRect = subControlCell( skinnable, rect, subControl, i ); + if ( cellRect.contains( pos ) ) + return i; + } + return -1; } -QRectF QskSkinlet::itemRect( const QskSkinnable*, - const QRectF&, QskAspect::Subcontrol, int index ) const +QskAspect::States QskSkinlet::subControlCellStates( + const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const { - // When a subControl is for a unknown number of item, f.e. in a menu - Q_UNUSED( index ) - return QRectF(); + return skinnable->skinStates(); } #include "moc_QskSkinlet.cpp" diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 797d4b47..93fc71e5 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -42,12 +42,17 @@ class QSK_EXPORT QskSkinlet virtual QRectF subControlRect( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol ) const; - virtual QRectF itemRect( const QskSkinnable*, + virtual QRectF subControlCell( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol, int index ) const; - virtual int itemIndexAt( const QskSkinnable*, + virtual int subControlCellIndexAt( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol, const QPointF& ) const; + virtual int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const; + + virtual QskAspect::States subControlCellStates( const QskSkinnable*, + QskAspect::Subcontrol, int index ) const; + const QVector< quint8 >& nodeRoles() const; void setOwnedBySkinnable( bool on ); @@ -154,4 +159,17 @@ inline QSizeF QskSkinlet::sizeHint( return QSizeF(); } +inline QRectF QskSkinlet::subControlCell( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol, int index ) const +{ + Q_UNUSED( index ) + return QRectF(); +} + +inline int QskSkinlet::subControlCellCount( + const QskSkinnable*, QskAspect::Subcontrol ) const +{ + return 1; +} + #endif