From 8e8179a2196b75959161145ffd4d57b6d29bdf29 Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Tue, 30 Apr 2024 16:22:37 +0200 Subject: [PATCH] feat(ColorWidget) : Add CMYK support --- .../gui/auto_additions/qgscolorwidgets.py | 4 + .../gui/auto_generated/qgscolorwidgets.sip.in | 20 +- .../gui/auto_generated/qgscolorwidgets.sip.in | 20 +- src/gui/qgscolorwidgets.cpp | 303 ++-- src/gui/qgscolorwidgets.h | 20 +- src/gui/qgscompoundcolorwidget.cpp | 90 +- src/gui/qgscompoundcolorwidget.h | 10 +- src/ui/qgscompoundcolorwidget.ui | 1441 +++++++++-------- tests/src/gui/CMakeLists.txt | 1 + tests/src/gui/testqgscompoundcolorwidget.cpp | 92 ++ tests/src/python/test_qgscolorwidget.py | 172 ++ 11 files changed, 1361 insertions(+), 812 deletions(-) create mode 100644 tests/src/gui/testqgscompoundcolorwidget.cpp create mode 100644 tests/src/python/test_qgscolorwidget.py diff --git a/python/PyQt6/gui/auto_additions/qgscolorwidgets.py b/python/PyQt6/gui/auto_additions/qgscolorwidgets.py index 06e7160642ee..e004c681cafc 100644 --- a/python/PyQt6/gui/auto_additions/qgscolorwidgets.py +++ b/python/PyQt6/gui/auto_additions/qgscolorwidgets.py @@ -7,6 +7,10 @@ QgsColorWidget.Saturation = QgsColorWidget.ColorComponent.Saturation QgsColorWidget.Value = QgsColorWidget.ColorComponent.Value QgsColorWidget.Alpha = QgsColorWidget.ColorComponent.Alpha +QgsColorWidget.Cyan = QgsColorWidget.ColorComponent.Cyan +QgsColorWidget.Magenta = QgsColorWidget.ColorComponent.Magenta +QgsColorWidget.Yellow = QgsColorWidget.ColorComponent.Yellow +QgsColorWidget.Black = QgsColorWidget.ColorComponent.Black QgsColorRampWidget.Horizontal = QgsColorRampWidget.Orientation.Horizontal QgsColorRampWidget.Vertical = QgsColorRampWidget.Orientation.Vertical QgsColorTextWidget.HexRgb = QgsColorTextWidget.ColorTextFormat.HexRgb diff --git a/python/PyQt6/gui/auto_generated/qgscolorwidgets.sip.in b/python/PyQt6/gui/auto_generated/qgscolorwidgets.sip.in index 9c00acd07c4f..8072da189a42 100644 --- a/python/PyQt6/gui/auto_generated/qgscolorwidgets.sip.in +++ b/python/PyQt6/gui/auto_generated/qgscolorwidgets.sip.in @@ -33,7 +33,11 @@ set to a color with an ambiguous hue (e.g., black or white shades). Hue, Saturation, Value, - Alpha + Alpha, + Cyan, + Magenta, + Yellow, + Black }; QgsColorWidget( QWidget *parent /TransferThis/ = 0, ColorComponent component = Multiple ); @@ -145,7 +149,7 @@ Returns the range of valid values for the color widget's component :return: maximum value allowed for color component, or -1 if widget has multiple components %End - int componentRange( ColorComponent component ) const; + static int componentRange( ColorComponent component ); %Docstring Returns the range of valid values a color component @@ -172,7 +176,7 @@ as QColor returns a hue of -1 if the color's hue is ambiguous (e.g., if the satu :return: explicitly set hue for widget %End - void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ) const; + static void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ); %Docstring Alters a color by modifying the value of a specific color component @@ -182,6 +186,16 @@ Alters a color by modifying the value of a specific color component valid range for the color component. %End + bool isCmyk() const; +%Docstring +Returns true if the color widget component is either Cyan, Magenta, Yellow or Black +%End + + static bool isCmyk( QgsColorWidget::ColorComponent component ); +%Docstring +Returns true if ``component`` is either Cyan, Magenta, Yellow or Black +%End + static const QPixmap &transparentBackground(); %Docstring Generates a checkboard pattern pixmap for use as a background to transparent colors diff --git a/python/gui/auto_generated/qgscolorwidgets.sip.in b/python/gui/auto_generated/qgscolorwidgets.sip.in index f898ca867c46..fd73e363e6d3 100644 --- a/python/gui/auto_generated/qgscolorwidgets.sip.in +++ b/python/gui/auto_generated/qgscolorwidgets.sip.in @@ -33,7 +33,11 @@ set to a color with an ambiguous hue (e.g., black or white shades). Hue, Saturation, Value, - Alpha + Alpha, + Cyan, + Magenta, + Yellow, + Black }; QgsColorWidget( QWidget *parent /TransferThis/ = 0, ColorComponent component = Multiple ); @@ -145,7 +149,7 @@ Returns the range of valid values for the color widget's component :return: maximum value allowed for color component, or -1 if widget has multiple components %End - int componentRange( ColorComponent component ) const; + static int componentRange( ColorComponent component ); %Docstring Returns the range of valid values a color component @@ -172,7 +176,7 @@ as QColor returns a hue of -1 if the color's hue is ambiguous (e.g., if the satu :return: explicitly set hue for widget %End - void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ) const; + static void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ); %Docstring Alters a color by modifying the value of a specific color component @@ -182,6 +186,16 @@ Alters a color by modifying the value of a specific color component valid range for the color component. %End + bool isCmyk() const; +%Docstring +Returns true if the color widget component is either Cyan, Magenta, Yellow or Black +%End + + static bool isCmyk( QgsColorWidget::ColorComponent component ); +%Docstring +Returns true if ``component`` is either Cyan, Magenta, Yellow or Black +%End + static const QPixmap &transparentBackground(); %Docstring Generates a checkboard pattern pixmap for use as a background to transparent colors diff --git a/src/gui/qgscolorwidgets.cpp b/src/gui/qgscolorwidgets.cpp index e2db43bf74c6..543f7197f332 100644 --- a/src/gui/qgscolorwidgets.cpp +++ b/src/gui/qgscolorwidgets.cpp @@ -102,6 +102,14 @@ int QgsColorWidget::componentValue( const QgsColorWidget::ColorComponent compone return mCurrentColor.value(); case QgsColorWidget::Alpha: return mCurrentColor.alpha(); + case QgsColorWidget::Cyan: + return mCurrentColor.cyan(); + case QgsColorWidget::Yellow: + return mCurrentColor.yellow(); + case QgsColorWidget::Magenta: + return mCurrentColor.magenta(); + case QgsColorWidget::Black: + return mCurrentColor.black(); default: return -1; } @@ -112,7 +120,7 @@ int QgsColorWidget::componentRange() const return componentRange( mComponent ); } -int QgsColorWidget::componentRange( const QgsColorWidget::ColorComponent component ) const +int QgsColorWidget::componentRange( const QgsColorWidget::ColorComponent component ) { if ( component == QgsColorWidget::Multiple ) { @@ -144,42 +152,133 @@ int QgsColorWidget::hue() const } } -void QgsColorWidget::alterColor( QColor &color, const QgsColorWidget::ColorComponent component, const int newValue ) const +void QgsColorWidget::alterColor( QColor &color, const QgsColorWidget::ColorComponent component, const int newValue ) { - int h, s, v, a; - color.getHsv( &h, &s, &v, &a ); - //clip value to sensible range const int clippedValue = std::min( std::max( 0, newValue ), componentRange( component ) ); + if ( isCmyk( component ) ) + { + int c, m, y, k, a; + color.getCmyk( &c, &m, &y, &k, &a ); + + switch ( component ) + { + case QgsColorWidget::Cyan: + if ( c == clippedValue ) + { + return; + } + color.setCmyk( clippedValue, m, y, k, a ); + break; + case QgsColorWidget::Magenta: + if ( m == clippedValue ) + { + return; + } + color.setCmyk( c, clippedValue, y, k, a ); + break; + case QgsColorWidget::Yellow: + if ( y == clippedValue ) + { + return; + } + color.setCmyk( c, m, clippedValue, k, a ); + break; + case QgsColorWidget::Black: + if ( k == clippedValue ) + { + return; + } + color.setCmyk( c, m, y, clippedValue, a ); + break; + default: + return; + } + } + else + { + int r, g, b, a; + color.getRgb( &r, &g, &b, &a ); + int h, s, v; + color.getHsv( &h, &s, &v ); + + switch ( component ) + { + case QgsColorWidget::Red: + if ( r == clippedValue ) + { + return; + } + color.setRed( clippedValue ); + break; + case QgsColorWidget::Green: + if ( g == clippedValue ) + { + return; + } + color.setGreen( clippedValue ); + break; + case QgsColorWidget::Blue: + if ( b == clippedValue ) + { + return; + } + color.setBlue( clippedValue ); + break; + case QgsColorWidget::Hue: + if ( h == clippedValue ) + { + return; + } + color.setHsv( clippedValue, s, v, a ); + break; + case QgsColorWidget::Saturation: + if ( s == clippedValue ) + { + return; + } + color.setHsv( h, clippedValue, v, a ); + break; + case QgsColorWidget::Value: + if ( v == clippedValue ) + { + return; + } + color.setHsv( h, s, clippedValue, a ); + break; + case QgsColorWidget::Alpha: + if ( a == clippedValue ) + { + return; + } + color.setAlpha( clippedValue ); + break; + default: + return; + } + } +} + +bool QgsColorWidget::isCmyk( QgsColorWidget::ColorComponent component ) +{ switch ( component ) { - case QgsColorWidget::Red: - color.setRed( clippedValue ); - return; - case QgsColorWidget::Green: - color.setGreen( clippedValue ); - return; - case QgsColorWidget::Blue: - color.setBlue( clippedValue ); - return; - case QgsColorWidget::Hue: - color.setHsv( clippedValue, s, v, a ); - return; - case QgsColorWidget::Saturation: - color.setHsv( h, clippedValue, v, a ); - return; - case QgsColorWidget::Value: - color.setHsv( h, s, clippedValue, a ); - return; - case QgsColorWidget::Alpha: - color.setAlpha( clippedValue ); - return; + case Cyan: + case Magenta: + case Yellow: + case Black: + return true; default: - return; + return false; } } +bool QgsColorWidget::isCmyk() const +{ + return isCmyk( mComponent ); +} + const QPixmap &QgsColorWidget::transparentBackground() { static QPixmap sTranspBkgrd; @@ -269,72 +368,19 @@ void QgsColorWidget::setComponentValue( const int value ) return; } - //clip value to valid range - int valueClipped = std::min( value, componentRange() ); - valueClipped = std::max( valueClipped, 0 ); - - int r, g, b, a; - mCurrentColor.getRgb( &r, &g, &b, &a ); - int h, s, v; - mCurrentColor.getHsv( &h, &s, &v ); //overwrite hue with explicit hue if required - h = hue(); - - switch ( mComponent ) + if ( mComponent == QgsColorWidget::Saturation || mComponent == QgsColorWidget::Value ) { - case QgsColorWidget::Red: - if ( r == valueClipped ) - { - return; - } - mCurrentColor.setRed( valueClipped ); - break; - case QgsColorWidget::Green: - if ( g == valueClipped ) - { - return; - } - mCurrentColor.setGreen( valueClipped ); - break; - case QgsColorWidget::Blue: - if ( b == valueClipped ) - { - return; - } - mCurrentColor.setBlue( valueClipped ); - break; - case QgsColorWidget::Hue: - if ( h == valueClipped ) - { - return; - } - mCurrentColor.setHsv( valueClipped, s, v, a ); - break; - case QgsColorWidget::Saturation: - if ( s == valueClipped ) - { - return; - } - mCurrentColor.setHsv( h, valueClipped, v, a ); - break; - case QgsColorWidget::Value: - if ( v == valueClipped ) - { - return; - } - mCurrentColor.setHsv( h, s, valueClipped, a ); - break; - case QgsColorWidget::Alpha: - if ( a == valueClipped ) - { - return; - } - mCurrentColor.setAlpha( valueClipped ); - break; - default: - return; + int h, s, v, a; + mCurrentColor.getHsv( &h, &s, &v, &a ); + + h = hue(); + + mCurrentColor.setHsv( h, s, v, a ); } + alterColor( mCurrentColor, mComponent, value ); + //update recorded hue if ( mCurrentColor.hue() >= 0 ) { @@ -839,30 +885,19 @@ void QgsColorBox::setComponent( const QgsColorWidget::ColorComponent component ) void QgsColorBox::setColor( const QColor &color, const bool emitSignals ) { //check if we need to redraw the box image - if ( mComponent == QgsColorWidget::Red && mCurrentColor.red() != color.red() ) - { - mDirty = true; - } - else if ( mComponent == QgsColorWidget::Green && mCurrentColor.green() != color.green() ) - { - mDirty = true; - } - else if ( mComponent == QgsColorWidget::Blue && mCurrentColor.blue() != color.blue() ) - { - mDirty = true; - } - else if ( mComponent == QgsColorWidget::Hue && color.hsvHue() >= 0 && hue() != color.hsvHue() ) - { - mDirty = true; - } - else if ( mComponent == QgsColorWidget::Saturation && mCurrentColor.hsvSaturation() != color.hsvSaturation() ) - { - mDirty = true; - } - else if ( mComponent == QgsColorWidget::Value && mCurrentColor.value() != color.value() ) - { - mDirty = true; - } + mDirty |= ( + ( mComponent == QgsColorWidget::Red && mCurrentColor.red() != color.red() ) || + ( mComponent == QgsColorWidget::Green && mCurrentColor.green() != color.green() ) || + ( mComponent == QgsColorWidget::Blue && mCurrentColor.blue() != color.blue() ) || + ( mComponent == QgsColorWidget::Hue && color.hsvHue() >= 0 && hue() != color.hsvHue() ) || + ( mComponent == QgsColorWidget::Saturation && mCurrentColor.hsvSaturation() != color.hsvSaturation() ) || + ( mComponent == QgsColorWidget::Value && mCurrentColor.value() != color.value() ) || + ( mComponent == QgsColorWidget::Cyan && mCurrentColor.cyan() != color.cyan() ) || + ( mComponent == QgsColorWidget::Magenta && mCurrentColor.magenta() != color.magenta() ) || + ( mComponent == QgsColorWidget::Yellow && mCurrentColor.yellow() != color.yellow() ) || + ( mComponent == QgsColorWidget::Black && mCurrentColor.black() != color.black() ) + ); + QgsColorWidget::setColor( color, emitSignals ); } @@ -949,14 +984,22 @@ QgsColorWidget::ColorComponent QgsColorBox::yComponent() const { case QgsColorWidget::Red: return QgsColorWidget::Green; - case QgsColorWidget:: Green: - case QgsColorWidget:: Blue: + case QgsColorWidget::Green: + case QgsColorWidget::Blue: return QgsColorWidget::Red; + case QgsColorWidget::Hue: - return QgsColorWidget:: Saturation; - case QgsColorWidget:: Saturation: - case QgsColorWidget:: Value: - return QgsColorWidget::Hue; + return QgsColorWidget::Saturation; + case QgsColorWidget::Saturation: + case QgsColorWidget::Value: + return QgsColorWidget::Hue; + + case QgsColorWidget::Magenta: + return QgsColorWidget::Yellow; + case QgsColorWidget::Yellow: + case QgsColorWidget::Cyan: + return QgsColorWidget::Magenta; + default: //should not occur return QgsColorWidget::Red; @@ -972,16 +1015,24 @@ QgsColorWidget::ColorComponent QgsColorBox::xComponent() const { switch ( mComponent ) { - case QgsColorWidget::Red: - case QgsColorWidget:: Green: + case QgsColorWidget::Red: + case QgsColorWidget::Green: return QgsColorWidget::Blue; - case QgsColorWidget:: Blue: + case QgsColorWidget::Blue: return QgsColorWidget::Green; + case QgsColorWidget::Hue: - case QgsColorWidget:: Saturation: - return QgsColorWidget:: Value; - case QgsColorWidget:: Value: - return QgsColorWidget::Saturation; + case QgsColorWidget::Saturation: + return QgsColorWidget::Value; + case QgsColorWidget::Value: + return QgsColorWidget::Saturation; + + case QgsColorWidget::Magenta: + case QgsColorWidget::Yellow: + return QgsColorWidget::Cyan; + case QgsColorWidget::Cyan: + return QgsColorWidget::Yellow; + default: //should not occur return QgsColorWidget::Red; diff --git a/src/gui/qgscolorwidgets.h b/src/gui/qgscolorwidgets.h index fd32563df263..02ef4775c2d0 100644 --- a/src/gui/qgscolorwidgets.h +++ b/src/gui/qgscolorwidgets.h @@ -53,7 +53,11 @@ class GUI_EXPORT QgsColorWidget : public QWidget Hue, //!< Hue component of color (based on HSV model) Saturation, //!< Saturation component of color (based on HSV model) Value, //!< Value component of color (based on HSV model) - Alpha //!< Alpha component (opacity) of color + Alpha, //!< Alpha component (opacity) of color + Cyan, //!< Cyan component (based on CMYK model) of color + Magenta, //!< Magenta component (based on CMYK model) of color + Yellow, //!< Yellow component (based on CMYK model) of color + Black //!< Black component (based on CMYK model) of color }; /** @@ -155,7 +159,7 @@ class GUI_EXPORT QgsColorWidget : public QWidget * Returns the range of valid values a color component * \returns maximum value allowed for color component */ - int componentRange( ColorComponent component ) const; + static int componentRange( ColorComponent component ); /** * Returns the value of a component of the widget's current color. This method correctly @@ -180,7 +184,17 @@ class GUI_EXPORT QgsColorWidget : public QWidget * \param newValue new value of color component. Values are automatically clipped to a * valid range for the color component. */ - void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ) const; + static void alterColor( QColor &color, QgsColorWidget::ColorComponent component, int newValue ); + + /** + * Returns true if the color widget component is either Cyan, Magenta, Yellow or Black + */ + bool isCmyk() const; + + /** + * Returns true if \a component is either Cyan, Magenta, Yellow or Black + */ + static bool isCmyk( QgsColorWidget::ColorComponent component ); /** * Generates a checkboard pattern pixmap for use as a background to transparent colors diff --git a/src/gui/qgscompoundcolorwidget.cpp b/src/gui/qgscompoundcolorwidget.cpp index ced8cd09d013..b7fd1697c057 100644 --- a/src/gui/qgscompoundcolorwidget.cpp +++ b/src/gui/qgscompoundcolorwidget.cpp @@ -53,6 +53,14 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsCompoundColorWidget::mTabWidget_currentChanged ); connect( mActionShowInButtons, &QAction::toggled, this, &QgsCompoundColorWidget::mActionShowInButtons_toggled ); + connect( mColorModel, static_cast( &QComboBox::currentIndexChanged ), this, [this]( int index ) + { + if ( index ) + setColor( this->color().toCmyk() ); + else + setColor( this->color().toRgb() ); + } ); + if ( widgetLayout == LayoutVertical ) { // shuffle stuff around @@ -112,7 +120,7 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c mSchemeToolButton->setMenu( schemeMenu ); connect( mSchemeComboBox, static_cast( &QComboBox::currentIndexChanged ), this, &QgsCompoundColorWidget::schemeIndexChanged ); - connect( mSchemeList, &QgsColorSchemeList::colorSelected, this, &QgsCompoundColorWidget::setColor ); + connect( mSchemeList, &QgsColorSchemeList::colorSelected, this, &QgsCompoundColorWidget::_setColor ); mOldColorLabel->hide(); @@ -127,6 +135,10 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c mSaturationSlider->setComponent( QgsColorWidget::Saturation ); mValueSlider->setComponent( QgsColorWidget::Value ); mAlphaSlider->setComponent( QgsColorWidget::Alpha ); + mCyanSlider->setComponent( QgsColorWidget::Cyan ); + mMagentaSlider->setComponent( QgsColorWidget::Magenta ); + mYellowSlider->setComponent( QgsColorWidget::Yellow ); + mBlackSlider->setComponent( QgsColorWidget::Black ); mSwatchButton1->setShowMenu( false ); mSwatchButton1->setBehavior( QgsColorButton::SignalOnly ); @@ -259,34 +271,38 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c mTabWidget->setCurrentIndex( currentTab ); //setup connections - connect( mColorBox, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mColorWheel, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mColorText, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mVerticalRamp, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mRedSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mGreenSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mBlueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mHueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mValueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mSaturationSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mAlphaSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mColorPreview, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton1, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton2, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton3, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton4, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton5, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton6, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton7, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton8, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton9, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton10, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton11, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton12, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton13, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton14, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton15, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); - connect( mSwatchButton16, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor ); + connect( mColorBox, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mColorWheel, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mColorText, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mVerticalRamp, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mRedSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mGreenSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mBlueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mHueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mValueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mCyanSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mMagentaSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mYellowSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mBlackSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mSaturationSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mAlphaSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mColorPreview, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton1, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton2, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton3, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton4, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton5, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton6, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton7, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton8, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton9, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton10, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton11, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton12, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton13, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton14, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton15, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); + connect( mSwatchButton16, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::_setColor ); } QgsCompoundColorWidget::~QgsCompoundColorWidget() @@ -707,6 +723,14 @@ void QgsCompoundColorWidget::stopPicking( QPoint eventPos, const bool takeSample } void QgsCompoundColorWidget::setColor( const QColor &color ) +{ + mColorModel->setCurrentIndex( color.spec() == QColor::Cmyk ? 1 : 0 ); + mRGB->setVisible( color.spec() != QColor::Cmyk ); + mCMYK->setVisible( color.spec() == QColor::Cmyk ); + _setColor( color ); +} + +void QgsCompoundColorWidget::_setColor( const QColor &color ) { if ( !color.isValid() ) { @@ -719,6 +743,12 @@ void QgsCompoundColorWidget::setColor( const QColor &color ) //opacity disallowed, so don't permit transparent colors fixedColor.setAlpha( 255 ); } + + if ( mColorModel->currentIndex() && fixedColor.spec() != QColor::Cmyk ) + { + fixedColor = fixedColor.toCmyk(); + } + const QList colorWidgets = this->findChildren(); const auto constColorWidgets = colorWidgets; for ( QgsColorWidget *widget : constColorWidgets ) @@ -731,6 +761,8 @@ void QgsCompoundColorWidget::setColor( const QColor &color ) widget->setColor( fixedColor ); widget->blockSignals( false ); } + + emit currentColorChanged( fixedColor ); } diff --git a/src/gui/qgscompoundcolorwidget.h b/src/gui/qgscompoundcolorwidget.h index 4683344b6952..2b7a527ca0bf 100644 --- a/src/gui/qgscompoundcolorwidget.h +++ b/src/gui/qgscompoundcolorwidget.h @@ -167,10 +167,14 @@ class GUI_EXPORT QgsCompoundColorWidget : public QgsPanelWidget, private Ui::Qgs void mSampleButton_clicked(); void mTabWidget_currentChanged( int index ); - private slots: - void mActionShowInButtons_toggled( bool state ); + /** + * Internal color setter. Set \a color without changing current color model (RGB or CMYK), + * contrary to public setColor() + */ + void _setColor( const QColor &color ); + private: static QScreen *findScreenAt( QPoint pos ); @@ -224,6 +228,8 @@ class GUI_EXPORT QgsCompoundColorWidget : public QgsPanelWidget, private Ui::Qgs //! Updates the state of actions for the current selected scheme void updateActionsForCurrentScheme(); + + friend class TestQgsCompoundColorWidget; }; #endif // QGSCOMPOUNDCOLORWIDGET_H diff --git a/src/ui/qgscompoundcolorwidget.ui b/src/ui/qgscompoundcolorwidget.ui index b23d000a4f07..aa1a016851ce 100644 --- a/src/ui/qgscompoundcolorwidget.ui +++ b/src/ui/qgscompoundcolorwidget.ui @@ -6,568 +6,163 @@ 0 0 - 597 - 329 + 588 + 481 - - - 0 - - - 0 - - - 0 - - - 0 - + 6 - - - - 2 - - - - 16 - 16 - + + + + + 0 + 0 + - - - - :/images/themes/default/mIconColorBox.svg:/images/themes/default/mIconColorBox.svg - - - - - - Color ramp - - - - - - - - - - - - - - :/images/themes/default/mIconColorWheel.svg:/images/themes/default/mIconColorWheel.svg - - - - - - Color wheel - - - - - - - - - - - :/images/themes/default/mIconColorSwatches.svg:/images/themes/default/mIconColorSwatches.svg - - - - - - Color swatches - - - - 2 - - - - - 1 - - - - - - - - - - - QToolButton::InstantPopup - - - - - - - - - - - - 1 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Add current color - - - - - - - :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg - - - - - - - Remove selected color - - - - - - - :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg - - - - - - - - - - - :/images/themes/default/mIconColorPicker.svg:/images/themes/default/mIconColorPicker.svg - - - - - - Color picker - - - - - - - - Sample average radius - - - - - - - px - - - 1 - - - 100 - - - - - - - - - Sample color - - - - - - - <i>Press space to sample a color from under the mouse cursor</i> - - - Qt::AutoText - - - true - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 1 - - - 1 - - - 1 - - - 1 - - - - - - 0 - 40 - - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - - - - - - - - - - - - - - - H - - - - - - - - - - - - - - - - - - - - - S - - - - - - - - - - - - - - - - - - - - - V - - - - - - - - - - - - - - - - - - - - - R - - - - - - - - - - - - - - - - - - - - - G - - - - - - - - - - - - - - - - - - - - - B - - - - - - - - - - - - - - Opacity - - - - - - - - - - - - - - HTML notation - - - - - - - + + + 1 + + + + + + 38 + 30 + + + + + 38 + 30 + + + + + + - - - - Qt::Vertical + + + + + 38 + 30 + - + - 20 - 0 + 38 + 30 - - - - - - - - - - 0 - 0 - - - - - 16777215 - 80 - - - - - - Current - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + - - - - Old + + + + + 38 + 30 + - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 38 + 30 + + + + - - - - - 0 - 0 - - + + - 28 - 0 + 38 + 30 - 28 - 16777215 + 38 + 30 - - Add color to swatch + + + + + + + + + + 38 + 30 + + + + + 38 + 30 + - - - :/images/themes/default/mActionAtlasNext.svg:/images/themes/default/mActionAtlasNext.svg + + + + + + + 38 + 30 + - + - 24 - 24 + 38 + 30 + + + - - - - QFrame::StyledPanel + + + + + 38 + 30 + - - QFrame::Raised + + + 38 + 30 + + + + - - - 1 - - - 1 - - - 1 - - - 1 - - - - - - 0 - 40 - - - - - - - - - - - - - 0 - 0 - - - - - 1 - - - + + 38 @@ -585,8 +180,8 @@ - - + + 38 @@ -604,8 +199,8 @@ - - + + 38 @@ -623,8 +218,8 @@ - - + + 38 @@ -642,8 +237,8 @@ - - + + 38 @@ -661,8 +256,8 @@ - - + + 38 @@ -680,8 +275,8 @@ - - + + 38 @@ -699,8 +294,8 @@ - - + + 38 @@ -718,8 +313,8 @@ - - + + 38 @@ -735,140 +330,694 @@ - - - - + + + + + + + + + + 0 + 0 + + + + + 16777215 + 80 + + + + + + + Current + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Old + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + - 38 - 30 + 28 + 0 - 38 - 30 + 28 + 16777215 + + Add color to swatch + - - - - - - - 38 - 30 - + + + :/images/themes/default/mActionAtlasNext.svg:/images/themes/default/mActionAtlasNext.svg - + - 38 - 30 + 24 + 24 - - + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + 0 + 40 + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - + + + + + + + 2 + + + + 16 + 16 + + + + + + :/images/themes/default/mIconColorBox.svg:/images/themes/default/mIconColorBox.svg + + + + + + Color ramp + + + + + + + + + + + + + + :/images/themes/default/mIconColorWheel.svg:/images/themes/default/mIconColorWheel.svg + + + + + + Color wheel + + + + + + + + + + + :/images/themes/default/mIconColorSwatches.svg:/images/themes/default/mIconColorSwatches.svg + + + + + + Color swatches + + + + 2 + + + + + 1 + + + + + + + + + + + QToolButton::InstantPopup + + + + + + + + + + + + 1 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add current color + + + + + + + :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg + + + + + + + Remove selected color + + + + + + + :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg + + + + + + + + + + + :/images/themes/default/mIconColorPicker.svg:/images/themes/default/mIconColorPicker.svg + + + + + + Color picker + + + + + + + + Sample average radius + + + + + + + px + + + 1 + + + 100 + + + + + + + + + Sample color + + + + + + + <i>Press space to sample a color from under the mouse cursor</i> + + + Qt::AutoText + + + true + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + 0 + 40 + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + + + + + + + Color model + + + + + + + + RGB + + + + + CMYK + + + + + + + + Qt::Horizontal + + + + 228 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + H + + + + + + + + + + + + + + + + + + + + + S + + + + + + + + + + + + + + + + + + + + + V + + + + + + + + + + + + + + + + + + + + + R + + + + + + + + + + + + + + + + + + + + + G + + + + + + + + + + + + + + + + + + + + + B + + + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + C + + + + + + + + + + + + + + + + + + + + + M + + + + + + + + + + + + + + + + + + + + + Y + + + + + + + + + + + + + + + + + + + + + K + + + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - - + + + + + + Opacity + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - - + + + + + + HTML notation + + + + + + + - - - - - 38 - 30 - + + + + Qt::Vertical - + - 38 - 30 + 20 + 0 - - - - + @@ -942,17 +1091,17 @@ - - QgsSpinBox - QSpinBox -
qgsspinbox.h
-
QgsColorButton QToolButton
qgscolorbutton.h
1
+ + QgsSpinBox + QSpinBox +
qgsspinbox.h
+
QgsColorBox QWidget diff --git a/tests/src/gui/CMakeLists.txt b/tests/src/gui/CMakeLists.txt index f2b2111d66a7..fcf1d67ebd3f 100644 --- a/tests/src/gui/CMakeLists.txt +++ b/tests/src/gui/CMakeLists.txt @@ -74,6 +74,7 @@ set(TESTS testqgsexternalresourcewidgetwrapper.cpp testqgsquerybuilder.cpp testqgsqueryresultwidget.cpp + testqgscompoundcolorwidget.cpp ) foreach(TESTSRC ${TESTS}) diff --git a/tests/src/gui/testqgscompoundcolorwidget.cpp b/tests/src/gui/testqgscompoundcolorwidget.cpp new file mode 100644 index 000000000000..2c7cdca1ad38 --- /dev/null +++ b/tests/src/gui/testqgscompoundcolorwidget.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + testqgscompoundcolorwidget.cpp + --------------------- + begin : 2024/05/07 + copyright : (C) 2024 by Julien Cabieces + email : julien dot cabieces at oslandia dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgstest.h" + +#include "qgscompoundcolorwidget.h" + +class TestQgsCompoundColorWidget : public QgsTest +{ + Q_OBJECT + + public: + + TestQgsCompoundColorWidget() : QgsTest( QStringLiteral( "Compound color widget Tests" ) ) {} + + private slots: + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + void init();// will be called before each testfunction is executed. + void cleanup();// will be called after every testfunction. + void testCmykConversion(); +}; + +void TestQgsCompoundColorWidget::initTestCase() +{ +} + +void TestQgsCompoundColorWidget::cleanupTestCase() +{ +} + +void TestQgsCompoundColorWidget::init() +{ +} + +void TestQgsCompoundColorWidget::cleanup() +{ +} + +void TestQgsCompoundColorWidget::testCmykConversion() +{ + QgsCompoundColorWidget w( nullptr, QColor( 10, 20, 30, 50 ) ); + w.setVisible( true ); + + QCOMPARE( w.color(), QColor( 10, 20, 30, 50 ) ); + QCOMPARE( w.mColorModel->currentIndex(), 0 ); + QVERIFY( w.mRGB->isVisible() ); + QVERIFY( !w.mCMYK->isVisible() ); + + // switch to CMYK + w.mColorModel->setCurrentIndex( 1 ); + QVERIFY( !w.mRGB->isVisible() ); + QVERIFY( w.mCMYK->isVisible() ); + QCOMPARE( w.mColorModel->currentIndex(), 1 ); + QCOMPARE( w.color(), QColor::fromCmyk( 170, 85, 0, 225, 50 ) ); + + // switch back to RGB + w.mColorModel->setCurrentIndex( 0 ); + QVERIFY( w.mRGB->isVisible() ); + QVERIFY( !w.mCMYK->isVisible() ); + QCOMPARE( w.mColorModel->currentIndex(), 0 ); + QCOMPARE( w.color(), QColor( 10, 20, 30, 50 ) ); + + // edit color in CMYK mode + w.mColorModel->setCurrentIndex( 1 ); + QVERIFY( !w.mRGB->isVisible() ); + QVERIFY( w.mCMYK->isVisible() ); + QCOMPARE( w.mColorModel->currentIndex(), 1 ); + QCOMPARE( w.color(), QColor::fromCmyk( 170, 85, 0, 225, 50 ) ); + + w.mCyanSlider->setColor( QColor::fromCmyk( 120, 85, 0, 225, 50 ), true ); + QCOMPARE( w.color(), QColor::fromCmyk( 120, 85, 0, 225, 50 ) ); + + // edit color in RGB, the returned color is still CMYK + w.mColorWheel->setColor( QColor( 10, 20, 30, 50 ), true ); + QCOMPARE( w.color(), QColor::fromCmyk( 170, 85, 0, 225, 50 ) ); +} + +QGSTEST_MAIN( TestQgsCompoundColorWidget ) +#include "testqgscompoundcolorwidget.moc" diff --git a/tests/src/python/test_qgscolorwidget.py b/tests/src/python/test_qgscolorwidget.py new file mode 100644 index 000000000000..6b57f033543d --- /dev/null +++ b/tests/src/python/test_qgscolorwidget.py @@ -0,0 +1,172 @@ +"""QGIS Unit tests for QgsColorWidget + +.. note:: This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +""" +__author__ = 'Julien Cabieces' +__date__ = '02/05/2024' +__copyright__ = 'Copyright 2024, The QGIS Project' + +from qgis.PyQt.QtGui import QColor +from qgis.gui import QgsColorWidget + +import unittest +from qgis.testing import start_app, QgisTestCase + +start_app() + + +class TestQgsWidget(QgisTestCase): + + def testAlterColor(self): + """ + test alterColor method + """ + + # rgb + color = QColor(12, 34, 56) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Red, 112) + self.assertEqual(color, QColor(112, 34, 56, 255)) + self.assertEqual(color.spec(), QColor.Spec.Rgb) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Green, 134) + self.assertEqual(color.spec(), QColor.Spec.Rgb) + self.assertEqual(color, QColor(112, 134, 56, 255)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Blue, 156) + self.assertEqual(color.spec(), QColor.Spec.Rgb) + self.assertEqual(color, QColor(112, 134, 156, 255)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Alpha, 210) + self.assertEqual(color.spec(), QColor.Spec.Rgb) + self.assertEqual(color, QColor(112, 134, 156, 210)) + + # hsv + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Hue, 100) + self.assertEqual(color.spec(), QColor.Spec.Hsv) + self.assertEqual(color, QColor.fromHsv(100, 72, 156, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Saturation, 150) + self.assertEqual(color.spec(), QColor.Spec.Hsv) + self.assertEqual(color, QColor.fromHsv(100, 150, 156, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Value, 200) + self.assertEqual(color.spec(), QColor.Spec.Hsv) + self.assertEqual(color, QColor.fromHsv(100, 150, 200, 210)) + + # clipped value + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Value, 300) + self.assertEqual(color.spec(), QColor.Spec.Hsv) + self.assertEqual(color, QColor.fromHsv(100, 150, 255, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Value, -2) + self.assertEqual(color.spec(), QColor.Spec.Hsv) + self.assertEqual(color, QColor.fromHsv(100, 150, 0, 210)) + + # cmyk + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Cyan, 22) + self.assertEqual(color.spec(), QColor.Spec.Cmyk) + self.assertEqual(color, QColor.fromCmyk(22, 0, 0, 255, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Magenta, 33) + self.assertEqual(color.spec(), QColor.Spec.Cmyk) + self.assertEqual(color, QColor.fromCmyk(22, 33, 0, 255, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Yellow, 44) + self.assertEqual(color.spec(), QColor.Spec.Cmyk) + self.assertEqual(color, QColor.fromCmyk(22, 33, 44, 255, 210)) + QgsColorWidget.alterColor(color, QgsColorWidget.ColorComponent.Black, 55) + self.assertEqual(color.spec(), QColor.Spec.Cmyk) + self.assertEqual(color, QColor.fromCmyk(22, 33, 44, 55, 210)) + + def testSetComponentValue(self): + """ + test setComponentValue method + """ + w = QgsColorWidget() + + w.setColor(QColor(12, 34, 56)) + self.assertEqual(w.color(), QColor(12, 34, 56)) + + # rgb + w.setComponent(QgsColorWidget.ColorComponent.Red) + w.setComponentValue(112) + self.assertEqual(w.color(), QColor(112, 34, 56, 255)) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + w.setComponent(QgsColorWidget.ColorComponent.Green) + w.setComponentValue(134) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + self.assertEqual(w.color(), QColor(112, 134, 56, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Blue) + w.setComponentValue(156) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + self.assertEqual(w.color(), QColor(112, 134, 156, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Alpha) + w.setComponentValue(210) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + self.assertEqual(w.color(), QColor(112, 134, 156, 210)) + + # hsv + w.setComponent(QgsColorWidget.ColorComponent.Hue) + w.setComponentValue(100) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 72, 156, 210)) + w.setComponent(QgsColorWidget.ColorComponent.Saturation) + w.setComponentValue(150) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 150, 156, 210)) + w.setComponent(QgsColorWidget.ColorComponent.Value) + w.setComponentValue(200) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 150, 200, 210)) + + # clipped value + w.setComponent(QgsColorWidget.ColorComponent.Value) + w.setComponentValue(300) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 150, 255, 210)) + w.setComponent(QgsColorWidget.ColorComponent.Value) + w.setComponentValue(-2) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 150, 0, 210)) + + # Multiple component has no effect + w.setComponent(QgsColorWidget.ColorComponent.Multiple) + w.setComponentValue(18) + self.assertEqual(w.color().spec(), QColor.Spec.Hsv) + self.assertEqual(w.color(), QColor.fromHsv(100, 150, 0, 210)) + + # set an achromatic color to check it keeps the hue + w.setColor(QColor(130, 130, 130, 255)) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + self.assertEqual(w.color(), QColor(130, 130, 130, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Value) + w.setComponentValue(42) + self.assertEqual(w.color(), QColor.fromHsv(100, 0, 42, 255)) + self.assertEqual(w.componentValue(QgsColorWidget.ColorComponent.Hue), 100) + + # cmyk + w.setComponent(QgsColorWidget.ColorComponent.Cyan) + w.setComponentValue(22) + self.assertEqual(w.color().spec(), QColor.Spec.Cmyk) + self.assertEqual(w.color(), QColor.fromCmyk(22, 0, 0, 213, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Magenta) + w.setComponentValue(33) + self.assertEqual(w.color().spec(), QColor.Spec.Cmyk) + self.assertEqual(w.color(), QColor.fromCmyk(22, 33, 0, 213, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Yellow) + w.setComponentValue(44) + self.assertEqual(w.color().spec(), QColor.Spec.Cmyk) + self.assertEqual(w.color(), QColor.fromCmyk(22, 33, 44, 213, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Black) + w.setComponentValue(55) + self.assertEqual(w.color().spec(), QColor.Spec.Cmyk) + self.assertEqual(w.color(), QColor.fromCmyk(22, 33, 44, 55, 255)) + + # set an achromatic color to check it keeps the hue (set from former cmyk values) + self.assertEqual(w.color().hue(), 30) + w.setColor(QColor(130, 130, 130, 255)) + self.assertEqual(w.color().spec(), QColor.Spec.Rgb) + self.assertEqual(w.color(), QColor(130, 130, 130, 255)) + w.setComponent(QgsColorWidget.ColorComponent.Value) + w.setComponentValue(42) + self.assertEqual(w.color(), QColor.fromHsv(30, 0, 42, 255)) + self.assertEqual(w.componentValue(QgsColorWidget.ColorComponent.Hue), 30) + + +if __name__ == '__main__': + unittest.main()