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..cd1786f04d48 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 + QColor::Spec colorSpec() const; +%Docstring +Returns color widget type of color, either RGB, HSV, CMYK, or Invalid if this component value is Multiple or Alpha +%End + + static QColor::Spec colorSpec( QgsColorWidget::ColorComponent component ); +%Docstring +Returns ``component`` type of color, either RGB, HSV, CMYK, or Invalid if ``component`` value is Multiple or Alpha +%End + static const QPixmap &transparentBackground(); %Docstring Generates a checkboard pattern pixmap for use as a background to transparent colors @@ -201,6 +215,7 @@ Generates a checkboard pattern pixmap for use as a background to transparent col virtual void mouseReleaseEvent( QMouseEvent *e ); + }; diff --git a/python/gui/auto_generated/qgscolorwidgets.sip.in b/python/gui/auto_generated/qgscolorwidgets.sip.in index f898ca867c46..3dea5fec41ed 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 + QColor::Spec colorSpec() const; +%Docstring +Returns color widget type of color, either RGB, HSV, CMYK, or Invalid if this component value is Multiple or Alpha +%End + + static QColor::Spec colorSpec( QgsColorWidget::ColorComponent component ); +%Docstring +Returns ``component`` type of color, either RGB, HSV, CMYK, or Invalid if ``component`` value is Multiple or Alpha +%End + static const QPixmap &transparentBackground(); %Docstring Generates a checkboard pattern pixmap for use as a background to transparent colors @@ -201,6 +215,7 @@ Generates a checkboard pattern pixmap for use as a background to transparent col virtual void mouseReleaseEvent( QMouseEvent *e ); + }; diff --git a/src/gui/qgscolorwidgets.cpp b/src/gui/qgscolorwidgets.cpp index e2db43bf74c6..c709b93c3e45 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,144 @@ 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 ( colorSpec( component ) == QColor::Spec::Cmyk ) + { + 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; + } + } +} + +QColor::Spec QgsColorWidget::colorSpec( 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 Red: + case Green: + case Blue: + return QColor::Spec::Rgb; + + case Hue: + case Saturation: + case Value: + return QColor::Spec::Hsv; + + case Cyan: + case Magenta: + case Yellow: + case Black: + return QColor::Spec::Cmyk; + default: - return; + return QColor::Spec::Invalid; } } +QColor::Spec QgsColorWidget::colorSpec() const +{ + return colorSpec( mComponent ); +} + const QPixmap &QgsColorWidget::transparentBackground() { static QPixmap sTranspBkgrd; @@ -269,72 +379,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 +896,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 +995,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 +1026,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..7ad88f2a9f20 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 color widget type of color, either RGB, HSV, CMYK, or Invalid if this component value is Multiple or Alpha + */ + QColor::Spec colorSpec() const; + + /** + * Returns \a component type of color, either RGB, HSV, CMYK, or Invalid if \a component value is Multiple or Alpha + */ + static QColor::Spec colorSpec( QgsColorWidget::ColorComponent component ); /** * Generates a checkboard pattern pixmap for use as a background to transparent colors @@ -197,6 +211,8 @@ class GUI_EXPORT QgsColorWidget : public QWidget void mouseMoveEvent( QMouseEvent *e ) override; void mousePressEvent( QMouseEvent *e ) override; void mouseReleaseEvent( QMouseEvent *e ) override; + + friend class TestQgsCompoundColorWidget; }; diff --git a/src/gui/qgscompoundcolorwidget.cpp b/src/gui/qgscompoundcolorwidget.cpp index ced8cd09d013..c4a5137dde6b 100644 --- a/src/gui/qgscompoundcolorwidget.cpp +++ b/src/gui/qgscompoundcolorwidget.cpp @@ -22,6 +22,7 @@ #include "qgsscreenhelper.h" #include "qgsguiutils.h" +#include #include #include #include @@ -41,18 +42,55 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c mScreenHelper = new QgsScreenHelper( this ); - connect( mHueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mHueRadio_toggled ); - connect( mSaturationRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mSaturationRadio_toggled ); - connect( mValueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mValueRadio_toggled ); - connect( mRedRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mRedRadio_toggled ); - connect( mGreenRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mGreenRadio_toggled ); - connect( mBlueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mBlueRadio_toggled ); + mRgbRadios = + { + { mHueRadio, QgsColorWidget::ColorComponent::Hue }, + { mSaturationRadio, QgsColorWidget::ColorComponent::Saturation }, + { mValueRadio, QgsColorWidget::ColorComponent::Value }, + { mRedRadio, QgsColorWidget::ColorComponent::Red }, + { mGreenRadio, QgsColorWidget::ColorComponent::Green }, + { mBlueRadio, QgsColorWidget::ColorComponent::Blue } + }; + + mCmykRadios = + { + { mCyanRadio, QgsColorWidget::ColorComponent::Cyan }, + { mMagentaRadio, QgsColorWidget::ColorComponent::Magenta }, + { mYellowRadio, QgsColorWidget::ColorComponent::Yellow }, + { mBlackRadio, QgsColorWidget::ColorComponent::Black } + }; + + mRgbGroup = new QButtonGroup( this ); + int i = 0; + for ( auto colorRadio : mRgbRadios ) + mRgbGroup->addButton( colorRadio.first, i++ ); + + mCmykGroup = new QButtonGroup( this ); + i = 0; + for ( auto colorRadio : mCmykRadios ) + mCmykGroup->addButton( colorRadio.first, i++ ); + + connect( mRgbGroup, &QButtonGroup::idToggled, this, &QgsCompoundColorWidget::onColorButtonGroupToggled ); + connect( mCmykGroup, &QButtonGroup::idToggled, this, &QgsCompoundColorWidget::onColorButtonGroupToggled ); connect( mAddColorToSchemeButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mAddColorToSchemeButton_clicked ); connect( mAddCustomColorButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mAddCustomColorButton_clicked ); connect( mSampleButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mSampleButton_clicked ); connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsCompoundColorWidget::mTabWidget_currentChanged ); connect( mActionShowInButtons, &QAction::toggled, this, &QgsCompoundColorWidget::mActionShowInButtons_toggled ); + mColorModel->addItem( tr( "RGB" ), QColor::Spec::Rgb ); + mColorModel->addItem( tr( "CMYK" ), QColor::Spec::Cmyk ); + connect( mColorModel, static_cast( &QComboBox::currentIndexChanged ), this, [this]( int ) + { + const QColor::Spec spec = static_cast< QColor::Spec >( mColorModel->currentData().toInt() ); + if ( spec == QColor::Spec::Cmyk ) + setColor( this->color().toCmyk() ); + else + setColor( this->color().toRgb() ); + + updateComponent(); + } ); + if ( widgetLayout == LayoutVertical ) { // shuffle stuff around @@ -112,7 +150,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 +165,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 ); @@ -232,61 +274,51 @@ QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &c setColor( color ); } - //restore active component radio button - const int activeRadio = settings.value( QStringLiteral( "Windows/ColorDialog/activeComponent" ), 2 ).toInt(); - switch ( activeRadio ) - { - case 0: - mHueRadio->setChecked( true ); - break; - case 1: - mSaturationRadio->setChecked( true ); - break; - case 2: - mValueRadio->setChecked( true ); - break; - case 3: - mRedRadio->setChecked( true ); - break; - case 4: - mGreenRadio->setChecked( true ); - break; - case 5: - mBlueRadio->setChecked( true ); - break; - } + // restore active Rgb/Cmyk component radio button + const int activeRgbRadio = settings.value( QStringLiteral( "Windows/ColorDialog/activeComponent" ), 2 ).toInt(); + if ( QAbstractButton *rgbRadio = mRgbGroup->button( activeRgbRadio ) ) + rgbRadio->setChecked( true ); + + const int activeCmykRadio = settings.value( QStringLiteral( "Windows/ColorDialog/activeCmykComponent" ), 0 ).toInt(); + if ( QAbstractButton *cmykRadio = mCmykGroup->button( activeCmykRadio ) ) + cmykRadio->setChecked( true ); + const int currentTab = settings.value( QStringLiteral( "Windows/ColorDialog/activeTab" ), 0 ).toInt(); 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() @@ -601,12 +633,9 @@ void QgsCompoundColorWidget::mTabWidget_currentChanged( int index ) { //disable radio buttons if not using the first tab, as they have no meaning for other tabs const bool enabled = index == 0; - mRedRadio->setEnabled( enabled ); - mBlueRadio->setEnabled( enabled ); - mGreenRadio->setEnabled( enabled ); - mHueRadio->setEnabled( enabled ); - mSaturationRadio->setEnabled( enabled ); - mValueRadio->setEnabled( enabled ); + const QList colorRadios{ mHueRadio, mSaturationRadio, mValueRadio, mRedRadio, mGreenRadio, mBlueRadio, mCyanRadio, mMagentaRadio, mYellowRadio, mBlackRadio }; + for ( QRadioButton *colorRadio : colorRadios ) + colorRadio->setEnabled( enabled ); } void QgsCompoundColorWidget::mActionShowInButtons_toggled( bool state ) @@ -641,21 +670,9 @@ void QgsCompoundColorWidget::saveSettings() QgsSettings settings; - //record active component - int activeRadio = 0; - if ( mHueRadio->isChecked() ) - activeRadio = 0; - if ( mSaturationRadio->isChecked() ) - activeRadio = 1; - if ( mValueRadio->isChecked() ) - activeRadio = 2; - if ( mRedRadio->isChecked() ) - activeRadio = 3; - if ( mGreenRadio->isChecked() ) - activeRadio = 4; - if ( mBlueRadio->isChecked() ) - activeRadio = 5; - settings.setValue( QStringLiteral( "Windows/ColorDialog/activeComponent" ), activeRadio ); + // record active component + settings.setValue( QStringLiteral( "Windows/ColorDialog/activeComponent" ), mRgbGroup->checkedId() ); + settings.setValue( QStringLiteral( "Windows/ColorDialog/activeCmykComponent" ), mCmykGroup->checkedId() ); //record current scheme settings.setValue( QStringLiteral( "Windows/ColorDialog/activeScheme" ), mSchemeComboBox->currentIndex() ); @@ -707,6 +724,15 @@ void QgsCompoundColorWidget::stopPicking( QPoint eventPos, const bool takeSample } void QgsCompoundColorWidget::setColor( const QColor &color ) +{ + const QColor::Spec colorSpec = color.spec() == QColor::Cmyk ? QColor::Cmyk : QColor::Rgb; + mColorModel->setCurrentIndex( mColorModel->findData( colorSpec ) ); + 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 +745,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 +763,8 @@ void QgsCompoundColorWidget::setColor( const QColor &color ) widget->setColor( fixedColor ); widget->blockSignals( false ); } + + emit currentColorChanged( fixedColor ); } @@ -850,58 +884,26 @@ void QgsCompoundColorWidget::keyPressEvent( QKeyEvent *e ) stopPicking( QCursor::pos(), e->key() == Qt::Key_Space ); } -void QgsCompoundColorWidget::mHueRadio_toggled( bool checked ) -{ - if ( checked ) - { - mColorBox->setComponent( QgsColorWidget::Hue ); - mVerticalRamp->setComponent( QgsColorWidget::Hue ); - } -} -void QgsCompoundColorWidget::mSaturationRadio_toggled( bool checked ) +void QgsCompoundColorWidget::updateComponent() { - if ( checked ) - { - mColorBox->setComponent( QgsColorWidget::Saturation ); - mVerticalRamp->setComponent( QgsColorWidget::Saturation ); - } -} + const bool isCmyk = mColorModel->currentData().toInt() == QColor::Spec::Cmyk; + const auto radios = isCmyk ? mCmykRadios : mRgbRadios; + const QButtonGroup *group = isCmyk ? mCmykGroup : mRgbGroup; -void QgsCompoundColorWidget::mValueRadio_toggled( bool checked ) -{ - if ( checked ) + const int id = group->checkedId(); + if ( id >= 0 && id < radios.count() ) { - mColorBox->setComponent( QgsColorWidget::Value ); - mVerticalRamp->setComponent( QgsColorWidget::Value ); + const QgsColorWidget::ColorComponent component = radios.at( group->checkedId() ).second; + mColorBox->setComponent( component ); + mVerticalRamp->setComponent( component ); } } -void QgsCompoundColorWidget::mRedRadio_toggled( bool checked ) +void QgsCompoundColorWidget::onColorButtonGroupToggled( int, bool checked ) { if ( checked ) - { - mColorBox->setComponent( QgsColorWidget::Red ); - mVerticalRamp->setComponent( QgsColorWidget::Red ); - } -} - -void QgsCompoundColorWidget::mGreenRadio_toggled( bool checked ) -{ - if ( checked ) - { - mColorBox->setComponent( QgsColorWidget::Green ); - mVerticalRamp->setComponent( QgsColorWidget::Green ); - } -} - -void QgsCompoundColorWidget::mBlueRadio_toggled( bool checked ) -{ - if ( checked ) - { - mColorBox->setComponent( QgsColorWidget::Blue ); - mVerticalRamp->setComponent( QgsColorWidget::Blue ); - } + updateComponent(); } void QgsCompoundColorWidget::mAddColorToSchemeButton_clicked() diff --git a/src/gui/qgscompoundcolorwidget.h b/src/gui/qgscompoundcolorwidget.h index 4683344b6952..a99683d78873 100644 --- a/src/gui/qgscompoundcolorwidget.h +++ b/src/gui/qgscompoundcolorwidget.h @@ -146,12 +146,7 @@ class GUI_EXPORT QgsCompoundColorWidget : public QgsPanelWidget, private Ui::Qgs private slots: - void mHueRadio_toggled( bool checked ); - void mSaturationRadio_toggled( bool checked ); - void mValueRadio_toggled( bool checked ); - void mRedRadio_toggled( bool checked ); - void mGreenRadio_toggled( bool checked ); - void mBlueRadio_toggled( bool checked ); + void onColorButtonGroupToggled( int, bool checked ); void mAddColorToSchemeButton_clicked(); @@ -167,14 +162,24 @@ 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 ); + /** + * Helper method to update current widget display with current component according to + * color model and selected color component radio button + */ + void updateComponent(); + QgsScreenHelper *mScreenHelper = nullptr; bool mAllowAlpha = true; @@ -185,6 +190,11 @@ class GUI_EXPORT QgsCompoundColorWidget : public QgsPanelWidget, private Ui::Qgs bool mDiscarded = false; + QList> mRgbRadios; + QList> mCmykRadios; + QButtonGroup *mCmykGroup = nullptr; + QButtonGroup *mRgbGroup = nullptr; + /** * Saves all widget settings */ @@ -224,6 +234,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..b9b58abff757 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,157 +313,730 @@ - - + + 38 30 - - - 38 - 30 - + + + 38 + 30 + + + + + + + + + + + + + + + 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 - - - - - + + + + + + + 0 + + + + 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 + + + + + + + + + + Qt::Horizontal + + + + 228 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + false + + + + + + + H + + + + + + + + + + + + + + + + + false + + + + + + + S + + + + + + + + + + + + + + + + + false + + + + + + + V + + + + + + + + + + + + + + + + + false + + + + + + + R + + + + + + + + + + + + + + + + + false + + + + + + + G + + + + + + + + + + + + + + + + + false + + + + + + + B + + + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + false + + + + + + + C + + + + + + + + + + + + + + + + + false + + + + + + + M + + + + + + + + + + + + + + + + + false + + + + + + + Y + + + + + + + + + + + + + + + + + false + + + + + + + K + + + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - - + + + + + + Opacity + + + + + + + - - - - - 38 - 30 - - - - - 38 - 30 - - - - - - + + + + + + HTML notation + + + + + + + - - - - - 38 - 30 - + + + + Qt::Vertical - + - 38 - 30 + 20 + 0 - - - - + 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..a6f48b5f1ac3 --- /dev/null +++ b/tests/src/gui/testqgscompoundcolorwidget.cpp @@ -0,0 +1,229 @@ +/*************************************************************************** + 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" +#include "qgssettings.h" + +Q_DECLARE_METATYPE( QgsColorWidget::ColorComponent ) + +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 testComponentChange(); + void testComponentSettings_data(); + void testComponentSettings(); + void testModelChange(); + void testTabChange(); +}; + +void TestQgsCompoundColorWidget::initTestCase() +{ + // Set up the QgsSettings environment + QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) ); + QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) ); + QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) ); +} + +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 ) ); +} + +void TestQgsCompoundColorWidget::testComponentSettings_data() +{ + QTest::addColumn( "settingsComponent" ); + QTest::addColumn( "expectedComponent" ); + QTest::addColumn( "newComponent" ); + QTest::addColumn( "newSettingsComponent" ); + + QTest::newRow( "hue" ) << 0 << QgsColorWidget::ColorComponent::Hue << QgsColorWidget::ColorComponent::Saturation << 1; + QTest::newRow( "saturation" ) << 1 << QgsColorWidget::ColorComponent::Saturation << QgsColorWidget::ColorComponent::Value << 2; + QTest::newRow( "value" ) << 2 << QgsColorWidget::ColorComponent::Value << QgsColorWidget::ColorComponent::Red << 3; + QTest::newRow( "red" ) << 3 << QgsColorWidget::ColorComponent::Red << QgsColorWidget::ColorComponent::Green << 4; + QTest::newRow( "green" ) << 4 << QgsColorWidget::ColorComponent::Green << QgsColorWidget::ColorComponent::Blue << 5; + QTest::newRow( "blue" ) << 5 << QgsColorWidget::ColorComponent::Blue << QgsColorWidget::ColorComponent::Hue << 0; + QTest::newRow( "cyan" ) << 0 << QgsColorWidget::ColorComponent::Cyan << QgsColorWidget::ColorComponent::Magenta << 1; + QTest::newRow( "magenta" ) << 1 << QgsColorWidget::ColorComponent::Magenta << QgsColorWidget::ColorComponent::Yellow << 2; + QTest::newRow( "yellow" ) << 2 << QgsColorWidget::ColorComponent::Yellow << QgsColorWidget::ColorComponent::Black << 3; + QTest::newRow( "black" ) << 3 << QgsColorWidget::ColorComponent::Black << QgsColorWidget::ColorComponent::Cyan << 0; +} + +void TestQgsCompoundColorWidget::testComponentSettings() +{ + QFETCH( int, settingsComponent ); + QFETCH( QgsColorWidget::ColorComponent, expectedComponent ); + QFETCH( QgsColorWidget::ColorComponent, newComponent ); + QFETCH( int, newSettingsComponent ); + + QgsSettings().setValue( QgsColorWidget::colorSpec( expectedComponent ) == QColor::Cmyk ? + QStringLiteral( "Windows/ColorDialog/activeCmykComponent" ) : QStringLiteral( "Windows/ColorDialog/activeComponent" ), settingsComponent ); + + QgsCompoundColorWidget w( nullptr, QgsColorWidget::colorSpec( expectedComponent ) == QColor::Cmyk ? + QColor::fromCmyk( 1, 2, 3, 4 ) : QColor( 10, 20, 30, 50 ) ); + w.setVisible( true ); + + QCOMPARE( w.mColorBox->component(), expectedComponent ); + QCOMPARE( w.mVerticalRamp->component(), expectedComponent ); + + ( QgsColorWidget::colorSpec( expectedComponent ) == QColor::Cmyk ? w.mCmykRadios : w.mRgbRadios ).at( newSettingsComponent ).first->setChecked( true ); + QCOMPARE( w.mColorBox->component(), newComponent ); + QCOMPARE( w.mVerticalRamp->component(), newComponent ); + + w.saveSettings(); + const int newValue = QgsSettings().value( QgsColorWidget::colorSpec( expectedComponent ) == QColor::Cmyk ? + QStringLiteral( "Windows/ColorDialog/activeCmykComponent" ) : QStringLiteral( "Windows/ColorDialog/activeComponent" ), -1 ).toInt(); + QCOMPARE( newValue, newSettingsComponent ); +} + +void TestQgsCompoundColorWidget::testComponentChange() +{ + QgsSettings().setValue( QStringLiteral( "Windows/ColorDialog/activeComponent" ), 3 ); + + QgsCompoundColorWidget w( nullptr, QColor( 10, 20, 30, 50 ) ); + w.setVisible( true ); + + QCOMPARE( w.mColorBox->component(), QgsColorWidget::Red ); + QCOMPARE( w.mVerticalRamp->component(), QgsColorWidget::Red ); + + const QList> colors = + { + { w.mHueRadio, QgsColorWidget::Hue }, + { w.mSaturationRadio, QgsColorWidget::Saturation }, + { w.mValueRadio, QgsColorWidget::Value }, + { w.mRedRadio, QgsColorWidget::Red }, + { w.mGreenRadio, QgsColorWidget::Green }, + { w.mBlueRadio, QgsColorWidget::Blue }, + { w.mCyanRadio, QgsColorWidget::Cyan }, + { w.mMagentaRadio, QgsColorWidget::Magenta }, + { w.mYellowRadio, QgsColorWidget::Yellow }, + { w.mBlackRadio, QgsColorWidget::Black } + }; + + for ( QPair color : colors ) + { + if ( QgsColorWidget::colorSpec( color.second ) != w.mColorModel->currentData() ) + w.mColorModel->setCurrentIndex( w.mColorModel->findData( QgsColorWidget::colorSpec( color.second ) ) ); + + color.first->setChecked( true ); + QCOMPARE( w.mColorBox->component(), color.second ); + QCOMPARE( w.mVerticalRamp->component(), color.second ); + } +} + +void TestQgsCompoundColorWidget::testModelChange() +{ + QgsCompoundColorWidget w( nullptr, QColor( 10, 20, 30, 50 ) ); + w.setVisible( true ); + + QCOMPARE( w.mColorModel->currentData(), QColor::Rgb ); + + w.mColorModel->setCurrentIndex( w.mColorModel->findData( QColor::Cmyk ) ); + QCOMPARE( w.mColorModel->currentData(), QColor::Cmyk ); + + w.setColor( QColor( 1, 2, 3 ) ); + QCOMPARE( w.mColorModel->currentData(), QColor::Rgb ); +} + +void TestQgsCompoundColorWidget::testTabChange() +{ + QgsCompoundColorWidget w( nullptr, QColor( 10, 20, 30, 50 ) ); + w.setVisible( true ); + + QCOMPARE( w.mTabWidget->currentIndex(), 0 ); + QVERIFY( w.mRedRadio->isEnabled() ); + QVERIFY( w.mBlueRadio->isEnabled() ); + QVERIFY( w.mGreenRadio->isEnabled() ); + QVERIFY( w.mHueRadio->isEnabled() ); + QVERIFY( w.mSaturationRadio->isEnabled() ); + QVERIFY( w.mCyanRadio->isEnabled() ); + QVERIFY( w.mMagentaRadio->isEnabled() ); + QVERIFY( w.mYellowRadio->isEnabled() ); + QVERIFY( w.mBlackRadio->isEnabled() ); + + w.mTabWidget->setCurrentIndex( 1 ); + QVERIFY( !w.mRedRadio->isEnabled() ); + QVERIFY( !w.mBlueRadio->isEnabled() ); + QVERIFY( !w.mGreenRadio->isEnabled() ); + QVERIFY( !w.mHueRadio->isEnabled() ); + QVERIFY( !w.mSaturationRadio->isEnabled() ); + QVERIFY( !w.mCyanRadio->isEnabled() ); + QVERIFY( !w.mMagentaRadio->isEnabled() ); + QVERIFY( !w.mYellowRadio->isEnabled() ); + QVERIFY( !w.mBlackRadio->isEnabled() ); +} + + + +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..948797d8e935 --- /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 TestQgsColorWidget(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()