diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 418ee92d..ea20539d 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -482,6 +482,8 @@ void Editor::setupSegmentedBar() using A = QskAspect; using Q = QskSegmentedBar; + const uint duration = 100; + { // Panel @@ -521,7 +523,7 @@ void Editor::setupSegmentedBar() setGradient( Q::Cursor | Q::Disabled, QColor( Qt::gray ).darker( 110 ) ); setBoxBorderColors( Q::Cursor | Q::Disabled, Qt::gray ); - setAnimation( Q::Cursor | A::Metric | A::Position, 100 ); + setAnimation( Q::Cursor | A::Metric | A::Position, duration ); } for( auto subControl : { Q::Panel, Q::Cursor } ) @@ -537,6 +539,8 @@ void Editor::setupSegmentedBar() for( auto state : { A::NoState, Q::Selected } ) setColor( Q::Text | state | Q::Disabled, m_pal.darker200 ); + + setAnimation( Q::Text | A::Color, duration ); } { diff --git a/src/controls/QskEvent.cpp b/src/controls/QskEvent.cpp index ba479d7a..cd84b5f4 100644 --- a/src/controls/QskEvent.cpp +++ b/src/controls/QskEvent.cpp @@ -208,9 +208,10 @@ QskGestureEvent* QskGestureEvent::clone() const // -- QskAnimatorEvent -QskAnimatorEvent::QskAnimatorEvent( QskAspect aspect, State state ) +QskAnimatorEvent::QskAnimatorEvent( QskAspect aspect, int index, State state ) : QskEvent( QskEvent::Animator ) , m_aspect( aspect ) + , m_index( index ) , m_state( state ) { } diff --git a/src/controls/QskEvent.h b/src/controls/QskEvent.h index ef91e5fc..4a0180c4 100644 --- a/src/controls/QskEvent.h +++ b/src/controls/QskEvent.h @@ -143,9 +143,10 @@ class QSK_EXPORT QskAnimatorEvent : public QskEvent Terminated }; - QskAnimatorEvent( QskAspect aspect, State state ); + QskAnimatorEvent( QskAspect aspect, int index, State state ); inline QskAspect aspect() const { return m_aspect; } + inline int index() const { return m_index; } inline State state() const { return m_state; } QskAnimatorEvent* clone() const override; @@ -155,6 +156,7 @@ class QSK_EXPORT QskAnimatorEvent : public QskEvent private: QskAspect m_aspect; + int m_index; State m_state; }; diff --git a/src/controls/QskHintAnimator.cpp b/src/controls/QskHintAnimator.cpp index af4dcd5c..e8a700bd 100644 --- a/src/controls/QskHintAnimator.cpp +++ b/src/controls/QskHintAnimator.cpp @@ -92,8 +92,9 @@ static inline bool qskCheckReceiverThread( const QObject* receiver ) return ( thread == QThread::currentThread() ); } -QskHintAnimator::QskHintAnimator( const QskAspect aspect ) noexcept +QskHintAnimator::QskHintAnimator( const QskAspect aspect, int index ) noexcept : m_aspect( aspect ) + , m_index( index ) { } @@ -106,6 +107,11 @@ void QskHintAnimator::setAspect( const QskAspect aspect ) noexcept m_aspect = aspect; } +void QskHintAnimator::setIndex( int index ) noexcept +{ + m_index = index; +} + void QskHintAnimator::setUpdateFlags( QskAnimationHint::UpdateFlags flags ) noexcept { m_updateFlags = flags; @@ -167,11 +173,14 @@ QDebug operator<<( QDebug debug, const QskHintAnimator& animator ) debug << animator.aspect() << ", " << animator.endValue().typeName() << ", "; + if ( animator.index() >= 0 ) + debug << animator.index() << ", "; + if ( animator.isRunning() ) debug << "R: " << animator.duration() << ", " << animator.elapsed(); else debug << "S" << animator.duration(); - + if ( auto control = animator.control() ) debug << ", " << control->className() << ", " << (void*) control; @@ -192,28 +201,46 @@ namespace qDeleteAll( *this ); } - inline const QskHintAnimator* find( const QskAspect aspect ) const + inline const QskHintAnimator* find( const QskAspect aspect, int index ) const { - auto it = std::lower_bound( cbegin(), cend(), aspect, lessThan ); - if ( it != cend() && (*it)->aspect() == aspect ) - return *it; + const Key key { aspect, index }; + + auto it = std::lower_bound( cbegin(), cend(), key, lessThan ); + if ( it != cend() ) + { + if ( ( ( *it )->aspect() == aspect ) && ( ( *it )->index() == index ) ) + return *it; + } return nullptr; } - inline QskHintAnimator* findOrInsert( const QskAspect aspect ) + inline QskHintAnimator* findOrInsert( const QskAspect aspect, int index ) { - auto it = std::lower_bound( begin(), end(), aspect, lessThan ); - if ( it == end() || (*it)->aspect() != aspect ) - it = insert( it, new QskHintAnimator( aspect ) ); + const Key key { aspect, index }; + + auto it = std::lower_bound( begin(), end(), key, lessThan ); + if ( it == end() || ( *it )->aspect() != aspect || ( *it )->index() != index ) + { + it = insert( it, new QskHintAnimator( aspect, index ) ); + } return *it; } private: - static inline bool lessThan( const QskHintAnimator* animator, const QskAspect& aspect ) + struct Key { - return animator->aspect() < aspect; + QskAspect aspect; + int index; + }; + + static inline bool lessThan( const QskHintAnimator* animator, const Key& key ) + { + if ( animator->aspect() == key.aspect ) + return animator->index() < key.index; + + return animator->aspect() < key.aspect; } }; @@ -281,7 +308,7 @@ QskHintAnimatorTable::~QskHintAnimatorTable() } void QskHintAnimatorTable::start( QskControl* control, - QskAspect aspect, QskAnimationHint animationHint, + const QskAspect aspect, int index, QskAnimationHint animationHint, const QVariant& from, const QVariant& to ) { if ( m_data == nullptr ) @@ -292,7 +319,7 @@ void QskHintAnimatorTable::start( QskControl* control, qskAnimatorGuard->registerTable( this ); } - auto animator = m_data->animators.findOrInsert( aspect ); + auto animator = m_data->animators.findOrInsert( aspect, index ); animator->setStartValue( from ); animator->setEndValue( to ); @@ -308,24 +335,24 @@ void QskHintAnimatorTable::start( QskControl* control, if ( qskCheckReceiverThread( control ) ) { - QskAnimatorEvent event( aspect, QskAnimatorEvent::Started ); + QskAnimatorEvent event( aspect, index, QskAnimatorEvent::Started ); QCoreApplication::sendEvent( control, &event ); } } -const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect ) const +const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const { if ( m_data ) - return m_data->animators.find( aspect ); + return m_data->animators.find( aspect, index ); return nullptr; } -QVariant QskHintAnimatorTable::currentValue( QskAspect aspect ) const +QVariant QskHintAnimatorTable::currentValue( QskAspect aspect, int index ) const { if ( m_data ) { - if ( auto animator = m_data->animators.find( aspect ) ) + if ( auto animator = m_data->animators.find( aspect, index ) ) { if ( animator->isRunning() ) return animator->currentValue(); @@ -340,7 +367,7 @@ bool QskHintAnimatorTable::cleanup() if ( m_data == nullptr ) return true; - auto &animators = m_data->animators; + auto& animators = m_data->animators; for ( auto it = animators.begin(); it != animators.end(); ) { @@ -351,6 +378,7 @@ bool QskHintAnimatorTable::cleanup() { const auto control = animator->control(); const auto aspect = animator->aspect(); + const auto index = animator->index(); delete animator; @@ -360,7 +388,9 @@ bool QskHintAnimatorTable::cleanup() { if ( qskCheckReceiverThread( control ) ) { - auto event = new QskAnimatorEvent( aspect, QskAnimatorEvent::Terminated ); + auto event = new QskAnimatorEvent( + aspect, index, QskAnimatorEvent::Terminated ); + QCoreApplication::postEvent( control, event ); } } diff --git a/src/controls/QskHintAnimator.h b/src/controls/QskHintAnimator.h index 71705a2a..96a1123b 100644 --- a/src/controls/QskHintAnimator.h +++ b/src/controls/QskHintAnimator.h @@ -19,12 +19,17 @@ class QSK_EXPORT QskHintAnimator : public QskVariantAnimator using Inherited = QskVariantAnimator; public: - QskHintAnimator( QskAspect = QskAspect() ) noexcept; + QskHintAnimator() noexcept = default; + QskHintAnimator( QskAspect, int index ) noexcept; + ~QskHintAnimator() override; void setAspect( QskAspect ) noexcept; QskAspect aspect() const noexcept; + void setIndex( int ) noexcept; + int index() const noexcept; + void setControl( QskControl* ) noexcept; QskControl* control() const noexcept; @@ -37,6 +42,7 @@ class QSK_EXPORT QskHintAnimator : public QskVariantAnimator private: QskAspect m_aspect; + int m_index = -1; QskAnimationHint::UpdateFlags m_updateFlags; QPointer< QskControl > m_control; }; @@ -54,11 +60,11 @@ class QSK_EXPORT QskHintAnimatorTable QskHintAnimatorTable(); ~QskHintAnimatorTable(); - void start( QskControl*, QskAspect, + void start( QskControl*, QskAspect, int index, QskAnimationHint, const QVariant& from, const QVariant& to ); - const QskHintAnimator* animator( QskAspect ) const; - QVariant currentValue( QskAspect ) const; + const QskHintAnimator* animator( QskAspect, int index = -1 ) const; + QVariant currentValue( QskAspect, int index = -1 ) const; bool cleanup(); bool isEmpty() const; @@ -75,6 +81,11 @@ inline QskAspect QskHintAnimator::aspect() const noexcept return m_aspect; } +inline int QskHintAnimator::index() const noexcept +{ + return m_index; +} + inline QskAnimationHint::UpdateFlags QskHintAnimator::updateFlags() const noexcept { return m_updateFlags; diff --git a/src/controls/QskSegmentedBar.cpp b/src/controls/QskSegmentedBar.cpp index d2a95ca0..14275b92 100644 --- a/src/controls/QskSegmentedBar.cpp +++ b/src/controls/QskSegmentedBar.cpp @@ -371,6 +371,7 @@ void QskSegmentedBar::setSelectedIndex( int index ) if( index != m_data->selectedIndex ) { + const auto oldIndex = m_data->selectedIndex; m_data->selectedIndex = index; movePositionHint( Cursor, index ); @@ -380,6 +381,14 @@ void QskSegmentedBar::setSelectedIndex( int index ) setSkinStateFlag( Minimum, ( m_data->selectedIndex == 0 ) ); setSkinStateFlag( Maximum, ( m_data->selectedIndex == count() - 1 ) ); + + const auto states = skinStates(); + + if ( oldIndex >= 0 ) + startHintTransitions( states | Selected, states, oldIndex ); + + if ( index >= 0 ) + startHintTransitions( states, states | Selected, index ); } } diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index a7cf17b7..3279bdf1 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -242,6 +242,8 @@ class QskSkinlet::PrivateData QskSkin* skin; QVector< quint8 > nodeRoles; + int animatorIndex = -1; + bool ownedBySkinnable : 1; }; @@ -269,6 +271,21 @@ 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; @@ -693,6 +710,25 @@ QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable, 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 ); + newNode = updateSampleNode( skinnable, subControl, i, node ); } diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 127af44e..79fa7554 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -71,6 +71,10 @@ 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 5c292424..b84afc29 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -938,13 +938,11 @@ QVariant QskSkinnable::animatedHint( if ( !m_data->animators.isEmpty() ) { - /* - The local animators were invented to be stateless - and we never have an aspect with a state here. - But that might change ... - */ + const int index = effectiveSkinlet()->animatorIndex(); - v = m_data->animators.currentValue( aspect ); + v = m_data->animators.currentValue( aspect, index ); + if ( !v.isValid() && index >= 0 ) + v = m_data->animators.currentValue( aspect, -1 ); } if ( status && v.isValid() ) @@ -1221,11 +1219,17 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const void QskSkinnable::startTransition( QskAspect aspect, QskAnimationHint animationHint, const QVariant& from, const QVariant& to ) { - aspect.setSubControl( effectiveSubcontrol( aspect.subControl() ) ); - startHintTransition( aspect, animationHint, from, to ); + startTransition( aspect, -1, animationHint, from, to ); } -void QskSkinnable::startHintTransition( QskAspect aspect, +void QskSkinnable::startTransition( QskAspect aspect, int index, + QskAnimationHint animationHint, const QVariant& from, const QVariant& to ) +{ + aspect.setSubControl( effectiveSubcontrol( aspect.subControl() ) ); + startHintTransition( aspect, index, animationHint, from, to ); +} + +void QskSkinnable::startHintTransition( QskAspect aspect, int index, QskAnimationHint animationHint, const QVariant& from, const QVariant& to ) { if ( animationHint.duration <= 0 || ( from == to ) ) @@ -1263,11 +1267,11 @@ void QskSkinnable::startHintTransition( QskAspect aspect, qDebug() << aspect << animationHint.duration; #endif - auto animator = m_data->animators.animator( aspect ); + auto animator = m_data->animators.animator( aspect, index ); if ( animator && animator->isRunning() ) v1 = animator->currentValue(); - m_data->animators.start( control, aspect, animationHint, v1, v2 ); + m_data->animators.start( control, aspect, index, animationHint, v1, v2 ); } void QskSkinnable::setSkinStateFlag( QskAspect::State stateFlag, bool on ) @@ -1333,7 +1337,7 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates ) } bool QskSkinnable::startHintTransitions( - QskAspect::States oldStates, QskAspect::States newStates ) + QskAspect::States oldStates, QskAspect::States newStates, int index ) { if ( !isTransitionAccepted( QskAspect() ) ) { @@ -1390,13 +1394,13 @@ bool QskSkinnable::startHintTransitions( that are finally resolved from the same hint in the skin table. */ - + doTransition = !skinTable.isResolutionMatching( a1, a2 ); } if ( doTransition ) { - startHintTransition( aspect, hint, + startHintTransition( aspect, index, hint, storedHint( a1 ), storedHint( a2 ) ); started = true; diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index b585fcac..e09bb84c 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -124,6 +124,9 @@ class QSK_EXPORT QskSkinnable void startTransition( QskAspect, QskAnimationHint, const QVariant& from, const QVariant& to ); + void startTransition( QskAspect, int index, + QskAnimationHint, const QVariant& from, const QVariant& to ); + QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const; QskControl* controlCast(); @@ -247,6 +250,8 @@ class QSK_EXPORT QskSkinnable const QskSkinHintTable& hintTable() const; + bool startHintTransitions( QskAspect::States, QskAspect::States, int index = -1 ); + protected: virtual void updateNode( QSGNode* ); virtual bool isTransitionAccepted( QskAspect ) const; @@ -258,8 +263,7 @@ class QSK_EXPORT QskSkinnable private: Q_DISABLE_COPY( QskSkinnable ) - bool startHintTransitions( QskAspect::States, QskAspect::States ); - void startHintTransition( QskAspect, + void startHintTransition( QskAspect, int index, QskAnimationHint, const QVariant& from, const QVariant& to ); QVariant animatedHint( QskAspect, QskSkinHintStatus* ) const;