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

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 
0007 #include <QList>
0008 #include <QAbstractSpinBox>
0009 #include <QSpinBox>
0010 #include <QDoubleSpinBox>
0011 #include <QPointer>
0012 #include <QCompleter>
0013 
0014 #include <functional>
0015 
0016 #include <KConfigGroup>
0017 #include <kstandardguiitem.h>
0018 
0019 #include "KoColorSpaceRegistry.h"
0020 #include <KoColorSet.h>
0021 #include <KisPaletteModel.h>
0022 #include <KisPaletteChooser.h>
0023 #include <kis_palette_view.h>
0024 #include <KoResourceServerProvider.h>
0025 #include <KoResourceServer.h>
0026 
0027 #include "kis_signal_compressor.h"
0028 #include "KoColorDisplayRendererInterface.h"
0029 
0030 #include "kis_spinbox_color_selector.h"
0031 
0032 #include "KisDlgInternalColorSelector.h"
0033 #include "ui_WdgDlgInternalColorSelector.h"
0034 #include "kis_config_notifier.h"
0035 #include "kis_color_input.h"
0036 #include "kis_icon_utils.h"
0037 #include "KisSqueezedComboBox.h"
0038 
0039 std::function<KisScreenColorSamplerBase *(QWidget *)> KisDlgInternalColorSelector::s_screenColorSamplerFactory = 0;
0040 
0041 struct KisDlgInternalColorSelector::Private
0042 {
0043     bool allowUpdates = true;
0044     KoColor currentColor;
0045     KoColor previousColor;
0046     KoColor sRGB = KoColor(KoColorSpaceRegistry::instance()->rgb8());
0047     const KoColorSpace *currentColorSpace;
0048     bool lockUsedCS = false;
0049     bool chooseAlpha = false;
0050     KisSignalCompressor *compressColorChanges;
0051     const KoColorDisplayRendererInterface *displayRenderer;
0052     KisHexColorInput *hexColorInput = 0;
0053     KisPaletteModel *paletteModel = 0;
0054     KisPaletteChooser *paletteChooser = 0;
0055     KisScreenColorSamplerBase *screenColorSampler = 0;
0056 };
0057 
0058 KisDlgInternalColorSelector::KisDlgInternalColorSelector(QWidget *parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer)
0059     : QDialog(parent)
0060     , m_d(new Private)
0061 {
0062     setModal(config.modal);
0063     setFocusPolicy(Qt::ClickFocus);
0064     m_ui = new Ui_WdgDlgInternalColorSelector();
0065     m_ui->setupUi(this);
0066 
0067     setWindowTitle(caption);
0068 
0069     m_d->currentColor = color;
0070     m_d->currentColorSpace = m_d->currentColor.colorSpace();
0071     m_d->displayRenderer = displayRenderer;
0072 
0073     m_ui->spinboxselector->slotSetColor(color);
0074     connect(m_ui->spinboxselector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor)));
0075 
0076     m_ui->spinboxHSXSelector->attachToSelector(m_ui->visualSelector);
0077 
0078     m_ui->visualSelector->setDisplayRenderer(displayRenderer);
0079     m_ui->visualSelector->setConfig(false, config.modal);
0080     if (config.visualColorSelector) {
0081         connect(m_ui->visualSelector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor)));
0082         connect(m_ui->visualSelector, SIGNAL(sigColorModelChanged()), this, SLOT(slotSelectorModelChanged()));
0083         connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_ui->visualSelector, SLOT(configurationChanged()));
0084     } else {
0085         m_ui->visualSelector->hide();
0086     }
0087     m_ui->visualSelector->slotSetColor(color);
0088 
0089     m_d->paletteChooser = new KisPaletteChooser(this);
0090     m_d->paletteModel = new KisPaletteModel(this);
0091     m_ui->bnPaletteChooser->setIcon(KisIconUtils::loadIcon("palette-library"));
0092     m_ui->paletteBox->setPaletteModel(m_d->paletteModel);
0093     m_ui->paletteBox->setDisplayRenderer(displayRenderer);
0094     m_ui->cmbNameList->setCompanionView(m_ui->paletteBox);
0095     connect(m_d->paletteChooser, SIGNAL(sigPaletteSelected(KoColorSetSP)), this, SLOT(slotChangePalette(KoColorSetSP)));
0096     connect(m_ui->cmbNameList, SIGNAL(sigColorSelected(KoColor)), SLOT(slotColorUpdated(KoColor)));
0097 
0098     // For some bizarre reason, the modal dialog doesn't like having the colorset set, so let's not.
0099     if (config.paletteBox) {
0100         //TODO: Add disable signal as well. Might be not necessary...?
0101         KConfigGroup cfg(KSharedConfig::openConfig()->group(""));
0102         QString paletteMd5 = cfg.readEntry("internal_selector_active_color_set_md5", QString());
0103         QString paletteName = cfg.readEntry("internal_selector_active_color_set", QString());
0104         KoResourceServer<KoColorSet>* rServer = KoResourceServerProvider::instance()->paletteServer();
0105         KoColorSetSP savedPal = rServer->resource(paletteMd5, "", paletteName);
0106         if (savedPal) {
0107             this->slotChangePalette(savedPal);
0108         } else {
0109             if (rServer->resourceCount()) {
0110                 savedPal = rServer->firstResource();
0111                 if (savedPal) {
0112                     this->slotChangePalette(savedPal);
0113                 }
0114             }
0115         }
0116 
0117         connect(m_ui->paletteBox, SIGNAL(sigColorSelected(KoColor)), this,
0118                 SLOT(slotColorUpdated(KoColor)));
0119         m_ui->bnPaletteChooser->setPopupWidget(m_d->paletteChooser);
0120     } else {
0121         m_ui->paletteBox->setEnabled(false);
0122         m_ui->cmbNameList->setEnabled(false);
0123         m_ui->bnPaletteChooser->setEnabled(false);
0124     }
0125 
0126     if (config.prevNextButtons) {
0127         m_ui->currentColor->setColor(m_d->currentColor);
0128         m_ui->currentColor->setDisplayRenderer(displayRenderer);
0129         m_ui->previousColor->setColor(m_d->previousColor);
0130         m_ui->previousColor->setDisplayRenderer(displayRenderer);
0131         connect(m_ui->previousColor, SIGNAL(triggered(KoColorPatch*)), SLOT(slotSetColorFromPatch(KoColorPatch*)));
0132     } else {
0133         m_ui->currentColor->hide();
0134         m_ui->previousColor->hide();
0135     }
0136 
0137     if (config.hexInput) {
0138         m_d->sRGB.fromKoColor(m_d->currentColor);
0139         m_d->hexColorInput = new KisHexColorInput(this, &m_d->sRGB);
0140         m_d->hexColorInput->update();
0141         connect(m_d->hexColorInput, SIGNAL(updated()), SLOT(slotSetColorFromHex()));
0142         m_ui->rightPane->addWidget(m_d->hexColorInput);
0143         m_d->hexColorInput->setToolTip(i18n("This is a hexcode input, for webcolors. It can only get colors in the sRGB space."));
0144     }
0145 
0146     // KisScreenColorSampler is in the kritaui module, so dependency inversion is used to access it.
0147     m_ui->screenColorSamplerWidget->setLayout(new QHBoxLayout());
0148     if (s_screenColorSamplerFactory) {
0149         m_d->screenColorSampler = s_screenColorSamplerFactory(m_ui->screenColorSamplerWidget);
0150         m_ui->screenColorSamplerWidget->layout()->addWidget(m_d->screenColorSampler);
0151         if (config.screenColorSampler) {
0152             connect(m_d->screenColorSampler, SIGNAL(sigNewColorSampled(KoColor)),this, SLOT(slotColorUpdated(KoColor)));
0153         } else {
0154             m_d->screenColorSampler->hide();
0155         }
0156     }
0157 
0158     m_d->compressColorChanges = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this);
0159     connect(m_d->compressColorChanges, SIGNAL(timeout()), this, SLOT(endUpdateWithNewColor()));
0160 
0161     KGuiItem::assign(m_ui->buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
0162     KGuiItem::assign(m_ui->buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
0163     connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()), Qt::UniqueConnection);
0164     connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()), Qt::UniqueConnection);
0165 
0166     connect(this, SIGNAL(finished(int)), SLOT(slotFinishUp()));
0167 }
0168 
0169 KisDlgInternalColorSelector::~KisDlgInternalColorSelector()
0170 {
0171     delete m_ui;
0172 }
0173 
0174 void KisDlgInternalColorSelector::slotColorUpdated(KoColor newColor)
0175 {
0176     // not-so-nice solution: if someone calls this slot directly and that code was
0177     // triggered by our compressor signal, our compressor is technically the sender()!
0178     if (sender() == m_d->compressColorChanges) {
0179         return;
0180     }
0181     // Do not accept external updates while a color update emit is pending;
0182     // Note: Assumes external updates only come from parent(), a separate slot might be better
0183     if (m_d->allowUpdates || (QObject::sender() && QObject::sender() != this->parent())) {
0184         // Enforce palette colors
0185         KConfigGroup group(KSharedConfig::openConfig(), "");
0186         if (group.readEntry("colorsettings/forcepalettecolors", false)) {
0187             newColor = m_ui->paletteBox->closestColor(newColor);
0188         }
0189 
0190         if (m_d->lockUsedCS){
0191             newColor.convertTo(m_d->currentColorSpace);
0192         } else {
0193             colorSpaceChanged(newColor.colorSpace());
0194         }
0195         m_d->currentColor = newColor;
0196         updateAllElements(QObject::sender());
0197     }
0198 }
0199 
0200 void KisDlgInternalColorSelector::slotSetColorFromPatch(KoColorPatch *patch)
0201 {
0202     slotColorUpdated(patch->color());
0203 }
0204 
0205 void KisDlgInternalColorSelector::colorSpaceChanged(const KoColorSpace *cs)
0206 {
0207     if (cs == m_d->currentColorSpace) {
0208         return;
0209     }
0210 
0211     m_d->currentColorSpace = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile());
0212     m_ui->spinboxselector->slotSetColorSpace(m_d->currentColorSpace);
0213     m_ui->visualSelector->slotSetColorSpace(m_d->currentColorSpace);
0214 
0215 }
0216 
0217 void KisDlgInternalColorSelector::lockUsedColorSpace(const KoColorSpace *cs)
0218 {
0219     colorSpaceChanged(cs);
0220     if (m_d->currentColor.colorSpace() != m_d->currentColorSpace) {
0221         m_d->currentColor.convertTo(m_d->currentColorSpace);
0222         m_ui->spinboxselector->slotSetColor(m_d->currentColor);
0223         m_ui->visualSelector->slotSetColor(m_d->currentColor);
0224     }
0225     m_d->lockUsedCS = true;
0226 }
0227 
0228 void KisDlgInternalColorSelector::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
0229 {
0230     if (displayRenderer) {
0231         m_d->displayRenderer = displayRenderer;
0232         m_ui->visualSelector->setDisplayRenderer(displayRenderer);
0233         m_ui->currentColor->setDisplayRenderer(displayRenderer);
0234         m_ui->previousColor->setDisplayRenderer(displayRenderer);
0235         m_ui->paletteBox->setDisplayRenderer(displayRenderer);
0236     } else {
0237         m_d->displayRenderer = KoDumbColorDisplayRenderer::instance();
0238     }
0239 }
0240 
0241 KoColor KisDlgInternalColorSelector::getModalColorDialog(const KoColor color, QWidget* parent, QString caption)
0242 {
0243     Config config = Config();
0244     KisDlgInternalColorSelector dialog(parent, color, config, caption);
0245     dialog.setPreviousColor(color);
0246     dialog.exec();
0247     return dialog.getCurrentColor();
0248 }
0249 
0250 KoColor KisDlgInternalColorSelector::getCurrentColor()
0251 {
0252     return m_d->currentColor;
0253 }
0254 
0255 void KisDlgInternalColorSelector::chooseAlpha(bool chooseAlpha)
0256 {
0257     m_d->chooseAlpha = chooseAlpha;
0258 }
0259 
0260 void KisDlgInternalColorSelector::setPreviousColor(KoColor c)
0261 {
0262     m_d->previousColor = c;
0263 }
0264 
0265 void KisDlgInternalColorSelector::reject()
0266 {
0267     slotColorUpdated(m_d->previousColor);
0268     QDialog::reject();
0269 }
0270 
0271 void KisDlgInternalColorSelector::updateAllElements(QObject *source)
0272 {
0273     //update everything!!!
0274     if (source != m_ui->spinboxselector) {
0275         m_ui->spinboxselector->slotSetColor(m_d->currentColor);
0276     }
0277     if (source != m_ui->visualSelector) {
0278         m_ui->visualSelector->slotSetColor(m_d->currentColor);
0279     }
0280 
0281     if (source != m_d->hexColorInput) {
0282         m_d->sRGB.fromKoColor(m_d->currentColor);
0283         m_d->hexColorInput->update();
0284     }
0285 
0286     if (source != m_ui->paletteBox) {
0287         m_ui->paletteBox->selectClosestColor(m_d->currentColor);
0288     }
0289 
0290     m_ui->previousColor->setColor(m_d->previousColor);
0291 
0292     m_ui->currentColor->setColor(m_d->currentColor);
0293 
0294     if (source && source != this->parent()) {
0295         m_d->allowUpdates = false;
0296         m_d->compressColorChanges->start();
0297     }
0298 
0299     if (m_d->screenColorSampler) {
0300         m_d->screenColorSampler->updateIcons();
0301     }
0302 }
0303 
0304 void KisDlgInternalColorSelector::slotSelectorModelChanged()
0305 {
0306     if (m_ui->visualSelector->isHSXModel()) {
0307         QString label;
0308         switch (m_ui->visualSelector->getColorModel()) {
0309         case KisVisualColorSelector::HSV:
0310             label = i18n("HSV");
0311             break;
0312         case KisVisualColorSelector::HSL:
0313             label = i18n("HSL");
0314             break;
0315         case KisVisualColorSelector::HSI:
0316             label = i18n("HSI");
0317             break;
0318         case KisVisualColorSelector::HSY:
0319             label = i18n("HSY'");
0320             break;
0321         default:
0322             label =  i18n("Unknown");
0323         }
0324         if (m_ui->tabWidget->count() == 1) {
0325             m_ui->tabWidget->addTab(m_ui->tab_hsx, label);
0326         }
0327         else {
0328             m_ui->tabWidget->setTabText(1, label);
0329         }
0330     }
0331     else {
0332         if (m_ui->tabWidget->count() == 2) {
0333             m_ui->tabWidget->removeTab(1);
0334         }
0335     }
0336 }
0337 
0338 void KisDlgInternalColorSelector::endUpdateWithNewColor()
0339 {
0340     emit signalForegroundColorChosen(m_d->currentColor);
0341     m_d->allowUpdates = true;
0342 }
0343 
0344 void KisDlgInternalColorSelector::focusInEvent(QFocusEvent *)
0345 {
0346     //setPreviousColor();
0347 }
0348 
0349 void KisDlgInternalColorSelector::slotFinishUp()
0350 {
0351     setPreviousColor(m_d->currentColor);
0352     KConfigGroup cfg(KSharedConfig::openConfig()->group(""));
0353     if (m_d->paletteModel) {
0354         if (m_d->paletteModel->colorSet()) {
0355             cfg.writeEntry("internal_selector_active_color_set_md5", m_d->paletteModel->colorSet()->md5Sum());
0356             cfg.writeEntry("internal_selector_active_color_set", m_d->paletteModel->colorSet()->name());
0357         }
0358     }
0359 }
0360 
0361 void KisDlgInternalColorSelector::slotSetColorFromHex()
0362 {
0363     slotColorUpdated(m_d->sRGB);
0364 }
0365 
0366 void KisDlgInternalColorSelector::slotChangePalette(KoColorSetSP set)
0367 {
0368     if (!set) {
0369         return;
0370     }
0371     m_d->paletteModel->setPalette(set);
0372 }
0373 
0374 void KisDlgInternalColorSelector::showEvent(QShowEvent *event)
0375 {
0376     updateAllElements(0);
0377     QDialog::showEvent(event);
0378 }
0379