File indexing completed on 2024-05-12 16:02:05

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "KisVisualColorSelector.h"
0007 
0008 #include <QRect>
0009 #include <QVector>
0010 #include <QVector3D>
0011 #include <QVector4D>
0012 #include <QVBoxLayout>
0013 #include <QList>
0014 #include <QtMath>
0015 
0016 #include <KSharedConfig>
0017 #include <KConfigGroup>
0018 
0019 #include "KoColorConversions.h"
0020 #include "KoColorDisplayRendererInterface.h"
0021 #include "KoColorProfile.h"
0022 #include "KoChannelInfo.h"
0023 #include <KoColorModelStandardIds.h>
0024 #include <QPointer>
0025 #include "kis_signal_compressor.h"
0026 #include "kis_debug.h"
0027 
0028 #include "KisVisualColorSelectorShape.h"
0029 #include "KisVisualRectangleSelectorShape.h"
0030 #include "KisVisualTriangleSelectorShape.h"
0031 #include "KisVisualEllipticalSelectorShape.h"
0032 
0033 struct KisVisualColorSelector::Private
0034 {
0035     KoColor currentcolor;
0036     const KoColorSpace *currentCS {0};
0037     QList<KisVisualColorSelectorShape*> widgetlist;
0038     bool acceptTabletEvents {false};
0039     bool circular {false};
0040     bool exposureSupported {false};
0041     bool isRGBA {false};
0042     bool isLinear {false};
0043     bool applyGamma {false};
0044     int displayPosition[4]; // map channel index to storage index for display
0045     int colorChannelCount {0};
0046     qreal gamma {2.2};
0047     qreal lumaRGB[3] {0.2126, 0.7152, 0.0722};
0048     QVector4D channelValues;
0049     QVector4D channelMaxValues;
0050     ColorModel model {ColorModel::None};
0051     const KoColorDisplayRendererInterface *displayRenderer {0};
0052     KisColorSelectorConfiguration acs_config;
0053     KisSignalCompressor *updateTimer {0};
0054 };
0055 
0056 KisVisualColorSelector::KisVisualColorSelector(QWidget *parent)
0057     : KisColorSelectorInterface(parent)
0058     , m_d(new Private)
0059 {
0060     this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
0061 
0062     KConfigGroup cfg =  KSharedConfig::openConfig()->group("advancedColorSelector");
0063     m_d->acs_config = KisColorSelectorConfiguration::fromString(cfg.readEntry("colorSelectorConfiguration", KisColorSelectorConfiguration().toString()));
0064     m_d->updateTimer = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE);
0065     connect(m_d->updateTimer, SIGNAL(timeout()), SLOT(slotRebuildSelectors()), Qt::UniqueConnection);
0066 }
0067 
0068 KisVisualColorSelector::~KisVisualColorSelector()
0069 {
0070     delete m_d->updateTimer;
0071 }
0072 
0073 void KisVisualColorSelector::slotSetColor(const KoColor &c)
0074 {
0075     if (!m_d->currentCS) {
0076         m_d->currentcolor = c;
0077         slotSetColorSpace(c.colorSpace());
0078     }
0079     else {
0080         m_d->currentcolor = c.convertedTo(m_d->currentCS);
0081         m_d->channelValues = convertKoColorToShapeCoordinates(m_d->currentcolor);
0082         Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0083             shape->setChannelValues(m_d->channelValues, true);
0084         }
0085     }
0086     if (isHSXModel()) {
0087         emit sigHSXChanged(QVector3D(m_d->channelValues));
0088     }
0089 }
0090 
0091 void KisVisualColorSelector::slotSetColorSpace(const KoColorSpace *cs)
0092 {
0093     if (!m_d->currentCS || *m_d->currentCS != *cs) {
0094         const KoColorSpace *csNew = cs;
0095 
0096         // PQ color space is not very suitable for selecting colors, substitute with linear one
0097         if (cs && cs->profile()
0098                && cs->colorModelId() == RGBAColorModelID
0099                && KoColorSpaceRegistry::instance()->p2020PQProfile()
0100                && cs->profile()->uniqueId() == KoColorSpaceRegistry::instance()->p2020PQProfile()->uniqueId())
0101         {
0102             csNew = KoColorSpaceRegistry::instance()->
0103                     colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(),
0104                                KoColorSpaceRegistry::instance()->p2020G10Profile());
0105         }
0106         m_d->currentCS = csNew;
0107         m_d->currentcolor = KoColor(csNew);
0108         slotRebuildSelectors();
0109     }
0110 }
0111 
0112 void KisVisualColorSelector::slotSetHSX(const QVector3D &hsx)
0113 {
0114     if (isHSXModel()) {
0115         m_d->channelValues = QVector4D(hsx, 0.f);
0116         Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0117             shape->setChannelValues(m_d->channelValues, true);
0118         }
0119         KoColor newColor = convertShapeCoordsToKoColor(QVector4D(hsx));
0120         if (newColor != m_d->currentcolor) {
0121             m_d->currentcolor = newColor;
0122             emit sigNewColor(m_d->currentcolor);
0123         }
0124     }
0125 }
0126 
0127 void KisVisualColorSelector::setConfig(bool forceCircular, bool forceSelfUpdate)
0128 {
0129     Q_UNUSED(forceSelfUpdate);
0130     m_d->circular = forceCircular;
0131 }
0132 
0133 void KisVisualColorSelector::setAcceptTabletEvents(bool on)
0134 {
0135     m_d->acceptTabletEvents = on;
0136     Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0137         shape->setAcceptTabletEvents(on);
0138     }
0139 }
0140 
0141 KoColor KisVisualColorSelector::getCurrentColor() const
0142 {
0143     return m_d->currentcolor;
0144 }
0145 
0146 QVector4D KisVisualColorSelector::getChannelValues() const
0147 {
0148     return m_d->channelValues;
0149 }
0150 
0151 KisVisualColorSelector::ColorModel KisVisualColorSelector::getColorModel() const
0152 {
0153     return m_d->model;
0154 }
0155 
0156 bool KisVisualColorSelector::isHSXModel() const
0157 {
0158     return (m_d->model >= ColorModel::HSV && m_d->model <= ColorModel::HSY);
0159 }
0160 
0161 KoColor KisVisualColorSelector::convertShapeCoordsToKoColor(const QVector4D &coordinates) const
0162 {
0163     KoColor c(m_d->currentCS);
0164     QVector4D baseValues(coordinates);
0165     QVector <float> channelValues(c.colorSpace()->channelCount());
0166     channelValues.fill(1.0);
0167 
0168     if (m_d->model != ColorModel::Channel && m_d->isRGBA == true) {
0169 
0170         if (m_d->model == ColorModel::HSV) {
0171             HSVToRGB(coordinates.x()*360, coordinates.y(), coordinates.z(), &baseValues[0], &baseValues[1], &baseValues[2]);
0172         }
0173         else if (m_d->model == ColorModel::HSL) {
0174             HSLToRGB(coordinates.x()*360, coordinates.y(), coordinates.z(), &baseValues[0], &baseValues[1], &baseValues[2]);
0175         }
0176         else if (m_d->model == ColorModel::HSI) {
0177             // why suddenly qreal?
0178             qreal temp[3];
0179             HSIToRGB(coordinates.x(), coordinates.y(), coordinates.z(), &temp[0], &temp[1], &temp[2]);
0180             baseValues.setX(temp[0]);
0181             baseValues.setY(temp[1]);
0182             baseValues.setZ(temp[2]);
0183         }
0184         else /*if (m_d->model == ColorModel::HSY)*/ {
0185             qreal temp[3];
0186             qreal Y = pow(coordinates.z(), m_d->gamma);
0187             HSYToRGB(coordinates.x(), coordinates.y(), Y, &temp[0], &temp[1], &temp[2],
0188                     m_d->lumaRGB[0], m_d->lumaRGB[1], m_d->lumaRGB[2]);
0189             baseValues.setX(temp[0]);
0190             baseValues.setY(temp[1]);
0191             baseValues.setZ(temp[2]);
0192             if (!m_d->isLinear) {
0193                 // Note: not all profiles define a TRC necessary for (de-)linearization,
0194                 // substituting with a linear profiles would be better
0195                 QVector<qreal> temp({baseValues[0], baseValues[1], baseValues[2]});
0196                 if (m_d->exposureSupported) {
0197                     m_d->currentCS->profile()->delinearizeFloatValue(temp);
0198                 }
0199                 else {
0200                     m_d->currentCS->profile()->delinearizeFloatValueFast(temp);
0201                 }
0202                 baseValues = QVector4D(temp[0], temp[1], temp[2], 0);
0203             }
0204         }
0205         if (m_d->applyGamma) {
0206             for (int i=0; i<3; i++) {
0207                 baseValues[i] = pow(baseValues[i], 2.2);
0208             }
0209         }
0210     }
0211 
0212     if (m_d->exposureSupported) {
0213         baseValues *= m_d->channelMaxValues;
0214     }
0215 
0216     for (int i=0; i<m_d->colorChannelCount; i++) {
0217         channelValues[m_d->displayPosition[i]] = baseValues[i];
0218     }
0219 
0220     c.colorSpace()->fromNormalisedChannelsValue(c.data(), channelValues);
0221 
0222     return c;
0223 
0224 }
0225 
0226 QVector4D KisVisualColorSelector::convertKoColorToShapeCoordinates(KoColor c) const
0227 {
0228     if (c.colorSpace() != m_d->currentCS) {
0229         c.convertTo(m_d->currentCS);
0230     }
0231     QVector <float> channelValues (c.colorSpace()->channelCount());
0232     channelValues.fill(1.0);
0233     m_d->currentCS->normalisedChannelsValue(c.data(), channelValues);
0234     QVector4D channelValuesDisplay(0, 0, 0, 0), coordinates(0, 0, 0, 0);
0235 
0236     for (int i =0; i<m_d->colorChannelCount; i++) {
0237         channelValuesDisplay[i] = channelValues[m_d->displayPosition[i]];
0238     }
0239 
0240     if (m_d->exposureSupported) {
0241         channelValuesDisplay /= m_d->channelMaxValues;
0242     }
0243     if (m_d->model != ColorModel::Channel && m_d->isRGBA == true) {
0244         if (m_d->isRGBA == true) {
0245             if (m_d->applyGamma) {
0246                 for (int i=0; i<3; i++) {
0247                     channelValuesDisplay[i] = pow(channelValuesDisplay[i], 1/2.2);
0248                 }
0249             }
0250             if (m_d->model == ColorModel::HSV) {
0251                 QVector3D hsv;
0252                 RGBToHSV(channelValuesDisplay[0], channelValuesDisplay[1], channelValuesDisplay[2], &hsv[0], &hsv[1], &hsv[2]);
0253                 hsv[0] /= 360;
0254                 coordinates = QVector4D(hsv, 0.f);
0255             } else if (m_d->model == ColorModel::HSL) {
0256                 QVector3D hsl;
0257                 RGBToHSL(channelValuesDisplay[0], channelValuesDisplay[1], channelValuesDisplay[2], &hsl[0], &hsl[1], &hsl[2]);
0258                 hsl[0] /= 360;
0259                 coordinates = QVector4D(hsl, 0.f);
0260             } else if (m_d->model == ColorModel::HSI) {
0261                 qreal hsi[3];
0262                 RGBToHSI(channelValuesDisplay[0], channelValuesDisplay[1], channelValuesDisplay[2], &hsi[0], &hsi[1], &hsi[2]);
0263                 coordinates = QVector4D(hsi[0], hsi[1], hsi[2], 0.f);
0264             } else if (m_d->model == ColorModel::HSY) {
0265                 if (!m_d->isLinear) {
0266                     // Note: not all profiles define a TRC necessary for (de-)linearization,
0267                     // substituting with a linear profiles would be better
0268                     QVector<qreal> temp({channelValuesDisplay[0], channelValuesDisplay[1], channelValuesDisplay[2]});
0269                     m_d->currentCS->profile()->linearizeFloatValue(temp);
0270                     channelValuesDisplay = QVector4D(temp[0], temp[1], temp[2], 0);
0271                 }
0272                 qreal hsy[3];
0273                 RGBToHSY(channelValuesDisplay[0], channelValuesDisplay[1], channelValuesDisplay[2], &hsy[0], &hsy[1], &hsy[2],
0274                          m_d->lumaRGB[0], m_d->lumaRGB[1], m_d->lumaRGB[2]);
0275                 hsy[2] = pow(hsy[2], 1/m_d->gamma);
0276                 coordinates = QVector4D(hsy[0], hsy[1], hsy[2], 0.f);
0277             }
0278             // if we couldn't determine a hue, keep last value
0279             if (coordinates[0] < 0) {
0280                 coordinates[0] = m_d->channelValues[0];
0281             }
0282             for (int i=0; i<3; i++) {
0283                 coordinates[i] = qBound(0.f, coordinates[i], 1.f);
0284             }
0285         }
0286     } else {
0287         for (int i=0; i<4; i++) {
0288             coordinates[i] = qBound(0.f, channelValuesDisplay[i], 1.f);
0289         }
0290     }
0291     return coordinates;
0292 }
0293 
0294 void KisVisualColorSelector::configurationChanged()
0295 {
0296     if (m_d->updateTimer) {
0297         m_d->updateTimer->start();
0298     }
0299 }
0300 
0301 void KisVisualColorSelector::slotDisplayConfigurationChanged()
0302 {
0303     Q_ASSERT(m_d->displayRenderer);
0304 
0305     if (m_d->currentCS)
0306     {
0307         m_d->channelMaxValues = QVector4D(1, 1, 1, 1);
0308         QList<KoChannelInfo *> channels = m_d->currentCS->channels();
0309         for (int i=0; i<m_d->colorChannelCount; ++i)
0310         {
0311             m_d->channelMaxValues[i] = m_d->displayRenderer->maxVisibleFloatValue(channels[m_d->displayPosition[i]]);
0312         }
0313         // need to re-scale our normalized channel values on exposure changes:
0314         m_d->channelValues = convertKoColorToShapeCoordinates(m_d->currentcolor);
0315         Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0316             shape->setChannelValues(m_d->channelValues, true);
0317         }
0318         if (isHSXModel()) {
0319             emit sigHSXChanged(QVector3D(m_d->channelValues));
0320         }
0321     }
0322 }
0323 
0324 void KisVisualColorSelector::slotRebuildSelectors()
0325 {
0326     KConfigGroup cfg =  KSharedConfig::openConfig()->group("advancedColorSelector");
0327     m_d->acs_config = KisColorSelectorConfiguration::fromString(cfg.readEntry("colorSelectorConfiguration", KisColorSelectorConfiguration().toString()));
0328 
0329     ColorModel oldModel = m_d->model;
0330     QList<KoChannelInfo *> channelList = m_d->currentCS->channels();
0331     int cCount = 0;
0332     Q_FOREACH(const KoChannelInfo *channel, channelList)
0333     {
0334         if (channel->channelType() != KoChannelInfo::ALPHA)
0335         {
0336             m_d->displayPosition[cCount] = channel->displayPosition();
0337             ++cCount;
0338         }
0339     }
0340     Q_ASSERT_X(cCount < 5, "", "unsupported channel count!");
0341     m_d->colorChannelCount = cCount;
0342 
0343     // TODO: The following is done because the IDs are actually strings. Ideally, in the future, we
0344     // refactor everything so that the IDs are actually proper enums or something faster.
0345     if (m_d->displayRenderer
0346             && (m_d->currentCS->colorDepthId() == Float16BitsColorDepthID
0347                 || m_d->currentCS->colorDepthId() == Float32BitsColorDepthID
0348                 || m_d->currentCS->colorDepthId() == Float64BitsColorDepthID)
0349             && m_d->currentCS->colorModelId() != LABAColorModelID
0350             && m_d->currentCS->colorModelId() != CMYKAColorModelID) {
0351         m_d->exposureSupported = true;
0352     } else {
0353         m_d->exposureSupported = false;
0354     }
0355     m_d->isRGBA = (m_d->currentCS->colorModelId() == RGBAColorModelID);
0356     const KoColorProfile *profile = m_d->currentCS->profile();
0357     m_d->isLinear = (profile && profile->isLinear());
0358 
0359     qDeleteAll(children());
0360     m_d->widgetlist.clear();
0361     // TODO: Layout only used for monochrome selector currently, but always present
0362     QLayout *layout = new QHBoxLayout(this);
0363     //recreate all the widgets.
0364     m_d->model = KisVisualColorSelector::Channel;
0365 
0366     if (m_d->currentCS->colorChannelCount() == 1) {
0367 
0368         KisVisualColorSelectorShape *bar;
0369 
0370         if (m_d->circular==false) {
0371             bar = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::onedimensional, m_d->currentCS, 0, 0,m_d->displayRenderer, 20);
0372             bar->setMaximumWidth(width()*0.1);
0373             bar->setMaximumHeight(height());
0374         }
0375         else {
0376             bar = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::onedimensional, m_d->currentCS, 0, 0,m_d->displayRenderer, 20, KisVisualEllipticalSelectorShape::borderMirrored);
0377             layout->setMargin(0);
0378         }
0379 
0380         connect(bar, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0381         layout->addWidget(bar);
0382         m_d->widgetlist.append(bar);
0383     }
0384     else if (m_d->currentCS->colorChannelCount() == 3) {
0385         KisVisualColorSelector::ColorModel modelS = KisVisualColorSelector::HSV;
0386         int channel1 = 0;
0387         int channel2 = 1;
0388         int channel3 = 2;
0389 
0390         switch(m_d->acs_config.subTypeParameter)
0391         {
0392         case KisColorSelectorConfiguration::H:
0393         case KisColorSelectorConfiguration::Hluma:
0394             channel1 = 0;
0395             break;
0396         case KisColorSelectorConfiguration::hsyS:
0397         case KisColorSelectorConfiguration::hsiS:
0398         case KisColorSelectorConfiguration::hslS:
0399         case KisColorSelectorConfiguration::hsvS:
0400             channel1 = 1;
0401             break;
0402         case KisColorSelectorConfiguration::V:
0403         case KisColorSelectorConfiguration::L:
0404         case KisColorSelectorConfiguration::I:
0405         case KisColorSelectorConfiguration::Y:
0406             channel1 = 2;
0407             break;
0408         default:
0409             Q_ASSERT_X(false, "", "Invalid acs_config.subTypeParameter");
0410         }
0411 
0412         switch(m_d->acs_config.mainTypeParameter)
0413         {
0414         case KisColorSelectorConfiguration::hsySH:
0415             modelS = KisVisualColorSelector::HSY;
0416             channel2 = 0;
0417             channel3 = 1;
0418             break;
0419         case KisColorSelectorConfiguration::hsiSH:
0420             modelS = KisVisualColorSelector::HSI;
0421             channel2 = 0;
0422             channel3 = 1;
0423             break;
0424         case KisColorSelectorConfiguration::hslSH:
0425             modelS = KisVisualColorSelector::HSL;
0426             channel2 = 0;
0427             channel3 = 1;
0428             break;
0429         case KisColorSelectorConfiguration::hsvSH:
0430             modelS = KisVisualColorSelector::HSV;
0431             channel2 = 0;
0432             channel3 = 1;
0433             break;
0434         case KisColorSelectorConfiguration::YH:
0435             modelS = KisVisualColorSelector::HSY;
0436             channel2 = 0;
0437             channel3 = 2;
0438             break;
0439         case KisColorSelectorConfiguration::LH:
0440             modelS = KisVisualColorSelector::HSL;
0441             channel2 = 0;
0442             channel3 = 2;
0443             break;
0444         case KisColorSelectorConfiguration::IH:
0445             modelS = KisVisualColorSelector::HSI;
0446             channel2 = 0;
0447             channel3 = 2;
0448             break;
0449         case KisColorSelectorConfiguration::VH:
0450             modelS = KisVisualColorSelector::HSV;
0451             channel2 = 0;
0452             channel3 = 2;
0453             break;
0454         case KisColorSelectorConfiguration::SY:
0455             modelS = KisVisualColorSelector::HSY;
0456             channel2 = 1;
0457             channel3 = 2;
0458             break;
0459         case KisColorSelectorConfiguration::SI:
0460             modelS = KisVisualColorSelector::HSI;
0461             channel2 = 1;
0462             channel3 = 2;
0463             break;
0464         case KisColorSelectorConfiguration::SL:
0465             modelS = KisVisualColorSelector::HSL;
0466             channel2 = 1;
0467             channel3 = 2;
0468             break;
0469         case KisColorSelectorConfiguration::SV:
0470         case KisColorSelectorConfiguration::SV2:
0471             modelS = KisVisualColorSelector::HSV;
0472             channel2 = 1;
0473             channel3 = 2;
0474             break;
0475         default:
0476             Q_ASSERT_X(false, "", "Invalid acs_config.mainTypeParameter");
0477         }
0478         if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0479             modelS = KisVisualColorSelector::HSV;
0480             //Triangle only really works in HSV mode.
0481         }
0482 
0483         // L*a*b* mimics the HSX selector types, but model is still Channel (until someone implements LCH)
0484         if (m_d->isRGBA) {
0485             m_d->model = modelS;
0486             m_d->gamma = cfg.readEntry("gamma", 2.2);
0487             m_d->applyGamma = (m_d->isLinear && modelS != ColorModel::HSY);
0488             // Note: only profiles that define colorants will give precise luma coefficients.
0489             // Maybe using the explicitly set values of the Advanced Color Selector is better?
0490             QVector <qreal> luma = m_d->currentCS->lumaCoefficients();
0491             memcpy(m_d->lumaRGB, luma.constData(), 3*sizeof(qreal));
0492         }
0493 
0494         KisVisualColorSelectorShape *bar;
0495         if (m_d->acs_config.subType == KisColorSelectorConfiguration::Ring) {
0496             bar = new KisVisualEllipticalSelectorShape(this,
0497                                                        KisVisualColorSelectorShape::onedimensional,
0498                                                        m_d->currentCS, channel1, channel1,
0499                                                        m_d->displayRenderer, 20,KisVisualEllipticalSelectorShape::border);
0500         }
0501         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular == false) {
0502             bar = new KisVisualRectangleSelectorShape(this,
0503                                                       KisVisualColorSelectorShape::onedimensional,
0504                                                       m_d->currentCS, channel1, channel1,
0505                                                       m_d->displayRenderer, 20);
0506         }
0507         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular == true) {
0508             bar = new KisVisualEllipticalSelectorShape(this,
0509                                                        KisVisualColorSelectorShape::onedimensional,
0510                                                        m_d->currentCS, channel1, channel1,
0511                                                        m_d->displayRenderer, 20, KisVisualEllipticalSelectorShape::borderMirrored);
0512         } else {
0513             // Accessing bar below would crash since it's not initialized.
0514             // Hopefully this can never happen.
0515             warnUI << "Invalid subType, cannot initialize KisVisualColorSelectorShape";
0516             Q_ASSERT_X(false, "", "Invalid subType, cannot initialize KisVisualColorSelectorShape");
0517             return;
0518         }
0519 
0520         m_d->widgetlist.append(bar);
0521 
0522         KisVisualColorSelectorShape *block;
0523         if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0524             block = new KisVisualTriangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0525                                                        m_d->currentCS, channel2, channel3,
0526                                                        m_d->displayRenderer);
0527         }
0528         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Square) {
0529             block = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0530                                                         m_d->currentCS, channel2, channel3,
0531                                                         m_d->displayRenderer);
0532         }
0533         else {
0534             block = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0535                                                          m_d->currentCS, channel2, channel3,
0536                                                          m_d->displayRenderer);
0537         }
0538 
0539         connect(bar, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0540         connect(block, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0541         m_d->widgetlist.append(block);
0542     }
0543     else if (m_d->currentCS->colorChannelCount() == 4) {
0544         KisVisualRectangleSelectorShape *block =  new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional, m_d->currentCS, 0, 1);
0545         KisVisualRectangleSelectorShape *block2 =  new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional, m_d->currentCS, 2, 3);
0546         connect(block, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0547         connect(block2, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0548         m_d->widgetlist.append(block);
0549         m_d->widgetlist.append(block2);
0550     }
0551 
0552     // make sure we call "our" resize function
0553     KisVisualColorSelector::resizeEvent(0);
0554 
0555     // finally recalculate channel values and update widgets
0556     if (m_d->displayRenderer) {
0557         slotDisplayConfigurationChanged();
0558     }
0559     m_d->channelValues = convertKoColorToShapeCoordinates(m_d->currentcolor);
0560     Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0561         shape->setChannelValues(m_d->channelValues, true);
0562         shape->setAcceptTabletEvents(m_d->acceptTabletEvents);
0563         // if this widget is currently visible, new children are hidden by default
0564         shape->show();
0565     }
0566     if (m_d->model != oldModel) {
0567         emit sigColorModelChanged();
0568     }
0569 }
0570 
0571 void KisVisualColorSelector::setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer)
0572 {
0573     if (m_d->displayRenderer) {
0574         m_d->displayRenderer->disconnect(this);
0575     }
0576     m_d->displayRenderer = displayRenderer;
0577     if (m_d->widgetlist.size()>0) {
0578         Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) {
0579             shape->setDisplayRenderer(displayRenderer);
0580         }
0581     }
0582     connect(m_d->displayRenderer, SIGNAL(displayConfigurationChanged()),
0583             SLOT(slotDisplayConfigurationChanged()), Qt::UniqueConnection);
0584     slotDisplayConfigurationChanged();
0585 }
0586 
0587 void KisVisualColorSelector::slotCursorMoved(QPointF pos)
0588 {
0589     const KisVisualColorSelectorShape *shape = qobject_cast<KisVisualColorSelectorShape *>(sender());
0590     Q_ASSERT(shape);
0591     QVector<int> channels = shape->getChannels();
0592     m_d->channelValues[channels.at(0)] = pos.x();
0593     if (shape->getDimensions() == KisVisualColorSelectorShape::twodimensional) {
0594         m_d->channelValues[channels.at(1)] = pos.y();
0595     }
0596     KoColor newColor = convertShapeCoordsToKoColor(m_d->channelValues);
0597     if (newColor != m_d->currentcolor) {
0598         m_d->currentcolor = newColor;
0599         emit sigNewColor(m_d->currentcolor);
0600     }
0601     if (isHSXModel()) {
0602         emit sigHSXChanged(QVector3D(m_d->channelValues));
0603     }
0604     Q_FOREACH (KisVisualColorSelectorShape *widget, m_d->widgetlist) {
0605         if (widget != shape){
0606             widget->setChannelValues(m_d->channelValues, false);
0607         }
0608     }
0609 }
0610 
0611 void KisVisualColorSelector::resizeEvent(QResizeEvent *) {
0612     int sizeValue = qMin(width(), height());
0613     int borderWidth = qMax(sizeValue*0.1, 20.0);
0614     QRect newrect(0,0, this->geometry().width(), this->geometry().height());
0615     if (!m_d->currentCS) {
0616         slotSetColorSpace(m_d->currentcolor.colorSpace());
0617     }
0618     if (m_d->currentCS->colorChannelCount()==3) {
0619         // set border width first, else the resized painting may have happened already, and we'd have to re-render
0620         m_d->widgetlist.at(0)->setBorderWidth(borderWidth);
0621         if (m_d->acs_config.subType == KisColorSelectorConfiguration::Ring) {
0622             m_d->widgetlist.at(0)->resize(sizeValue,sizeValue);
0623         }
0624         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular==false) {
0625             m_d->widgetlist.at(0)->resize(borderWidth, sizeValue);
0626         }
0627         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular==true) {
0628             m_d->widgetlist.at(0)->resize(sizeValue,sizeValue);
0629         }
0630 
0631         if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0632             m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForTriangle(newrect));
0633         }
0634         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Square) {
0635             m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForSquare(newrect));
0636         }
0637         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Wheel) {
0638             m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForCircle(newrect));
0639         }
0640     }
0641     else if (m_d->currentCS->colorChannelCount() == 4) {
0642         int sizeBlock = qMin(width()/2 - 8, height());
0643         m_d->widgetlist.at(0)->setGeometry(0, 0, sizeBlock, sizeBlock);
0644         m_d->widgetlist.at(1)->setGeometry(sizeBlock + 8, 0, sizeBlock, sizeBlock);
0645     }
0646 }