smooth state transitions for listbox row selections

This commit is contained in:
Uwe Rathmann 2023-08-10 18:43:24 +02:00
parent ac4f190733
commit 3eb62bb692
7 changed files with 34 additions and 65 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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