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

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
0003  * SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #include "kis_spinbox_color_selector.h"
0008 #include <QFormLayout>
0009 #include <QLabel>
0010 #include "kis_double_parse_spin_box.h"
0011 #include "kis_int_parse_spin_box.h"
0012 #include "kis_signal_compressor.h"
0013 
0014 #include <KoConfig.h>
0015 #ifdef HAVE_OPENEXR
0016 #include <half.h>
0017 #endif
0018 #include <KoChannelInfo.h>
0019 #include <KoColorModelStandardIds.h>
0020 #include <KoColorSpaceTraits.h>
0021 #include <KoColorSpaceMaths.h>
0022 #include <KoColorSpaceRegistry.h>
0023 
0024 struct KisSpinboxColorSelector::Private
0025 {
0026     QList <QLabel*> labels;
0027     QList <KisIntParseSpinBox*> spinBoxList;
0028     QList <KisDoubleParseSpinBox*> doubleSpinBoxList;
0029     KoColor color;
0030     const KoColorSpace *cs {0};
0031     bool chooseAlpha {false};
0032     QFormLayout *layout {0};
0033 };
0034 
0035 KisSpinboxColorSelector::KisSpinboxColorSelector(QWidget *parent)
0036     : QWidget(parent)
0037     , m_d(new Private)
0038 {
0039     this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
0040     m_d->layout = new QFormLayout(this);
0041 }
0042 
0043 KisSpinboxColorSelector::~KisSpinboxColorSelector()
0044 {
0045 
0046 }
0047 
0048 void KisSpinboxColorSelector::slotSetColor(KoColor color)
0049 {
0050     m_d->color = color;
0051     slotSetColorSpace(m_d->color.colorSpace());
0052     updateSpinboxesWithNewValues();
0053 }
0054 
0055 void KisSpinboxColorSelector::slotSetColorSpace(const KoColorSpace *cs)
0056 {
0057     if (cs == m_d->cs) {
0058         return;
0059     }
0060 
0061     m_d->cs = cs;
0062     //remake spinboxes
0063     delete m_d->layout;
0064     m_d->layout = new QFormLayout(this);
0065 
0066     Q_FOREACH(QObject *o, m_d->labels) {
0067         o->deleteLater();
0068     }
0069     Q_FOREACH(QObject *o, m_d->spinBoxList) {
0070         o->deleteLater();
0071     }
0072     Q_FOREACH(QObject *o, m_d->doubleSpinBoxList) {
0073         o->deleteLater();
0074     }
0075 
0076     m_d->labels.clear();
0077     m_d->spinBoxList.clear();
0078     m_d->doubleSpinBoxList.clear();
0079 
0080     QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels());
0081     Q_FOREACH (KoChannelInfo* channel, channels) {
0082         QString inputLabel = channel->name() + ":";
0083         QLabel *inlb = new QLabel(this);
0084         m_d->labels << inlb;
0085         inlb->setText(inputLabel);
0086         switch (channel->channelValueType()) {
0087         case KoChannelInfo::UINT8: {
0088             KisIntParseSpinBox *input = new KisIntParseSpinBox(this);
0089             input->setMinimum(0);
0090             input->setMaximum(0xFF);
0091             m_d->spinBoxList.append(input);
0092             connect(input, SIGNAL(valueChanged(int)), this,  SLOT(slotUpdateFromSpinBoxes()));
0093             if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) {
0094                 inlb->setVisible(false);
0095                 input->setVisible(false);
0096                 input->blockSignals(true);
0097             }
0098             else {
0099                 m_d->layout->addRow(inlb, input);
0100             }
0101         }
0102             break;
0103         case KoChannelInfo::UINT16: {
0104             KisIntParseSpinBox *input = new KisIntParseSpinBox(this);
0105             input->setMinimum(0);
0106             input->setMaximum(0xFFFF);
0107             m_d->spinBoxList.append(input);
0108             connect(input, SIGNAL(valueChanged(int)), this,  SLOT(slotUpdateFromSpinBoxes()));
0109             if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) {
0110                 inlb->setVisible(false);
0111                 input->setVisible(false);
0112                 input->blockSignals(true);
0113             }
0114             else {
0115                 m_d->layout->addRow(inlb,input);
0116             }
0117         }
0118             break;
0119         case KoChannelInfo::UINT32: {
0120             KisIntParseSpinBox *input = new KisIntParseSpinBox(this);
0121             input->setMinimum(0);
0122             input->setMaximum(0xFFFFFFFF);
0123             m_d->spinBoxList.append(input);
0124             connect(input, SIGNAL(valueChanged(int)), this,  SLOT(slotUpdateFromSpinBoxes()));
0125             if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) {
0126                 inlb->setVisible(false);
0127                 input->setVisible(false);
0128                 input->blockSignals(true);
0129             }
0130             else {
0131                 m_d->layout->addRow(inlb,input);
0132             }
0133         }
0134             break;
0135 #ifdef HAVE_OPENEXR
0136         case KoChannelInfo::FLOAT16: {
0137             half m_uiMin, m_uiMax;
0138             if (cs->colorModelId() == LABAColorModelID || cs->colorModelId() == CMYKAColorModelID) {
0139                 m_uiMin = channel->getUIMin();
0140                 m_uiMax = channel->getUIMax();
0141             } else {
0142                 m_uiMin = 0;
0143                 m_uiMax = KoColorSpaceMathsTraits<half>::max;
0144             }
0145 
0146             KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this);
0147             input->setMinimum(m_uiMin);
0148             input->setMaximum(m_uiMax);
0149             input->setSingleStep(0.1);
0150             m_d->doubleSpinBoxList.append(input);
0151             connect(input, SIGNAL(valueChanged(double)), this,  SLOT(slotUpdateFromSpinBoxes()));
0152             if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) {
0153                 inlb->setVisible(false);
0154                 input->setVisible(false);
0155                 input->blockSignals(true);
0156             }
0157             else {
0158                 m_d->layout->addRow(inlb,input);
0159             }
0160         }
0161             break;
0162 #endif
0163         case KoChannelInfo::FLOAT32: {
0164             float m_uiMin, m_uiMax;
0165             if (cs->colorModelId() == LABAColorModelID || cs->colorModelId() == CMYKAColorModelID) {
0166                 m_uiMin = channel->getUIMin();
0167                 m_uiMax = channel->getUIMax();
0168             } else {
0169                 m_uiMin = 0;
0170                 m_uiMax = KoColorSpaceMathsTraits<float>::max;
0171             }
0172 
0173             KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this);
0174             input->setMinimum(m_uiMin);
0175             input->setMaximum(m_uiMax);
0176             input->setSingleStep(0.1);
0177             m_d->doubleSpinBoxList.append(input);
0178             connect(input, SIGNAL(valueChanged(double)), this,  SLOT(slotUpdateFromSpinBoxes()));
0179             if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) {
0180                 inlb->setVisible(false);
0181                 input->setVisible(false);
0182                 input->blockSignals(true);
0183             }
0184             else {
0185                 m_d->layout->addRow(inlb,input);
0186             }
0187         }
0188             break;
0189         default:
0190             Q_ASSERT(false);
0191         }
0192 
0193     }
0194 }
0195 
0196 void KisSpinboxColorSelector::createColorFromSpinboxValues()
0197 {
0198     KoColor newColor(m_d->cs);
0199     int channelcount = m_d->cs->channelCount();
0200     QVector <float> channelValues(channelcount);
0201     channelValues.fill(1.0);
0202     QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels());
0203 
0204     for (int i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) {
0205         int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels());
0206 
0207         if (channels.at(i)->channelValueType()==KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)){
0208 
0209             int value = m_d->spinBoxList.at(i)->value();
0210             channelValues[channelposition] = KoColorSpaceMaths<quint8,float>::scaleToA(value);
0211 
0212         } else if (channels.at(i)->channelValueType()==KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)){
0213 
0214             channelValues[channelposition] = KoColorSpaceMaths<quint16,float>::scaleToA(m_d->spinBoxList.at(i)->value());
0215 
0216         } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 ||
0217                     channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 ||
0218                     channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) {
0219 
0220             channelValues[channelposition] = m_d->doubleSpinBoxList.at(i)->value();
0221 
0222         }
0223     }
0224 
0225     m_d->cs->fromNormalisedChannelsValue(newColor.data(), channelValues);
0226     newColor.setOpacity(m_d->color.opacityU8());
0227 
0228     m_d->color = newColor;
0229 }
0230 
0231 void KisSpinboxColorSelector::slotUpdateFromSpinBoxes()
0232 {
0233     createColorFromSpinboxValues();
0234     emit sigNewColor(m_d->color);
0235 }
0236 
0237 void KisSpinboxColorSelector::updateSpinboxesWithNewValues()
0238 {
0239     int channelcount = m_d->cs->channelCount();
0240     QVector <float> channelValues(channelcount);
0241     channelValues.fill(1.0);
0242     m_d->cs->normalisedChannelsValue(m_d->color.data(), channelValues);
0243     QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels());
0244 
0245     int i;
0246     /*while (QLayoutItem *item = this->layout()->takeAt(0))
0247     {
0248         item->widget()->blockSignals(true);
0249     }*/
0250     for (i=0; i<m_d->spinBoxList.size(); i++) {
0251         m_d->spinBoxList.at(i)->blockSignals(true);
0252     }
0253     for (i=0; i<m_d->doubleSpinBoxList.size(); i++) {
0254         m_d->doubleSpinBoxList.at(i)->blockSignals(true);
0255     }
0256 
0257     for (i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) {
0258         int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels());
0259         if (channels.at(i)->channelValueType() == KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)) {
0260             int value = KoColorSpaceMaths<float, quint8>::scaleToA(channelValues[channelposition]);
0261             m_d->spinBoxList.at(i)->setValue(value);
0262         } else if (channels.at(i)->channelValueType() == KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)) {
0263             m_d->spinBoxList.at(i)->setValue(KoColorSpaceMaths<float, quint16>::scaleToA(channelValues[channelposition]));
0264         } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 ||
0265                     channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 ||
0266                     channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) {
0267             float value = channels.at(i)->getUIMin() + channelValues[channelposition] * channels.at(i)->getUIUnitValue();
0268             m_d->doubleSpinBoxList.at(i)->setValue(value);
0269         }
0270     }
0271 
0272     for (i=0; i<m_d->spinBoxList.size(); i++) {
0273         m_d->spinBoxList.at(i)->blockSignals(false);
0274     }
0275     for (i=0; i<m_d->doubleSpinBoxList.size(); i++) {
0276         m_d->doubleSpinBoxList.at(i)->blockSignals(false);
0277     }
0278     /*while (QLayoutItem *item = this->layout()->takeAt(0))
0279     {
0280         item->widget()->blockSignals(false);
0281     }*/
0282 }
0283 
0284