From 3eb62bb692b299bccc611c4f8fe48932de49201d Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Thu, 10 Aug 2023 18:43:24 +0200 Subject: [PATCH] smooth state transitions for listbox row selections --- src/controls/QskListView.cpp | 11 +++------ src/controls/QskListViewSkinlet.cpp | 4 +-- src/controls/QskSkinStateChanger.h | 11 ++++----- src/controls/QskSkinlet.cpp | 38 +---------------------------- src/controls/QskSkinlet.h | 4 --- src/controls/QskSkinnable.cpp | 25 ++++++++++++++----- src/controls/QskSkinnable.h | 6 +++-- 7 files changed, 34 insertions(+), 65 deletions(-) diff --git a/src/controls/QskListView.cpp b/src/controls/QskListView.cpp index e1bae2f7..b74e0c38 100644 --- a/src/controls/QskListView.cpp +++ b/src/controls/QskListView.cpp @@ -76,15 +76,10 @@ class QskListView::PrivateData inline void startTransitions( QskListView* listView, int row, QskAspect::States oldStates, QskAspect::States newStates ) { - /* - working implementation can be found in - https://github.com/uwerat/qskinny/tree/features/listview - */ + using Q = QskListView; - Q_UNUSED( listView ); - Q_UNUSED( row ); - Q_UNUSED( oldStates ); - Q_UNUSED( newStates ); + listView->startHintTransitions( + { Q::Cell, Q::Text }, oldStates, newStates, row ); } public: diff --git a/src/controls/QskListViewSkinlet.cpp b/src/controls/QskListViewSkinlet.cpp index 33de9cba..77907d75 100644 --- a/src/controls/QskListViewSkinlet.cpp +++ b/src/controls/QskListViewSkinlet.cpp @@ -204,7 +204,7 @@ void QskListViewSkinlet::updateBackgroundNodes( for ( int row = listViewNode->rowMin(); row <= listViewNode->rowMax(); row++ ) { QskSkinStateChanger stateChanger( listView ); - stateChanger.setStates( sampleStates( listView, Q::Cell, row ) ); + stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row ); const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row ); @@ -391,7 +391,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView, using namespace QskSGNode; QskSkinStateChanger stateChanger( listView ); - stateChanger.setStates( sampleStates( listView, Q::Cell, row ) ); + stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row ); QSGNode* newNode = nullptr; diff --git a/src/controls/QskSkinStateChanger.h b/src/controls/QskSkinStateChanger.h index f13d3145..906fdbae 100644 --- a/src/controls/QskSkinStateChanger.h +++ b/src/controls/QskSkinStateChanger.h @@ -15,7 +15,7 @@ class QskSkinStateChanger QskSkinStateChanger( const QskSkinnable* ); ~QskSkinStateChanger(); - void setStates( QskAspect::States ); + void setStates( QskAspect::States, int sampleIndex = -1 ); void resetStates(); private: @@ -34,16 +34,15 @@ inline QskSkinStateChanger::~QskSkinStateChanger() resetStates(); } -inline void QskSkinStateChanger::setStates( QskAspect::States states ) +inline void QskSkinStateChanger::setStates( + QskAspect::States states, int sampleIndex ) { - if ( states != m_skinnable->skinStates() ) - m_skinnable->replaceSkinStates( states ); + m_skinnable->replaceSkinStates( states, sampleIndex ); } inline void QskSkinStateChanger::resetStates() { - if ( m_oldStates != m_skinnable->skinStates() ) - m_skinnable->replaceSkinStates( m_oldStates ); + m_skinnable->replaceSkinStates( m_oldStates, -1 ); } #endif diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index d19a1e93..e6351519 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -282,8 +282,6 @@ class QskSkinlet::PrivateData QskSkin* skin; QVector< quint8 > nodeRoles; - int animatorIndex = -1; - bool ownedBySkinnable : 1; }; @@ -311,21 +309,6 @@ bool QskSkinlet::isOwnedBySkinnable() const return m_data->ownedBySkinnable; } -void QskSkinlet::setAnimatorIndex( int index ) -{ - m_data->animatorIndex = index; -} - -void QskSkinlet::resetAnimatorIndex() -{ - m_data->animatorIndex = -1; -} - -int QskSkinlet::animatorIndex() const -{ - return m_data->animatorIndex; -} - void QskSkinlet::setNodeRoles( const QVector< quint8 >& nodeRoles ) { m_data->nodeRoles = nodeRoles; @@ -796,26 +779,7 @@ QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable, const auto newStates = sampleStates( skinnable, subControl, i ); QskSkinStateChanger stateChanger( skinnable ); - stateChanger.setStates( newStates ); - - class IndexChanger - { - public: - inline IndexChanger( const QskSkinlet* skinlet, int index ) - : m_skinlet( const_cast< QskSkinlet* >( skinlet ) ) - { - m_skinlet->setAnimatorIndex( index ); - } - - inline ~IndexChanger() - { - m_skinlet->resetAnimatorIndex(); - } - private: - QskSkinlet* m_skinlet; - }; - - IndexChanger indexChanger( this, i ); + stateChanger.setStates( newStates, i ); newNode = updateSampleNode( skinnable, subControl, i, node ); } diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 44291712..3cfc7db0 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -71,10 +71,6 @@ class QSK_EXPORT QskSkinlet void setOwnedBySkinnable( bool on ); bool isOwnedBySkinnable() const; - void setAnimatorIndex( int ); - void resetAnimatorIndex(); - int animatorIndex() const; - // Helper functions for creating nodes static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 52430f34..fa97a45f 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -248,6 +248,8 @@ class QskSkinnable::PrivateData QskSkinHintTable hintTable; QskHintAnimatorTable animators; + int sampleIndex = -1; // for the ugly QskSkinStateChanger hack + typedef std::map< QskAspect::Subcontrol, QskAspect::Subcontrol > ProxyMap; ProxyMap* subcontrolProxies = nullptr; @@ -993,11 +995,11 @@ QVariant QskSkinnable::animatedHint( if ( !m_data->animators.isEmpty() ) { - const int index = effectiveSkinlet()->animatorIndex(); + const auto a = qskAnimatorAspect( aspect ); - v = m_data->animators.currentValue( aspect, index ); - if ( !v.isValid() && index >= 0 ) - v = m_data->animators.currentValue( aspect, -1 ); + v = m_data->animators.currentValue( a, m_data->sampleIndex ); + if ( !v.isValid() && m_data->sampleIndex >= 0 ) + v = m_data->animators.currentValue( a, -1 ); } if ( status && v.isValid() ) @@ -1309,7 +1311,7 @@ void QskSkinnable::startHintTransition( QskAspect aspect, int index, aspect = qskAnimatorAspect( aspect ); #if DEBUG_ANIMATOR - qDebug() << aspect << animationHint.duration; + qDebug() << aspect << index << animationHint.duration; #endif auto animator = m_data->animators.animator( aspect, index ); @@ -1328,9 +1330,20 @@ void QskSkinnable::setSkinStateFlag( QskAspect::State stateFlag, bool on ) setSkinStates( newState ); } -void QskSkinnable::replaceSkinStates( QskAspect::States newStates ) +void QskSkinnable::replaceSkinStates( + QskAspect::States newStates, int sampleIndex ) { + /* + Hack time: we might need different hints for a specific instance + of a subcontrol ( f.e the selected row in a list box ), what is not + supported by QskAspect. + + As a workaround we use QskSkinStateChanger, that sets/restores this state/index + while retrieving the skin hints. + */ + m_data->skinStates = newStates; + m_data->sampleIndex = sampleIndex; // needed to find specific animators } void QskSkinnable::addSkinStates( QskAspect::States states ) diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index d8e455a2..51d2f1a7 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -39,6 +39,7 @@ class QskGraphic; class QskSkin; class QskSkinlet; class QskSkinHintTable; +class QskSkinStateChanger; class QSK_EXPORT QskSkinHintStatus { @@ -149,8 +150,6 @@ class QSK_EXPORT QskSkinnable void addSkinStates( QskAspect::States ); void clearSkinStates( QskAspect::States ); - void replaceSkinStates( QskAspect::States ); - bool hasSkinState( QskAspect::State ) const; QskAspect::States skinStates() const; @@ -281,6 +280,9 @@ class QSK_EXPORT QskSkinnable QVariant interpolatedHint( QskAspect, QskSkinHintStatus* ) const; const QVariant& storedHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + friend class QskSkinStateChanger; + void replaceSkinStates( QskAspect::States, int sampleIndex = -1 ); + class PrivateData; std::unique_ptr< PrivateData > m_data; };