tracking states of the aspects in a QskSkinHintTable

This commit is contained in:
Uwe Rathmann 2022-03-28 21:28:56 +02:00
parent a38a4a101e
commit 1eae47aefa
5 changed files with 27 additions and 74 deletions

View File

@ -128,7 +128,6 @@ class QskSkin::PrivateData
std::unordered_map< const QMetaObject*, SkinletData > skinletMap; std::unordered_map< const QMetaObject*, SkinletData > skinletMap;
QskSkinHintTable hintTable; QskSkinHintTable hintTable;
QskAspect::States stateMask = QskAspect::AllStates;
std::unordered_map< int, QFont > fonts; std::unordered_map< int, QFont > fonts;
std::unordered_map< int, QskColorFilter > graphicFilters; std::unordered_map< int, QskColorFilter > graphicFilters;
@ -345,22 +344,6 @@ const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const
return QPlatformDialogHelper::buttonLayout( orientation, policy ); return QPlatformDialogHelper::buttonLayout( orientation, policy );
} }
void QskSkin::setStateMask( QskAspect::States mask )
{
for ( auto state : { QskControl::Disabled, QskControl::Hovered, QskControl::Focused } )
{
if ( mask & state )
m_data->stateMask |= state;
else
m_data->stateMask &= ~state;
}
}
QskAspect::States QskSkin::stateMask() const
{
return m_data->stateMask;
}
QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject ) QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject )
{ {
while ( metaObject ) while ( metaObject )

View File

@ -77,9 +77,6 @@ class QSK_EXPORT QskSkin : public QObject
virtual const int* dialogButtonLayout( Qt::Orientation ) const; virtual const int* dialogButtonLayout( Qt::Orientation ) const;
virtual QString dialogButtonText( int button ) const; virtual QString dialogButtonText( int button ) const;
void setStateMask( QskAspect::States );
QskAspect::States stateMask() const;
QskSkinlet* skinlet( const QMetaObject* ); QskSkinlet* skinlet( const QMetaObject* );
const QskSkinHintTable& hintTable() const; const QskSkinHintTable& hintTable() const;

View File

@ -67,7 +67,7 @@ QskSkinHintTable::QskSkinHintTable()
QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other ) QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other )
: m_hints( nullptr ) : m_hints( nullptr )
, m_animatorCount( other.m_animatorCount ) , m_animatorCount( other.m_animatorCount )
, m_statefulCount( other.m_statefulCount ) , m_states( other.m_states )
{ {
if ( other.m_hints ) if ( other.m_hints )
m_hints = new HintMap( *( other.m_hints ) ); m_hints = new HintMap( *( other.m_hints ) );
@ -81,7 +81,7 @@ QskSkinHintTable::~QskSkinHintTable()
QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other ) QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other )
{ {
m_animatorCount = other.m_animatorCount; m_animatorCount = other.m_animatorCount;
m_statefulCount = other.m_statefulCount; m_states = other.m_states;
if ( other.m_hints ) if ( other.m_hints )
{ {
@ -126,11 +126,7 @@ bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint )
QSK_ASSERT_COUNTER( m_animatorCount ); QSK_ASSERT_COUNTER( m_animatorCount );
} }
if ( aspect.hasStates() ) m_states |= aspect.states();
{
m_statefulCount++;
QSK_ASSERT_COUNTER( m_statefulCount );
}
return true; return true;
} }
@ -158,8 +154,7 @@ bool QskSkinHintTable::removeHint( QskAspect aspect )
if ( aspect.isAnimator() ) if ( aspect.isAnimator() )
m_animatorCount--; m_animatorCount--;
if ( aspect.hasStates() ) // how to clear m_states ? TODO ...
m_statefulCount--;
if ( m_hints->empty() ) if ( m_hints->empty() )
{ {
@ -184,8 +179,7 @@ QVariant QskSkinHintTable::takeHint( QskAspect aspect )
if ( aspect.isAnimator() ) if ( aspect.isAnimator() )
m_animatorCount--; m_animatorCount--;
if ( aspect.hasStates() ) // how to clear m_states ? TODO ...
m_statefulCount--;
if ( m_hints->empty() ) if ( m_hints->empty() )
{ {
@ -206,14 +200,14 @@ void QskSkinHintTable::clear()
m_hints = nullptr; m_hints = nullptr;
m_animatorCount = 0; m_animatorCount = 0;
m_statefulCount = 0; m_states = QskAspect::NoState;
} }
const QVariant* QskSkinHintTable::resolvedHint( const QVariant* QskSkinHintTable::resolvedHint(
QskAspect aspect, QskAspect* resolvedAspect ) const QskAspect aspect, QskAspect* resolvedAspect ) const
{ {
if ( m_hints != nullptr ) if ( m_hints != nullptr )
return qskResolvedHint( aspect, *m_hints, resolvedAspect ); return qskResolvedHint( aspect & m_states, *m_hints, resolvedAspect );
return nullptr; return nullptr;
} }
@ -223,7 +217,7 @@ QskAspect QskSkinHintTable::resolvedAspect( QskAspect aspect ) const
QskAspect a; QskAspect a;
if ( m_hints != nullptr ) if ( m_hints != nullptr )
qskResolvedHint( aspect, *m_hints, &a ); qskResolvedHint( aspect & m_states, *m_hints, &a );
return a; return a;
} }
@ -233,6 +227,8 @@ QskAspect QskSkinHintTable::resolvedAnimator(
{ {
if ( m_hints && m_animatorCount > 0 ) if ( m_hints && m_animatorCount > 0 )
{ {
aspect &= m_states;
Q_FOREVER Q_FOREVER
{ {
auto it = m_hints->find( aspect ); auto it = m_hints->find( aspect );
@ -268,15 +264,16 @@ bool QskSkinHintTable::setAnimation(
bool QskSkinHintTable::isResolutionMatching( bool QskSkinHintTable::isResolutionMatching(
QskAspect aspect1, QskAspect aspect2 ) const QskAspect aspect1, QskAspect aspect2 ) const
{ {
// remove states we do not have early
aspect1 &= m_states;
aspect2 &= m_states;
if ( aspect1 == aspect2 ) if ( aspect1 == aspect2 )
return true; return true;
if ( aspect1.trunk() != aspect2.trunk() ) if ( aspect1.trunk() != aspect2.trunk() )
return false; return false;
if ( !hasStates() )
return false;
const auto a1 = aspect1; const auto a1 = aspect1;
const auto a2 = aspect2; const auto a2 = aspect2;

View File

@ -40,9 +40,10 @@ class QSK_EXPORT QskSkinHintTable
const std::unordered_map< QskAspect, QVariant >& hints() const; const std::unordered_map< QskAspect, QVariant >& hints() const;
bool hasAnimators() const; bool hasAnimators() const;
bool hasStates() const;
bool hasHints() const; bool hasHints() const;
QskAspect::States states() const;
void clear(); void clear();
const QVariant* resolvedHint( QskAspect, const QVariant* resolvedHint( QskAspect,
@ -62,7 +63,7 @@ class QSK_EXPORT QskSkinHintTable
HintMap* m_hints = nullptr; HintMap* m_hints = nullptr;
unsigned short m_animatorCount = 0; unsigned short m_animatorCount = 0;
unsigned short m_statefulCount = 0; QskAspect::States m_states;
}; };
inline bool QskSkinHintTable::hasHints() const inline bool QskSkinHintTable::hasHints() const
@ -70,9 +71,9 @@ inline bool QskSkinHintTable::hasHints() const
return m_hints != nullptr; return m_hints != nullptr;
} }
inline bool QskSkinHintTable::hasStates() const inline QskAspect::States QskSkinHintTable::states() const
{ {
return m_statefulCount > 0; return m_states;
} }
inline bool QskSkinHintTable::hasAnimators() const inline bool QskSkinHintTable::hasAnimators() const

View File

@ -940,23 +940,12 @@ const QVariant& QskSkinnable::storedHint(
{ {
const auto skin = effectiveSkin(); const auto skin = effectiveSkin();
// clearing all state bits not being handled from the skin
aspect.clearStates( ~skin->stateMask() );
QskAspect resolvedAspect; QskAspect resolvedAspect;
const auto& localTable = m_data->hintTable; const auto& localTable = m_data->hintTable;
if ( localTable.hasHints() ) if ( localTable.hasHints() )
{ {
auto a = aspect; if ( const auto value = localTable.resolvedHint( aspect, &resolvedAspect ) )
if ( !localTable.hasStates() )
{
// we don't need to clear the state bits stepwise
a.clearStates();
}
if ( const QVariant* value = localTable.resolvedHint( a, &resolvedAspect ) )
{ {
if ( status ) if ( status )
{ {
@ -972,10 +961,7 @@ const QVariant& QskSkinnable::storedHint(
const auto& skinTable = skin->hintTable(); const auto& skinTable = skin->hintTable();
if ( skinTable.hasHints() ) if ( skinTable.hasHints() )
{ {
auto a = aspect; if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
const QVariant* value = skinTable.resolvedHint( a, &resolvedAspect );
if ( value )
{ {
if ( status ) if ( status )
{ {
@ -993,8 +979,7 @@ const QVariant& QskSkinnable::storedHint(
aspect.setSubControl( QskAspect::Control ); aspect.setSubControl( QskAspect::Control );
aspect.clearStates(); aspect.clearStates();
value = skinTable.resolvedHint( aspect, &resolvedAspect ); if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
if ( value )
{ {
if ( status ) if ( status )
{ {
@ -1257,7 +1242,8 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
if ( skin ) if ( skin )
{ {
const auto mask = skin->stateMask(); const auto mask = skin->hintTable().states() | m_data->hintTable.states();
if ( ( newStates & mask ) == ( m_data->skinStates & mask ) ) if ( ( newStates & mask ) == ( m_data->skinStates & mask ) )
{ {
// the modified bits are not handled by the skin // the modified bits are not handled by the skin
@ -1297,24 +1283,13 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
const auto primitive = static_cast< QskAspect::Primitive >( i ); const auto primitive = static_cast< QskAspect::Primitive >( i );
aspect.setPrimitive( type, primitive ); aspect.setPrimitive( type, primitive );
auto a1 = aspect | m_data->skinStates; const auto a1 = aspect | m_data->skinStates;
auto a2 = aspect | newStates; const auto a2 = aspect | newStates;
bool doTransition = true; bool doTransition = true;
if ( !m_data->hintTable.hasStates() ) if ( m_data->hintTable.states() == QskAspect::NoState )
{
/*
The hints are found by stripping the state bits one by
one until a lookup into the hint table is successful.
So for deciding whether two aspects lead to the same hint
we can stop as soon as the aspects have the same state bits.
This way we can reduce the number of lookups significantly
for skinnables with many state bits.
*/
doTransition = !skinTable.isResolutionMatching( a1, a2 ); doTransition = !skinTable.isResolutionMatching( a1, a2 );
}
if ( doTransition ) if ( doTransition )
{ {