QskSkinTransition fixed to work with graphic roles

This commit is contained in:
Uwe Rathmann 2018-03-22 11:22:13 +01:00
parent c4325d5f45
commit 736a28d02f
3 changed files with 156 additions and 55 deletions

View File

@ -96,6 +96,12 @@ static QVector< AnimatorCandidate > qskAnimatorCandidates(
const int role2 = entry.second.toInt(); const int role2 = entry.second.toInt();
/*
When the role is the same we already have the animators
for the graphic filter table running
*/
if ( role1 != role2 )
{
const auto it1 = oldFilters.find( role1 ); const auto it1 = oldFilters.find( role1 );
const auto it2 = newFilters.find( role2 ); const auto it2 = newFilters.find( role2 );
@ -111,6 +117,7 @@ static QVector< AnimatorCandidate > qskAnimatorCandidates(
QVariant::fromValue( f2 ) ); QVariant::fromValue( f2 ) );
} }
} }
}
break; break;
} }
case QskAspect::FontRole: case QskAspect::FontRole:
@ -167,27 +174,31 @@ namespace
m_notifyConnection = QskAnimator::addAdvanceHandler( this, m_notifyConnection = QskAnimator::addAdvanceHandler( this,
SLOT( notify( QQuickWindow* ) ) ); SLOT( notify( QQuickWindow* ) ) );
for ( auto& it : m_map ) for ( auto& it : m_hintAnimatorMap )
it.second.start();
for ( auto& it : m_graphicFilterAnimatorMap )
it.second.start(); it.second.start();
} }
bool isRunning() const bool isRunning() const
{ {
return !m_map.empty(); return !m_hintAnimatorMap.empty();
} }
void reset() void reset()
{ {
disconnect( m_notifyConnection ); disconnect( m_notifyConnection );
m_map.clear(); m_hintAnimatorMap.clear();
m_graphicFilterAnimatorMap.clear();
m_updateInfos.clear(); m_updateInfos.clear();
} }
inline QVariant animatedHint( QskAspect::Aspect aspect ) const inline QVariant animatedHint( QskAspect::Aspect aspect ) const
{ {
auto it = m_map.find( aspect ); auto it = m_hintAnimatorMap.find( aspect );
if ( it != m_map.cend() ) if ( it != m_hintAnimatorMap.cend() )
{ {
const auto& animator = it->second; const auto& animator = it->second;
if ( animator.isRunning() ) if ( animator.isRunning() )
@ -197,6 +208,49 @@ namespace
return QVariant(); return QVariant();
} }
inline QVariant animatedGraphicFilter( int graphicRole ) const
{
auto it = m_graphicFilterAnimatorMap.find( graphicRole );
if ( it != m_graphicFilterAnimatorMap.cend() )
{
const auto& animator = it->second;
if ( animator.isRunning() )
return animator.currentValue();
}
return QVariant();
}
void addGraphicFilterAnimators(
QQuickWindow* window, const QskAnimationHint& animatorHint,
const std::unordered_map< int, QskColorFilter >& oldFilters,
const std::unordered_map< int, QskColorFilter >& newFilters )
{
const QskColorFilter noFilter;
for ( auto it2 = newFilters.begin(); it2 != newFilters.end(); ++it2 )
{
auto it1 = oldFilters.find( it2->first );
if ( it1 == oldFilters.cend() )
it1 = oldFilters.find( 0 );
const auto& f1 = ( it1 != oldFilters.cend() ) ? it1->second : noFilter;
const auto& f2 = it2->second;
if ( f1 != f2 )
{
QskVariantAnimator animator;
animator.setWindow( window );
animator.setDuration( animatorHint.duration );
animator.setEasingCurve( animatorHint.type );
animator.setStartValue( QVariant::fromValue( f1 ) );
animator.setEndValue( QVariant::fromValue( f2 ) );
m_graphicFilterAnimatorMap.emplace( it2->first, animator );
}
}
}
void addAnimators( QQuickItem* item, void addAnimators( QQuickItem* item,
const QskAnimationHint& animatorHint, const QskAnimationHint& animatorHint,
const QVector< AnimatorCandidate >& candidates, QskSkin* skin ) const QVector< AnimatorCandidate >& candidates, QskSkin* skin )
@ -207,7 +261,17 @@ namespace
if ( auto control = qobject_cast< QskControl* >( item ) ) if ( auto control = qobject_cast< QskControl* >( item ) )
{ {
if ( control->isInitiallyPainted() && ( skin == control->effectiveSkin() ) ) if ( control->isInitiallyPainted() && ( skin == control->effectiveSkin() ) )
{
addControlAnimators( control, animatorHint, candidates ); addControlAnimators( control, animatorHint, candidates );
#if 1
/*
As it is hard to identify which controls depend on the animated
graphic filters we schedule an initial update and let the
controls do the rest: see QskSkinnable::effectiveGraphicFilter
*/
control->update();
#endif
}
} }
const auto children = item->childItems(); const auto children = item->childItems();
@ -237,9 +301,9 @@ namespace
} }
} }
if ( !m_map.empty() ) if ( !m_hintAnimatorMap.empty() )
{ {
if ( !m_map.begin()->second.isRunning() ) if ( !m_hintAnimatorMap.begin()->second.isRunning() )
reset(); reset();
} }
} }
@ -307,19 +371,19 @@ namespace
continue; continue;
} }
addAnimator( control, candidate, animatorHint ); addAnimator( control->window(), candidate, animatorHint );
storeUpdateInfo( control, candidate.aspect ); storeUpdateInfo( control, candidate.aspect );
} }
} }
void addAnimator( QskControl* control, void addAnimator( QQuickWindow* window,
const AnimatorCandidate& candidate, QskAnimationHint animationHint ) const AnimatorCandidate& candidate, QskAnimationHint animationHint )
{ {
auto it = m_map.find( candidate.aspect ); auto it = m_hintAnimatorMap.find( candidate.aspect );
if ( it != m_map.end() ) if ( it != m_hintAnimatorMap.end() )
return; // already there return; // already there
it = m_map.emplace( candidate.aspect, QskHintAnimator() ).first; it = m_hintAnimatorMap.emplace( candidate.aspect, QskHintAnimator() ).first;
auto& animator = it->second; auto& animator = it->second;
animator.setAspect( candidate.aspect ); animator.setAspect( candidate.aspect );
@ -330,7 +394,7 @@ namespace
animator.setEasingCurve( animationHint.type ); animator.setEasingCurve( animationHint.type );
animator.setControl( nullptr ); animator.setControl( nullptr );
animator.setWindow( control->window() ); animator.setWindow( window );
} }
inline void storeUpdateInfo( QskControl* control, QskAspect::Aspect aspect ) inline void storeUpdateInfo( QskControl* control, QskAspect::Aspect aspect )
@ -351,7 +415,8 @@ namespace
m_updateInfos.insert( it, info ); m_updateInfos.insert( it, info );
} }
std::map< QskAspect::Aspect, QskHintAnimator > m_map; std::unordered_map< QskAspect::Aspect, QskHintAnimator > m_hintAnimatorMap;
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; QMetaObject::Connection m_notifyConnection;
@ -400,14 +465,14 @@ QskSkin* QskSkinTransition::targetSkin() const
return m_skins[1]; return m_skins[1];
} }
void QskSkinTransition::setAnimation( QskAnimationHint animation ) void QskSkinTransition::setAnimation( QskAnimationHint animationHint )
{ {
m_animation = animation; m_animationHint = animationHint;
} }
QskAnimationHint QskSkinTransition::animation() const QskAnimationHint QskSkinTransition::animation() const
{ {
return m_animation; return m_animationHint;
} }
void QskSkinTransition::updateSkin( QskSkin*, QskSkin* ) void QskSkinTransition::updateSkin( QskSkin*, QskSkin* )
@ -425,7 +490,7 @@ void QskSkinTransition::process()
qskSkinAnimator->reset(); qskSkinAnimator->reset();
if ( ( m_animation.duration <= 0 ) || ( m_mask == 0 ) ) if ( ( m_animationHint.duration <= 0 ) || ( m_mask == 0 ) )
{ {
// no animations, we can apply the changes // no animations, we can apply the changes
updateSkin( m_skins[0], m_skins[1] ); updateSkin( m_skins[0], m_skins[1] );
@ -433,13 +498,13 @@ void QskSkinTransition::process()
} }
QVector< AnimatorCandidate > candidates; QVector< AnimatorCandidate > candidates;
const auto oldFilters = m_skins[0]->graphicFilters();
{ {
// copy out all hints before updating the skin // copy out all hints before updating the skin
// - would be good to have Copy on Write here // - would be good to have Copy on Write here
const auto oldTable = m_skins[0]->hintTable(); const auto oldTable = m_skins[0]->hintTable();
const auto oldFilters = m_skins[0]->graphicFilters();
// apply the changes // apply the changes
updateSkin( m_skins[0], m_skins[1] ); updateSkin( m_skins[0], m_skins[1] );
@ -450,20 +515,29 @@ void QskSkinTransition::process()
if ( !candidates.isEmpty() ) if ( !candidates.isEmpty() )
{ {
/* bool firstWindow = true;
finally we schedule the animators the hard way by running
over the the item trees. for the moment o.k. but we should
find a way not to create lots of identical animator objects for
each object.
*/
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< const QQuickWindow* >( window ) ) if ( auto quickWindow = qobject_cast< QQuickWindow* >( window ) )
{ {
if ( firstWindow )
{
qskSkinAnimator->addGraphicFilterAnimators(
quickWindow, m_animationHint,
oldFilters, m_skins[1]->graphicFilters() );
firstWindow = false;
}
/*
finally we schedule the animators the hard way by running
over the the item trees.
*/
qskSkinAnimator->addAnimators( quickWindow->contentItem(), qskSkinAnimator->addAnimators( quickWindow->contentItem(),
m_animation, candidates, m_skins[1] ); m_animationHint, candidates, m_skins[1] );
} }
} }
@ -484,4 +558,12 @@ QVariant QskSkinTransition::animatedHint( QskAspect::Aspect aspect )
return qskSkinAnimator->animatedHint( aspect ); return qskSkinAnimator->animatedHint( aspect );
} }
QVariant QskSkinTransition::animatedGraphicFilter( int graphicRole )
{
if ( !qskSkinAnimator.exists() )
return QVariant();
return qskSkinAnimator->animatedGraphicFilter( graphicRole );
}
#include "QskSkinTransition.moc" #include "QskSkinTransition.moc"

View File

@ -39,13 +39,14 @@ public:
static bool isRunning(); static bool isRunning();
static QVariant animatedHint( QskAspect::Aspect ); static QVariant animatedHint( QskAspect::Aspect );
static QVariant animatedGraphicFilter( int graphicRole );
protected: protected:
virtual void updateSkin( QskSkin*, QskSkin* ); virtual void updateSkin( QskSkin*, QskSkin* );
private: private:
QskSkin* m_skins[2]; QskSkin* m_skins[2];
QskAnimationHint m_animation; QskAnimationHint m_animationHint;
Type m_mask : 2; Type m_mask : 2;
}; };

View File

@ -84,10 +84,10 @@ static inline bool qskCompareResolvedStates(
// clear the placement bit and restart with the initial state // clear the placement bit and restart with the initial state
aspect1 = a1; aspect1 = a1;
aspect1.setPlacement( static_cast< QskAspect::Placement>( 0 ) ); aspect1.setPlacement( static_cast< QskAspect::Placement >( 0 ) );
aspect2 = a2; aspect2 = a2;
aspect2.setPlacement( static_cast< QskAspect::Placement>( 0 ) ); aspect2.setPlacement( static_cast< QskAspect::Placement >( 0 ) );
} }
} }
else else
@ -176,12 +176,12 @@ const QskSkinlet* QskSkinnable::effectiveSkinlet() const
return m_data->skinlet; return m_data->skinlet;
} }
QskSkinHintTable &QskSkinnable::hintTable() QskSkinHintTable& QskSkinnable::hintTable()
{ {
return m_data->hintTable; return m_data->hintTable;
} }
const QskSkinHintTable &QskSkinnable::hintTable() const const QskSkinHintTable& QskSkinnable::hintTable() const
{ {
return m_data->hintTable; return m_data->hintTable;
} }
@ -325,7 +325,6 @@ QskColorFilter QskSkinnable::effectiveGraphicFilter(
aspect.setPlacement( effectivePlacement() ); aspect.setPlacement( effectivePlacement() );
aspect = aspect | QskAspect::GraphicRole; aspect = aspect | QskAspect::GraphicRole;
#if 1
QskSkinHintStatus status; QskSkinHintStatus status;
const QVariant hint = storedHint( aspect | skinState(), &status ); const QVariant hint = storedHint( aspect | skinState(), &status );
@ -336,13 +335,32 @@ QskColorFilter QskSkinnable::effectiveGraphicFilter(
aspect.setSubControl( status.aspect.subControl() ); aspect.setSubControl( status.aspect.subControl() );
} }
#endif
if ( !aspect.isAnimator() ) if ( !aspect.isAnimator() )
{ {
const QVariant v = animatedValue( aspect, nullptr ); QVariant v = animatedValue( aspect, nullptr );
if ( v.canConvert< QskColorFilter >() ) if ( v.canConvert< QskColorFilter >() )
return v.value< QskColorFilter >(); return v.value< QskColorFilter >();
if ( QskSkinTransition::isRunning() )
{
v = QskSkinTransition::animatedGraphicFilter( 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();
}
return v.value< QskColorFilter >();
}
}
} }
return effectiveSkin()->graphicFilter( hint.toInt() ); return effectiveSkin()->graphicFilter( hint.toInt() );