File indexing completed on 2024-05-19 04:29:29

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
0003  * SPDX-FileCopyrightText: 2022 Mathias Wein <lynx.mw+kde@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #include "KisVisualColorSelector.h"
0008 
0009 #include <QVector4D>
0010 #include <QList>
0011 #include <QPointer>
0012 
0013 #include <KSharedConfig>
0014 #include <KConfigGroup>
0015 
0016 #include "KoColorDisplayRendererInterface.h"
0017 #include <KoColorModelStandardIds.h>
0018 //#include <QPointer>
0019 #include "kis_signal_compressor.h"
0020 #include "kis_debug.h"
0021 
0022 #include "KisVisualColorSelectorShape.h"
0023 #include "KisVisualDiamondSelectorShape.h"
0024 #include "KisVisualRectangleSelectorShape.h"
0025 #include "KisVisualTriangleSelectorShape.h"
0026 #include "KisVisualEllipticalSelectorShape.h"
0027 
0028 struct KisVisualColorSelector::Private
0029 {
0030     QList<KisVisualColorSelectorShape*> widgetlist;
0031     bool acceptTabletEvents {false};
0032     bool circular {false};
0033     bool proofColors {false};
0034     bool initialized {false};
0035     bool useACSConfig {true};
0036     bool autoAdjustExposure {true};
0037     int colorChannelCount {0};
0038     int minimumSliderWidth {16};
0039     Qt::Edge sliderPosition {Qt::LeftEdge};
0040     qreal stretchLimit {1.5};
0041     QVector4D channelValues;
0042     KisVisualColorSelector::RenderMode renderMode {RenderMode::DynamicBackground};
0043     KisColorSelectorConfiguration acs_config;
0044     KisSignalCompressor *updateTimer {0};
0045     KisVisualColorModelSP selectorModel;
0046     QPointer<const KoColorDisplayRendererInterface> displayRenderer;
0047     KoGamutMaskSP gamutMask;
0048 };
0049 
0050 KisVisualColorSelector::KisVisualColorSelector(QWidget *parent, KisVisualColorModelSP model)
0051     : KisColorSelectorInterface(parent)
0052     , m_d(new Private)
0053 {
0054     m_d->acs_config = validatedConfiguration(KisColorSelectorConfiguration());
0055     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0056 
0057     loadACSConfig();
0058     if (model) {
0059         setSelectorModel(model);
0060     } else {
0061         setSelectorModel(KisVisualColorModelSP(new KisVisualColorModel));
0062         m_d->selectorModel->slotLoadACSConfig();
0063     }
0064 
0065     m_d->updateTimer = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE);
0066     connect(m_d->updateTimer, SIGNAL(timeout()), SLOT(slotReloadConfiguration()), Qt::UniqueConnection);
0067 }
0068 
0069 KisVisualColorSelector::~KisVisualColorSelector()
0070 {
0071     delete m_d->updateTimer;
0072 }
0073 
0074 QSize KisVisualColorSelector::minimumSizeHint() const
0075 {
0076     return QSize(75, 75);
0077 }
0078 
0079 void KisVisualColorSelector::setSelectorModel(KisVisualColorModelSP model)
0080 {
0081     if (model == m_d->selectorModel) {
0082         return;
0083     }
0084     if (m_d->selectorModel) {
0085         m_d->selectorModel->disconnect(this);
0086     }
0087     connect(model.data(), SIGNAL(sigChannelValuesChanged(QVector4D,quint32)),
0088                           SLOT(slotChannelValuesChanged(QVector4D,quint32)));
0089     connect(model.data(), SIGNAL(sigColorModelChanged()), SLOT(slotColorModelChanged()));
0090     connect(model.data(), SIGNAL(sigColorSpaceChanged()), SLOT(slotColorSpaceChanged()));
0091     // to keep the KisColorSelectorInterface API functional:
0092     connect(model.data(), SIGNAL(sigNewColor(KoColor)), this, SIGNAL(sigNewColor(KoColor)));
0093     m_d->selectorModel = model;
0094     m_d->initialized = false;
0095     rebuildSelector();
0096 }
0097 
0098 KisVisualColorModelSP KisVisualColorSelector::selectorModel() const
0099 {
0100     return m_d->selectorModel;
0101 }
0102 
0103 void KisVisualColorSelector::setConfig(bool forceCircular, bool forceSelfUpdate)
0104 {
0105     Q_UNUSED(forceSelfUpdate);
0106     if (forceCircular != m_d->circular) {
0107         m_d->circular = forceCircular;
0108         m_d->initialized = false;
0109         rebuildSelector();
0110     }
0111 }
0112 
0113 const KisColorSelectorConfiguration &KisVisualColorSelector::configuration() const
0114 {
0115     return m_d->acs_config;
0116 }
0117 
0118 void KisVisualColorSelector::setConfiguration(const KisColorSelectorConfiguration *config)
0119 {
0120     m_d->useACSConfig = !config;
0121     if (config) {
0122         // applies immediately, while signalled rebuilds from krita configuration changes
0123         // are queued, so make sure we cancel queued updates
0124         m_d->updateTimer->stop();
0125         KisColorSelectorConfiguration configNew = validatedConfiguration(*config);
0126         if (configNew != m_d->acs_config) {
0127             m_d->acs_config = configNew;
0128             m_d->initialized = false;
0129             rebuildSelector();
0130         }
0131     } else {
0132         m_d->initialized = false;
0133         m_d->updateTimer->start();
0134     }
0135 }
0136 
0137 void KisVisualColorSelector::setAcceptTabletEvents(bool on)
0138 {
0139     m_d->acceptTabletEvents = on;
0140     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0141         shape->setAcceptTabletEvents(on);
0142     }
0143 }
0144 
0145 KoColor KisVisualColorSelector::getCurrentColor() const
0146 {
0147     if (m_d->selectorModel) {
0148         return m_d->selectorModel->currentColor();
0149     }
0150     return KoColor();
0151 }
0152 
0153 void KisVisualColorSelector::setMinimumSliderWidth(int width)
0154 {
0155     int newWidth = qMax(5, width);
0156     if (newWidth != m_d->minimumSliderWidth) {
0157         m_d->minimumSliderWidth = width;
0158         KisVisualColorSelector::resizeEvent(0);
0159     }
0160 }
0161 
0162 const KoColorDisplayRendererInterface *KisVisualColorSelector::displayRenderer() const
0163 {
0164     return m_d->displayRenderer ? m_d->displayRenderer : KoDumbColorDisplayRenderer::instance();
0165 }
0166 
0167 KisVisualColorSelector::RenderMode KisVisualColorSelector::renderMode() const
0168 {
0169     return m_d->renderMode;
0170 }
0171 
0172 void KisVisualColorSelector::setRenderMode(KisVisualColorSelector::RenderMode mode)
0173 {
0174     if (mode != m_d->renderMode) {
0175         m_d->renderMode = mode;
0176         for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0177             shape->forceImageUpdate();
0178             shape->update();
0179         }
0180     }
0181 }
0182 
0183 bool KisVisualColorSelector::autoAdjustExposure() const
0184 {
0185     return m_d->autoAdjustExposure;
0186 }
0187 
0188 void KisVisualColorSelector::setAutoAdjustExposure(bool enabled)
0189 {
0190     m_d->autoAdjustExposure = enabled;
0191 }
0192 
0193 bool KisVisualColorSelector::proofColors() const
0194 {
0195     return m_d->proofColors;
0196 }
0197 
0198 void KisVisualColorSelector::setProofColors(bool enabled)
0199 {
0200     if (enabled != m_d->proofColors) {
0201         m_d->proofColors = enabled;
0202         for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0203             shape->forceImageUpdate();
0204             shape->update();
0205         }
0206     }
0207 }
0208 
0209 void KisVisualColorSelector::setSliderPosition(Qt::Edge edge)
0210 {
0211     if (edge != Qt::TopEdge && edge != Qt::LeftEdge) {
0212         return;
0213     }
0214 
0215     if (edge != m_d->sliderPosition) {
0216         m_d->sliderPosition = edge;
0217         rebuildSelector();
0218     }
0219 }
0220 
0221 KoGamutMask *KisVisualColorSelector::activeGamutMask() const
0222 {
0223     return m_d->gamutMask.data();
0224 }
0225 
0226 void KisVisualColorSelector::slotSetColor(const KoColor &c)
0227 {
0228     if (m_d->selectorModel) {
0229         m_d->selectorModel->slotSetColor(c);
0230     }
0231 }
0232 
0233 void KisVisualColorSelector::slotSetColorSpace(const KoColorSpace *cs)
0234 {
0235     if (m_d->selectorModel) {
0236         m_d->selectorModel->slotSetColorSpace(cs);
0237     }
0238 }
0239 
0240 void KisVisualColorSelector::slotConfigurationChanged()
0241 {
0242     if (m_d->updateTimer && m_d->useACSConfig) {
0243         // NOTE: this timer is because notifyConfigChanged() is only called
0244         // via KisConfig::setCustomColorSelectorColorSpace(), but at this point
0245         // Advanced Color Selector has not written the relevant config values yet.
0246         m_d->initialized = false;
0247         m_d->updateTimer->start();
0248     }
0249 }
0250 
0251 void KisVisualColorSelector::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
0252 {
0253     switchDisplayRenderer(displayRenderer);
0254 
0255     if (m_d->selectorModel) {
0256         slotDisplayConfigurationChanged();
0257     }
0258 }
0259 
0260 void KisVisualColorSelector::slotGamutMaskChanged(KoGamutMaskSP mask)
0261 {
0262     // Note: KisCanvasResourceProvider currently does not distinguish
0263     // between activating, switching and property changes of a gamut mask
0264     m_d->gamutMask = mask;
0265     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0266         shape->updateGamutMask();
0267     }
0268 }
0269 
0270 void KisVisualColorSelector::slotGamutMaskUnset()
0271 {
0272     m_d->gamutMask.clear();
0273     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0274         shape->updateGamutMask();
0275     }
0276 }
0277 
0278 void KisVisualColorSelector::slotGamutMaskPreviewUpdate()
0279 {
0280     // Shapes currently always requests preview shapes if available, so more of the same...
0281     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0282         shape->updateGamutMask();
0283     }
0284 }
0285 
0286 void KisVisualColorSelector::slotChannelValuesChanged(const QVector4D &values, quint32 channelFlags)
0287 {
0288     // about to (re-)build selector, values will be fetched when done
0289     if (!m_d->initialized) {
0290         return;
0291     }
0292     m_d->channelValues = values;
0293     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0294         shape->setChannelValues(m_d->channelValues, channelFlags);
0295     }
0296 }
0297 
0298 void KisVisualColorSelector::slotColorModelChanged()
0299 {
0300     // TODO: triangle <=> diamond switch only happens on HSV <=> non-HSV, but
0301     // the previous color model is not accessible right now
0302     if (!m_d->initialized || m_d->selectorModel->colorChannelCount() != m_d->colorChannelCount
0303             || m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0304         m_d->initialized = false;
0305         rebuildSelector();
0306     } else {
0307         slotDisplayConfigurationChanged();
0308     }
0309 }
0310 
0311 void KisVisualColorSelector::slotColorSpaceChanged()
0312 {
0313     if (m_d->autoAdjustExposure && m_d->selectorModel && m_d->selectorModel->supportsExposure()) {
0314         m_d->selectorModel->setMaxChannelValues(calculateMaxChannelValues());
0315     }
0316 }
0317 
0318 void KisVisualColorSelector::slotCursorMoved(QPointF pos)
0319 {
0320     const KisVisualColorSelectorShape *shape = qobject_cast<KisVisualColorSelectorShape *>(sender());
0321     KIS_SAFE_ASSERT_RECOVER_RETURN(shape);
0322 
0323     m_d->channelValues[shape->channel(0)] = pos.x();
0324     if (shape->getDimensions() == KisVisualColorSelectorShape::twodimensional) {
0325         m_d->channelValues[shape->channel(1)] = pos.y();
0326     }
0327 
0328     for (KisVisualColorSelectorShape *widget : qAsConst(m_d->widgetlist)) {
0329         if (widget != shape){
0330             widget->setChannelValues(m_d->channelValues, shape->channelMask());
0331         }
0332     }
0333     m_d->selectorModel->slotSetChannelValues(m_d->channelValues);
0334 }
0335 
0336 void KisVisualColorSelector::slotDisplayConfigurationChanged()
0337 {
0338     if (m_d->autoAdjustExposure && m_d->selectorModel && m_d->selectorModel->supportsExposure()) {
0339         m_d->selectorModel->setMaxChannelValues(calculateMaxChannelValues());
0340     }
0341     // TODO: can we be smarter about forced updates?
0342     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0343         shape->forceImageUpdate();
0344         shape->update();
0345     }
0346 }
0347 
0348 void KisVisualColorSelector::slotReloadConfiguration()
0349 {
0350     if (m_d->useACSConfig) {
0351         loadACSConfig();
0352         // this may trigger slotColorModelChanged() so check afterwards if we already rebuild
0353         m_d->selectorModel->slotLoadACSConfig();
0354         if (!m_d->initialized) {
0355             rebuildSelector();
0356         }
0357     }
0358 }
0359 
0360 void KisVisualColorSelector::rebuildSelector()
0361 {
0362     qDeleteAll(m_d->widgetlist);
0363     m_d->widgetlist.clear();
0364 
0365     if (!m_d->selectorModel || m_d->selectorModel->colorModel() == KisVisualColorModel::None) {
0366         return;
0367     }
0368 
0369     m_d->colorChannelCount = m_d->selectorModel->colorChannelCount();
0370 
0371     //recreate all the widgets.
0372 
0373     if (m_d->colorChannelCount == 1) {
0374 
0375         KisVisualColorSelectorShape *bar;
0376 
0377         if (m_d->circular) {
0378             bar = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::onedimensional,
0379                                                        0, 0, 20, KisVisualEllipticalSelectorShape::borderMirrored);
0380         }
0381         else {
0382             bar = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::onedimensional,
0383                                                       0, 0, 20);
0384         }
0385 
0386         connect(bar, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0387         m_d->widgetlist.append(bar);
0388     }
0389     else if (m_d->colorChannelCount == 3) {
0390         int channel1 = 0;
0391         int channel2 = 1;
0392         int channel3 = 2;
0393 
0394         switch(m_d->acs_config.subTypeParameter)
0395         {
0396         case KisColorSelectorConfiguration::H:
0397         case KisColorSelectorConfiguration::Hluma:
0398             channel1 = 0;
0399             break;
0400         case KisColorSelectorConfiguration::hsvS:
0401             channel1 = 1;
0402             break;
0403         case KisColorSelectorConfiguration::V:
0404             channel1 = 2;
0405             break;
0406         default:
0407             Q_ASSERT_X(false, "", "Invalid acs_config.subTypeParameter");
0408         }
0409 
0410         switch(m_d->acs_config.mainTypeParameter)
0411         {
0412         case KisColorSelectorConfiguration::hsvSH:
0413             channel2 = 0;
0414             channel3 = 1;
0415             break;
0416         case KisColorSelectorConfiguration::VH:
0417             channel2 = 0;
0418             channel3 = 2;
0419             break;
0420         case KisColorSelectorConfiguration::SV:
0421             channel2 = 1;
0422             channel3 = 2;
0423             break;
0424         default:
0425             Q_ASSERT_X(false, "", "Invalid acs_config.mainTypeParameter");
0426         }
0427 
0428         KisVisualColorSelectorShape *bar;
0429         if (m_d->acs_config.subType == KisColorSelectorConfiguration::Ring) {
0430             bar = new KisVisualEllipticalSelectorShape(this,
0431                                                        KisVisualColorSelectorShape::onedimensional,
0432                                                        channel1, channel1, 20,
0433                                                        KisVisualEllipticalSelectorShape::border);
0434         }
0435         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular == false) {
0436             KisVisualRectangleSelectorShape::singelDTypes orientation = useHorizontalSlider() ?
0437                         KisVisualRectangleSelectorShape::horizontal : KisVisualRectangleSelectorShape::vertical;
0438 
0439             bar = new KisVisualRectangleSelectorShape(this,
0440                                                       KisVisualColorSelectorShape::onedimensional,
0441                                                       channel1, channel1, 20, orientation);
0442         }
0443         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular == true) {
0444             bar = new KisVisualEllipticalSelectorShape(this,
0445                                                        KisVisualColorSelectorShape::onedimensional,
0446                                                        channel1, channel1,
0447                                                        20, KisVisualEllipticalSelectorShape::borderMirrored);
0448         } else {
0449             // Accessing bar below would crash since it's not initialized.
0450             // Hopefully this can never happen.
0451             warnUI << "Invalid subType, cannot initialize KisVisualColorSelectorShape";
0452             Q_ASSERT_X(false, "", "Invalid subType, cannot initialize KisVisualColorSelectorShape");
0453             return;
0454         }
0455 
0456         m_d->widgetlist.append(bar);
0457 
0458         KisVisualColorSelectorShape *block;
0459         if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0460             if (m_d->selectorModel->colorModel() == KisVisualColorModel::HSV) {
0461                 block = new KisVisualTriangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0462                                                            channel2, channel3);
0463             } else {
0464                 block = new KisVisualDiamondSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0465                                                            channel2, channel3);
0466             }
0467         }
0468         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Square) {
0469             block = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0470                                                         channel2, channel3);
0471         }
0472         else {
0473             block = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::twodimensional,
0474                                                          channel2, channel3);
0475         }
0476 
0477         connect(bar, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0478         connect(block, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0479         m_d->widgetlist.append(block);
0480     }
0481     else if (m_d->colorChannelCount == 4) {
0482         KisVisualRectangleSelectorShape *block =  new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional, 0, 1);
0483         KisVisualRectangleSelectorShape *block2 =  new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional, 2, 3);
0484         connect(block, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0485         connect(block2, SIGNAL(sigCursorMoved(QPointF)), SLOT(slotCursorMoved(QPointF)));
0486         m_d->widgetlist.append(block);
0487         m_d->widgetlist.append(block2);
0488     }
0489 
0490     m_d->initialized = true;
0491     // make sure we call "our" resize function
0492     KisVisualColorSelector::resizeEvent(0);
0493 
0494     for (KisVisualColorSelectorShape *shape : qAsConst(m_d->widgetlist)) {
0495         shape->setAcceptTabletEvents(m_d->acceptTabletEvents);
0496         // if this widget is currently visible, new children are hidden by default
0497         shape->show();
0498     }
0499 
0500     // finally update widgets with new channel values
0501     slotChannelValuesChanged(m_d->selectorModel->channelValues(), (1u << m_d->colorChannelCount) - 1);
0502 }
0503 
0504 void KisVisualColorSelector::resizeEvent(QResizeEvent *)
0505 {
0506     if (!m_d->selectorModel || !m_d->initialized) {
0507         KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->widgetlist.isEmpty() || !m_d->initialized);
0508         return;
0509     }
0510     int sizeValue = qMin(width(), height());
0511     // due to masking/antialiasing, the visible width is ~4 pixels less, so add them here
0512     const int margin = 4;
0513     const qreal sliderRatio = 0.09;
0514     int borderWidth = qMax(int(sizeValue * sliderRatio), m_d->minimumSliderWidth) + margin;
0515     QRect newrect(0,0, this->geometry().width(), this->geometry().height());
0516 
0517     if (m_d->colorChannelCount == 1) {
0518         if (m_d->circular) {
0519             m_d->widgetlist.at(0)->resize(sizeValue, sizeValue);
0520         }
0521         else {
0522             KisVisualRectangleSelectorShape *slider = qobject_cast<KisVisualRectangleSelectorShape *>(m_d->widgetlist.at(0));
0523             KIS_SAFE_ASSERT_RECOVER_RETURN(slider);
0524             if (useHorizontalSlider()) {
0525                 int sliderWidth = qMax(width()/10, m_d->minimumSliderWidth);
0526                 sliderWidth = qMin(sliderWidth, height());
0527                 int y = (height() - sliderWidth)/2;
0528                 slider->setOneDimensionalType(KisVisualRectangleSelectorShape::horizontal);
0529                 slider->setGeometry(0, y, width(), sliderWidth);
0530             }
0531             else {
0532                 // vertical slider
0533                 int sliderWidth = qMax(height()/10, m_d->minimumSliderWidth);
0534                 sliderWidth = qMin(sliderWidth, width());
0535                 int x = (width() - sliderWidth)/2;
0536                 slider->setOneDimensionalType(KisVisualRectangleSelectorShape::vertical);
0537                 slider->setGeometry(x, 0, sliderWidth, height());
0538             }
0539         }
0540     }
0541     else if (m_d->colorChannelCount == 3) {
0542         m_d->widgetlist.at(0)->setBorderWidth(borderWidth);
0543         // Ring
0544         if (m_d->acs_config.subType == KisColorSelectorConfiguration::Ring ||
0545             (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider && m_d->circular)) {
0546 
0547             m_d->widgetlist.at(0)->setGeometry((width() - sizeValue)/2, (height() - sizeValue)/2,
0548                                                sizeValue, sizeValue);
0549         }
0550         // Slider Bar
0551         else if (m_d->acs_config.subType == KisColorSelectorConfiguration::Slider) {
0552             // limit stretch; only vertical slider currently
0553             if (useHorizontalSlider()) {
0554                 newrect.setWidth(qMin(newrect.width(), qRound((newrect.height() - borderWidth) * m_d->stretchLimit)));
0555                 newrect.setHeight(qMin(newrect.height(), qRound(sizeValue * m_d->stretchLimit + borderWidth)));
0556 
0557                 m_d->widgetlist.at(0)->setGeometry(0, 0, newrect.width(), borderWidth);
0558             }
0559             else {
0560                 newrect.setWidth(qMin(newrect.width(), qRound(sizeValue * m_d->stretchLimit + borderWidth)));
0561                 newrect.setHeight(qMin(newrect.height(), qRound((newrect.width() - borderWidth) * m_d->stretchLimit)));
0562 
0563                 m_d->widgetlist.at(0)->setGeometry(0, 0, borderWidth, newrect.height());
0564             }
0565 
0566         }
0567 
0568         if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Triangle) {
0569             if (m_d->selectorModel->colorModel() == KisVisualColorModel::HSV) {
0570                 m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForTriangle(newrect));
0571             } else {
0572                 m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForCircle(newrect));
0573             }
0574         }
0575         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Square) {
0576             m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForSquare(newrect));
0577         }
0578         else if (m_d->acs_config.mainType == KisColorSelectorConfiguration::Wheel) {
0579             m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForCircle(newrect));
0580         }
0581         // center horizontally
0582         QRect boundRect(m_d->widgetlist.at(0)->geometry() | m_d->widgetlist.at(1)->geometry());
0583         int offset = (width() - boundRect.width()) / 2 - boundRect.left();
0584         m_d->widgetlist.at(0)->move(m_d->widgetlist.at(0)->pos() + QPoint(offset, 0));
0585         m_d->widgetlist.at(1)->move(m_d->widgetlist.at(1)->pos() + QPoint(offset, 0));
0586     }
0587     else if (m_d->colorChannelCount == 4) {
0588         int sizeBlock = qMin(width()/2 - 8, height());
0589         m_d->widgetlist.at(0)->setGeometry(0, 0, sizeBlock, sizeBlock);
0590         m_d->widgetlist.at(1)->setGeometry(sizeBlock + 8, 0, sizeBlock, sizeBlock);
0591     }
0592 }
0593 
0594 bool KisVisualColorSelector::useHorizontalSlider()
0595 {
0596     if (m_d->colorChannelCount == 1) {
0597         return width() > height();
0598     }
0599     else {
0600         return m_d->sliderPosition == Qt::TopEdge;
0601     }
0602 }
0603 
0604 void KisVisualColorSelector::switchDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
0605 {
0606     if (displayRenderer != m_d->displayRenderer) {
0607         if (m_d->displayRenderer) {
0608             m_d->displayRenderer->disconnect(this);
0609         }
0610         if (displayRenderer) {
0611             connect(displayRenderer, SIGNAL(displayConfigurationChanged()),
0612                     SLOT(slotDisplayConfigurationChanged()), Qt::UniqueConnection);
0613         }
0614         m_d->displayRenderer = displayRenderer;
0615     }
0616 }
0617 
0618 QVector4D KisVisualColorSelector::calculateMaxChannelValues()
0619 {
0620     // Note: This calculation only makes sense for HDR color spaces
0621     QVector4D maxChannelValues = QVector4D(1, 1, 1, 1);
0622     const QList<KoChannelInfo *> channels = m_d->selectorModel->colorSpace()->channels();
0623 
0624     for (int i = 0; i < channels.size(); i++) {
0625         const KoChannelInfo *channel = channels.at(i);
0626         if (channel->channelType() != KoChannelInfo::ALPHA) {
0627             quint32 logical = channel->displayPosition();
0628             if (logical > m_d->selectorModel->colorSpace()->alphaPos()) {
0629                 --logical;
0630             }
0631             maxChannelValues[logical] = displayRenderer()->maxVisibleFloatValue(channel);
0632         }
0633     }
0634 
0635     return maxChannelValues;
0636 }
0637 
0638 void KisVisualColorSelector::loadACSConfig()
0639 {
0640     KConfigGroup cfg =  KSharedConfig::openConfig()->group("advancedColorSelector");
0641     KisColorSelectorConfiguration raw_config = KisColorSelectorConfiguration::fromString(
0642                 cfg.readEntry("colorSelectorConfiguration", KisColorSelectorConfiguration().toString()));
0643     m_d->acs_config = validatedConfiguration(raw_config);
0644 }
0645 
0646 KisColorSelectorConfiguration KisVisualColorSelector::validatedConfiguration(const KisColorSelectorConfiguration &cfg)
0647 {
0648     KisColorSelectorConfiguration validated(cfg);
0649     bool ok = true;
0650 
0651     switch (validated.mainType) {
0652     case KisColorSelectorConfiguration::Triangle:
0653     case KisColorSelectorConfiguration::Square:
0654     case KisColorSelectorConfiguration::Wheel:
0655         break;
0656     default:
0657         ok = false;
0658     }
0659 
0660     switch (validated.subType) {
0661     case KisColorSelectorConfiguration::Ring:
0662     case KisColorSelectorConfiguration::Slider:
0663         break;
0664     default:
0665         ok = false;
0666     }
0667 
0668     switch(validated.subTypeParameter)
0669     {
0670     case KisColorSelectorConfiguration::H:
0671     case KisColorSelectorConfiguration::hsvS:
0672     case KisColorSelectorConfiguration::V:
0673         break;
0674     // translate to HSV
0675     case KisColorSelectorConfiguration::hsyS:
0676     case KisColorSelectorConfiguration::hsiS:
0677     case KisColorSelectorConfiguration::hslS:
0678         validated.subTypeParameter = KisColorSelectorConfiguration::hsvS;
0679         break;
0680     case KisColorSelectorConfiguration::L:
0681     case KisColorSelectorConfiguration::I:
0682     case KisColorSelectorConfiguration::Y:
0683         validated.subTypeParameter = KisColorSelectorConfiguration::V;
0684         break;
0685     default:
0686         ok = false;
0687     }
0688 
0689     switch(validated.mainTypeParameter)
0690     {
0691     case KisColorSelectorConfiguration::SV:
0692     case KisColorSelectorConfiguration::hsvSH:
0693     case KisColorSelectorConfiguration::VH:
0694         break;
0695     // translate to HSV
0696     case KisColorSelectorConfiguration::SL:
0697     case KisColorSelectorConfiguration::SV2:
0698     case KisColorSelectorConfiguration::SI:
0699     case KisColorSelectorConfiguration::SY:
0700         validated.mainTypeParameter = KisColorSelectorConfiguration::SV;
0701         break;
0702     case KisColorSelectorConfiguration::hslSH:
0703     case KisColorSelectorConfiguration::hsiSH:
0704     case KisColorSelectorConfiguration::hsySH:
0705         validated.mainTypeParameter = KisColorSelectorConfiguration::hsvSH;
0706         break;
0707     case KisColorSelectorConfiguration::LH:
0708     case KisColorSelectorConfiguration::IH:
0709     case KisColorSelectorConfiguration::YH:
0710         validated.mainTypeParameter = KisColorSelectorConfiguration::VH;
0711         break;
0712     default:
0713         ok = false;
0714     }
0715 
0716     if (ok) {
0717         return validated;
0718     }
0719     return KisColorSelectorConfiguration(KisColorSelectorConfiguration::Triangle,
0720                                          KisColorSelectorConfiguration::Ring,
0721                                          KisColorSelectorConfiguration::SV,
0722                                          KisColorSelectorConfiguration::H);
0723 }