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;
QskSkinHintTable hintTable;
QskAspect::States stateMask = QskAspect::AllStates;
std::unordered_map< int, QFont > fonts;
std::unordered_map< int, QskColorFilter > graphicFilters;
@ -345,22 +344,6 @@ const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const
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 )
{
while ( metaObject )

View File

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

View File

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

View File

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

View File

@ -940,23 +940,12 @@ const QVariant& QskSkinnable::storedHint(
{
const auto skin = effectiveSkin();
// clearing all state bits not being handled from the skin
aspect.clearStates( ~skin->stateMask() );
QskAspect resolvedAspect;
const auto& localTable = m_data->hintTable;
if ( localTable.hasHints() )
{
auto a = aspect;
if ( !localTable.hasStates() )
{
// we don't need to clear the state bits stepwise
a.clearStates();
}
if ( const QVariant* value = localTable.resolvedHint( a, &resolvedAspect ) )
if ( const auto value = localTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -972,10 +961,7 @@ const QVariant& QskSkinnable::storedHint(
const auto& skinTable = skin->hintTable();
if ( skinTable.hasHints() )
{
auto a = aspect;
const QVariant* value = skinTable.resolvedHint( a, &resolvedAspect );
if ( value )
if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -993,8 +979,7 @@ const QVariant& QskSkinnable::storedHint(
aspect.setSubControl( QskAspect::Control );
aspect.clearStates();
value = skinTable.resolvedHint( aspect, &resolvedAspect );
if ( value )
if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -1257,7 +1242,8 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
if ( skin )
{
const auto mask = skin->stateMask();
const auto mask = skin->hintTable().states() | m_data->hintTable.states();
if ( ( newStates & mask ) == ( m_data->skinStates & mask ) )
{
// 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 );
aspect.setPrimitive( type, primitive );
auto a1 = aspect | m_data->skinStates;
auto a2 = aspect | newStates;
const auto a1 = aspect | m_data->skinStates;
const auto a2 = aspect | newStates;
bool doTransition = true;
if ( !m_data->hintTable.hasStates() )
{
/*
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.
*/
if ( m_data->hintTable.states() == QskAspect::NoState )
doTransition = !skinTable.isResolutionMatching( a1, a2 );
}
if ( doTransition )
{