QskSkinTransition fixed for multiple windows

This commit is contained in:
Uwe Rathmann 2019-02-03 12:48:43 +01:00
parent 3efb1f93e7
commit 724c1e4a66
3 changed files with 164 additions and 72 deletions

View File

@ -157,20 +157,21 @@ static QVector< AnimatorCandidate > qskAnimatorCandidates(
namespace namespace
{ {
class AnimatorGroup final : public QObject class AnimatorGroup
{ {
Q_OBJECT
public: public:
AnimatorGroup() AnimatorGroup( QQuickWindow* window = nullptr )
: m_window( window )
{ {
} }
inline const QQuickWindow* window() const
{
return m_window;
}
void start() void start()
{ {
m_notifyConnection =
QskAnimator::addAdvanceHandler( this, SLOT(notify(QQuickWindow*)) );
for ( auto& it : m_hintAnimatorMap ) for ( auto& it : m_hintAnimatorMap )
it.second.start(); it.second.start();
@ -178,20 +179,6 @@ namespace
it.second.start(); 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 inline QVariant animatedHint( QskAspect::Aspect aspect ) const
{ {
auto it = m_hintAnimatorMap.find( aspect ); auto it = m_hintAnimatorMap.find( aspect );
@ -219,7 +206,7 @@ namespace
} }
void addGraphicFilterAnimators( void addGraphicFilterAnimators(
QQuickWindow* window, const QskAnimationHint& animatorHint, const QskAnimationHint& animatorHint,
const std::unordered_map< int, QskColorFilter >& oldFilters, const std::unordered_map< int, QskColorFilter >& oldFilters,
const std::unordered_map< int, QskColorFilter >& newFilters ) const std::unordered_map< int, QskColorFilter >& newFilters )
{ {
@ -237,7 +224,7 @@ namespace
if ( f1 != f2 ) if ( f1 != f2 )
{ {
QskVariantAnimator animator; QskVariantAnimator animator;
animator.setWindow( window ); animator.setWindow( m_window );
animator.setDuration( animatorHint.duration ); animator.setDuration( animatorHint.duration );
animator.setEasingCurve( animatorHint.type ); animator.setEasingCurve( animatorHint.type );
animator.setStartValue( QVariant::fromValue( f1 ) ); animator.setStartValue( QVariant::fromValue( f1 ) );
@ -275,16 +262,11 @@ namespace
addAnimators( child, animatorHint, candidates, skin ); addAnimators( child, animatorHint, candidates, skin );
} }
private Q_SLOTS: void update()
void notify( QQuickWindow* window )
{ {
if ( m_updateInfos.empty() )
return;
for ( auto& info : m_updateInfos ) for ( auto& info : m_updateInfos )
{ {
QskControl* control = info.control; if ( auto control = info.control )
if ( control && control->window() == window )
{ {
if ( info.updateModes & UpdateInfo::Polish ) if ( info.updateModes & UpdateInfo::Polish )
{ {
@ -296,15 +278,10 @@ namespace
control->update(); control->update();
} }
} }
if ( !m_hintAnimatorMap.empty() )
{
if ( !m_hintAnimatorMap.begin()->second.isRunning() )
reset();
}
} }
private: private:
void addControlAnimators( QskControl* control, const QskAnimationHint& animatorHint, void addControlAnimators( QskControl* control, const QskAnimationHint& animatorHint,
const QVector< AnimatorCandidate >& candidates ) const QVector< AnimatorCandidate >& candidates )
{ {
@ -411,15 +388,113 @@ namespace
m_updateInfos.insert( it, info ); m_updateInfos.insert( it, info );
} }
QQuickWindow* m_window;
std::unordered_map< QskAspect::Aspect, QskHintAnimator > m_hintAnimatorMap; std::unordered_map< QskAspect::Aspect, QskHintAnimator > m_hintAnimatorMap;
std::unordered_map< int, QskVariantAnimator > m_graphicFilterAnimatorMap; std::unordered_map< int, QskVariantAnimator > m_graphicFilterAnimatorMap;
std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration 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() QskSkinTransition::QskSkinTransition()
: m_mask( QskSkinTransition::AllTypes ) : m_mask( QskSkinTransition::AllTypes )
@ -514,14 +589,17 @@ void QskSkinTransition::process()
bool doGraphicFilter = m_mask & QskSkinTransition::Color; bool doGraphicFilter = m_mask & QskSkinTransition::Color;
const auto windows = qGuiApp->topLevelWindows(); const auto windows = qGuiApp->topLevelWindows();
for ( const auto window : windows ) for ( const auto window : windows )
{ {
if ( auto quickWindow = qobject_cast< QQuickWindow* >( window ) ) if ( auto quickWindow = qobject_cast< QQuickWindow* >( window ) )
{ {
auto* group = new AnimatorGroup( quickWindow );
if ( doGraphicFilter ) if ( doGraphicFilter )
{ {
qskSkinAnimator->addGraphicFilterAnimators( group->addGraphicFilterAnimators(
quickWindow, m_animationHint, oldFilters, m_animationHint, oldFilters,
m_skins[ 1 ]->graphicFilters() ); m_skins[ 1 ]->graphicFilters() );
doGraphicFilter = false; doGraphicFilter = false;
@ -532,8 +610,10 @@ void QskSkinTransition::process()
over the the item trees. over the the item trees.
*/ */
qskSkinAnimator->addAnimators( quickWindow->contentItem(), group->addAnimators( quickWindow->contentItem(),
m_animationHint, candidates, m_skins[ 1 ] ); m_animationHint, candidates, m_skins[ 1 ] );
qskSkinAnimator->add( group );
} }
} }
@ -543,23 +623,34 @@ void QskSkinTransition::process()
bool QskSkinTransition::isRunning() 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() ) if ( qskSkinAnimator.exists() )
return QVariant(); {
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() ) if ( qskSkinAnimator.exists() )
return QVariant(); {
if ( const auto group = qskSkinAnimator->animatorGroup( window ) )
return group->animatedGraphicFilter( graphicRole );
}
return qskSkinAnimator->animatedGraphicFilter( graphicRole ); return QVariant();
} }
#include "QskSkinTransition.moc" #include "QskSkinTransition.moc"

View File

@ -5,6 +5,7 @@
#include "QskAspect.h" #include "QskAspect.h"
class QskSkin; class QskSkin;
class QQuickWindow;
class QVariant; class QVariant;
class QSK_EXPORT QskSkinTransition class QSK_EXPORT QskSkinTransition
@ -36,8 +37,8 @@ class QSK_EXPORT QskSkinTransition
void process(); void process();
static bool isRunning(); static bool isRunning();
static QVariant animatedHint( QskAspect::Aspect ); static QVariant animatedHint( const QQuickWindow*, QskAspect::Aspect );
static QVariant animatedGraphicFilter( int graphicRole ); static QVariant animatedGraphicFilter( const QQuickWindow*, int graphicRole );
protected: protected:
virtual void updateSkin( QskSkin*, QskSkin* ); virtual void updateSkin( QskSkin*, QskSkin* );

View File

@ -340,22 +340,19 @@ QskColorFilter QskSkinnable::effectiveGraphicFilter(
if ( v.canConvert< QskColorFilter >() ) if ( v.canConvert< QskColorFilter >() )
return v.value< 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 ( v.canConvert< QskColorFilter >() )
{ {
if ( owningControl() ) /*
{ As it is hard to find out which controls depend
/* on the animated graphic filters we reschedule
As it is hard to find out which controls depend our updates here.
on the animated graphic filters we reschedule */
our updates here. control->update();
*/
owningControl()->update();
}
return v.value< QskColorFilter >(); return v.value< QskColorFilter >();
} }
} }
@ -478,16 +475,19 @@ QVariant QskSkinnable::animatedValue(
and are state aware and are state aware
*/ */
if ( aspect.state() == QskAspect::NoState ) if ( const auto control = owningControl() )
aspect = aspect | skinState();
Q_FOREVER
{ {
v = QskSkinTransition::animatedHint( aspect ); if ( aspect.state() == QskAspect::NoState )
if ( v.isValid() || aspect.state() == QskAspect::NoState ) aspect = aspect | skinState();
break;
aspect.clearState( aspect.topState() ); Q_FOREVER
{
v = QskSkinTransition::animatedHint( control->window(), aspect );
if ( v.isValid() || aspect.state() == QskAspect::NoState )
break;
aspect.clearState( aspect.topState() );
}
} }
} }
} }