File indexing completed on 2024-06-16 04:16:02

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Adam Celarek <kdedev at xibo dot at>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "kis_shade_selector_line.h"
0008 
0009 #include <QPainter>
0010 #include <QColor>
0011 #include <QMouseEvent>
0012 
0013 #include <cmath>
0014 
0015 #include <ksharedconfig.h>
0016 #include <kconfig.h>
0017 #include <kconfiggroup.h>
0018 #include <klocalizedstring.h>
0019 #include <KoColorSpaceRegistry.h>
0020 
0021 #include "kis_canvas2.h"
0022 
0023 #include "kis_color_selector_base_proxy.h"
0024 #include "kis_display_color_converter.h"
0025 #include "kis_paint_device.h"
0026 
0027 
0028 KisShadeSelectorLine::KisShadeSelectorLine(KisColorSelectorBaseProxy *parentProxy,
0029                                            QWidget *parent)
0030     : KisShadeSelectorLineBase(parent),
0031       m_cachedColorSpace(0),
0032       m_displayHelpText(false),
0033       m_parentProxy(parentProxy)
0034 {
0035     setParam(0, 0, 0, 0, 0, 0);
0036     updateSettings();
0037     setMouseTracking(true);
0038     m_mouseX=width()/2;
0039     m_isDown=false;
0040 }
0041 
0042 KisShadeSelectorLine::KisShadeSelectorLine(qreal hueDelta, qreal satDelta, qreal valDelta,
0043                                            KisColorSelectorBaseProxy *parentProxy, QWidget *parent, qreal hueShift, qreal satShift, qreal valShift) :
0044     KisShadeSelectorLineBase(parent),
0045     m_cachedColorSpace(0),
0046     m_displayHelpText(false),
0047     m_parentProxy(parentProxy)
0048 {
0049     setParam(hueDelta, satDelta, valDelta, hueShift, satShift, valShift);
0050     updateSettings();
0051     m_mouseX=width()/2;
0052     m_isDown=false;
0053 }
0054 
0055 KisShadeSelectorLine::~KisShadeSelectorLine()
0056 {
0057 }
0058 
0059 void KisShadeSelectorLine::setParam(qreal hueDelta, qreal satDelta, qreal valDelta, qreal hueShift, qreal satShift, qreal valShift)
0060 {
0061     m_hueDelta = hueDelta;
0062     m_saturationDelta = satDelta;
0063     m_valueDelta = valDelta;
0064 
0065     m_hueShift = hueShift;
0066     m_saturationShift = satShift;
0067     m_valueShift = valShift;
0068 }
0069 
0070 void KisShadeSelectorLine::setColor(const KoColor &color)
0071 {
0072     m_realColor = color;
0073     m_realColor.convertTo(m_parentProxy->colorSpace());
0074     m_mouseX=width()/2;
0075 
0076     update();
0077 }
0078 
0079 void KisShadeSelectorLine::updateSettings()
0080 {
0081     KConfigGroup cfg =  KSharedConfig::openConfig()->group("advancedColorSelector");
0082 
0083     m_gradient = cfg.readEntry("minimalShadeSelectorAsGradient", false);
0084     m_patchCount = cfg.readEntry("minimalShadeSelectorPatchCount", 10);
0085     m_lineHeight = cfg.readEntry("minimalShadeSelectorLineHeight", 20);
0086 
0087     setMaximumHeight(m_lineHeight);
0088     setMinimumHeight(m_lineHeight);
0089 }
0090 
0091 QString KisShadeSelectorLine::toString() const
0092 {
0093     return QString("%1|%2|%3|%4|%5|%6|%7").arg(m_lineNumber).arg(m_hueDelta).arg(m_saturationDelta).arg(m_valueDelta).arg(m_hueShift).arg(m_saturationShift).arg(m_valueShift);
0094 }
0095 
0096 void KisShadeSelectorLine::fromString(const QString& string)
0097 {
0098     QStringList strili = string.split('|');
0099     m_lineNumber = strili.at(0).toInt();
0100     m_hueDelta = strili.at(1).toDouble();
0101     m_saturationDelta = strili.at(2).toDouble();
0102     m_valueDelta = strili.at(3).toDouble();
0103     if(strili.size()==4) return;            // don't crash, if reading old config files.
0104     m_hueShift = strili.at(4).toDouble();
0105     m_saturationShift = strili.at(5).toDouble();
0106     m_valueShift = strili.at(6).toDouble();
0107 }
0108 
0109 void KisShadeSelectorLine::paintEvent(QPaintEvent *)
0110 {
0111 
0112     if (m_cachedColorSpace != m_parentProxy->colorSpace()) {
0113         m_realPixelCache = new KisPaintDevice(m_parentProxy->colorSpace());
0114         m_cachedColorSpace = m_parentProxy->colorSpace();
0115     }
0116     else {
0117         m_realPixelCache->clear();
0118     }
0119 
0120     int patchCount = 0;
0121     int patchSpacing = 0;
0122     int patchWidth = 0;
0123 
0124     if(m_gradient) {
0125         patchCount = width();
0126         patchSpacing = 0;
0127         patchWidth = 1;
0128     }
0129     else {
0130         patchCount = m_patchCount;
0131         patchSpacing = 3;
0132         patchWidth = std::lround((width() - patchSpacing * patchCount) / qreal(patchCount));
0133     }
0134     qreal hueStep;
0135     qreal saturationStep;
0136     qreal valueStep;
0137 
0138     if(m_gradient){
0139        hueStep=m_hueDelta/qreal(patchCount-10);
0140        saturationStep=m_saturationDelta/qreal(patchCount-10);
0141        valueStep=m_valueDelta/qreal(patchCount-10);
0142     }
0143     else{
0144        hueStep=m_hueDelta/qreal(patchCount);
0145        saturationStep=m_saturationDelta/qreal(patchCount);
0146        valueStep=m_valueDelta/qreal(patchCount);
0147     }
0148 
0149     qreal baseHue;
0150     qreal baseSaturation;
0151     qreal baseValue;
0152     m_parentProxy->converter()->
0153         getHsvF(m_realColor, &baseHue, &baseSaturation, &baseValue);
0154 
0155     int z=0;
0156     for(int i=-patchCount/2; i<=patchCount/2; i++) {
0157         if(i==0 && patchCount%2==0) continue;
0158         qreal hue = baseHue + (i * hueStep) + m_hueShift;
0159         while (hue < 0.0) hue += 1.0;
0160         while (hue > 1.0) hue -= 1.0;
0161 
0162         qreal saturation = qBound<qreal>(0., baseSaturation + (i * saturationStep) + m_saturationShift, 1.);
0163         qreal value = qBound<qreal>(0., baseValue + (i * valueStep) + m_valueShift, 1.);
0164 
0165         if (qAbs(i) <= 5 && m_gradient) {
0166             hue = baseHue;
0167             saturation=baseSaturation;
0168             value=baseValue;
0169         }
0170 
0171         const QRect patchRect(z * (patchWidth + patchSpacing), 0, patchWidth, m_lineHeight);
0172         KoColor patchColor = m_parentProxy->converter()->fromHsvF(hue, saturation, value);
0173 
0174         patchColor.convertTo(m_realPixelCache->colorSpace());
0175         m_realPixelCache->fill(patchRect, patchColor);
0176 
0177         z++;
0178     }
0179 
0180     QPainter wpainter(this);
0181     if (!isEnabled()) {
0182         wpainter.setOpacity(0.2);
0183     }
0184     const QImage renderedImage = m_parentProxy->converter()->toQImage(m_realPixelCache).scaledToWidth(m_width);
0185     wpainter.drawImage(0, 0, renderedImage);
0186     if (m_gradient) {
0187         wpainter.setPen(QColor(175,175,175));
0188         wpainter.drawRect(renderedImage.width()/2-5,0,10,renderedImage.height()-1);
0189         wpainter.setPen(QColor(75,75,75));
0190         wpainter.drawRect(renderedImage.width()/2-4,0,8,renderedImage.height()-1);
0191         wpainter.setPen(QColor(175,175,175));
0192         const int mouseX = qBound(5, m_mouseX, m_width - 5);
0193         wpainter.drawRect(mouseX-5,0,10,renderedImage.height()-1);
0194         wpainter.setPen(QColor(75,75,75));
0195         wpainter.drawRect(mouseX-4,0,8,renderedImage.height()-1);
0196     }
0197 
0198     if(m_displayHelpText) {
0199         QString helpText(i18n("delta h=%1 s=%2 v=%3 shift h=%4 s=%5 v=%6",
0200                          m_hueDelta,
0201                          m_saturationDelta,
0202                          m_valueDelta,
0203                          m_hueShift,
0204                          m_saturationShift,
0205                          m_valueShift));
0206         wpainter.setPen(QColor(255,255,255));
0207         wpainter.drawText(rect(), helpText);
0208     }
0209 }
0210 
0211 void KisShadeSelectorLine::resizeEvent(QResizeEvent *e)
0212 {
0213     QSize m_old = e->oldSize();
0214     QSize m_new = e->size();
0215     int m_nWidth = m_new.width();
0216     int m_oWidth = m_old.width();
0217     m_width = width();
0218     m_mouseX = m_mouseX * m_nWidth / m_oWidth;
0219 }
0220 void KisShadeSelectorLine::mousePressEvent(QMouseEvent* e)
0221 {
0222     if(e->button()!=Qt::LeftButton && e->button()!=Qt::RightButton) {
0223         e->setAccepted(false);
0224         return;
0225     }
0226     if (e->y() > 0 && e->y() < height()) {
0227         m_parentProxy->showColorPreview();
0228         e->accept();
0229         m_mouseX = e->x();
0230         m_isDown=true;
0231         update();
0232      }
0233 }
0234 
0235 void KisShadeSelectorLine::mouseMoveEvent(QMouseEvent *e)
0236 {
0237     if ((m_isDown) && (e->buttons() & Qt::LeftButton)) {
0238         m_mouseX=e->x();
0239         const QPoint mouseEv(qBound(5, m_mouseX, m_width - 5), 5);
0240         KoColor color(Acs::sampleColor(m_realPixelCache, mouseEv));
0241         m_parentProxy->updateColorPreview(color);
0242         update();
0243     }
0244 }
0245 
0246 void KisShadeSelectorLine::mouseReleaseEvent(QMouseEvent * e)
0247 {
0248     if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) {
0249         e->ignore();
0250         return;
0251     }
0252     m_mouseX=e->x();
0253     const QPoint mouseEv(qBound(5, m_mouseX, m_width - 5), 5);
0254     KoColor color(Acs::sampleColor(m_realPixelCache, mouseEv));
0255     m_parentProxy->updateColorPreview(color);
0256     Acs::ColorRole role = Acs::buttonToRole(e->button());
0257 
0258     KConfigGroup cfg =  KSharedConfig::openConfig()->group("advancedColorSelector");
0259 
0260     bool onRightClick = cfg.readEntry("shadeSelectorUpdateOnRightClick", false);
0261     bool onLeftClick = cfg.readEntry("shadeSelectorUpdateOnLeftClick", false);
0262 
0263     bool explicitColorReset =
0264         (e->button() == Qt::LeftButton && onLeftClick) ||
0265         (e->button() == Qt::RightButton && onRightClick);
0266 
0267     m_parentProxy->updateColor(color, role, explicitColorReset);
0268     e->accept();
0269     m_isDown=false;
0270 }