towards improved QskGradient

This commit is contained in:
Uwe Rathmann 2022-10-24 16:40:47 +02:00
parent 99132276fc
commit 03ce740b29
7 changed files with 189 additions and 158 deletions

View File

@ -205,11 +205,11 @@ void Box::setGradient(
{ {
const QskHctColor hctColor( base ); const QskHctColor hctColor( base );
QVector< QRgb > rgb; QVector< QRgb > colors;
rgb.reserve( 10 ); colors.reserve( 10 );
for ( int i = 0; i < 10; i++ ) for ( int i = 0; i < 10; i++ )
rgb += hctColor.toned( 90 - i * 7 ).rgb(); colors += hctColor.toned( 90 - i * 7 ).rgb();
setGradient( QskGradient( orientation, QskGradient::colorStops( rgb, true ) ) ); setGradient( QskGradient( orientation, qskBuildGradientStops( colors, true ) ) );
} }

View File

@ -29,15 +29,14 @@ namespace
{ {
const QskHctColor hctColor( base ); const QskHctColor hctColor( base );
QVector< QRgb > rgb; QVector< QRgb > colors;
rgb += hctColor.toned( 75 ).rgb(); colors += hctColor.toned( 75 ).rgb();
rgb += hctColor.toned( 60 ).rgb(); colors += hctColor.toned( 60 ).rgb();
rgb += hctColor.toned( 45 ).rgb(); colors += hctColor.toned( 45 ).rgb();
rgb += hctColor.toned( 30 ).rgb(); colors += hctColor.toned( 30 ).rgb();
const auto stops = QskGradient::colorStops( rgb, true ); setBarGradient( QskGradient( orientation(),
qskBuildGradientStops( colors, true ) ) );
setBarGradient( QskGradient( orientation(), stops ) );
} }
}; };
} }

View File

@ -9,8 +9,6 @@
#include <qhashfunctions.h> #include <qhashfunctions.h>
#include <qvariant.h> #include <qvariant.h>
#include <algorithm>
static void qskRegisterGradient() static void qskRegisterGradient()
{ {
qRegisterMetaType< QskGradient >(); qRegisterMetaType< QskGradient >();
@ -37,9 +35,7 @@ static inline bool qskIsGradientValid( const QskGradientStops& stops )
return false; return false;
if ( stops.first().position() != 0.0 || stops.last().position() != 1.0 ) if ( stops.first().position() != 0.0 || stops.last().position() != 1.0 )
{
return false; return false;
}
if ( !stops.first().color().isValid() ) if ( !stops.first().color().isValid() )
return false; return false;
@ -56,29 +52,6 @@ static inline bool qskIsGradientValid( const QskGradientStops& stops )
return true; return true;
} }
static inline bool qskIsMonochrome( const QskGradientStops& stops )
{
for ( int i = 1; i < stops.size(); i++ )
{
if ( stops[ i ].color() != stops[ 0 ].color() )
return false;
}
return true;
}
static inline bool qskIsVisible( const QskGradientStops& stops )
{
for ( const auto& stop : stops )
{
const auto& c = stop.color();
if ( c.isValid() && c.alpha() > 0 )
return true;
}
return false;
}
static inline QColor qskInterpolated( static inline QColor qskInterpolated(
const QskGradientStop& s1, const QskGradientStop& s2, qreal pos ) const QskGradientStop& s1, const QskGradientStop& s2, qreal pos )
{ {
@ -183,53 +156,6 @@ static inline QskGradientStops qskExtractedStops(
return extracted; return extracted;
} }
static inline QskGradientStops qskGradientStops( const QGradientStops& qtStops )
{
QskGradientStops stops;
stops.reserve( qtStops.count() );
for ( const auto& s : qtStops )
stops += QskGradientStop( s.first, s.second );
return stops;
}
static inline QskGradientStops qskColorStops(
const QRgb* rgb, int count, bool discrete )
{
QskGradientStops stops;
if ( discrete )
stops.reserve( 2 * count - 2 );
else
stops.reserve( count );
stops += QskGradientStop( 0.0, rgb[0] );
if ( discrete )
{
const auto step = 1.0 / count;
for ( int i = 1; i < count; i++ )
{
const qreal pos = i * step;
stops += QskGradientStop( pos, rgb[i - 1] );
stops += QskGradientStop( pos, rgb[i] );
}
}
else
{
const auto step = 1.0 / ( count - 1 );
for ( int i = 1; i < count - 1; i++ )
stops += QskGradientStop( i * step, rgb[i] );
}
stops += QskGradientStop( 1.0, rgb[count - 1] );
return stops;
}
QskGradient::QskGradient( Orientation orientation ) noexcept QskGradient::QskGradient( Orientation orientation ) noexcept
: m_orientation( orientation ) : m_orientation( orientation )
, m_isDirty( false ) , m_isDirty( false )
@ -277,7 +203,7 @@ QskGradient::QskGradient( Qt::Orientation orientation, QGradient::Preset preset
QskGradient::QskGradient( Orientation orientation, QGradient::Preset preset ) QskGradient::QskGradient( Orientation orientation, QGradient::Preset preset )
: QskGradient( orientation ) : QskGradient( orientation )
{ {
setStops( qskGradientStops( QGradient( preset ).stops() ) ); setStops( qskBuildGradientStops( QGradient( preset ).stops() ) );
} }
QskGradient::~QskGradient() QskGradient::~QskGradient()
@ -380,20 +306,35 @@ void QskGradient::setStops( const QskGradientStops& stops )
m_isDirty = true; m_isDirty = true;
} }
int QskGradient::stopCount() const int QskGradient::stopCount() const noexcept
{ {
return m_stops.count(); return m_stops.count();
} }
qreal QskGradient::stopAt( int index ) const qreal QskGradient::stopAt( int index ) const noexcept
{ {
if ( index >= m_stops.size() ) if ( index < 0 || index >= m_stops.size() )
return -1.0; return -1.0;
return m_stops[ index ].position(); return m_stops[ index ].position();
} }
QColor QskGradient::colorAt( int index ) const bool QskGradient::hasStopAt( qreal value ) const noexcept
{
// better use binary search TODO ...
for ( auto& stop : m_stops )
{
if ( stop.position() == value )
return true;
if ( stop.position() > value )
break;
}
return false;
}
QColor QskGradient::colorAt( int index ) const noexcept
{ {
if ( index >= m_stops.size() ) if ( index >= m_stops.size() )
return QColor(); return QColor();
@ -416,21 +357,6 @@ void QskGradient::setAlpha( int alpha )
m_isDirty = true; m_isDirty = true;
} }
bool QskGradient::hasStopAt( qreal value ) const noexcept
{
// better use binary search TODO ...
for ( auto& stop : m_stops )
{
if ( stop.position() == value )
return true;
if ( stop.position() > value )
break;
}
return false;
}
void QskGradient::reverse() void QskGradient::reverse()
{ {
if ( isMonochrome() ) if ( isMonochrome() )
@ -611,39 +537,6 @@ QVariant QskGradient::interpolate(
return QVariant::fromValue( from.interpolated( to, progress ) ); return QVariant::fromValue( from.interpolated( to, progress ) );
} }
QskGradientStops QskGradient::colorStops(
const QVector< QRgb >& rgb, bool discrete )
{
const int count = rgb.count();
if ( count == 0 )
return QskGradientStops();
if ( count == 1 )
{
QskGradientStops stops;
stops.reserve( 2 );
stops += QskGradientStop( 0.0, rgb[0] );
stops += QskGradientStop( 1.0, rgb[0] );
return stops;
}
return qskColorStops( rgb.constData(), count, discrete );
}
QGradientStops QskGradient::qtStops() const
{
QGradientStops qstops;
qstops.reserve( m_stops.count() );
for ( const auto& stop : m_stops )
qstops += { stop.position(), stop.color() };
return qstops;
}
void QskGradient::clearStops() void QskGradient::clearStops()
{ {
if ( !m_stops.isEmpty() ) if ( !m_stops.isEmpty() )
@ -655,9 +548,6 @@ void QskGradient::clearStops()
QskHashValue QskGradient::hash( QskHashValue seed ) const QskHashValue QskGradient::hash( QskHashValue seed ) const
{ {
if ( m_stops.isEmpty() )
return seed;
const auto o = orientation(); const auto o = orientation();
auto hash = qHashBits( &o, sizeof( o ), seed ); auto hash = qHashBits( &o, sizeof( o ), seed );
@ -667,7 +557,6 @@ QskHashValue QskGradient::hash( QskHashValue seed ) const
return hash; return hash;
} }
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h> #include <qdebug.h>
@ -704,13 +593,13 @@ QDebug operator<<( QDebug debug, const QskGradient& gradient )
} }
else else
{ {
const auto& s = gradient.stops(); const auto& stops = gradient.stops();
for ( int i = 0; i < s.count(); i++ ) for ( int i = 0; i < stops.count(); i++ )
{ {
if ( i != 0 ) if ( i != 0 )
debug << ", "; debug << ", ";
debug << s[i]; debug << stops[i];
} }
} }
} }

View File

@ -98,15 +98,10 @@ class QSK_EXPORT QskGradient
QskHashValue hash( QskHashValue seed ) const; QskHashValue hash( QskHashValue seed ) const;
Q_INVOKABLE qreal stopAt( int index ) const; Q_INVOKABLE qreal stopAt( int index ) const noexcept;
Q_INVOKABLE QColor colorAt( int index ) const; Q_INVOKABLE QColor colorAt( int index ) const noexcept;
Q_INVOKABLE int stopCount() const; Q_INVOKABLE int stopCount() const noexcept;
QGradientStops qtStops() const;
static QskGradientStops colorStops(
const QVector< QRgb >&, bool discrete = false );
private: private:
void updateStatusBits() const; void updateStatusBits() const;

View File

@ -8,6 +8,7 @@
#include <qhashfunctions.h> #include <qhashfunctions.h>
#include <qvariant.h> #include <qvariant.h>
#include <qbrush.h>
#include <algorithm> #include <algorithm>
@ -94,3 +95,128 @@ QDebug operator<<( QDebug debug, const QskGradientStop& stop )
#endif #endif
#include "moc_QskGradientStop.cpp" #include "moc_QskGradientStop.cpp"
// some helper functions around QskGradientStops
bool qskIsVisible( const QskGradientStops& stops ) noexcept
{
for ( const auto& stop : stops )
{
const auto& c = stop.color();
if ( c.isValid() && c.alpha() > 0 )
return true;
}
return false;
}
bool qskIsMonochrome( const QskGradientStops& stops ) noexcept
{
for ( int i = 1; i < stops.size(); i++ )
{
if ( stops[ i ].color() != stops[ 0 ].color() )
return false;
}
return true;
}
QskGradientStops qskTransparentGradientStops( const QskGradientStops& stops, qreal ratio )
{
auto newStops = stops;
for ( auto& stop : newStops )
{
auto c = stop.color();
c.setAlpha( c.alpha() * ratio );
stop.setColor( c );
}
return newStops;
}
QVector< QskGradientStop > qskBuildGradientStops( const QGradientStops& qtStops )
{
QVector< QskGradientStop > stops;
stops.reserve( qtStops.count() );
for ( const auto& s : qtStops )
stops += QskGradientStop( s.first, s.second );
return stops;
}
template< typename T >
static inline QVector< QskGradientStop > qskCreateStops(
const QVector< T > colors, bool discrete )
{
QVector< QskGradientStop > stops;
const auto count = colors.count();
if ( count == 0 )
return stops;
if ( count == 1 )
{
stops.reserve( 2 );
stops += QskGradientStop( 0.0, colors[0] );
stops += QskGradientStop( 1.0, colors[0] );
return stops;
}
if ( discrete )
{
const auto step = 1.0 / count;
stops.reserve( 2 * count - 2 );
stops += QskGradientStop( 0.0, colors[0] );
for ( int i = 1; i < count; i++ )
{
const qreal pos = i * step;
stops += QskGradientStop( pos, colors[i - 1] );
stops += QskGradientStop( pos, colors[i] );
}
stops += QskGradientStop( 1.0, colors[count - 1] );
}
else
{
const auto step = 1.0 / ( count - 1 );
stops.reserve( count );
stops += QskGradientStop( 0.0, colors[0] );
for ( int i = 1; i < count - 1; i++ )
stops += QskGradientStop( i * step, colors[i] );
stops += QskGradientStop( 1.0, colors[count - 1] );
}
return stops;
}
QskGradientStops qskBuildGradientStops( const QVector< QRgb >& colors, bool discrete )
{
return qskCreateStops( colors, discrete );
}
QskGradientStops qskBuildGradientStops( const QVector< QColor >& colors, bool discrete )
{
return qskCreateStops( colors, discrete );
}
QGradientStops qskToQGradientStops( const QskGradientStops& stops )
{
QGradientStops qstops;
qstops.reserve( stops.count() );
for ( const auto& stop : stops )
qstops += { stop.position(), stop.color() };
return qstops;
}

View File

@ -12,6 +12,8 @@
#include <qmetatype.h> #include <qmetatype.h>
#include <qvector.h> #include <qvector.h>
typedef QPair< qreal, QColor > QGradientStop;
class QSK_EXPORT QskGradientStop class QSK_EXPORT QskGradientStop
{ {
Q_GADGET Q_GADGET
@ -22,6 +24,7 @@ class QSK_EXPORT QskGradientStop
public: public:
constexpr QskGradientStop() noexcept; constexpr QskGradientStop() noexcept;
constexpr QskGradientStop( qreal position, const QColor& ) noexcept; constexpr QskGradientStop( qreal position, const QColor& ) noexcept;
constexpr QskGradientStop( const QGradientStop& ) noexcept;
QskGradientStop( qreal position, Qt::GlobalColor ) noexcept; QskGradientStop( qreal position, Qt::GlobalColor ) noexcept;
QskGradientStop( qreal position, QRgb ) noexcept; QskGradientStop( qreal position, QRgb ) noexcept;
@ -57,8 +60,6 @@ class QSK_EXPORT QskGradientStop
Q_DECLARE_METATYPE( QskGradientStop ) Q_DECLARE_METATYPE( QskGradientStop )
typedef QVector< QskGradientStop > QskGradientStops;
inline constexpr QskGradientStop::QskGradientStop() noexcept inline constexpr QskGradientStop::QskGradientStop() noexcept
: m_position( -1.0 ) : m_position( -1.0 )
{ {
@ -83,6 +84,11 @@ inline QskGradientStop::QskGradientStop(
{ {
} }
inline constexpr QskGradientStop::QskGradientStop( const QGradientStop& qtStop ) noexcept
: QskGradientStop( qtStop.first, qtStop.second )
{
}
inline constexpr qreal QskGradientStop::position() const noexcept inline constexpr qreal QskGradientStop::position() const noexcept
{ {
return m_position; return m_position;
@ -116,4 +122,18 @@ QSK_EXPORT QDebug operator<<( QDebug, const QskGradientStop& );
#endif #endif
typedef QVector< QskGradientStop > QskGradientStops;
QSK_EXPORT bool qskIsMonochrome( const QskGradientStops& ) noexcept;
QSK_EXPORT bool qskIsVisible( const QskGradientStops& ) noexcept;
QSK_EXPORT QskGradientStops qskBuildGradientStops(
const QVector< QRgb >&, bool discrete = false );
QSK_EXPORT QskGradientStops qskBuildGradientStops(
const QVector< QColor >&, bool discrete = false );
QSK_EXPORT QskGradientStops qskBuildGradientStops( const QVector< QGradientStop >& );
QSK_EXPORT QVector< QGradientStop > qskToQGradientStops( const QVector< QskGradientStop >& );
#endif #endif

View File

@ -23,17 +23,19 @@ void QskArcRenderer::renderArc(const QRectF& rect,
QBrush brush; QBrush brush;
const auto qStops = qskToQGradientStops( gradient.stops() );
if( gradient.orientation() == QskGradient::Vertical ) if( gradient.orientation() == QskGradient::Vertical )
{ {
QRadialGradient radial( rect.center(), qMin( rect.width(), rect.height() ) ); QRadialGradient radial( rect.center(), qMin( rect.width(), rect.height() ) );
radial.setStops( gradient.qtStops() ); radial.setStops( qStops );
brush = radial; brush = radial;
} }
else else
{ {
QConicalGradient conical( rect.center(), metrics.startAngle() ); QConicalGradient conical( rect.center(), metrics.startAngle() );
conical.setStops( gradient.qtStops() ); conical.setStops( qStops );
brush = conical; brush = conical;
} }