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

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