moving away from std::unordered_map towards QHash. For transitions between
color schemes we need to copy out hash tables, what is way much easier with the COW concept of the Qt containers. Also: according to https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html QHash seems to be faster in the most relevant category "Random full reads: execution time (integers)"
This commit is contained in:
parent
34e8dd9d65
commit
9ca02d7f1c
|
|
@ -102,22 +102,14 @@ class Window : public QskWindow
|
||||||
private:
|
private:
|
||||||
void setAlternativeSkin( bool on )
|
void setAlternativeSkin( bool on )
|
||||||
{
|
{
|
||||||
auto oldSkin = qskSkinManager->skin();
|
|
||||||
if ( oldSkin->parent() == qskSkinManager )
|
|
||||||
oldSkin->setParent( nullptr ); // otherwise setSkin deletes it
|
|
||||||
|
|
||||||
auto newSkin = qskSkinManager->setSkin( alternativeSkin( on ) );
|
|
||||||
|
|
||||||
QskSkinTransition transition;
|
QskSkinTransition transition;
|
||||||
|
transition.setSourceSkin( qskSkinManager->skin() );
|
||||||
|
|
||||||
transition.setSourceSkin( oldSkin );
|
if ( auto skin = qskSkinManager->setSkin( alternativeSkin( on ) ) )
|
||||||
transition.setTargetSkin( newSkin );
|
{
|
||||||
transition.setAnimation( QskAnimationHint( 600, QEasingCurve::Linear ) );
|
transition.setTargetSkin( skin );
|
||||||
|
transition.run( 600 );
|
||||||
transition.process();
|
}
|
||||||
|
|
||||||
if ( oldSkin->parent() == nullptr )
|
|
||||||
delete oldSkin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString alternativeSkin( bool on ) const
|
QString alternativeSkin( bool on ) const
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
#include <qpa/qplatformtheme.h>
|
#include <qpa/qplatformtheme.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "QskBox.h"
|
#include "QskBox.h"
|
||||||
#include "QskBoxSkinlet.h"
|
#include "QskBoxSkinlet.h"
|
||||||
|
|
@ -104,6 +103,8 @@
|
||||||
#include "QskStatusIndicator.h"
|
#include "QskStatusIndicator.h"
|
||||||
#include "QskStatusIndicatorSkinlet.h"
|
#include "QskStatusIndicatorSkinlet.h"
|
||||||
|
|
||||||
|
#include <qhash.h>
|
||||||
|
|
||||||
static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
|
static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
|
||||||
{
|
{
|
||||||
const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
|
const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
|
||||||
|
|
@ -137,19 +138,19 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMetaObject* metaObject;
|
const QMetaObject* metaObject;
|
||||||
QskSkinlet* skinlet;
|
QskSkinlet* skinlet; // mutable ???
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class QskSkin::PrivateData
|
class QskSkin::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unordered_map< const QMetaObject*, SkinletData > skinletMap;
|
QHash< const QMetaObject*, SkinletData > skinletMap;
|
||||||
|
|
||||||
QskSkinHintTable hintTable;
|
QskSkinHintTable hintTable;
|
||||||
|
|
||||||
std::unordered_map< int, QFont > fonts;
|
QHash< int, QFont > fonts;
|
||||||
std::unordered_map< int, QskColorFilter > graphicFilters;
|
QHash< int, QskColorFilter > graphicFilters;
|
||||||
|
|
||||||
QskGraphicProviderMap graphicProviders;
|
QskGraphicProviderMap graphicProviders;
|
||||||
};
|
};
|
||||||
|
|
@ -229,9 +230,9 @@ void QskSkin::declareSkinlet( const QMetaObject* metaObject,
|
||||||
|
|
||||||
const auto it = m_data->skinletMap.find( metaObject );
|
const auto it = m_data->skinletMap.find( metaObject );
|
||||||
|
|
||||||
if ( it != m_data->skinletMap.cend() )
|
if ( it != m_data->skinletMap.end() )
|
||||||
{
|
{
|
||||||
auto& entry = it->second;
|
auto& entry = it.value();
|
||||||
if ( entry.metaObject != skinletMetaObject )
|
if ( entry.metaObject != skinletMetaObject )
|
||||||
{
|
{
|
||||||
entry.metaObject = skinletMetaObject;
|
entry.metaObject = skinletMetaObject;
|
||||||
|
|
@ -276,18 +277,18 @@ void QskSkin::setFont( int fontRole, const QFont& font )
|
||||||
|
|
||||||
void QskSkin::resetFont( int fontRole )
|
void QskSkin::resetFont( int fontRole )
|
||||||
{
|
{
|
||||||
m_data->fonts.erase( fontRole );
|
m_data->fonts.remove( fontRole );
|
||||||
}
|
}
|
||||||
|
|
||||||
QFont QskSkin::font( int fontRole ) const
|
QFont QskSkin::font( int fontRole ) const
|
||||||
{
|
{
|
||||||
auto it = m_data->fonts.find( fontRole );
|
auto it = m_data->fonts.constFind( fontRole );
|
||||||
if ( it != m_data->fonts.cend() )
|
if ( it != m_data->fonts.constEnd() )
|
||||||
return it->second;
|
return it.value();
|
||||||
|
|
||||||
it = m_data->fonts.find( QskSkin::DefaultFont );
|
it = m_data->fonts.constFind( QskSkin::DefaultFont );
|
||||||
if ( it != m_data->fonts.cend() )
|
if ( it != m_data->fonts.constEnd() )
|
||||||
return it->second;
|
return it.value();
|
||||||
|
|
||||||
return QGuiApplication::font();
|
return QGuiApplication::font();
|
||||||
}
|
}
|
||||||
|
|
@ -299,16 +300,12 @@ void QskSkin::setGraphicFilter( int graphicRole, const QskColorFilter& colorFilt
|
||||||
|
|
||||||
void QskSkin::resetGraphicFilter( int graphicRole )
|
void QskSkin::resetGraphicFilter( int graphicRole )
|
||||||
{
|
{
|
||||||
m_data->graphicFilters.erase( graphicRole );
|
m_data->graphicFilters.remove( graphicRole );
|
||||||
}
|
}
|
||||||
|
|
||||||
QskColorFilter QskSkin::graphicFilter( int graphicRole ) const
|
QskColorFilter QskSkin::graphicFilter( int graphicRole ) const
|
||||||
{
|
{
|
||||||
auto it = m_data->graphicFilters.find( graphicRole );
|
return m_data->graphicFilters.value( graphicRole );
|
||||||
if ( it != m_data->graphicFilters.cend() )
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
return QskColorFilter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QskSkinHintTable& QskSkin::hintTable() const
|
const QskSkinHintTable& QskSkin::hintTable() const
|
||||||
|
|
@ -321,12 +318,12 @@ QskSkinHintTable& QskSkin::hintTable()
|
||||||
return m_data->hintTable;
|
return m_data->hintTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map< int, QFont >& QskSkin::fonts() const
|
const QHash< int, QFont >& QskSkin::fonts() const
|
||||||
{
|
{
|
||||||
return m_data->fonts;
|
return m_data->fonts;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map< int, QskColorFilter >& QskSkin::graphicFilters() const
|
const QHash< int, QskColorFilter >& QskSkin::graphicFilters() const
|
||||||
{
|
{
|
||||||
return m_data->graphicFilters;
|
return m_data->graphicFilters;
|
||||||
}
|
}
|
||||||
|
|
@ -375,9 +372,9 @@ const QMetaObject* QskSkin::skinletMetaObject( const QMetaObject* metaObject ) c
|
||||||
{
|
{
|
||||||
while ( metaObject )
|
while ( metaObject )
|
||||||
{
|
{
|
||||||
auto it = m_data->skinletMap.find( metaObject );
|
auto it = m_data->skinletMap.constFind( metaObject );
|
||||||
if ( it != m_data->skinletMap.cend() )
|
if ( it != m_data->skinletMap.constEnd() )
|
||||||
return it->second.metaObject;
|
return it.value().metaObject;
|
||||||
|
|
||||||
metaObject = metaObject->superClass();
|
metaObject = metaObject->superClass();
|
||||||
}
|
}
|
||||||
|
|
@ -390,9 +387,9 @@ QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject )
|
||||||
while ( metaObject )
|
while ( metaObject )
|
||||||
{
|
{
|
||||||
auto it = m_data->skinletMap.find( metaObject );
|
auto it = m_data->skinletMap.find( metaObject );
|
||||||
if ( it != m_data->skinletMap.cend() )
|
if ( it != m_data->skinletMap.end() )
|
||||||
{
|
{
|
||||||
auto& entry = it->second;
|
auto& entry = it.value();
|
||||||
|
|
||||||
if ( entry.skinlet == nullptr )
|
if ( entry.skinlet == nullptr )
|
||||||
entry.skinlet = qskNewSkinlet( entry.metaObject, this );
|
entry.skinlet = qskNewSkinlet( entry.metaObject, this );
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class QskSkinnable;
|
class QskSkinnable;
|
||||||
class QskSkinlet;
|
class QskSkinlet;
|
||||||
|
|
@ -25,6 +24,7 @@ class QskGraphicProvider;
|
||||||
class QskSkinHintTable;
|
class QskSkinHintTable;
|
||||||
|
|
||||||
class QVariant;
|
class QVariant;
|
||||||
|
template< typename Key, typename T > class QHash;
|
||||||
|
|
||||||
class QSK_EXPORT QskSkin : public QObject
|
class QSK_EXPORT QskSkin : public QObject
|
||||||
{
|
{
|
||||||
|
|
@ -91,8 +91,8 @@ class QSK_EXPORT QskSkin : public QObject
|
||||||
const QskSkinHintTable& hintTable() const;
|
const QskSkinHintTable& hintTable() const;
|
||||||
QskSkinHintTable& hintTable();
|
QskSkinHintTable& hintTable();
|
||||||
|
|
||||||
const std::unordered_map< int, QFont >& fonts() const;
|
const QHash< int, QFont >& fonts() const;
|
||||||
const std::unordered_map< int, QskColorFilter >& graphicFilters() const;
|
const QHash< int, QskColorFilter >& graphicFilters() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void declareSkinlet( const QMetaObject* metaObject,
|
void declareSkinlet( const QMetaObject* metaObject,
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,19 @@
|
||||||
const QVariant QskSkinHintTable::invalidHint;
|
const QVariant QskSkinHintTable::invalidHint;
|
||||||
|
|
||||||
inline const QVariant* qskResolvedHint( QskAspect aspect,
|
inline const QVariant* qskResolvedHint( QskAspect aspect,
|
||||||
const std::unordered_map< QskAspect, QVariant >& hints,
|
const QHash< QskAspect, QVariant >& hints, QskAspect* resolvedAspect )
|
||||||
QskAspect* resolvedAspect )
|
|
||||||
{
|
{
|
||||||
auto a = aspect;
|
auto a = aspect;
|
||||||
|
|
||||||
Q_FOREVER
|
Q_FOREVER
|
||||||
{
|
{
|
||||||
auto it = hints.find( aspect );
|
auto it = hints.constFind( aspect );
|
||||||
if ( it != hints.cend() )
|
if ( it != hints.constEnd() )
|
||||||
{
|
{
|
||||||
if ( resolvedAspect )
|
if ( resolvedAspect )
|
||||||
*resolvedAspect = aspect;
|
*resolvedAspect = aspect;
|
||||||
|
|
||||||
return &it->second;
|
return &it.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
@ -74,17 +73,53 @@ QskSkinHintTable::QskSkinHintTable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other )
|
||||||
|
: m_animatorCount( other.m_animatorCount )
|
||||||
|
, m_states( other.m_states )
|
||||||
|
{
|
||||||
|
if ( other.m_hints )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
A previous implementation was using STL containers - however:
|
||||||
|
|
||||||
|
according to https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html
|
||||||
|
QHash does slightly faster lookups than std::unordered_map in the category
|
||||||
|
"Random full reads: execution time (integers)", that is the most relevant one
|
||||||
|
in our use case.
|
||||||
|
|
||||||
|
Considering, that the "copy on write" strategy of QHash makes the implementation
|
||||||
|
of copy/assignment operators much easier ( needed in QskSkinTransition ) we prefer
|
||||||
|
using the Qt container over the STL counterparts.
|
||||||
|
*/
|
||||||
|
m_hints = new QHash< QskAspect, QVariant >( *other.m_hints );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QskSkinHintTable::~QskSkinHintTable()
|
QskSkinHintTable::~QskSkinHintTable()
|
||||||
{
|
{
|
||||||
delete m_hints;
|
delete m_hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map< QskAspect, QVariant >& QskSkinHintTable::hints() const
|
QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other )
|
||||||
|
{
|
||||||
|
m_animatorCount = ( other.m_animatorCount );
|
||||||
|
m_states = other.m_states;
|
||||||
|
|
||||||
|
delete m_hints;
|
||||||
|
m_hints = nullptr;
|
||||||
|
|
||||||
|
if ( other.m_hints )
|
||||||
|
m_hints = new QHash< QskAspect, QVariant >( *other.m_hints );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QHash< QskAspect, QVariant >& QskSkinHintTable::hints() const
|
||||||
{
|
{
|
||||||
if ( m_hints )
|
if ( m_hints )
|
||||||
return *m_hints;
|
return *m_hints;
|
||||||
|
|
||||||
static std::unordered_map< QskAspect, QVariant > dummyHints;
|
static QHash< QskAspect, QVariant > dummyHints;
|
||||||
return dummyHints;
|
return dummyHints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +128,7 @@ const std::unordered_map< QskAspect, QVariant >& QskSkinHintTable::hints() const
|
||||||
bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint )
|
bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint )
|
||||||
{
|
{
|
||||||
if ( m_hints == nullptr )
|
if ( m_hints == nullptr )
|
||||||
m_hints = new HintMap();
|
m_hints = new QHash< QskAspect, QVariant >();
|
||||||
|
|
||||||
auto it = m_hints->find( aspect );
|
auto it = m_hints->find( aspect );
|
||||||
if ( it == m_hints->end() )
|
if ( it == m_hints->end() )
|
||||||
|
|
@ -111,9 +146,9 @@ bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( it->second != skinHint )
|
if ( it.value() != skinHint )
|
||||||
{
|
{
|
||||||
it->second = skinHint;
|
it.value() = skinHint;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +162,7 @@ bool QskSkinHintTable::removeHint( QskAspect aspect )
|
||||||
if ( m_hints == nullptr )
|
if ( m_hints == nullptr )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool erased = m_hints->erase( aspect );
|
const bool erased = m_hints->remove( aspect );
|
||||||
|
|
||||||
if ( erased )
|
if ( erased )
|
||||||
{
|
{
|
||||||
|
|
@ -153,7 +188,7 @@ QVariant QskSkinHintTable::takeHint( QskAspect aspect )
|
||||||
auto it = m_hints->find( aspect );
|
auto it = m_hints->find( aspect );
|
||||||
if ( it != m_hints->end() )
|
if ( it != m_hints->end() )
|
||||||
{
|
{
|
||||||
const auto value = it->second;
|
const auto value = it.value();
|
||||||
m_hints->erase( it );
|
m_hints->erase( it );
|
||||||
|
|
||||||
if ( aspect.isAnimator() )
|
if ( aspect.isAnimator() )
|
||||||
|
|
@ -214,7 +249,7 @@ QskAspect QskSkinHintTable::resolvedAnimator(
|
||||||
auto it = m_hints->find( aspect );
|
auto it = m_hints->find( aspect );
|
||||||
if ( it != m_hints->cend() )
|
if ( it != m_hints->cend() )
|
||||||
{
|
{
|
||||||
hint = it->second.value< QskAnimationHint >();
|
hint = it.value().value< QskAnimationHint >();
|
||||||
return aspect;
|
return aspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include "QskAspect.h"
|
#include "QskAspect.h"
|
||||||
|
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
#include <unordered_map>
|
#include <qhash.h>
|
||||||
|
|
||||||
class QskAnimationHint;
|
class QskAnimationHint;
|
||||||
|
|
||||||
|
|
@ -17,8 +17,11 @@ class QSK_EXPORT QskSkinHintTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QskSkinHintTable();
|
QskSkinHintTable();
|
||||||
|
QskSkinHintTable( const QskSkinHintTable& );
|
||||||
~QskSkinHintTable();
|
~QskSkinHintTable();
|
||||||
|
|
||||||
|
QskSkinHintTable& operator=( const QskSkinHintTable& );
|
||||||
|
|
||||||
bool setAnimation( QskAspect, QskAnimationHint );
|
bool setAnimation( QskAspect, QskAnimationHint );
|
||||||
QskAnimationHint animation( QskAspect ) const;
|
QskAnimationHint animation( QskAspect ) const;
|
||||||
|
|
||||||
|
|
@ -33,7 +36,7 @@ class QSK_EXPORT QskSkinHintTable
|
||||||
|
|
||||||
bool hasHint( QskAspect ) const;
|
bool hasHint( QskAspect ) const;
|
||||||
|
|
||||||
const std::unordered_map< QskAspect, QVariant >& hints() const;
|
const QHash< QskAspect, QVariant >& hints() const;
|
||||||
|
|
||||||
bool hasAnimators() const;
|
bool hasAnimators() const;
|
||||||
bool hasHints() const;
|
bool hasHints() const;
|
||||||
|
|
@ -53,12 +56,10 @@ class QSK_EXPORT QskSkinHintTable
|
||||||
bool isResolutionMatching( QskAspect, QskAspect ) const;
|
bool isResolutionMatching( QskAspect, QskAspect ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY( QskSkinHintTable )
|
|
||||||
|
|
||||||
static const QVariant invalidHint;
|
static const QVariant invalidHint;
|
||||||
|
|
||||||
typedef std::unordered_map< QskAspect, QVariant > HintMap;
|
QHash< QskAspect, QVariant >* m_hints = nullptr;
|
||||||
HintMap* m_hints = nullptr;
|
|
||||||
|
|
||||||
unsigned short m_animatorCount = 0;
|
unsigned short m_animatorCount = 0;
|
||||||
QskAspect::States m_states;
|
QskAspect::States m_states;
|
||||||
|
|
@ -81,19 +82,16 @@ inline bool QskSkinHintTable::hasAnimators() const
|
||||||
|
|
||||||
inline bool QskSkinHintTable::hasHint( QskAspect aspect ) const
|
inline bool QskSkinHintTable::hasHint( QskAspect aspect ) const
|
||||||
{
|
{
|
||||||
if ( m_hints != nullptr )
|
return m_hints && m_hints->contains( aspect );
|
||||||
return m_hints->find( aspect ) != m_hints->cend();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QVariant& QskSkinHintTable::hint( QskAspect aspect ) const
|
inline const QVariant& QskSkinHintTable::hint( QskAspect aspect ) const
|
||||||
{
|
{
|
||||||
if ( m_hints != nullptr )
|
if ( m_hints != nullptr )
|
||||||
{
|
{
|
||||||
auto it = m_hints->find( aspect );
|
auto it = m_hints->constFind( aspect );
|
||||||
if ( it != m_hints->cend() )
|
if ( it != m_hints->constEnd() )
|
||||||
return it->second;
|
return it.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
return invalidHint;
|
return invalidHint;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,15 @@
|
||||||
#include <qguiapplication.h>
|
#include <qguiapplication.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qvector.h>
|
#include <qvector.h>
|
||||||
|
#include <qhash.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static bool qskHasHintTable( const QskSkin* skin, const QskSkinHintTable& hintTable )
|
||||||
|
{
|
||||||
|
return skin->hintTable().hints().isSharedWith( hintTable.hints() );
|
||||||
|
}
|
||||||
|
|
||||||
static void qskSendStyleEventRecursive( QQuickItem* item )
|
static void qskSendStyleEventRecursive( QQuickItem* item )
|
||||||
{
|
{
|
||||||
QEvent event( QEvent::StyleChange );
|
QEvent event( QEvent::StyleChange );
|
||||||
|
|
@ -31,11 +36,11 @@ static void qskSendStyleEventRecursive( QQuickItem* item )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qskAddCandidates( const QskSkinTransition::Type mask,
|
static void qskAddCandidates( const QskSkinTransition::Type mask,
|
||||||
const QskSkin* skin, QSet< QskAspect >& candidates )
|
const QHash< QskAspect, QVariant >& hints, QSet< QskAspect >& candidates )
|
||||||
{
|
{
|
||||||
for ( const auto& entry : skin->hintTable().hints() )
|
for ( auto it = hints.constBegin(); it != hints.constEnd(); ++it )
|
||||||
{
|
{
|
||||||
const auto aspect = entry.first.trunk();
|
const auto aspect = it.key().trunk();
|
||||||
|
|
||||||
if ( aspect.isAnimator() )
|
if ( aspect.isAnimator() )
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -127,11 +132,11 @@ namespace
|
||||||
QVariant animatedGraphicFilter( int graphicRole ) const;
|
QVariant animatedGraphicFilter( int graphicRole ) const;
|
||||||
|
|
||||||
void addGraphicFilterAnimators( const QskAnimationHint&,
|
void addGraphicFilterAnimators( const QskAnimationHint&,
|
||||||
const QskSkin*, const QskSkin* );
|
const QHash< int, QskColorFilter >&, const QHash< int, QskColorFilter >& );
|
||||||
|
|
||||||
void addItemAspects( QQuickItem*,
|
void addItemAspects( QQuickItem*,
|
||||||
const QskAnimationHint&, const QSet< QskAspect >&,
|
const QskAnimationHint&, const QSet< QskAspect >&,
|
||||||
const QskSkin*, const QskSkin* );
|
const QskSkinHintTable&, const QskSkinHintTable& );
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
|
@ -142,7 +147,7 @@ namespace
|
||||||
|
|
||||||
void addHints( const QskControl*,
|
void addHints( const QskControl*,
|
||||||
const QskAnimationHint&, const QSet< QskAspect >& candidates,
|
const QskAnimationHint&, const QSet< QskAspect >& candidates,
|
||||||
const QskSkin* skin1, const QskSkin* skin2 );
|
const QskSkinHintTable&, const QskSkinHintTable& );
|
||||||
|
|
||||||
void storeAnimator( const QskControl*, const QskAspect,
|
void storeAnimator( const QskControl*, const QskAspect,
|
||||||
const QVariant&, const QVariant&, QskAnimationHint );
|
const QVariant&, const QVariant&, QskAnimationHint );
|
||||||
|
|
@ -150,8 +155,8 @@ namespace
|
||||||
void storeUpdateInfo( const QskControl*, QskAspect );
|
void storeUpdateInfo( const QskControl*, QskAspect );
|
||||||
|
|
||||||
QQuickWindow* m_window;
|
QQuickWindow* m_window;
|
||||||
std::unordered_map< QskAspect, HintAnimator > m_animatorMap;
|
QHash< QskAspect, HintAnimator > m_animatorMap;
|
||||||
std::unordered_map< int, QskVariantAnimator > m_graphicFilterAnimatorMap;
|
QHash< int, QskVariantAnimator > m_graphicFilterAnimatorMap;
|
||||||
std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration
|
std::vector< UpdateInfo > m_updateInfos; // vector: for fast iteration
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -203,24 +208,24 @@ inline const QQuickWindow* WindowAnimator::window() const
|
||||||
void WindowAnimator::start()
|
void WindowAnimator::start()
|
||||||
{
|
{
|
||||||
for ( auto& it : m_animatorMap )
|
for ( auto& it : m_animatorMap )
|
||||||
it.second.start();
|
it.start();
|
||||||
|
|
||||||
for ( auto& it : m_graphicFilterAnimatorMap )
|
for ( auto& it : m_graphicFilterAnimatorMap )
|
||||||
it.second.start();
|
it.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowAnimator::isRunning() const
|
bool WindowAnimator::isRunning() const
|
||||||
{
|
{
|
||||||
if ( !m_animatorMap.empty() )
|
if ( !m_animatorMap.empty() )
|
||||||
{
|
{
|
||||||
const auto& animator = m_animatorMap.begin()->second;
|
const auto& animator = m_animatorMap.constBegin().value();
|
||||||
if ( animator.isRunning() )
|
if ( animator.isRunning() )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !m_graphicFilterAnimatorMap.empty() )
|
if ( !m_graphicFilterAnimatorMap.empty() )
|
||||||
{
|
{
|
||||||
const auto& animator = m_graphicFilterAnimatorMap.begin()->second;
|
const auto& animator = m_graphicFilterAnimatorMap.constBegin().value();
|
||||||
if ( animator.isRunning() )
|
if ( animator.isRunning() )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -230,10 +235,10 @@ bool WindowAnimator::isRunning() const
|
||||||
|
|
||||||
inline QVariant WindowAnimator::animatedHint( QskAspect aspect ) const
|
inline QVariant WindowAnimator::animatedHint( QskAspect aspect ) const
|
||||||
{
|
{
|
||||||
auto it = m_animatorMap.find( aspect );
|
auto it = m_animatorMap.constFind( aspect );
|
||||||
if ( it != m_animatorMap.cend() )
|
if ( it != m_animatorMap.constEnd() )
|
||||||
{
|
{
|
||||||
const auto& animator = it->second;
|
const auto& animator = it.value();
|
||||||
if ( animator.isRunning() )
|
if ( animator.isRunning() )
|
||||||
return animator.currentValue();
|
return animator.currentValue();
|
||||||
}
|
}
|
||||||
|
|
@ -243,10 +248,10 @@ inline QVariant WindowAnimator::animatedHint( QskAspect aspect ) const
|
||||||
|
|
||||||
inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const
|
inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const
|
||||||
{
|
{
|
||||||
auto it = m_graphicFilterAnimatorMap.find( graphicRole );
|
auto it = m_graphicFilterAnimatorMap.constFind( graphicRole );
|
||||||
if ( it != m_graphicFilterAnimatorMap.cend() )
|
if ( it != m_graphicFilterAnimatorMap.constEnd() )
|
||||||
{
|
{
|
||||||
const auto& animator = it->second;
|
const auto& animator = it.value();
|
||||||
if ( animator.isRunning() )
|
if ( animator.isRunning() )
|
||||||
return animator.currentValue();
|
return animator.currentValue();
|
||||||
}
|
}
|
||||||
|
|
@ -254,22 +259,21 @@ inline QVariant WindowAnimator::animatedGraphicFilter( int graphicRole ) const
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowAnimator::addGraphicFilterAnimators( const QskAnimationHint& animatorHint,
|
void WindowAnimator::addGraphicFilterAnimators(
|
||||||
const QskSkin* skin1, const QskSkin* skin2 )
|
const QskAnimationHint& animatorHint,
|
||||||
|
const QHash< int, QskColorFilter >& filters1,
|
||||||
|
const QHash< int, QskColorFilter >& filters2 )
|
||||||
{
|
{
|
||||||
const QskColorFilter noFilter;
|
const QskColorFilter noFilter;
|
||||||
|
|
||||||
const auto& filter1 = skin1->graphicFilters();
|
for ( auto it2 = filters2.constBegin(); it2 != filters2.constEnd(); ++it2 )
|
||||||
const auto& filter2 = skin2->graphicFilters();
|
|
||||||
|
|
||||||
for ( auto it2 = filter2.begin(); it2 != filter2.end(); ++it2 )
|
|
||||||
{
|
{
|
||||||
auto it1 = filter1.find( it2->first );
|
auto it1 = filters1.constFind( it2.key() );
|
||||||
if ( it1 == filter1.cend() )
|
if ( it1 == filters1.constEnd() )
|
||||||
it1 = filter1.find( 0 );
|
it1 = filters1.constFind( 0 );
|
||||||
|
|
||||||
const auto& f1 = ( it1 != filter1.cend() ) ? it1->second : noFilter;
|
const auto& f1 = ( it1 != filters1.constEnd() ) ? it1.value() : noFilter;
|
||||||
const auto& f2 = it2->second;
|
const auto& f2 = it2.value();
|
||||||
|
|
||||||
if ( f1 != f2 )
|
if ( f1 != f2 )
|
||||||
{
|
{
|
||||||
|
|
@ -280,23 +284,24 @@ void WindowAnimator::addGraphicFilterAnimators( const QskAnimationHint& animator
|
||||||
animator.setStartValue( QVariant::fromValue( f1 ) );
|
animator.setStartValue( QVariant::fromValue( f1 ) );
|
||||||
animator.setEndValue( QVariant::fromValue( f2 ) );
|
animator.setEndValue( QVariant::fromValue( f2 ) );
|
||||||
|
|
||||||
m_graphicFilterAnimatorMap.emplace( it2->first, animator );
|
m_graphicFilterAnimatorMap.emplace( it2.key(), animator );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowAnimator::addItemAspects( QQuickItem* item,
|
void WindowAnimator::addItemAspects( QQuickItem* item,
|
||||||
const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates,
|
const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates,
|
||||||
const QskSkin* skin1, const QskSkin* skin2 )
|
const QskSkinHintTable& table1, const QskSkinHintTable& table2 )
|
||||||
{
|
{
|
||||||
if ( !item->isVisible() )
|
if ( !item->isVisible() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( auto control = qskControlCast( item ) )
|
if ( auto control = qskControlCast( item ) )
|
||||||
{
|
{
|
||||||
if ( control->isInitiallyPainted() && ( control->effectiveSkin() == skin2 ) )
|
if ( control->isInitiallyPainted() &&
|
||||||
|
qskHasHintTable( control->effectiveSkin(), table2 ) )
|
||||||
{
|
{
|
||||||
addHints( control, animatorHint, candidates, skin1, skin2 );
|
addHints( control, animatorHint, candidates, table1, table2 );
|
||||||
#if 1
|
#if 1
|
||||||
/*
|
/*
|
||||||
As it is hard to identify which controls depend on the animated
|
As it is hard to identify which controls depend on the animated
|
||||||
|
|
@ -310,7 +315,7 @@ void WindowAnimator::addItemAspects( QQuickItem* item,
|
||||||
|
|
||||||
const auto children = item->childItems();
|
const auto children = item->childItems();
|
||||||
for ( auto child : children )
|
for ( auto child : children )
|
||||||
addItemAspects( child, animatorHint, candidates, skin1, skin2 );
|
addItemAspects( child, animatorHint, candidates, table1, table2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowAnimator::update()
|
void WindowAnimator::update()
|
||||||
|
|
@ -333,15 +338,12 @@ void WindowAnimator::update()
|
||||||
|
|
||||||
void WindowAnimator::addHints( const QskControl* control,
|
void WindowAnimator::addHints( const QskControl* control,
|
||||||
const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates,
|
const QskAnimationHint& animatorHint, const QSet< QskAspect >& candidates,
|
||||||
const QskSkin* skin1, const QskSkin* skin2 )
|
const QskSkinHintTable& table1, const QskSkinHintTable& table2 )
|
||||||
{
|
{
|
||||||
const auto subControls = control->subControls();
|
const auto subControls = control->subControls();
|
||||||
|
|
||||||
const auto& localTable = control->hintTable();
|
const auto& localTable = control->hintTable();
|
||||||
|
|
||||||
const auto& table1 = skin1->hintTable();
|
|
||||||
const auto& table2 = skin2->hintTable();
|
|
||||||
|
|
||||||
for ( auto aspect : candidates )
|
for ( auto aspect : candidates )
|
||||||
{
|
{
|
||||||
if ( !isControlAffected( control, subControls, aspect ) )
|
if ( !isControlAffected( control, subControls, aspect ) )
|
||||||
|
|
@ -548,8 +550,12 @@ void ApplicationAnimator::cleanup( QQuickWindow* window )
|
||||||
class QskSkinTransition::PrivateData
|
class QskSkinTransition::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QskSkin* skins[ 2 ] = {};
|
struct
|
||||||
QskAnimationHint animationHint;
|
{
|
||||||
|
QskSkinHintTable hintTable;
|
||||||
|
QHash< int, QskColorFilter > graphicFilters;
|
||||||
|
} tables[ 2 ];
|
||||||
|
|
||||||
Type mask = QskSkinTransition::AllTypes;
|
Type mask = QskSkinTransition::AllTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -572,57 +578,38 @@ QskSkinTransition::Type QskSkinTransition::mask() const
|
||||||
return m_data->mask;
|
return m_data->mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskSkinTransition::setSourceSkin( QskSkin* skin )
|
void QskSkinTransition::setSourceSkin( const QskSkin* skin )
|
||||||
{
|
{
|
||||||
m_data->skins[ 0 ] = skin;
|
auto& tables = m_data->tables[ 0 ];
|
||||||
|
|
||||||
|
tables.hintTable = skin->hintTable();
|
||||||
|
tables.graphicFilters = skin->graphicFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
QskSkin* QskSkinTransition::sourceSkin() const
|
void QskSkinTransition::setTargetSkin( const QskSkin* skin )
|
||||||
{
|
{
|
||||||
return m_data->skins[ 0 ];
|
auto& tables = m_data->tables[ 1 ];
|
||||||
|
|
||||||
|
tables.hintTable = skin->hintTable();
|
||||||
|
tables.graphicFilters = skin->graphicFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskSkinTransition::setTargetSkin( QskSkin* skin )
|
void QskSkinTransition::run( const QskAnimationHint& animationHint )
|
||||||
{
|
|
||||||
m_data->skins[ 1 ] = skin;
|
|
||||||
}
|
|
||||||
|
|
||||||
QskSkin* QskSkinTransition::targetSkin() const
|
|
||||||
{
|
|
||||||
return m_data->skins[ 1 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskSkinTransition::setAnimation( QskAnimationHint animationHint )
|
|
||||||
{
|
|
||||||
m_data->animationHint = animationHint;
|
|
||||||
}
|
|
||||||
|
|
||||||
QskAnimationHint QskSkinTransition::animation() const
|
|
||||||
{
|
|
||||||
return m_data->animationHint;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskSkinTransition::updateSkin( QskSkin*, QskSkin* )
|
|
||||||
{
|
|
||||||
// nop
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskSkinTransition::process()
|
|
||||||
{
|
{
|
||||||
qskApplicationAnimator->reset();
|
qskApplicationAnimator->reset();
|
||||||
|
|
||||||
auto skin1 = m_data->skins[ 0 ];
|
const auto& table1 = m_data->tables[ 0 ].hintTable;
|
||||||
auto skin2 = m_data->skins[ 1 ];
|
const auto& table2 = m_data->tables[ 1 ].hintTable;
|
||||||
|
|
||||||
|
const auto& graphicFilters1 = m_data->tables[ 0 ].graphicFilters;
|
||||||
|
const auto& graphicFilters2 = m_data->tables[ 1 ].graphicFilters;
|
||||||
|
|
||||||
QSet< QskAspect > candidates;
|
QSet< QskAspect > candidates;
|
||||||
|
|
||||||
if ( skin1 && skin2 )
|
if ( ( animationHint.duration > 0 ) && ( m_data->mask != 0 ) )
|
||||||
{
|
{
|
||||||
if ( ( m_data->animationHint.duration > 0 ) && ( m_data->mask != 0 ) )
|
qskAddCandidates( m_data->mask, table1.hints(), candidates );
|
||||||
{
|
qskAddCandidates( m_data->mask, table2.hints(), candidates );
|
||||||
qskAddCandidates( m_data->mask, skin1, candidates );
|
|
||||||
qskAddCandidates( m_data->mask, skin2, candidates );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !candidates.isEmpty() )
|
if ( !candidates.isEmpty() )
|
||||||
|
|
@ -635,17 +622,18 @@ void QskSkinTransition::process()
|
||||||
{
|
{
|
||||||
if ( auto w = qobject_cast< QQuickWindow* >( window ) )
|
if ( auto w = qobject_cast< QQuickWindow* >( window ) )
|
||||||
{
|
{
|
||||||
if ( !w->isVisible() || ( qskEffectiveSkin( w ) != skin2 ) )
|
if ( !w->isVisible() )
|
||||||
{
|
continue;
|
||||||
|
|
||||||
|
if ( !qskHasHintTable( qskEffectiveSkin( w ), table2 ) )
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
auto animator = new WindowAnimator( w );
|
auto animator = new WindowAnimator( w );
|
||||||
|
|
||||||
if ( doGraphicFilter )
|
if ( doGraphicFilter )
|
||||||
{
|
{
|
||||||
animator->addGraphicFilterAnimators(
|
animator->addGraphicFilterAnimators( animationHint,
|
||||||
m_data->animationHint, skin1, skin2 );
|
graphicFilters1, graphicFilters2 );
|
||||||
|
|
||||||
doGraphicFilter = false;
|
doGraphicFilter = false;
|
||||||
}
|
}
|
||||||
|
|
@ -656,7 +644,7 @@ void QskSkinTransition::process()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
animator->addItemAspects( w->contentItem(),
|
animator->addItemAspects( w->contentItem(),
|
||||||
m_data->animationHint, candidates, skin1, skin2 );
|
animationHint, candidates, table1, table2 );
|
||||||
|
|
||||||
qskApplicationAnimator->add( animator );
|
qskApplicationAnimator->add( animator );
|
||||||
}
|
}
|
||||||
|
|
@ -664,9 +652,6 @@ void QskSkinTransition::process()
|
||||||
|
|
||||||
qskApplicationAnimator->start();
|
qskApplicationAnimator->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the changes
|
|
||||||
updateSkin( skin1, skin2 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskSkinTransition::isRunning()
|
bool QskSkinTransition::isRunning()
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@
|
||||||
#include "QskAspect.h"
|
#include "QskAspect.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class QskSkin;
|
|
||||||
class QskAnimationHint;
|
class QskAnimationHint;
|
||||||
|
class QskSkin;
|
||||||
|
|
||||||
class QQuickWindow;
|
class QQuickWindow;
|
||||||
class QVariant;
|
class QVariant;
|
||||||
|
template< typename Key, typename T > class QHash;
|
||||||
|
|
||||||
class QSK_EXPORT QskSkinTransition
|
class QSK_EXPORT QskSkinTransition
|
||||||
{
|
{
|
||||||
|
|
@ -28,27 +30,18 @@ class QSK_EXPORT QskSkinTransition
|
||||||
QskSkinTransition();
|
QskSkinTransition();
|
||||||
virtual ~QskSkinTransition();
|
virtual ~QskSkinTransition();
|
||||||
|
|
||||||
void setSourceSkin( QskSkin* );
|
void setSourceSkin( const QskSkin* );
|
||||||
QskSkin* sourceSkin() const;
|
void setTargetSkin( const QskSkin* );
|
||||||
|
|
||||||
void setTargetSkin( QskSkin* );
|
|
||||||
QskSkin* targetSkin() const;
|
|
||||||
|
|
||||||
void setAnimation( QskAnimationHint );
|
|
||||||
QskAnimationHint animation() const;
|
|
||||||
|
|
||||||
void setMask( Type );
|
void setMask( Type );
|
||||||
Type mask() const;
|
Type mask() const;
|
||||||
|
|
||||||
void process();
|
void run( const QskAnimationHint& );
|
||||||
|
|
||||||
static bool isRunning();
|
static bool isRunning();
|
||||||
static QVariant animatedHint( const QQuickWindow*, QskAspect );
|
static QVariant animatedHint( const QQuickWindow*, QskAspect );
|
||||||
static QVariant animatedGraphicFilter( const QQuickWindow*, int graphicRole );
|
static QVariant animatedGraphicFilter( const QQuickWindow*, int graphicRole );
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void updateSkin( QskSkin*, QskSkin* );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY( QskSkinTransition )
|
Q_DISABLE_COPY( QskSkinTransition )
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,23 +152,13 @@ void Skinny::setSkin( int index, QskAnimationHint hint )
|
||||||
if ( index == names.indexOf( qskSkinManager->skinName() ) )
|
if ( index == names.indexOf( qskSkinManager->skinName() ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto oldSkin = qskSkinManager->skin();
|
QskSkinTransition transition;
|
||||||
if ( oldSkin->parent() == qskSkinManager )
|
transition.setSourceSkin( qskSkinManager->skin() );
|
||||||
oldSkin->setParent( nullptr ); // otherwise setSkin deletes it
|
|
||||||
|
|
||||||
if ( auto newSkin = qskSkinManager->setSkin( names[ index ] ) )
|
if ( auto skin = qskSkinManager->setSkin( names[ index ] ) )
|
||||||
{
|
{
|
||||||
QskSkinTransition transition;
|
transition.setTargetSkin( skin );
|
||||||
|
transition.run( hint );
|
||||||
//transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO
|
|
||||||
transition.setSourceSkin( oldSkin );
|
|
||||||
transition.setTargetSkin( newSkin );
|
|
||||||
transition.setAnimation( hint );
|
|
||||||
|
|
||||||
transition.process();
|
|
||||||
|
|
||||||
if ( oldSkin->parent() == nullptr )
|
|
||||||
delete oldSkin;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,10 +168,10 @@ void Skinny::changeFonts( int increment )
|
||||||
|
|
||||||
const auto fonts = skin->fonts();
|
const auto fonts = skin->fonts();
|
||||||
|
|
||||||
for ( auto it = fonts.begin(); it != fonts.end(); ++it )
|
for ( auto it = fonts.constBegin(); it != fonts.constEnd(); ++it )
|
||||||
{
|
{
|
||||||
auto role = it->first;
|
auto role = it.key();
|
||||||
auto font = it->second;
|
auto font = it.value();
|
||||||
|
|
||||||
if ( font.pixelSize() > 0 )
|
if ( font.pixelSize() > 0 )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue