QskSkinHintTableEditor: add overloads for all states

... also, remove part of the logic when looking up current states.
This commit is contained in:
Peter Hartmann 2021-07-12 15:29:15 +02:00
parent 279ec9537c
commit b49305248a
7 changed files with 288 additions and 3 deletions

View File

@ -8,7 +8,8 @@ SUBDIRS = \
tools \
support \
examples \
playground
playground \
tests
OTHER_FILES = \
doc/Doxyfile \
@ -24,3 +25,4 @@ skins.depends = src
support.depends = src skins
examples.depends = tools support skins qmlexport
playground.depends = tools support skins qmlexport
tests.depends = src

View File

@ -27,9 +27,9 @@ inline const QVariant* qskResolvedHint( QskAspect aspect,
return &it->second;
}
if ( const auto topState = aspect.topState() )
if ( aspect.hasState() )
{
aspect.clearState( topState );
aspect.clearStates();
continue;
}

View File

@ -12,6 +12,8 @@
#include "QskBoxBorderColors.h"
#include "QskGradient.h"
#include <QVariant>
namespace
{
inline QskAspect aspectStrutSize( QskAspect aspect )
@ -75,6 +77,31 @@ QskSkinHintTable* QskSkinHintTableEditor::table() const
return m_table;
}
void QskSkinHintTableEditor::setHint( QskAspect aspect, const QVariant& hint, QskAspect::State state )
{
forAllCombinationsSetHint( state, aspect, hint );
}
bool QskSkinHintTableEditor::removeHint( QskAspect aspect, QskAspect::State state )
{
return forAllCombinationsRemoveHint( state, aspect );
}
void QskSkinHintTableEditor::setFlagHint( QskAspect aspect, const QVariant& hint, QskAspect::State state )
{
setHint( aspect | QskAspect::Flag, hint, state );
}
void QskSkinHintTableEditor::setMetricHint( QskAspect aspect, const QVariant& hint, QskAspect::State state )
{
setHint( aspect | QskAspect::Metric, hint, state );
}
void QskSkinHintTableEditor::setColorHint( QskAspect aspect, const QVariant& hint, QskAspect::State state )
{
setHint( aspect | QskAspect::Color, hint, state );
}
void QskSkinHintTableEditor::setFlag( QskAspect aspect, int flag )
{
setFlagHint( aspect, flag );
@ -132,6 +159,11 @@ void QskSkinHintTableEditor::setGradient( QskAspect aspect, const QskGradient& g
setColorHint( aspect, gradient );
}
void QskSkinHintTableEditor::setGradient( QskAspect aspect, const QskGradient& gradient, QskAspect::State state )
{
setColorHint( aspect, QVariant::fromValue( gradient ), state );
}
QskGradient QskSkinHintTableEditor::gradient( QskAspect aspect ) const
{
return colorHint< QskGradient >( aspect );
@ -279,6 +311,12 @@ void QskSkinHintTableEditor::setBoxShape(
setMetricHint( aspectShape( aspect ), shape );
}
void QskSkinHintTableEditor::setBoxShape(
QskAspect aspect, const QskBoxShapeMetrics& shape, QskAspect::State state )
{
setMetricHint( aspectShape( aspect ), QVariant::fromValue( shape ), state );
}
void QskSkinHintTableEditor::removeBoxShape( QskAspect aspect )
{
return removeMetricHint( aspectShape( aspect ) );
@ -309,6 +347,12 @@ void QskSkinHintTableEditor::setBoxBorderMetrics(
setMetricHint( aspectBorder( aspect ), borderMetrics );
}
void QskSkinHintTableEditor::setBoxBorderMetrics(
QskAspect aspect, const QskBoxBorderMetrics& borderMetrics, QskAspect::State state )
{
setMetricHint( aspectBorder( aspect ), QVariant::fromValue( borderMetrics ), state );
}
void QskSkinHintTableEditor::removeBoxBorderMetric( QskAspect aspect )
{
return removeMetricHint( aspectBorder( aspect ) );
@ -325,6 +369,12 @@ void QskSkinHintTableEditor::setBoxBorderColors(
setColorHint( aspectBorder( aspect ), borderColors );
}
void QskSkinHintTableEditor::setBoxBorderColors(
QskAspect aspect, const QskBoxBorderColors& borderColors, QskAspect::State state )
{
setColorHint( aspectBorder( aspect ), QVariant::fromValue( borderColors ), state );
}
void QskSkinHintTableEditor::setBoxBorderColors( QskAspect aspect,
const QColor& left, const QColor& top, const QColor& right, const QColor& bottom )
{
@ -341,3 +391,104 @@ QskBoxBorderColors QskSkinHintTableEditor::boxBorderColors( QskAspect aspect ) c
{
return colorHint< QskBoxBorderColors >( aspectBorder( aspect ) );
}
void QskSkinHintTableEditor::forAllCombinationsSetHint( QskAspect::State state,
QskAspect aspect, const QVariant& hint )
{
uint population = qPopulationCount( quint16( state ) );
// first find out which bits are set:
quint16 s = state;
uint i;
std::vector< quint16 > positions;
positions.reserve( population );
// use this instead of calling reserve(), trading execution time against space:
// ### even better: don't store positions, but calculate pairs of indices
// quint16 bla[16];
while( s != 0 ) // O(population)
{
i = 15 - qCountLeadingZeroBits( s );
quint16 testBit = ( 1 << i );
positions.push_back( i );
s = s ^ testBit;
}
for( uint i = 1; i <= population; ++i ) // O(population)
{
calculateCombinationsSetHint( positions, 0, positions.size() - 1, 0, i, QskAspect::NoState, aspect, hint );
}
}
void QskSkinHintTableEditor::calculateCombinationsSetHint( const std::vector< quint16 >& arr,
int start, int end, int index, int r,
QskAspect::State state, QskAspect aspect,
const QVariant& hint )
{
if( index == r )
{
setHint( aspect | state, hint );
}
for( int i = start; i <= end && end - i + 1 >= r - index; i++ )
{
auto currentState = state | static_cast< QskAspect::State >( 1 << arr[i] );
calculateCombinationsSetHint( arr, i + 1, end, index + 1, r, currentState, aspect, hint );
}
}
bool QskSkinHintTableEditor::forAllCombinationsRemoveHint( QskAspect::State state,
QskAspect aspect )
{
uint population = qPopulationCount( quint16( state ) );
// first find out which bits are set:
quint16 s = state;
uint i;
std::vector< quint16 > positions;
positions.reserve( population );
// use this instead of calling reserve(), trading execution time against space:
// ### even better: don't store positions, but calculate pairs of indices
// quint16 bla[16];
while( s != 0 ) // O(population)
{
i = 15 - qCountLeadingZeroBits( s );
quint16 testBit = ( 1 << i );
positions.push_back( i );
s = s ^ testBit;
}
bool ret = false;
for( uint i = 1; i <= population; ++i ) // O(population)
{
bool result = calculateCombinationsRemoveHint( positions, 0, positions.size() - 1, 0, i, QskAspect::NoState, aspect );
ret = ret || result;
}
return ret;
}
bool QskSkinHintTableEditor::calculateCombinationsRemoveHint( const std::vector< quint16 >& arr,
int start, int end, int index, int r,
QskAspect::State state, QskAspect aspect )
{
if( index == r )
{
return removeHint( aspect | state );
}
bool ret = false;
for( int i = start; i <= end && end - i + 1 >= r - index; i++ )
{
auto currentState = state | static_cast< QskAspect::State >( 1 << arr[i] );
bool result = calculateCombinationsRemoveHint( arr, i + 1, end, index + 1, r, currentState, aspect );
ret = ret || result;
}
return ret;
}

View File

@ -30,9 +30,11 @@ class QSK_EXPORT QskSkinHintTableEditor
// generic access
void setHint( QskAspect, const QVariant& );
void setHint( QskAspect, const QVariant&, QskAspect::State );
const QVariant& hint( QskAspect ) const;
bool removeHint( QskAspect );
bool removeHint( QskAspect, QskAspect::State );
QVariant takeHint( QskAspect );
bool hasHint( QskAspect ) const;
@ -48,6 +50,7 @@ class QSK_EXPORT QskSkinHintTableEditor
// flag/metric/color
void setFlagHint( QskAspect, const QVariant& );
void setFlagHint( QskAspect, const QVariant&, QskAspect::State );
void removeFlagHint( QskAspect );
QVariant flagHint( QskAspect ) const;
@ -55,6 +58,7 @@ class QSK_EXPORT QskSkinHintTableEditor
template< typename T > T flagHint( QskAspect ) const;
void setMetricHint( QskAspect, const QVariant& );
void setMetricHint( QskAspect, const QVariant&, QskAspect::State );
void removeMetricHint( QskAspect );
QVariant metricHint( QskAspect ) const;
@ -62,6 +66,7 @@ class QSK_EXPORT QskSkinHintTableEditor
template< typename T > T metricHint( QskAspect ) const;
void setColorHint( QskAspect, const QVariant& );
void setColorHint( QskAspect, const QVariant&, QskAspect::State );
void removeColorHint( QskAspect );
QVariant colorHint( QskAspect ) const;
@ -84,6 +89,7 @@ class QSK_EXPORT QskSkinHintTableEditor
void setHGradient( QskAspect, const QColor&, const QColor& );
void setVGradient( QskAspect, const QColor&, const QColor& );
void setGradient( QskAspect, const QskGradient& );
void setGradient( QskAspect, const QskGradient&, QskAspect::State state );
QskGradient gradient( QskAspect ) const;
void setStrutSize( QskAspect, const QSizeF& );
@ -123,6 +129,7 @@ class QSK_EXPORT QskSkinHintTableEditor
void setBoxShape( QskAspect, qreal topLeft, qreal topRight,
qreal bottomLeft, qreal bottomRight, Qt::SizeMode = Qt::AbsoluteSize );
void setBoxShape( QskAspect, const QskBoxShapeMetrics& );
void setBoxShape( QskAspect, const QskBoxShapeMetrics&, QskAspect::State );
void removeBoxShape( QskAspect );
QskBoxShapeMetrics boxShape( QskAspect ) const;
@ -131,16 +138,29 @@ class QSK_EXPORT QskSkinHintTableEditor
void setBoxBorderMetrics( QskAspect, qreal left, qreal top,
qreal right, qreal bottom, Qt::SizeMode = Qt::AbsoluteSize );
void setBoxBorderMetrics( QskAspect, const QskBoxBorderMetrics& );
void setBoxBorderMetrics( QskAspect, const QskBoxBorderMetrics&, QskAspect::State );
void removeBoxBorderMetric( QskAspect );
QskBoxBorderMetrics boxBorderMetrics( QskAspect ) const;
void setBoxBorderColors( QskAspect, const QskBoxBorderColors& );
void setBoxBorderColors( QskAspect, const QskBoxBorderColors&, QskAspect::State );
void setBoxBorderColors( QskAspect, const QColor& left, const QColor& top,
const QColor& right, const QColor& bottom );
void removeBoxBorderColors( QskAspect );
QskBoxBorderColors boxBorderColors( QskAspect ) const;
private:
void forAllCombinationsSetHint( QskAspect::State, QskAspect,
const QVariant& hint );
void calculateCombinationsSetHint( const std::vector< quint16 >& arr,
int start, int end, int index, int r,
QskAspect::State state, QskAspect aspect,
const QVariant& hint );
bool forAllCombinationsRemoveHint( QskAspect::State, QskAspect );
bool calculateCombinationsRemoveHint( const std::vector< quint16 >& arr,
int start, int end, int index, int r,
QskAspect::State state, QskAspect aspect );
QskSkinHintTable* m_table = nullptr;
};

View File

@ -0,0 +1,102 @@
/******************************************************************************
* QSkinny - Copyright (C) 2021 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include <QskBox.h>
#include <QskBoxBorderColors.h>
#include <QskSkin.h>
#include <QskSkinHintTableEditor.h>
#include <QGuiApplication>
#include <QtTest>
class TestSkinHints : public QObject
{
Q_OBJECT
private Q_SLOTS:
void setHints();
void removeHints();
private:
QskSkin m_skin;
QskSkinHintTableEditor ed = QskSkinHintTableEditor( &m_skin.hintTable() );
};
void TestSkinHints::setHints()
{
QskBoxBorderColors colors;
QVERIFY( colors.colorAt( Qt::TopEdge ) == QColor() );
ed.setBoxBorderColors( QskBox::Panel, { Qt::red },
QskControl::Disabled
| QskControl::Hovered
| QskControl::Focused
);
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Disabled );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Hovered );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Focused );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Disabled | QskControl::Hovered );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Disabled | QskControl::Focused );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Hovered | QskControl::Focused );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
colors = ed.boxBorderColors( QskBox::Panel | QskControl::Disabled | QskControl::Hovered | QskControl::Focused );
QVERIFY( colors.colorAt( Qt::TopEdge ) == Qt::red );
}
void TestSkinHints::removeHints()
{
bool removed = ed.removeHint( QskBox::Panel | QskAspect::Color,
QskControl::Hovered
| QskControl::Focused
);
QVERIFY( removed == false );
ed.setColorHint( QskBox::Panel, QColor( Qt::green ),
QskControl::Disabled
| QskControl::Hovered
| QskControl::Focused
);
removed = ed.removeHint( QskBox::Panel | QskAspect::Color,
QskControl::Disabled
| QskControl::Hovered
| QskControl::Focused
);
QVERIFY( removed == true );
removed = ed.removeHint( QskBox::Panel | QskAspect::Color,
QskControl::Disabled
| QskControl::Hovered
| QskControl::Focused
);
QVERIFY( removed == false );
ed.setColorHint( QskBox::Panel, QColor( Qt::green ),
QskControl::Disabled
| QskControl::Hovered
| QskControl::Focused
);
removed = ed.removeHint( QskBox::Panel | QskAspect::Color,
QskControl::Disabled
| QskControl::Hovered
);
QVERIFY( removed == true );
}
QTEST_MAIN(TestSkinHints)
#include "SkinHints.moc"

View File

@ -0,0 +1,6 @@
CONFIG += testcase qskinny
TARGET = tst_skinhints
SOURCES += SkinHints.cpp
QT += testlib
INCLUDEPATH *= $${QSK_DIRS}

4
tests/tests.pro Normal file
View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
skinhints