From d0a888ab741650a71ed83561bedba21c07bacdcf Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 23 Feb 2024 13:46:23 +0100 Subject: [PATCH] smooth transition of font sizes added --- src/controls/QskSkin.cpp | 28 +++++---- src/controls/QskSkinTransition.cpp | 95 +++++++++++++++++++++++++++++- src/controls/QskSkinTransition.h | 7 ++- src/controls/QskSkinnable.cpp | 24 ++++++-- 4 files changed, 136 insertions(+), 18 deletions(-) diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index 51de03f0..61af02a0 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -124,6 +124,22 @@ static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* return skinlet; } +// also used in QskSkinTransition.cpp TODO ... + +QFont qskResolvedFont( const QHash< QskFontRole, QFont >& fontTable, + const QskFontRole& fontRole ) +{ + auto it = fontTable.constFind( fontRole ); + if ( it != fontTable.constEnd() ) + return it.value(); + + it = fontTable.constFind( QskFontRole() ); + if ( it != fontTable.constEnd() ) + return it.value(); + + return QGuiApplication::font(); +} + namespace { class SkinletData @@ -374,17 +390,7 @@ void QskSkin::resetFont( const QskFontRole& fontRole ) QFont QskSkin::font( const QskFontRole& fontRole ) const { - const auto& table = m_data->fonts; - - auto it = table.constFind( fontRole ); - if ( it != table.constEnd() ) - return it.value(); - - it = table.constFind( QskFontRole() ); - if ( it != m_data->fonts.constEnd() ) - return it.value(); - - return QGuiApplication::font(); + return qskResolvedFont( m_data->fonts, fontRole ); } void QskSkin::setGraphicFilter( int graphicRole, const QskColorFilter& colorFilter ) diff --git a/src/controls/QskSkinTransition.cpp b/src/controls/QskSkinTransition.cpp index 76c5c7e3..4f7dc399 100644 --- a/src/controls/QskSkinTransition.cpp +++ b/src/controls/QskSkinTransition.cpp @@ -11,6 +11,8 @@ #include "QskHintAnimator.h" #include "QskSkin.h" #include "QskSkinHintTable.h" +#include "QskFontRole.h" +#include "QskAspect.h" #include #include @@ -86,12 +88,10 @@ static void qskAddCandidates( const QskSkinTransition::Type mask, { isCandidate = mask & QskSkinTransition::Color; } -#if 0 else if ( aspect.primitive() == QskAspect::FontRole ) { isCandidate = mask & QskSkinTransition::Metric; } -#endif break; } case QskAspect::Color: @@ -161,10 +161,14 @@ namespace QVariant animatedHint( QskAspect ) const; QVariant animatedGraphicFilter( int graphicRole ) const; + QVariant animatedFontSize( const QskFontRole& ) const; void addGraphicFilterAnimators( const QskAnimationHint&, const QHash< int, QskColorFilter >&, const QHash< int, QskColorFilter >& ); + void addFontSizeAnimators( const QskAnimationHint&, + const QHash< QskFontRole, QFont >&, const QHash< QskFontRole, QFont >& ); + void addItemAspects( QQuickItem*, const QskAnimationHint&, const QSet< QskAspect >&, const QskSkinHintTable&, const QskSkinHintTable& ); @@ -186,8 +190,11 @@ namespace void storeUpdateInfo( const QskControl*, QskAspect ); QQuickWindow* m_window; + QHash< QskAspect, HintAnimator > m_animatorMap; QHash< int, QskVariantAnimator > m_graphicFilterAnimatorMap; + QHash< QskFontRole, QskVariantAnimator > m_fontSizeAnimatorMap; + std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration }; @@ -243,6 +250,9 @@ void WindowAnimator::start() for ( auto& it : m_graphicFilterAnimatorMap ) it.start(); + + for ( auto& it : m_fontSizeAnimatorMap ) + it.start(); } bool WindowAnimator::isRunning() const @@ -261,6 +271,13 @@ bool WindowAnimator::isRunning() const return true; } + if ( !m_fontSizeAnimatorMap.empty() ) + { + const auto& animator = m_fontSizeAnimatorMap.constBegin().value(); + if ( animator.isRunning() ) + return true; + } + return false; } @@ -290,6 +307,19 @@ inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const return QVariant(); } +inline QVariant WindowAnimator::animatedFontSize( const QskFontRole& fontRole ) const +{ + auto it = m_fontSizeAnimatorMap.constFind( fontRole ); + if ( it != m_fontSizeAnimatorMap.constEnd() ) + { + const auto& animator = it.value(); + if ( animator.isRunning() ) + return animator.currentValue(); + } + + return QVariant(); +} + void WindowAnimator::addGraphicFilterAnimators( const QskAnimationHint& animatorHint, const QHash< int, QskColorFilter >& filters1, @@ -320,6 +350,42 @@ void WindowAnimator::addGraphicFilterAnimators( } } +// from QskSkin.cpp +extern QFont qskResolvedFont( + const QHash< QskFontRole, QFont >&, const QskFontRole& ); + +void WindowAnimator::addFontSizeAnimators( + const QskAnimationHint& animatorHint, + const QHash< QskFontRole, QFont >& fonts1, + const QHash< QskFontRole, QFont >& fonts2 ) +{ + for ( int i = 0; i <= QskFontRole::Display; i++ ) + { + for ( int j = 0; j <= QskFontRole::VeryHigh; j++ ) + { + const QskFontRole fontRole( + static_cast< QskFontRole::Category >( i ), + static_cast< QskFontRole::Emphasis >( j ) + ); + + const auto size1 = qskResolvedFont( fonts1, fontRole ).pixelSize(); + const auto size2 = qskResolvedFont( fonts2, fontRole ).pixelSize(); + + if ( ( size1 > 0 ) && ( size2 > 0 ) && ( size1 != size2 ) ) + { + QskVariantAnimator animator; + animator.setWindow( m_window ); + animator.setDuration( animatorHint.duration ); + animator.setEasingCurve( animatorHint.type ); + animator.setStartValue( QVariant::fromValue( size1 ) ); + animator.setEndValue( QVariant::fromValue( size2 ) ); + + m_fontSizeAnimatorMap.insert( fontRole, animator ); + } + } + } +} + void WindowAnimator::addItemAspects( QQuickItem* item, const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates, const QskSkinHintTable& table1, const QskSkinHintTable& table2 ) @@ -602,6 +668,7 @@ class QskSkinTransition::PrivateData { QskSkinHintTable hintTable; QHash< int, QskColorFilter > graphicFilters; + QHash< QskFontRole, QFont > fontTable; } tables[ 2 ]; Type mask = QskSkinTransition::AllTypes; @@ -632,6 +699,7 @@ void QskSkinTransition::setSourceSkin( const QskSkin* skin ) tables.hintTable = skin->hintTable(); tables.graphicFilters = skin->graphicFilters(); + tables.fontTable = skin->fontTable(); } void QskSkinTransition::setTargetSkin( const QskSkin* skin ) @@ -640,6 +708,7 @@ void QskSkinTransition::setTargetSkin( const QskSkin* skin ) tables.hintTable = skin->hintTable(); tables.graphicFilters = skin->graphicFilters(); + tables.fontTable = skin->fontTable(); } void QskSkinTransition::run( const QskAnimationHint& animationHint ) @@ -652,6 +721,9 @@ void QskSkinTransition::run( const QskAnimationHint& animationHint ) const auto& graphicFilters1 = m_data->tables[ 0 ].graphicFilters; const auto& graphicFilters2 = m_data->tables[ 1 ].graphicFilters; + const auto& fontTable1 = m_data->tables[ 0 ].fontTable; + const auto& fontTable2 = m_data->tables[ 1 ].fontTable; + QSet< QskAspect > candidates; if ( ( animationHint.duration > 0 ) && ( m_data->mask != 0 ) ) @@ -663,6 +735,7 @@ void QskSkinTransition::run( const QskAnimationHint& animationHint ) if ( !candidates.isEmpty() ) { bool doGraphicFilter = m_data->mask & QskSkinTransition::Color; + bool doFont = m_data->mask & QskSkinTransition::Metric; const auto windows = qGuiApp->topLevelWindows(); @@ -686,6 +759,12 @@ void QskSkinTransition::run( const QskAnimationHint& animationHint ) doGraphicFilter = false; } + if ( doFont ) + { + animator->addFontSizeAnimators( animationHint, + fontTable1, fontTable2 ); + } + /* finally we schedule the animators the hard way by running over the the item trees. @@ -734,4 +813,16 @@ QVariant QskSkinTransition::animatedGraphicFilter( return QVariant(); } +QVariant QskSkinTransition::animatedFontSize( + const QQuickWindow* window, const QskFontRole& fontRole ) +{ + if ( qskApplicationAnimator.exists() ) + { + if ( const auto animator = qskApplicationAnimator->windowAnimator( window ) ) + return animator->animatedFontSize( fontRole ); + } + + return QVariant(); +} + #include "QskSkinTransition.moc" diff --git a/src/controls/QskSkinTransition.h b/src/controls/QskSkinTransition.h index 58d5da6f..fad3dd38 100644 --- a/src/controls/QskSkinTransition.h +++ b/src/controls/QskSkinTransition.h @@ -6,14 +6,17 @@ #ifndef QSK_SKIN_TRANSITION_H #define QSK_SKIN_TRANSITION_H -#include "QskAspect.h" +#include "QskGlobal.h" #include class QskAnimationHint; +class QskFontRole; +class QskAspect; class QskSkin; class QQuickWindow; class QVariant; + template< typename Key, typename T > class QHash; class QSK_EXPORT QskSkinTransition @@ -39,8 +42,10 @@ class QSK_EXPORT QskSkinTransition void run( const QskAnimationHint& ); static bool isRunning(); + static QVariant animatedHint( const QQuickWindow*, QskAspect ); static QVariant animatedGraphicFilter( const QQuickWindow*, int graphicRole ); + static QVariant animatedFontSize( const QQuickWindow*, const QskFontRole& ); private: Q_DISABLE_COPY( QskSkinTransition ) diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 5f63e0dc..f1c79795 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -130,7 +130,7 @@ static inline constexpr QskAspect qskAnimatorAspect( const QskAspect aspect ) the effective aspect in animatedHint. */ - return aspect.type() | aspect.subControl() | aspect.primitive(); + return aspect.type() | aspect.subControl() | aspect.primitive(); } static inline void qskTriggerUpdates( QskAspect aspect, QQuickItem* item ) @@ -724,7 +724,7 @@ QskFontRole QskSkinnable::fontRoleHint( aspect | QskAspect::FontRole, status ).value< QskFontRole >(); } -QFont QskSkinnable::effectiveFont( const QskAspect aspect ) const +QFont QskSkinnable::effectiveFont( QskAspect aspect ) const { const auto hint = effectiveSkinHint( aspect | QskAspect::FontRole ); if ( hint.canConvert< QFont >() ) @@ -736,8 +736,24 @@ QFont QskSkinnable::effectiveFont( const QskAspect aspect ) const */ return hint.value< QFont >(); } - - return effectiveSkin()->font( hint.value< QskFontRole >() ); + + const auto fontRole = hint.value< QskFontRole >(); + + auto font = effectiveSkin()->font( fontRole ); + + if ( auto item = owningItem() ) + { + const auto v = QskSkinTransition::animatedFontSize( + item->window(), fontRole ); + + if ( v.canConvert< int >() ) + { + font.setPixelSize( v.value< int >() ); + item->update(); // design flaw: see effectiveGraphicFilter + } + } + + return font; } qreal QskSkinnable::effectiveFontHeight( const QskAspect aspect ) const