diff --git a/examples/boxes/Box.cpp b/examples/boxes/Box.cpp index defdc82c..dbad97ac 100644 --- a/examples/boxes/Box.cpp +++ b/examples/boxes/Box.cpp @@ -63,17 +63,16 @@ void Box::setBackground( FillType type, const QRgb base, bool inverted ) return; } - double hue, chroma; - QskHctColor::getHueAndChroma( base, hue, chroma ); + const QskHctColor htcColor( base ); if ( type == Solid ) { - setGradient( QskHctColor::rgb( hue, chroma, 50 ) ); + setGradient( htcColor.toned( 50 ).rgb() ); } else { - const auto dark = QskHctColor::rgb( hue, chroma, 40 ); - const auto light = QskHctColor::rgb( hue, chroma, 70 ); + const auto dark = htcColor.toned( 40 ).rgb(); + const auto light = htcColor.toned( 70 ).rgb(); const auto orientation = static_cast< QskGradient::Orientation >( type - 2 ); @@ -100,12 +99,11 @@ void Box::setBorder( BorderType type, const QRgb base ) return; } - double hue, chroma; - QskHctColor::getHueAndChroma( base, hue, chroma ); + const QskHctColor htcColor( base ); - const auto dark = QskHctColor::rgb( hue, chroma, 40 ); - const auto mid = QskHctColor::rgb( hue, chroma, 65 ); - const auto light = QskHctColor::rgb( hue, chroma, 90 ); + const auto dark = htcColor.toned( 40 ).rgb(); + const auto mid = htcColor.toned( 65 ).rgb(); + const auto light = htcColor.toned( 90 ).rgb(); switch ( static_cast< int >( type ) ) { @@ -206,17 +204,13 @@ void Box::setGradient( const QskGradient& gradient ) void Box::setGradient( const QskGradient::Orientation orientation, const QRgb base ) { - double hue, chroma; - QskHctColor::getHueAndChroma( base, hue, chroma ); + const QskHctColor hctColor( base ); QVector< QRgb > rgb; rgb.reserve( 10 ); for ( int i = 0; i < 10; i++ ) - { - const auto tone = 90 - i * 7; - rgb += QskHctColor::rgb( hue, chroma, tone ); - } + rgb += hctColor.toned( 90 - i * 7 ).rgb(); setGradient( QskGradient( orientation, QskGradient::colorStops( rgb, true ) ) ); } diff --git a/examples/gallery/progressbar/ProgressBarPage.cpp b/examples/gallery/progressbar/ProgressBarPage.cpp index 5bd7a1d7..e3e0146b 100644 --- a/examples/gallery/progressbar/ProgressBarPage.cpp +++ b/examples/gallery/progressbar/ProgressBarPage.cpp @@ -27,14 +27,13 @@ namespace void setTheme( const QRgb base ) { - double hue, chroma; - QskHctColor::getHueAndChroma( base, hue, chroma ); + const QskHctColor hctColor( base ); QVector< QRgb > rgb; - rgb += QskHctColor::rgb( hue, chroma, 75 ); - rgb += QskHctColor::rgb( hue, chroma, 60 ); - rgb += QskHctColor::rgb( hue, chroma, 45 ); - rgb += QskHctColor::rgb( hue, chroma, 30 ); + rgb += hctColor.toned( 75 ).rgb(); + rgb += hctColor.toned( 60 ).rgb(); + rgb += hctColor.toned( 45 ).rgb(); + rgb += hctColor.toned( 30 ).rgb(); const auto stops = QskGradient::colorStops( rgb, true ); diff --git a/src/common/QskHctColor.cpp b/src/common/QskHctColor.cpp index 61a51f55..78adff96 100644 --- a/src/common/QskHctColor.cpp +++ b/src/common/QskHctColor.cpp @@ -349,6 +349,21 @@ static inline int delinearized( double rgbComponent ) return qBound( 0, qRound( v * 255 ), 255 ); } +static inline double labF( double t ) +{ + constexpr double e = 216.0 / 24389.0; + + if ( t > e ) + { + return pow( t, 1.0 / 3.0 ); + } + else + { + constexpr double kappa = 24389.0 / 27.0; + return ( kappa * t + 16 ) / 116; + } +} + static inline double labInvf( double ft ) { const double e = 216.0 / 24389.0; @@ -732,7 +747,7 @@ static QRgb findResultByJ( double hueRadians, double chroma, double y ) return 0; } -QRgb QskHctColor::rgb( double hue, double chroma, double tone ) +static inline QRgb getRgb( double hue, double chroma, double tone ) { if ( chroma < 0.0001 || tone < 0.0001 || tone > 99.9999 ) return argbFromLstar( tone ); @@ -778,7 +793,7 @@ static XYZ xyzFromArgb( QRgb rgb) return matrixMultiply( xyz, SRGB_TO_XYZ ); } -void QskHctColor::getHueAndChroma( QRgb rgb, double& hue, double& chroma ) +static void getHTC( QRgb rgb, double& hue, double& chroma, double& tone ) { ViewingConditions vc; @@ -832,4 +847,54 @@ void QskHctColor::getHueAndChroma( QRgb rgb, double& hue, double& chroma ) chroma = alpha * sqrt(J / 100.0); } + + { + tone = 116.0 * labF( y / 100.0 ) - 16.0; + } } + +QskHctColor::QskHctColor( QRgb rgb ) +{ + getHTC( rgb, m_hue, m_chroma, m_tone ); +} + +void QskHctColor::setHue( qreal hue ) +{ + m_hue = fmod( hue, 360.0 ); + if ( m_hue < 0.0 ) + m_hue += 360.0; +} + +void QskHctColor::setChroma( qreal chroma ) noexcept +{ + m_chroma = ( chroma < 0.0 ) ? 0.0 : chroma; +} + +void QskHctColor::setTone( qreal tone ) noexcept +{ + m_tone = qBound( 0.0, tone, 100.0 ); +} + +void QskHctColor::setRgb( QRgb rgb ) +{ + getHTC( rgb, m_hue, m_chroma, m_tone ); +} + +QRgb QskHctColor::rgb() const +{ + return getRgb( m_hue, m_chroma, m_tone ); +} + +#ifndef QT_NO_DEBUG_STREAM + +#include + +QDebug operator<<( QDebug debug, const QskHctColor& color ) +{ + debug.nospace() << "HTC(" + << color.hue() << "," << color.chroma() << "," << color.tone() << ")"; + + return debug.space(); +} + +#endif diff --git a/src/common/QskHctColor.h b/src/common/QskHctColor.h index d8782e12..041c0e4e 100644 --- a/src/common/QskHctColor.h +++ b/src/common/QskHctColor.h @@ -20,26 +20,68 @@ https://material-foundation.github.io/material-theme-builder/#/custom shows how to create a tonal palette from a given RGB color. + */ - The methods in QskHctColor allow to do the same: - - QVector palette( const QRgb rgb ) - { - double hue, chroma; - QskHctColor::getHueAndChroma( rgb, hue, chroma ); - - QVector< QRgb > pal; - for ( int tone = 0; tone <= 100; tone += 10 ) - pal += QskHctColor::rgb( hue, chroma, tone ); - - return pal; - } -*/ - -namespace QskHctColor +class QSK_EXPORT QskHctColor +{ + public: + constexpr QskHctColor() noexcept = default; + constexpr QskHctColor( qreal hue, qreal chrome, qreal tone = 40 ) noexcept; + + QskHctColor( QRgb ); + + void setHue( qreal hue ); + constexpr qreal hue() const noexcept; + + void setChroma( qreal chroma ) noexcept; + constexpr qreal chroma() const noexcept; + + void setTone( qreal tone ) noexcept; + constexpr qreal tone() const noexcept; + + constexpr QskHctColor toned( qreal tone ) const noexcept; + + void setRgb( QRgb ); + QRgb rgb() const; + + private: + qreal m_hue = 0; // [0.0, 360.0[ + qreal m_chroma = 0; + qreal m_tone = 0; // [0.0, 100.0] +}; + +Q_DECLARE_TYPEINFO( QskHctColor, Q_MOVABLE_TYPE ); + +inline constexpr QskHctColor::QskHctColor( qreal hue, qreal chroma, qreal tone ) noexcept + : m_hue( hue ) + , m_chroma( chroma ) + , m_tone( tone ) { - QSK_EXPORT QRgb rgb( double hue, double chroma, double tone ); - QSK_EXPORT void getHueAndChroma( QRgb rgb, double& hue, double& chroma ); } +inline constexpr qreal QskHctColor::hue() const noexcept +{ + return m_hue; +} + +inline constexpr qreal QskHctColor::chroma() const noexcept +{ + return m_chroma; +} + +inline constexpr qreal QskHctColor::tone() const noexcept +{ + return m_tone; +} + +inline constexpr QskHctColor QskHctColor::toned( qreal tone ) const noexcept +{ + return QskHctColor( m_hue, m_chroma, tone ); +} + +#ifndef QT_NO_DEBUG_STREAM + class QDebug; + QSK_EXPORT QDebug operator<<( QDebug, const QskHctColor& ); +#endif + #endif