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 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 );
}
{

View File

@ -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 )
{
}

View File

@ -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;
};

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -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 );
}
}

View File

@ -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 );
}

View File

@ -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*,

View File

@ -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;

View File

@ -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;