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 }