index added for animator lookups to allow smooth transitions f.e when

selcting an cell in a list box
This commit is contained in:
Uwe Rathmann 2022-09-13 12:40:44 +02:00
parent 7ca1e2f261
commit 4f8a76234a
10 changed files with 149 additions and 44 deletions

View File

@ -482,6 +482,8 @@ void Editor::setupSegmentedBar()
using A = QskAspect; using A = QskAspect;
using Q = QskSegmentedBar; using Q = QskSegmentedBar;
const uint duration = 100;
{ {
// Panel // Panel
@ -521,7 +523,7 @@ void Editor::setupSegmentedBar()
setGradient( Q::Cursor | Q::Disabled, QColor( Qt::gray ).darker( 110 ) ); setGradient( Q::Cursor | Q::Disabled, QColor( Qt::gray ).darker( 110 ) );
setBoxBorderColors( Q::Cursor | Q::Disabled, Qt::gray ); 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 } ) for( auto subControl : { Q::Panel, Q::Cursor } )
@ -537,6 +539,8 @@ void Editor::setupSegmentedBar()
for( auto state : { A::NoState, Q::Selected } ) for( auto state : { A::NoState, Q::Selected } )
setColor( Q::Text | state | Q::Disabled, m_pal.darker200 ); setColor( Q::Text | state | Q::Disabled, m_pal.darker200 );
setAnimation( Q::Text | A::Color, duration );
} }
{ {

View File

@ -208,9 +208,10 @@ QskGestureEvent* QskGestureEvent::clone() const
// -- QskAnimatorEvent // -- QskAnimatorEvent
QskAnimatorEvent::QskAnimatorEvent( QskAspect aspect, State state ) QskAnimatorEvent::QskAnimatorEvent( QskAspect aspect, int index, State state )
: QskEvent( QskEvent::Animator ) : QskEvent( QskEvent::Animator )
, m_aspect( aspect ) , m_aspect( aspect )
, m_index( index )
, m_state( state ) , m_state( state )
{ {
} }

View File

@ -143,9 +143,10 @@ class QSK_EXPORT QskAnimatorEvent : public QskEvent
Terminated Terminated
}; };
QskAnimatorEvent( QskAspect aspect, State state ); QskAnimatorEvent( QskAspect aspect, int index, State state );
inline QskAspect aspect() const { return m_aspect; } inline QskAspect aspect() const { return m_aspect; }
inline int index() const { return m_index; }
inline State state() const { return m_state; } inline State state() const { return m_state; }
QskAnimatorEvent* clone() const override; QskAnimatorEvent* clone() const override;
@ -155,6 +156,7 @@ class QSK_EXPORT QskAnimatorEvent : public QskEvent
private: private:
QskAspect m_aspect; QskAspect m_aspect;
int m_index;
State m_state; State m_state;
}; };

View File

@ -92,8 +92,9 @@ static inline bool qskCheckReceiverThread( const QObject* receiver )
return ( thread == QThread::currentThread() ); return ( thread == QThread::currentThread() );
} }
QskHintAnimator::QskHintAnimator( const QskAspect aspect ) noexcept QskHintAnimator::QskHintAnimator( const QskAspect aspect, int index ) noexcept
: m_aspect( aspect ) : m_aspect( aspect )
, m_index( index )
{ {
} }
@ -106,6 +107,11 @@ void QskHintAnimator::setAspect( const QskAspect aspect ) noexcept
m_aspect = aspect; m_aspect = aspect;
} }
void QskHintAnimator::setIndex( int index ) noexcept
{
m_index = index;
}
void QskHintAnimator::setUpdateFlags( QskAnimationHint::UpdateFlags flags ) noexcept void QskHintAnimator::setUpdateFlags( QskAnimationHint::UpdateFlags flags ) noexcept
{ {
m_updateFlags = flags; m_updateFlags = flags;
@ -167,6 +173,9 @@ QDebug operator<<( QDebug debug, const QskHintAnimator& animator )
debug << animator.aspect() << ", " << animator.endValue().typeName() << ", "; debug << animator.aspect() << ", " << animator.endValue().typeName() << ", ";
if ( animator.index() >= 0 )
debug << animator.index() << ", ";
if ( animator.isRunning() ) if ( animator.isRunning() )
debug << "R: " << animator.duration() << ", " << animator.elapsed(); debug << "R: " << animator.duration() << ", " << animator.elapsed();
else else
@ -192,28 +201,46 @@ namespace
qDeleteAll( *this ); 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 ); const Key key { aspect, index };
if ( it != cend() && (*it)->aspect() == aspect )
return *it; auto it = std::lower_bound( cbegin(), cend(), key, lessThan );
if ( it != cend() )
{
if ( ( ( *it )->aspect() == aspect ) && ( ( *it )->index() == index ) )
return *it;
}
return nullptr; 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 ); const Key key { aspect, index };
if ( it == end() || (*it)->aspect() != aspect )
it = insert( it, new QskHintAnimator( aspect ) ); 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; return *it;
} }
private: 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, void QskHintAnimatorTable::start( QskControl* control,
QskAspect aspect, QskAnimationHint animationHint, const QskAspect aspect, int index, QskAnimationHint animationHint,
const QVariant& from, const QVariant& to ) const QVariant& from, const QVariant& to )
{ {
if ( m_data == nullptr ) if ( m_data == nullptr )
@ -292,7 +319,7 @@ void QskHintAnimatorTable::start( QskControl* control,
qskAnimatorGuard->registerTable( this ); qskAnimatorGuard->registerTable( this );
} }
auto animator = m_data->animators.findOrInsert( aspect ); auto animator = m_data->animators.findOrInsert( aspect, index );
animator->setStartValue( from ); animator->setStartValue( from );
animator->setEndValue( to ); animator->setEndValue( to );
@ -308,24 +335,24 @@ void QskHintAnimatorTable::start( QskControl* control,
if ( qskCheckReceiverThread( control ) ) if ( qskCheckReceiverThread( control ) )
{ {
QskAnimatorEvent event( aspect, QskAnimatorEvent::Started ); QskAnimatorEvent event( aspect, index, QskAnimatorEvent::Started );
QCoreApplication::sendEvent( control, &event ); QCoreApplication::sendEvent( control, &event );
} }
} }
const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect ) const const QskHintAnimator* QskHintAnimatorTable::animator( QskAspect aspect, int index ) const
{ {
if ( m_data ) if ( m_data )
return m_data->animators.find( aspect ); return m_data->animators.find( aspect, index );
return nullptr; return nullptr;
} }
QVariant QskHintAnimatorTable::currentValue( QskAspect aspect ) const QVariant QskHintAnimatorTable::currentValue( QskAspect aspect, int index ) const
{ {
if ( m_data ) if ( m_data )
{ {
if ( auto animator = m_data->animators.find( aspect ) ) if ( auto animator = m_data->animators.find( aspect, index ) )
{ {
if ( animator->isRunning() ) if ( animator->isRunning() )
return animator->currentValue(); return animator->currentValue();
@ -340,7 +367,7 @@ bool QskHintAnimatorTable::cleanup()
if ( m_data == nullptr ) if ( m_data == nullptr )
return true; return true;
auto &animators = m_data->animators; auto& animators = m_data->animators;
for ( auto it = animators.begin(); it != animators.end(); ) for ( auto it = animators.begin(); it != animators.end(); )
{ {
@ -351,6 +378,7 @@ bool QskHintAnimatorTable::cleanup()
{ {
const auto control = animator->control(); const auto control = animator->control();
const auto aspect = animator->aspect(); const auto aspect = animator->aspect();
const auto index = animator->index();
delete animator; delete animator;
@ -360,7 +388,9 @@ bool QskHintAnimatorTable::cleanup()
{ {
if ( qskCheckReceiverThread( control ) ) if ( qskCheckReceiverThread( control ) )
{ {
auto event = new QskAnimatorEvent( aspect, QskAnimatorEvent::Terminated ); auto event = new QskAnimatorEvent(
aspect, index, QskAnimatorEvent::Terminated );
QCoreApplication::postEvent( control, event ); QCoreApplication::postEvent( control, event );
} }
} }

View File

@ -19,12 +19,17 @@ class QSK_EXPORT QskHintAnimator : public QskVariantAnimator
using Inherited = QskVariantAnimator; using Inherited = QskVariantAnimator;
public: public:
QskHintAnimator( QskAspect = QskAspect() ) noexcept; QskHintAnimator() noexcept = default;
QskHintAnimator( QskAspect, int index ) noexcept;
~QskHintAnimator() override; ~QskHintAnimator() override;
void setAspect( QskAspect ) noexcept; void setAspect( QskAspect ) noexcept;
QskAspect aspect() const noexcept; QskAspect aspect() const noexcept;
void setIndex( int ) noexcept;
int index() const noexcept;
void setControl( QskControl* ) noexcept; void setControl( QskControl* ) noexcept;
QskControl* control() const noexcept; QskControl* control() const noexcept;
@ -37,6 +42,7 @@ class QSK_EXPORT QskHintAnimator : public QskVariantAnimator
private: private:
QskAspect m_aspect; QskAspect m_aspect;
int m_index = -1;
QskAnimationHint::UpdateFlags m_updateFlags; QskAnimationHint::UpdateFlags m_updateFlags;
QPointer< QskControl > m_control; QPointer< QskControl > m_control;
}; };
@ -54,11 +60,11 @@ class QSK_EXPORT QskHintAnimatorTable
QskHintAnimatorTable(); QskHintAnimatorTable();
~QskHintAnimatorTable(); ~QskHintAnimatorTable();
void start( QskControl*, QskAspect, void start( QskControl*, QskAspect, int index,
QskAnimationHint, const QVariant& from, const QVariant& to ); QskAnimationHint, const QVariant& from, const QVariant& to );
const QskHintAnimator* animator( QskAspect ) const; const QskHintAnimator* animator( QskAspect, int index = -1 ) const;
QVariant currentValue( QskAspect ) const; QVariant currentValue( QskAspect, int index = -1 ) const;
bool cleanup(); bool cleanup();
bool isEmpty() const; bool isEmpty() const;
@ -75,6 +81,11 @@ inline QskAspect QskHintAnimator::aspect() const noexcept
return m_aspect; return m_aspect;
} }
inline int QskHintAnimator::index() const noexcept
{
return m_index;
}
inline QskAnimationHint::UpdateFlags QskHintAnimator::updateFlags() const noexcept inline QskAnimationHint::UpdateFlags QskHintAnimator::updateFlags() const noexcept
{ {
return m_updateFlags; return m_updateFlags;

View File

@ -371,6 +371,7 @@ void QskSegmentedBar::setSelectedIndex( int index )
if( index != m_data->selectedIndex ) if( index != m_data->selectedIndex )
{ {
const auto oldIndex = m_data->selectedIndex;
m_data->selectedIndex = index; m_data->selectedIndex = index;
movePositionHint( Cursor, index ); movePositionHint( Cursor, index );
@ -380,6 +381,14 @@ void QskSegmentedBar::setSelectedIndex( int index )
setSkinStateFlag( Minimum, ( m_data->selectedIndex == 0 ) ); setSkinStateFlag( Minimum, ( m_data->selectedIndex == 0 ) );
setSkinStateFlag( Maximum, ( m_data->selectedIndex == count() - 1 ) ); 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 );
} }
} }

View File

@ -242,6 +242,8 @@ class QskSkinlet::PrivateData
QskSkin* skin; QskSkin* skin;
QVector< quint8 > nodeRoles; QVector< quint8 > nodeRoles;
int animatorIndex = -1;
bool ownedBySkinnable : 1; bool ownedBySkinnable : 1;
}; };
@ -269,6 +271,21 @@ bool QskSkinlet::isOwnedBySkinnable() const
return m_data->ownedBySkinnable; 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 ) void QskSkinlet::setNodeRoles( const QVector< quint8 >& nodeRoles )
{ {
m_data->nodeRoles = nodeRoles; m_data->nodeRoles = nodeRoles;
@ -693,6 +710,25 @@ QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable,
QskSkinStateChanger stateChanger( skinnable ); QskSkinStateChanger stateChanger( skinnable );
stateChanger.setStates( newStates ); 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 ); newNode = updateSampleNode( skinnable, subControl, i, node );
} }

View File

@ -71,6 +71,10 @@ class QSK_EXPORT QskSkinlet
void setOwnedBySkinnable( bool on ); void setOwnedBySkinnable( bool on );
bool isOwnedBySkinnable() const; bool isOwnedBySkinnable() const;
void setAnimatorIndex( int );
void resetAnimatorIndex();
int animatorIndex() const;
// Helper functions for creating nodes // Helper functions for creating nodes
static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*,

View File

@ -938,13 +938,11 @@ QVariant QskSkinnable::animatedHint(
if ( !m_data->animators.isEmpty() ) if ( !m_data->animators.isEmpty() )
{ {
/* const int index = effectiveSkinlet()->animatorIndex();
The local animators were invented to be stateless
and we never have an aspect with a state here.
But that might change ...
*/
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() ) if ( status && v.isValid() )
@ -1221,11 +1219,17 @@ bool QskSkinnable::isTransitionAccepted( QskAspect aspect ) const
void QskSkinnable::startTransition( QskAspect aspect, void QskSkinnable::startTransition( QskAspect aspect,
QskAnimationHint animationHint, const QVariant& from, const QVariant& to ) QskAnimationHint animationHint, const QVariant& from, const QVariant& to )
{ {
aspect.setSubControl( effectiveSubcontrol( aspect.subControl() ) ); startTransition( aspect, -1, animationHint, from, to );
startHintTransition( aspect, 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 ) QskAnimationHint animationHint, const QVariant& from, const QVariant& to )
{ {
if ( animationHint.duration <= 0 || ( from == to ) ) if ( animationHint.duration <= 0 || ( from == to ) )
@ -1263,11 +1267,11 @@ void QskSkinnable::startHintTransition( QskAspect aspect,
qDebug() << aspect << animationHint.duration; qDebug() << aspect << animationHint.duration;
#endif #endif
auto animator = m_data->animators.animator( aspect ); auto animator = m_data->animators.animator( aspect, index );
if ( animator && animator->isRunning() ) if ( animator && animator->isRunning() )
v1 = animator->currentValue(); 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 ) void QskSkinnable::setSkinStateFlag( QskAspect::State stateFlag, bool on )
@ -1333,7 +1337,7 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
} }
bool QskSkinnable::startHintTransitions( bool QskSkinnable::startHintTransitions(
QskAspect::States oldStates, QskAspect::States newStates ) QskAspect::States oldStates, QskAspect::States newStates, int index )
{ {
if ( !isTransitionAccepted( QskAspect() ) ) if ( !isTransitionAccepted( QskAspect() ) )
{ {
@ -1396,7 +1400,7 @@ bool QskSkinnable::startHintTransitions(
if ( doTransition ) if ( doTransition )
{ {
startHintTransition( aspect, hint, startHintTransition( aspect, index, hint,
storedHint( a1 ), storedHint( a2 ) ); storedHint( a1 ), storedHint( a2 ) );
started = true; started = true;

View File

@ -124,6 +124,9 @@ class QSK_EXPORT QskSkinnable
void startTransition( QskAspect, void startTransition( QskAspect,
QskAnimationHint, const QVariant& from, const QVariant& to ); 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; QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const;
QskControl* controlCast(); QskControl* controlCast();
@ -247,6 +250,8 @@ class QSK_EXPORT QskSkinnable
const QskSkinHintTable& hintTable() const; const QskSkinHintTable& hintTable() const;
bool startHintTransitions( QskAspect::States, QskAspect::States, int index = -1 );
protected: protected:
virtual void updateNode( QSGNode* ); virtual void updateNode( QSGNode* );
virtual bool isTransitionAccepted( QskAspect ) const; virtual bool isTransitionAccepted( QskAspect ) const;
@ -258,8 +263,7 @@ class QSK_EXPORT QskSkinnable
private: private:
Q_DISABLE_COPY( QskSkinnable ) Q_DISABLE_COPY( QskSkinnable )
bool startHintTransitions( QskAspect::States, QskAspect::States ); void startHintTransition( QskAspect, int index,
void startHintTransition( QskAspect,
QskAnimationHint, const QVariant& from, const QVariant& to ); QskAnimationHint, const QVariant& from, const QVariant& to );
QVariant animatedHint( QskAspect, QskSkinHintStatus* ) const; QVariant animatedHint( QskAspect, QskSkinHintStatus* ) const;