diff --git a/src/controls/QskSkinTransition.cpp b/src/controls/QskSkinTransition.cpp index 3456feef..da032586 100644 --- a/src/controls/QskSkinTransition.cpp +++ b/src/controls/QskSkinTransition.cpp @@ -157,20 +157,21 @@ static QVector< AnimatorCandidate > qskAnimatorCandidates( namespace { - class AnimatorGroup final : public QObject + class AnimatorGroup { - Q_OBJECT - public: - AnimatorGroup() + AnimatorGroup( QQuickWindow* window = nullptr ) + : m_window( window ) { } + inline const QQuickWindow* window() const + { + return m_window; + } + void start() { - m_notifyConnection = - QskAnimator::addAdvanceHandler( this, SLOT(notify(QQuickWindow*)) ); - for ( auto& it : m_hintAnimatorMap ) it.second.start(); @@ -178,20 +179,6 @@ namespace it.second.start(); } - bool isRunning() const - { - return !m_hintAnimatorMap.empty(); - } - - void reset() - { - disconnect( m_notifyConnection ); - - m_hintAnimatorMap.clear(); - m_graphicFilterAnimatorMap.clear(); - m_updateInfos.clear(); - } - inline QVariant animatedHint( QskAspect::Aspect aspect ) const { auto it = m_hintAnimatorMap.find( aspect ); @@ -219,7 +206,7 @@ namespace } void addGraphicFilterAnimators( - QQuickWindow* window, const QskAnimationHint& animatorHint, + const QskAnimationHint& animatorHint, const std::unordered_map< int, QskColorFilter >& oldFilters, const std::unordered_map< int, QskColorFilter >& newFilters ) { @@ -237,7 +224,7 @@ namespace if ( f1 != f2 ) { QskVariantAnimator animator; - animator.setWindow( window ); + animator.setWindow( m_window ); animator.setDuration( animatorHint.duration ); animator.setEasingCurve( animatorHint.type ); animator.setStartValue( QVariant::fromValue( f1 ) ); @@ -275,16 +262,11 @@ namespace addAnimators( child, animatorHint, candidates, skin ); } - private Q_SLOTS: - void notify( QQuickWindow* window ) + void update() { - if ( m_updateInfos.empty() ) - return; - for ( auto& info : m_updateInfos ) { - QskControl* control = info.control; - if ( control && control->window() == window ) + if ( auto control = info.control ) { if ( info.updateModes & UpdateInfo::Polish ) { @@ -296,15 +278,10 @@ namespace control->update(); } } - - if ( !m_hintAnimatorMap.empty() ) - { - if ( !m_hintAnimatorMap.begin()->second.isRunning() ) - reset(); - } } private: + void addControlAnimators( QskControl* control, const QskAnimationHint& animatorHint, const QVector< AnimatorCandidate >& candidates ) { @@ -411,15 +388,113 @@ namespace m_updateInfos.insert( it, info ); } + QQuickWindow* m_window; std::unordered_map< QskAspect::Aspect, QskHintAnimator > m_hintAnimatorMap; std::unordered_map< int, QskVariantAnimator > m_graphicFilterAnimatorMap; std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration + }; - QMetaObject::Connection m_notifyConnection; + class AnimatorGroups : public QObject + { + Q_OBJECT + + public: + ~AnimatorGroups() + { + reset(); + } + + inline AnimatorGroup* animatorGroup( const QQuickWindow* window ) + { + if ( !m_animatorGroups.empty() && window ) + { + for ( auto group : m_animatorGroups ) + { + if ( group->window() == window ) + return group; + } + } + + return nullptr; + } + + void add( AnimatorGroup* group ) + { + m_animatorGroups.push_back( group ); + } + + void start() + { + m_connections[0] = QskAnimator::addAdvanceHandler( + this, SLOT(notify(QQuickWindow*)), Qt::UniqueConnection ); + + m_connections[1] = QskAnimator::addCleanupHandler( + this, SLOT(cleanup(QQuickWindow*)), Qt::UniqueConnection ); + + for ( auto& group : m_animatorGroups ) + group->start(); + } + + void reset() + { + qDeleteAll( m_animatorGroups ); + m_animatorGroups.clear(); + + disconnect( m_connections[0] ); + disconnect( m_connections[1] ); + } + + inline bool isRunning() const + { + return !m_animatorGroups.empty(); + } + + private Q_SLOTS: + void notify( QQuickWindow* window ) + { + for ( auto& group : m_animatorGroups ) + { + if ( group->window() == window ) + { + group->update(); + return; + } + } + } + + void cleanup( QQuickWindow* window ) + { + for ( auto it = m_animatorGroups.begin(); + it != m_animatorGroups.end(); ++it ) + { + auto group = *it; + if ( group->window() == window ) + { + m_animatorGroups.erase( it ); + delete group; + + break; + } + } + + if ( m_animatorGroups.empty() ) + reset(); + } + + private: + /* + It should be possible to find an implementation, that interpolates + a skin hint only once for all windows. But as our animtors are driven by + QQuickWindow::afterAnimating the code will have to be somehow tricky. + But as skin transitions are no operations, that happen often, we can accept + the overhaed of the current implementation and do the finetuning later. + */ + std::vector< AnimatorGroup* > m_animatorGroups; + QMetaObject::Connection m_connections[2]; }; } -Q_GLOBAL_STATIC( AnimatorGroup, qskSkinAnimator ) +Q_GLOBAL_STATIC( AnimatorGroups, qskSkinAnimator ) QskSkinTransition::QskSkinTransition() : m_mask( QskSkinTransition::AllTypes ) @@ -514,14 +589,17 @@ void QskSkinTransition::process() bool doGraphicFilter = m_mask & QskSkinTransition::Color; const auto windows = qGuiApp->topLevelWindows(); + for ( const auto window : windows ) { if ( auto quickWindow = qobject_cast< QQuickWindow* >( window ) ) { + auto* group = new AnimatorGroup( quickWindow ); + if ( doGraphicFilter ) { - qskSkinAnimator->addGraphicFilterAnimators( - quickWindow, m_animationHint, oldFilters, + group->addGraphicFilterAnimators( + m_animationHint, oldFilters, m_skins[ 1 ]->graphicFilters() ); doGraphicFilter = false; @@ -532,8 +610,10 @@ void QskSkinTransition::process() over the the item trees. */ - qskSkinAnimator->addAnimators( quickWindow->contentItem(), + group->addAnimators( quickWindow->contentItem(), m_animationHint, candidates, m_skins[ 1 ] ); + + qskSkinAnimator->add( group ); } } @@ -543,23 +623,34 @@ void QskSkinTransition::process() bool QskSkinTransition::isRunning() { - return qskSkinAnimator.exists() && qskSkinAnimator->isRunning(); + if ( qskSkinAnimator.exists() ) + return qskSkinAnimator->isRunning(); + + return false; } -QVariant QskSkinTransition::animatedHint( QskAspect::Aspect aspect ) +QVariant QskSkinTransition::animatedHint( + const QQuickWindow* window, QskAspect::Aspect aspect ) { - if ( !qskSkinAnimator.exists() ) - return QVariant(); + if ( qskSkinAnimator.exists() ) + { + if ( const auto group = qskSkinAnimator->animatorGroup( window ) ) + return group->animatedHint( aspect ); + } - return qskSkinAnimator->animatedHint( aspect ); + return QVariant(); } -QVariant QskSkinTransition::animatedGraphicFilter( int graphicRole ) +QVariant QskSkinTransition::animatedGraphicFilter( + const QQuickWindow* window, int graphicRole ) { - if ( !qskSkinAnimator.exists() ) - return QVariant(); + if ( qskSkinAnimator.exists() ) + { + if ( const auto group = qskSkinAnimator->animatorGroup( window ) ) + return group->animatedGraphicFilter( graphicRole ); + } - return qskSkinAnimator->animatedGraphicFilter( graphicRole ); + return QVariant(); } #include "QskSkinTransition.moc" diff --git a/src/controls/QskSkinTransition.h b/src/controls/QskSkinTransition.h index 0794d38e..5265e8db 100644 --- a/src/controls/QskSkinTransition.h +++ b/src/controls/QskSkinTransition.h @@ -5,6 +5,7 @@ #include "QskAspect.h" class QskSkin; +class QQuickWindow; class QVariant; class QSK_EXPORT QskSkinTransition @@ -36,8 +37,8 @@ class QSK_EXPORT QskSkinTransition void process(); static bool isRunning(); - static QVariant animatedHint( QskAspect::Aspect ); - static QVariant animatedGraphicFilter( int graphicRole ); + static QVariant animatedHint( const QQuickWindow*, QskAspect::Aspect ); + static QVariant animatedGraphicFilter( const QQuickWindow*, int graphicRole ); protected: virtual void updateSkin( QskSkin*, QskSkin* ); diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 8da2f440..f3033dae 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -340,22 +340,19 @@ QskColorFilter QskSkinnable::effectiveGraphicFilter( if ( v.canConvert< QskColorFilter >() ) return v.value< QskColorFilter >(); - if ( QskSkinTransition::isRunning() ) + if ( auto control = owningControl() ) { - v = QskSkinTransition::animatedGraphicFilter( hint.toInt() ); + v = QskSkinTransition::animatedGraphicFilter( + control->window(), hint.toInt() ); if ( v.canConvert< QskColorFilter >() ) { - if ( owningControl() ) - { - /* - As it is hard to find out which controls depend - on the animated graphic filters we reschedule - our updates here. - */ - owningControl()->update(); - } - + /* + As it is hard to find out which controls depend + on the animated graphic filters we reschedule + our updates here. + */ + control->update(); return v.value< QskColorFilter >(); } } @@ -478,16 +475,19 @@ QVariant QskSkinnable::animatedValue( and are state aware */ - if ( aspect.state() == QskAspect::NoState ) - aspect = aspect | skinState(); - - Q_FOREVER + if ( const auto control = owningControl() ) { - v = QskSkinTransition::animatedHint( aspect ); - if ( v.isValid() || aspect.state() == QskAspect::NoState ) - break; + if ( aspect.state() == QskAspect::NoState ) + aspect = aspect | skinState(); - aspect.clearState( aspect.topState() ); + Q_FOREVER + { + v = QskSkinTransition::animatedHint( control->window(), aspect ); + if ( v.isValid() || aspect.state() == QskAspect::NoState ) + break; + + aspect.clearState( aspect.topState() ); + } } } }