diff --git a/libs/widgets/KisVisualColorSelectorShape.cpp b/libs/widgets/KisVisualColorSelectorShape.cpp index dd62069bad..715a216cf1 100644 --- a/libs/widgets/KisVisualColorSelectorShape.cpp +++ b/libs/widgets/KisVisualColorSelectorShape.cpp @@ -1,621 +1,621 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisVisualColorSelectorShape.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorConversions.h" #include "KoColorDisplayRendererInterface.h" #include "KoChannelInfo.h" #include #include #include "kis_signal_compressor.h" #include "kis_debug.h" struct KisVisualColorSelectorShape::Private { QImage gradient; QImage fullSelector; bool imagesNeedUpdate {true}; QPointF currentCoordinates; Dimensions dimension; ColorModel model; const KoColorSpace *colorSpace; KoColor currentColor; int channel1; int channel2; KisSignalCompressor *updateTimer {0}; bool mousePressActive = false; const KoColorDisplayRendererInterface *displayRenderer = 0; qreal hue = 0.0; qreal sat = 0.0; qreal tone = 0.0; bool usesOCIO = false; bool isRGBA = false; bool is8Bit = false; }; KisVisualColorSelectorShape::KisVisualColorSelectorShape(QWidget *parent, KisVisualColorSelectorShape::Dimensions dimension, KisVisualColorSelectorShape::ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer): QWidget(parent), m_d(new Private) { m_d->dimension = dimension; m_d->model = model; m_d->colorSpace = cs; // TODO: The following is done because the IDs are actually strings. Ideally, in the future, we // refactor everything so that the IDs are actually proper enums or something faster. if (m_d->displayRenderer && (m_d->colorSpace->colorDepthId() == Float16BitsColorDepthID || m_d->colorSpace->colorDepthId() == Float32BitsColorDepthID || m_d->colorSpace->colorDepthId() == Float64BitsColorDepthID) && m_d->colorSpace->colorModelId() != LABAColorModelID && m_d->colorSpace->colorModelId() != CMYKAColorModelID) { m_d->usesOCIO = true; } else { m_d->usesOCIO = false; } if (m_d->colorSpace->colorModelId() == RGBAColorModelID) { m_d->isRGBA = true; } else { m_d->isRGBA = false; } if (m_d->colorSpace->colorDepthId() == Integer8BitsColorDepthID) { m_d->is8Bit = true; } else { m_d->is8Bit = false; } m_d->currentColor = KoColor(); m_d->currentColor.setOpacity(1.0); m_d->currentColor.convertTo(cs); int maxchannel = m_d->colorSpace->colorChannelCount()-1; m_d->channel1 = qBound(0, channel1, maxchannel); m_d->channel2 = qBound(0, channel2, maxchannel); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // HACK: the updateTimer isn't connected to anything, we only check whether it's still active // and running in order to determine whether we will emit a certain signal. m_d->updateTimer = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); setDisplayRenderer(displayRenderer); show(); } KisVisualColorSelectorShape::~KisVisualColorSelectorShape() { } void KisVisualColorSelectorShape::updateCursor() { QPointF point1 = convertKoColorToShapeCoordinate(m_d->currentColor); if (point1 != m_d->currentCoordinates) { m_d->currentCoordinates = point1; } } QPointF KisVisualColorSelectorShape::getCursorPosition() { return m_d->currentCoordinates; } void KisVisualColorSelectorShape::setColor(KoColor c) { //qDebug() << this << "KisVisualColorSelectorShape::setColor"; if (c.colorSpace() != m_d->colorSpace) { c.convertTo(m_d->colorSpace); } m_d->currentColor = c; updateCursor(); m_d->imagesNeedUpdate = true; update(); } void KisVisualColorSelectorShape::setColorFromSibling(KoColor c) { //qDebug() << this << "setColorFromSibling"; if (c.colorSpace() != m_d->colorSpace) { c.convertTo(m_d->colorSpace); } m_d->currentColor = c; m_d->imagesNeedUpdate = true; update(); } void KisVisualColorSelectorShape::setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { if (m_d->displayRenderer) { m_d->displayRenderer->disconnect(this); } m_d->displayRenderer = displayRenderer; } else { m_d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } connect(m_d->displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(updateFromChangedDisplayRenderer()), Qt::UniqueConnection); } void KisVisualColorSelectorShape::updateFromChangedDisplayRenderer() { //qDebug() << this << "updateFromChangedDisplayRenderer();"; m_d->imagesNeedUpdate = true; updateCursor(); //m_d->currentColor = convertShapeCoordinateToKoColor(getCursorPosition()); update(); } void KisVisualColorSelectorShape::forceImageUpdate() { //qDebug() << this << "forceImageUpdate"; m_d->imagesNeedUpdate = true; } QColor KisVisualColorSelectorShape::getColorFromConverter(KoColor c){ QColor col; KoColor color = c; if (m_d->displayRenderer) { color.convertTo(m_d->displayRenderer->getPaintingColorSpace()); col = m_d->displayRenderer->toQColor(c); } else { col = c.toQColor(); } return col; } void KisVisualColorSelectorShape::slotSetActiveChannels(int channel1, int channel2) { //qDebug() << this << "slotSetActiveChannels"; int maxchannel = m_d->colorSpace->colorChannelCount()-1; m_d->channel1 = qBound(0, channel1, maxchannel); m_d->channel2 = qBound(0, channel2, maxchannel); m_d->imagesNeedUpdate = true; update(); } bool KisVisualColorSelectorShape::imagesNeedUpdate() const { return m_d->imagesNeedUpdate; } QImage KisVisualColorSelectorShape::getImageMap() { //qDebug() << this << ">>>>>>>>> getImageMap()" << m_d->imagesNeedUpdate; if (m_d->imagesNeedUpdate == true) { // Fill a buffer with the right kocolors quint8 *data = new quint8[width() * height() * m_d->currentColor.colorSpace()->pixelSize()]; quint8 *dataPtr = data; for (int y = 0; y < height(); y++) { for (int x=0; x < width(); x++) { QPointF newcoordinate = convertWidgetCoordinateToShapeCoordinate(QPoint(x, y)); KoColor c = convertShapeCoordinateToKoColor(newcoordinate); memcpy(dataPtr, c.data(), m_d->currentColor.colorSpace()->pixelSize()); dataPtr += m_d->currentColor.colorSpace()->pixelSize(); } } // Convert the buffer to a qimage if (m_d->displayRenderer) { m_d->gradient = m_d->displayRenderer->convertToQImage(m_d->currentColor.colorSpace(), data, width(), height()); } else { m_d->gradient = m_d->currentColor.colorSpace()->convertToQImage(data, width(), height(), 0, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } delete[] data; m_d->imagesNeedUpdate = false; // safeguard: if (m_d->gradient.isNull()) { m_d->gradient = QImage(width(), height(), QImage::Format_ARGB32); m_d->gradient.fill(Qt::black); } } return m_d->gradient; } KoColor KisVisualColorSelectorShape::convertShapeCoordinateToKoColor(QPointF coordinates, bool cursor) { //qDebug() << this << ">>>>>>>>> convertShapeCoordinateToKoColor()" << coordinates; KoColor c = m_d->currentColor; QVector channelValues (c.colorSpace()->channelCount()); channelValues.fill(1.0); c.colorSpace()->normalisedChannelsValue(c.data(), channelValues); QVector channelValuesDisplay = channelValues; QVector maxvalue(c.colorSpace()->channelCount()); maxvalue.fill(1.0); if (m_d->usesOCIO == true) { for (int ch = 0; ch < maxvalue.size(); ch++) { KoChannelInfo *channel = m_d->colorSpace->channels()[ch]; maxvalue[ch] = m_d->displayRenderer->maxVisibleFloatValue(channel); channelValues[ch] = channelValues[ch]/(maxvalue[ch]); channelValuesDisplay[KoChannelInfo::displayPositionToChannelIndex(ch, m_d->colorSpace->channels())] = channelValues[ch]; } } else { for (int i =0; i < channelValues.size();i++) { channelValuesDisplay[KoChannelInfo::displayPositionToChannelIndex(i, m_d->colorSpace->channels())] = qBound((float)0.0,channelValues[i], (float)1.0); } } qreal huedivider = 1.0; qreal huedivider2 = 1.0; if (m_d->channel1 == 0) { huedivider = 360.0; } if (m_d->channel2 == 0) { huedivider2 = 360.0; } if (m_d->model != ColorModel::Channel && m_d->isRGBA == true) { if (m_d->model == ColorModel::HSV) { /* * RGBToHSV has a undefined hue possibility. This means that hue will be -1. * This can be annoying for dealing with a selector, but I understand it is being * used for the KoColorSelector... For now implement a qMax here. */ QVector inbetween(3); RGBToHSV(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); inbetween[m_d->channel1] = coordinates.x()*huedivider; if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y()*huedivider2; } if (cursor) { setHSX(convertvectorfloatToqreal(inbetween)); Q_EMIT sigHSXchange(); } HSVToRGB(qMax(inbetween[0],(float)0.0), inbetween[1], inbetween[2], &channelValuesDisplay[0], &channelValuesDisplay[1], &channelValuesDisplay[2]); } else if (m_d->model == ColorModel::HSL) { /* * HSLToRGB can give negative values on the grey. I fixed the fromNormalisedChannel function to clamp, * but you might want to manually clamp for floating point values. */ QVector inbetween(3); RGBToHSL(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); inbetween[m_d->channel1] = fmod(coordinates.x()*huedivider, 360.0); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y()*huedivider2; } if (cursor) { setHSX(convertvectorfloatToqreal(inbetween)); Q_EMIT sigHSXchange(); } HSLToRGB(qMax(inbetween[0], (float)0.0), inbetween[1], inbetween[2], &channelValuesDisplay[0], &channelValuesDisplay[1], &channelValuesDisplay[2]); } else if (m_d->model == ColorModel::HSI) { /* * HSI is a modified HSY function. */ QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSI(chan2[0],chan2[1], chan2[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = getHSX(inbetween); inbetween[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y(); } if (cursor) { setHSX(inbetween); Q_EMIT sigHSXchange(); } HSIToRGB(inbetween[0], inbetween[1], inbetween[2],&chan2[0],&chan2[1], &chan2[2]); channelValuesDisplay = convertvectorqrealTofloat(chan2); } else /*if (m_d->model == ColorModel::HSY)*/ { /* * HSY is pretty slow to render due being a pretty over-the-top function. * Might be worth investigating whether HCY can be used instead, but I have had * some weird results with that. */ QVector luma= m_d->colorSpace->lumaCoefficients(); QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSY(chan2[0],chan2[1], chan2[2], &inbetween[0], &inbetween[1], &inbetween[2], luma[0], luma[1], luma[2]); inbetween = getHSX(inbetween); inbetween[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y(); } if (cursor) { setHSX(inbetween); Q_EMIT sigHSXchange(); } HSYToRGB(inbetween[0], inbetween[1], inbetween[2],&chan2[0],&chan2[1], &chan2[2], luma[0], luma[1], luma[2]); channelValuesDisplay = convertvectorqrealTofloat(chan2); } } else { channelValuesDisplay[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { channelValuesDisplay[m_d->channel2] = coordinates.y(); } } for (int i=0; icolorSpace->channels())]*(maxvalue[i]); } c.colorSpace()->fromNormalisedChannelsValue(c.data(), channelValues); return c; } QPointF KisVisualColorSelectorShape::convertKoColorToShapeCoordinate(KoColor c) { ////qDebug() << this << ">>>>>>>>> convertKoColorToShapeCoordinate()"; if (c.colorSpace() != m_d->colorSpace) { c.convertTo(m_d->colorSpace); } QVector channelValues (m_d->currentColor.colorSpace()->channelCount()); channelValues.fill(1.0); m_d->colorSpace->normalisedChannelsValue(c.data(), channelValues); QVector channelValuesDisplay = channelValues; QVector maxvalue(c.colorSpace()->channelCount()); maxvalue.fill(1.0); if (m_d->usesOCIO == true) { for (int ch = 0; chcolorSpace->channels()[ch]; maxvalue[ch] = m_d->displayRenderer->maxVisibleFloatValue(channel); channelValues[ch] = channelValues[ch]/(maxvalue[ch]); channelValuesDisplay[KoChannelInfo::displayPositionToChannelIndex(ch, m_d->colorSpace->channels())] = channelValues[ch]; } } else { for (int i =0; icolorSpace->channels())] = qBound((float)0.0,channelValues[i], (float)1.0); } } QPointF coordinates(0.0,0.0); qreal huedivider = 1.0; qreal huedivider2 = 1.0; if (m_d->channel1==0) { huedivider = 360.0; } if (m_d->channel2==0) { huedivider2 = 360.0; } if (m_d->model != ColorModel::Channel && m_d->isRGBA == true) { if (m_d->isRGBA == true) { if (m_d->model == ColorModel::HSV){ QVector inbetween(3); RGBToHSV(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); coordinates.setX(inbetween[m_d->channel1]/huedivider); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]/huedivider2); } } else if (m_d->model == ColorModel::HSL) { QVector inbetween(3); RGBToHSL(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); coordinates.setX(inbetween[m_d->channel1]/huedivider); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]/huedivider2); } } else if (m_d->model == ColorModel::HSI) { QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSI(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = getHSX(inbetween); coordinates.setX(inbetween[m_d->channel1]); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]); } } else if (m_d->model == ColorModel::HSY) { QVector luma = m_d->colorSpace->lumaCoefficients(); QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSY(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2], luma[0], luma[1], luma[2]); inbetween = getHSX(inbetween); coordinates.setX(inbetween[m_d->channel1]); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]); } } } } else { coordinates.setX(qBound((float)0.0, channelValuesDisplay[m_d->channel1], (float)1.0)); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(qBound((float)0.0, channelValuesDisplay[m_d->channel2], (float)1.0)); } } return coordinates; } QVector KisVisualColorSelectorShape::convertvectorqrealTofloat(QVector real) { QVector vloat(real.size()); for (int i=0; i KisVisualColorSelectorShape::convertvectorfloatToqreal(QVector vloat) { QVector real(vloat.size()); for (int i=0; ibutton()==Qt::LeftButton) { m_d->mousePressActive = true; QPointF coordinates = convertWidgetCoordinateToShapeCoordinate(e->pos()); KoColor col = convertShapeCoordinateToKoColor(coordinates, true); setColor(col); Q_EMIT sigNewColor(col); m_d->updateTimer->start(); } } void KisVisualColorSelectorShape::mouseMoveEvent(QMouseEvent *e) { if (m_d->mousePressActive==true && this->mask().contains(e->pos())) { QPointF coordinates = convertWidgetCoordinateToShapeCoordinate(e->pos()); quint8* oldData = m_d->currentColor.data(); KoColor col = convertShapeCoordinateToKoColor(coordinates, true); QRect offsetrect(this->geometry().topLeft() + QPoint(7.0, 7.0), this->geometry().bottomRight() - QPoint(7.0, 7.0)); if (offsetrect.contains(e->pos()) || (m_d->colorSpace->difference(col.data(), oldData) > 5)) { setColor(col); if (!m_d->updateTimer->isActive()) { Q_EMIT sigNewColor(col); m_d->updateTimer->start(); } } } else { e->ignore(); } } void KisVisualColorSelectorShape::mouseReleaseEvent(QMouseEvent *) { m_d->mousePressActive = false; } void KisVisualColorSelectorShape::paintEvent(QPaintEvent*) { QPainter painter(this); //check if old and new colors differ. if (m_d->imagesNeedUpdate) { setMask(getMaskMap()); } drawCursor(); painter.drawImage(0,0,m_d->fullSelector); } -KisVisualColorSelectorShape::Dimensions KisVisualColorSelectorShape::getDimensions() +KisVisualColorSelectorShape::Dimensions KisVisualColorSelectorShape::getDimensions() const { return m_d->dimension; } KisVisualColorSelectorShape::ColorModel KisVisualColorSelectorShape::getColorModel() { return m_d->model; } void KisVisualColorSelectorShape::setFullImage(QImage full) { m_d->fullSelector = full; } KoColor KisVisualColorSelectorShape::getCurrentColor() { return m_d->currentColor; } QVector KisVisualColorSelectorShape::getHSX(QVector hsx, bool wrangler) { QVector ihsx = hsx; if (!wrangler){ //Ok, so this docker will not update luminosity if there's not at the least 3% more variation. //This is necessary for 8bit. if (m_d->is8Bit == true){ if (hsx[2]>m_d->tone-0.03 && hsx[2]tone+0.03) { ihsx[2] = m_d->tone; } } else { if (hsx[2]>m_d->tone-0.005 && hsx[2]tone+0.005) { ihsx[2] = m_d->tone; } } if (m_d->model==HSV){ if (hsx[2]<=0.0) { ihsx[1] = m_d->sat; } } else { if ((hsx[2]<=0.0 || hsx[2]>=1.0)) { ihsx[1] = m_d->sat; } } if ((hsx[1]<=0.0 || hsx[0]<0.0)){ ihsx[0]=m_d->hue; } } else { ihsx[0]=m_d->hue; ihsx[1]=m_d->sat; ihsx[2]=m_d->tone; } return ihsx; } void KisVisualColorSelectorShape::setHSX(QVector hsx, bool wrangler) { if (wrangler){ m_d->tone = hsx[2]; m_d->sat = hsx[1]; m_d->hue = hsx[0]; } else { if (m_d->channel1==2 || m_d->channel2==2){ m_d->tone=hsx[2]; } if (m_d->model==HSV){ if (hsx[2]>0.0) { m_d->sat = hsx[1]; } } else { if ((hsx[2]>0.0 || hsx[2]<1.0)) { m_d->sat = hsx[1]; } } if ((hsx[1]>0.0 && hsx[0]>=0.0)){ m_d->hue = hsx[0]; } } } -QVector KisVisualColorSelectorShape::getChannels() +QVector KisVisualColorSelectorShape::getChannels() const { QVector channels(2); channels[0] = m_d->channel1; channels[1] = m_d->channel2; return channels; } diff --git a/libs/widgets/KisVisualColorSelectorShape.h b/libs/widgets/KisVisualColorSelectorShape.h index a24219a26c..d65761c109 100644 --- a/libs/widgets/KisVisualColorSelectorShape.h +++ b/libs/widgets/KisVisualColorSelectorShape.h @@ -1,236 +1,236 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_VISUAL_COLOR_SELECTOR_SHAPE_H #define KIS_VISUAL_COLOR_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisVisualColorSelector.h" #include "KisColorSelectorConfiguration.h" /** * @brief The KisVisualColorSelectorShape class * A 2d widget can represent at maximum 2 coordinates. * So first decide howmany coordinates you need. (onedimensional, or twodimensional) * Then the model, (Channel, HSV, HSL, HSI, YUV). Channel is the raw color channels. * When it finds a non-implemented feature it'll return to Channel. * Then, select the channels you wish to be affected. This uses the model, so for cmyk * the channel is c=0, m=1, y=2, k=3, but for hsv, hue=0, sat=1, and val=2 * These can also be set with 'slotsetactive channels'. * Then finally, connect the displayrenderer, you can also do this with 'setdisplayrenderer' * * Either way, this class is made to be subclassed, with a few virtuals so that the geometry * can be calculated properly. */ class KisVisualColorSelectorShape : public QWidget { Q_OBJECT public: /** * @brief The Dimensions enum * Whether or not the shape is single or two dimensional. **/ enum Dimensions{onedimensional, twodimensional}; enum ColorModel{Channel, HSV, HSL, HSI, HSY, YUV}; explicit KisVisualColorSelectorShape(QWidget *parent, KisVisualColorSelectorShape::Dimensions dimension, KisVisualColorSelectorShape::ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisVisualColorSelectorShape() override; /** * @brief getCursorPosition * @return current cursor position in shape-coordinates. */ QPointF getCursorPosition(); /** * @brief getDimensions * @return whether this is a single or twodimensional widget. */ - Dimensions getDimensions(); + Dimensions getDimensions() const; /** * @brief getColorModel * @return the model of this widget. */ ColorModel getColorModel(); /** * @brief getPixmap * @return the pixmap of the gradient, for drawing on with a subclass. * the pixmap will not change unless 'm_d->setPixmap=true' which is toggled by * refresh and update functions. */ bool imagesNeedUpdate() const; QImage getImageMap(); /** * @brief setFullImage * Set the full widget image to be painted. * @param full this should be the full image. */ void setFullImage(QImage full); /** * @brief getCurrentColor * @return the current kocolor */ KoColor getCurrentColor(); /** * @brief setDisplayRenderer * disconnect the old display renderer if needed and connect the new one. * @param displayRenderer */ void setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getColorFromConverter * @param c a koColor. * @return get the qcolor from the given kocolorusing this widget's display renderer. */ QColor getColorFromConverter(KoColor c); /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ virtual QRect getSpaceForSquare(QRect geom) = 0; virtual QRect getSpaceForCircle(QRect geom) = 0; virtual QRect getSpaceForTriangle(QRect geom) = 0; /** * @brief forceImageUpdate * force the image to recache. */ void forceImageUpdate(); /** * @brief setBorderWidth * set the border of the single dimensional selector. * @param width */ virtual void setBorderWidth(int width) = 0; /** * @brief getChannels * get used channels * @return */ - QVector getChannels(); + QVector getChannels() const; /** * @brief setHSX * This is for the cursor not to change when selecting * black, white, and desaturated values. Will not change the non-native values. * @param hsx the hsx value. * @param wrangler defines whether this docker will update luminosity if there's not at the least 3\% more variation */ void setHSX(QVector hsx, bool wrangler=false); /** * @brief getHSX sets the sat and hue so they won't * switch around much. * @param hsx the hsx values. * @param wrangler defines whether this docker will update luminosity if there's not at the least 3\% more variation * @return returns hsx, corrected. */ QVector getHSX(QVector hsx, bool wrangler= false); Q_SIGNALS: void sigNewColor(KoColor col); void sigHSXchange(); public Q_SLOTS: /** * @brief setColor * Set this widget's current color and change the cursor position. * @param c */ void setColor(KoColor c); /** * @brief setColorFromSibling * set this widget's current color, but don't change the cursor position, * instead sent out a signal of the new color. * @param c */ void setColorFromSibling(KoColor c); /** * @brief slotSetActiveChannels * Change the active channels if necessary. * @param channel1 used by single and twodimensional widgets. * @param channel2 only used by twodimensional widgets. */ void slotSetActiveChannels(int channel1, int channel2); /** * @brief updateFromChangedDisplayRenderer * for updating from the display renderer... not sure why this one is public. */ void updateFromChangedDisplayRenderer(); protected: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void paintEvent(QPaintEvent*) override; private: struct Private; const QScopedPointer m_d; /** * @brief convertShapeCoordinateToWidgetCoordinate * @return take the position in the shape and convert it to screen coordinates. */ - virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) = 0; + virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) const = 0; /** * @brief convertWidgetCoordinateToShapeCoordinate * Convert a coordinate in the widget's height/width to a shape coordinate. * @param coordinate the position your wish to have the shape coordinates of. */ - virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) = 0; + virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const = 0; /** * @brief updateCursor * Update the cursor position. */ void updateCursor(); QPointF convertKoColorToShapeCoordinate(KoColor c); KoColor convertShapeCoordinateToKoColor(QPointF coordinates, bool cursor = false); /** * @brief getPixmap * @return the pixmap of this shape. */ virtual QRegion getMaskMap() = 0; virtual void drawCursor() = 0; QVector convertvectorqrealTofloat(QVector real); QVector convertvectorfloatToqreal(QVector vloat); }; #endif diff --git a/libs/widgets/KisVisualEllipticalSelectorShape.cpp b/libs/widgets/KisVisualEllipticalSelectorShape.cpp index 0fc9374e7d..421c9f725d 100644 --- a/libs/widgets/KisVisualEllipticalSelectorShape.cpp +++ b/libs/widgets/KisVisualEllipticalSelectorShape.cpp @@ -1,242 +1,242 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisVisualEllipticalSelectorShape.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorConversions.h" #include "KoColorDisplayRendererInterface.h" #include "KoChannelInfo.h" #include #include #include "kis_signal_compressor.h" #include "kis_debug.h" #include "kis_global.h" KisVisualEllipticalSelectorShape::KisVisualEllipticalSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int barWidth, singelDTypes d) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { //qDebug() << "creating KisVisualEllipticalSelectorShape" << this; m_type = d; m_barWidth = barWidth; } KisVisualEllipticalSelectorShape::~KisVisualEllipticalSelectorShape() { //qDebug() << "deleting KisVisualEllipticalSelectorShape" << this; } QSize KisVisualEllipticalSelectorShape::sizeHint() const { return QSize(180,180); } void KisVisualEllipticalSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualEllipticalSelectorShape::getSpaceForSquare(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QLineF radius(b.center(), QPointF(b.left()+m_barWidth, b.center().y()) ); radius.setAngle(135); QPointF tl = radius.p2(); radius.setAngle(315); QPointF br = radius.p2(); QRect r(tl.toPoint(), br.toPoint()); return r; } QRect KisVisualEllipticalSelectorShape::getSpaceForCircle(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QPointF tl = QPointF (b.topLeft().x()+m_barWidth, b.topLeft().y()+m_barWidth); QPointF br = QPointF (b.bottomRight().x()-m_barWidth, b.bottomRight().y()-m_barWidth); QRect r(tl.toPoint(), br.toPoint()); return r; } QRect KisVisualEllipticalSelectorShape::getSpaceForTriangle(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QLineF radius(b.center(), QPointF(b.left()+m_barWidth, b.center().y()) ); radius.setAngle(90);//point at yellowgreen :) QPointF t = radius.p2(); radius.setAngle(330);//point to purple :) QPointF br = radius.p2(); radius.setAngle(210);//point to cerulean :) QPointF bl = radius.p2(); QPointF tl = QPoint(bl.x(),t.y()); QRect r(tl.toPoint(), br.toPoint()); return r; } -QPointF KisVisualEllipticalSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) +QPointF KisVisualEllipticalSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const { qreal x; qreal y; qreal offset=7.0; qreal a = (qreal)width()*0.5; QPointF center(a, a); QLineF line(center, QPoint((m_barWidth*0.5),a)); qreal angle = coordinate.x()*360.0; angle = fmod(angle+180.0,360.0); angle = 180.0-angle; angle = angle+180.0; if (m_type==KisVisualEllipticalSelectorShape::borderMirrored) { angle = (coordinate.x()/2)*360.0; angle = fmod((angle+270.0), 360.0); } line.setAngle(angle); if (getDimensions()!=KisVisualColorSelectorShape::onedimensional) { line.setLength(qMin(coordinate.y()*(a-offset), a-offset)); } x = qRound(line.p2().x()); y = qRound(line.p2().y()); return QPointF(x,y); } -QPointF KisVisualEllipticalSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) +QPointF KisVisualEllipticalSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const { //default implementation: qreal x = 0.5; qreal y = 1.0; qreal offset = 7.0; QPointF center = QRectF(QPointF(0.0, 0.0), this->size()).center(); qreal a = (this->width()/2); qreal xRel = center.x()-coordinate.x(); qreal yRel = center.y()-coordinate.y(); qreal radius = sqrt(xRel*xRel+yRel*yRel); if (m_type!=KisVisualEllipticalSelectorShape::borderMirrored){ qreal angle = atan2(yRel, xRel); angle = kisRadiansToDegrees(angle); angle = fmod(angle+360, 360.0); x = angle/360.0; if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { y = qBound(0.0,radius/(a-offset), 1.0); } } else { qreal angle = atan2(xRel, yRel); angle = kisRadiansToDegrees(angle); angle = fmod(angle+180, 360.0); if (angle>180.0) { angle = 360.0-angle; } x = (angle/360.0)*2; if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { y = qBound(0.0,(radius+offset)/a, 1.0); } } return QPointF(x, y); } QRegion KisVisualEllipticalSelectorShape::getMaskMap() { QRegion mask = QRegion(0,0,width(),height(), QRegion::Ellipse); if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2), QRegion::Ellipse)); } return mask; } void KisVisualEllipticalSelectorShape::resizeEvent(QResizeEvent *) { //qDebug() << this << "KisVisualEllipticalSelectorShape::resizeEvent"; forceImageUpdate(); } void KisVisualEllipticalSelectorShape::drawCursor() { //qDebug() << this << "KisVisualEllipticalSelectorShape::drawCursor: image needs update" << imagesNeedUpdate(); QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); QImage fullSelector = getImageMap(); QColor col = getColorFromConverter(getCurrentColor()); QPainter painter; painter.begin(&fullSelector); painter.setRenderHint(QPainter::Antialiasing); QRect innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawEllipse(QRect(0,0,width(),height())); if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { painter.setBrush(Qt::SolidPattern); painter.drawEllipse(innerRect); } painter.restore(); QBrush fill; fill.setStyle(Qt::SolidPattern); int cursorwidth = 5; if (m_type==KisVisualEllipticalSelectorShape::borderMirrored) { painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y()); painter.drawEllipse(mirror, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); } else { painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); } painter.end(); setFullImage(fullSelector); } diff --git a/libs/widgets/KisVisualEllipticalSelectorShape.h b/libs/widgets/KisVisualEllipticalSelectorShape.h index a09ecc156f..7cd388c23b 100644 --- a/libs/widgets/KisVisualEllipticalSelectorShape.h +++ b/libs/widgets/KisVisualEllipticalSelectorShape.h @@ -1,73 +1,73 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISVISUALCOLORSELECTOR_H #define KISVISUALCOLORSELECTOR_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" class KisVisualEllipticalSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{border, borderMirrored}; explicit KisVisualEllipticalSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int barWidth=20, KisVisualEllipticalSelectorShape::singelDTypes d = KisVisualEllipticalSelectorShape::border ); ~KisVisualEllipticalSelectorShape() override; void setBorderWidth(int width) override; /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: - QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; - QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; + QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const override; + QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const override; singelDTypes m_type; int m_barWidth; QRegion getMaskMap() override; void drawCursor() override; QSize sizeHint() const override; }; #endif // KISVISUALCOLORSELECTOR_H diff --git a/libs/widgets/KisVisualRectangleSelectorShape.cpp b/libs/widgets/KisVisualRectangleSelectorShape.cpp index fecdfbbe60..cd89ad9188 100644 --- a/libs/widgets/KisVisualRectangleSelectorShape.cpp +++ b/libs/widgets/KisVisualRectangleSelectorShape.cpp @@ -1,372 +1,372 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisVisualRectangleSelectorShape.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorConversions.h" #include "KoColorDisplayRendererInterface.h" #include "KoChannelInfo.h" #include #include #include "kis_signal_compressor.h" #include "kis_debug.h" KisVisualRectangleSelectorShape::KisVisualRectangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int width, singelDTypes d) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { //qDebug() << "creating KisVisualRectangleSelectorShape" << this; m_type = d; m_barWidth = width; } KisVisualRectangleSelectorShape::~KisVisualRectangleSelectorShape() { //qDebug() << "deleting KisVisualRectangleSelectorShape" << this; } void KisVisualRectangleSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualRectangleSelectorShape::getSpaceForSquare(QRect geom) { QPointF tl; QPointF br; if (m_type==KisVisualRectangleSelectorShape::vertical) { br = geom.bottomRight(); tl = QPoint(geom.topLeft().x()+m_barWidth, geom.topLeft().y()); } else if (m_type==KisVisualRectangleSelectorShape::horizontal) { br = geom.bottomRight(); tl = QPoint(geom.topLeft().x(), geom.topLeft().y()+m_barWidth); } else { tl = QPointF (geom.topLeft().x()+m_barWidth, geom.topLeft().y()+m_barWidth); br = QPointF (geom.bottomRight().x()-m_barWidth, geom.bottomRight().y()-m_barWidth); } QRect a(tl.toPoint(), br.toPoint()); QRect r(a.left(), a.top(), qMin(a.height(), a.width()), qMin(a.height(), a.width())); return r; } QRect KisVisualRectangleSelectorShape::getSpaceForCircle(QRect geom) { return getSpaceForSquare(geom); } QRect KisVisualRectangleSelectorShape::getSpaceForTriangle(QRect geom) { return getSpaceForSquare(geom); } -QPointF KisVisualRectangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) +QPointF KisVisualRectangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const { qreal x = 0.5 * m_barWidth; qreal y = 0.5 * m_barWidth; qreal offset = 5.0; KisVisualColorSelectorShape::Dimensions dimension = getDimensions(); if (dimension == KisVisualColorSelectorShape::onedimensional) { if ( m_type == KisVisualRectangleSelectorShape::vertical) { y = qMin(coordinate.x()*(height()-offset*2)+offset, (qreal)height()); } else if (m_type == KisVisualRectangleSelectorShape::horizontal) { x = qMin(coordinate.x()*(width()-offset*2)+offset, (qreal)width()); } else if (m_type == KisVisualRectangleSelectorShape::border) { QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth); QPointF left (innerRect.left(),innerRect.center().y()); QList polygonLines; polygonLines.append(QLineF(left, innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), left)); qreal totalLength =0.0; Q_FOREACH(QLineF line, polygonLines) { totalLength += line.length(); } qreal length = coordinate.x()*totalLength; QPointF intersect(x,y); Q_FOREACH(QLineF line, polygonLines) { if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } x = qRound(intersect.x()); y = qRound(intersect.y()); } else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ { QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth); QPointF bottom (innerRect.center().x(), innerRect.bottom()); QList polygonLines; polygonLines.append(QLineF(bottom, innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), bottom)); qreal totalLength =0.0; Q_FOREACH(QLineF line, polygonLines) { totalLength += line.length(); } qreal length = coordinate.x()*(totalLength/2); QPointF intersect(x,y); if (coordinate.y()==1) { for (int i = polygonLines.size()-1; i==0; i--) { QLineF line = polygonLines.at(i); if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } } else { Q_FOREACH(QLineF line, polygonLines) { if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } } x = qRound(intersect.x()); y = qRound(intersect.y()); } } else { x = qMin(coordinate.x()*(height()-offset*2)+offset, (qreal)height()); y = qMin(coordinate.y()*(width()-offset*2)+offset, (qreal)width()); } return QPointF(x,y); } -QPointF KisVisualRectangleSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) +QPointF KisVisualRectangleSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const { //default implementation: qreal x = 0.5; qreal y = 0.5; qreal offset = 5.0; KisVisualColorSelectorShape::Dimensions dimension = getDimensions(); if (dimension == KisVisualColorSelectorShape::onedimensional ) { if (m_type == KisVisualRectangleSelectorShape::vertical) { x = (coordinate.y()-offset)/(height()-offset*2); } else if (m_type == KisVisualRectangleSelectorShape::horizontal) { x = (coordinate.x()-offset)/(width()-offset*2); } else if (m_type == KisVisualRectangleSelectorShape::border) { //border QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); QPointF left (innerRect.left(),innerRect.center().y()); QList polygonLines; polygonLines.append(QLineF(left, innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), left)); QLineF radius(coordinate, this->geometry().center()); QPointF intersect(0.5,0.5); qreal length = 0.0; qreal totalLength = 0.0; bool foundIntersect = false; Q_FOREACH(QLineF line, polygonLines) { if (line.intersect(radius,&intersect)==QLineF::BoundedIntersection && foundIntersect==false) { foundIntersect = true; length+=QLineF(line.p1(), intersect).length(); } if (foundIntersect==false) { length+=line.length(); } totalLength+=line.length(); } x = length/totalLength; } else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ { //border QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); QPointF bottom (innerRect.center().x(), innerRect.bottom()); QList polygonLines; polygonLines.append(QLineF(bottom, innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), bottom)); QLineF radius(coordinate, this->geometry().center()); QPointF intersect(0.5,0.5); qreal length = 0.0; qreal totalLength = 0.0; bool foundIntersect = false; Q_FOREACH(QLineF line, polygonLines) { if (line.intersect(radius,&intersect)==QLineF::BoundedIntersection && foundIntersect==false) { foundIntersect = true; length+=QLineF(line.p1(), intersect).length(); } if (foundIntersect==false) { length+=line.length(); } totalLength+=line.length(); } int halflength = totalLength/2; if (length>halflength) { x = (halflength - (length-halflength))/halflength; y = 1.0; } else { x = length/halflength; y = 0.0; } } } else { x = (coordinate.x()-offset)/(width()-offset*2); y = (coordinate.y()-offset)/(height()-offset*2); } x = qBound((qreal)0.0, x, (qreal)1.0); y = qBound((qreal)0.0, y, (qreal)1.0); return QPointF(x, y); } QRegion KisVisualRectangleSelectorShape::getMaskMap() { QRegion mask = QRegion(0,0,width(),height()); if (m_type==KisVisualRectangleSelectorShape::border || m_type==KisVisualRectangleSelectorShape::borderMirrored) { mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2))); } return mask; } void KisVisualRectangleSelectorShape::resizeEvent(QResizeEvent *) { //qDebug() << this << "KisVisualRectangleSelectorShape::resizeEvent"; forceImageUpdate(); } void KisVisualRectangleSelectorShape::drawCursor() { //qDebug() << this << "KisVisualRectangleSelectorShape::drawCursor: image needs update" << imagesNeedUpdate(); QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); QImage fullSelector = getImageMap(); QColor col = getColorFromConverter(getCurrentColor()); QPainter painter; painter.begin(&fullSelector); painter.setRenderHint(QPainter::Antialiasing); //QPainterPath path; QBrush fill; fill.setStyle(Qt::SolidPattern); int cursorwidth = 5; QRect rect(cursorPoint.toPoint().x()-cursorwidth,cursorPoint.toPoint().y()-cursorwidth, cursorwidth*2,cursorwidth*2); if (m_type==KisVisualRectangleSelectorShape::vertical){ int x = ( cursorPoint.x()-(width()/2)+1 ); int y = ( cursorPoint.y()-cursorwidth ); rect.setCoords(x, y, x+width()-2, y+(cursorwidth*2)); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawLine(QLine(QPoint(0.0,0.0), QPoint(0.0,height()))); painter.drawLine(QLine(QPoint(width(),0.0), QPoint(width(),height()))); painter.restore(); } else { int x = cursorPoint.x()-cursorwidth; int y = cursorPoint.y()-(height()/2)+1; rect.setCoords(x, y, x+(cursorwidth*2), y+cursorwidth-2); } QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); if (getDimensions() == KisVisualColorSelectorShape::onedimensional && m_type!=KisVisualRectangleSelectorShape::border && m_type!=KisVisualRectangleSelectorShape::borderMirrored) { painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawRect(rect); //set filter conversion! fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); rect.setCoords(rect.topLeft().x()+1, rect.topLeft().y()+1, rect.topLeft().x()+rect.width()-2, rect.topLeft().y()+rect.height()-2); painter.drawRect(rect); }else if(m_type==KisVisualRectangleSelectorShape::borderMirrored){ painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y()); painter.drawEllipse(mirror, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); } else { painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawRect(QRect(0,0,width(),height())); painter.restore(); painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); } painter.end(); setFullImage(fullSelector); } diff --git a/libs/widgets/KisVisualRectangleSelectorShape.h b/libs/widgets/KisVisualRectangleSelectorShape.h index 4fe72d216c..bc3f7716f2 100644 --- a/libs/widgets/KisVisualRectangleSelectorShape.h +++ b/libs/widgets/KisVisualRectangleSelectorShape.h @@ -1,71 +1,71 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_VISUAL_RECTANGLE_SELECTOR_SHAPE_H #define KIS_VISUAL_RECTANGLE_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" class KisVisualRectangleSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{vertical, horizontal, border, borderMirrored}; explicit KisVisualRectangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int width=20, KisVisualRectangleSelectorShape::singelDTypes d = KisVisualRectangleSelectorShape::vertical ); ~KisVisualRectangleSelectorShape() override; void setBorderWidth(int width) override; /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: - QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; - QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; + QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const override; + QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const override; singelDTypes m_type; int m_barWidth; QRegion getMaskMap() override; void drawCursor() override; }; #endif diff --git a/libs/widgets/KisVisualTriangleSelectorShape.cpp b/libs/widgets/KisVisualTriangleSelectorShape.cpp index 91e4741801..7420fb92b7 100644 --- a/libs/widgets/KisVisualTriangleSelectorShape.cpp +++ b/libs/widgets/KisVisualTriangleSelectorShape.cpp @@ -1,206 +1,206 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisVisualTriangleSelectorShape.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorConversions.h" #include "KoColorDisplayRendererInterface.h" #include "KoChannelInfo.h" #include #include #include "kis_signal_compressor.h" #include "kis_debug.h" #include "kis_global.h" KisVisualTriangleSelectorShape::KisVisualTriangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int barwidth) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { //qDebug() << "creating KisVisualTriangleSelectorShape" << this; m_barWidth = barwidth; setTriangle(); } KisVisualTriangleSelectorShape::~KisVisualTriangleSelectorShape() { //qDebug() << "deleting KisVisualTriangleSelectorShape" << this; } void KisVisualTriangleSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualTriangleSelectorShape::getSpaceForSquare(QRect geom) { return geom; } QRect KisVisualTriangleSelectorShape::getSpaceForCircle(QRect geom) { return geom; } QRect KisVisualTriangleSelectorShape::getSpaceForTriangle(QRect geom) { return geom; } void KisVisualTriangleSelectorShape::setTriangle() { QPoint apex = QPoint (width()*0.5,0); QPolygon triangle; triangle<< QPoint(0,height()) << apex << QPoint(width(),height()) << QPoint(0,height()); m_triangle = triangle; QLineF a(triangle.at(0),triangle.at(1)); QLineF b(triangle.at(0),triangle.at(2)); QLineF ap(triangle.at(2), a.pointAt(0.5)); QLineF bp(triangle.at(1), b.pointAt(0.5)); QPointF intersect; ap.intersect(bp,&intersect); m_center = intersect; QLineF r(triangle.at(0), intersect); m_radius = r.length(); } -QPointF KisVisualTriangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) +QPointF KisVisualTriangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const { qreal offset=7.0;//the offset is so we get a nice little border that allows selecting extreme colors better. qreal yOffset = (cos(kisDegreesToRadians(30))*offset)*2; qreal xOffset = qFloor(sin(kisDegreesToRadians(30))*offset); qreal y = qMax(qMin((coordinate.y()*(height()-yOffset-offset))+yOffset, (qreal)height()-offset),yOffset); qreal triWidth = width(); qreal horizontalLineLength = ((y-yOffset)*(2./sqrt(3.))); qreal horizontalLineStart = (triWidth*0.5)-(horizontalLineLength*0.5); qreal relativeX = qMin(coordinate.x()*(horizontalLineLength), horizontalLineLength); qreal x = qMax(relativeX + horizontalLineStart + xOffset, horizontalLineStart+xOffset); if (y<=yOffset){ x = 0.5*width(); } return QPointF(x,y); } -QPointF KisVisualTriangleSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) +QPointF KisVisualTriangleSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const { //default implementation: gotten from the kotrianglecolorselector/kis_color_selector_triangle. qreal x = 0.5; qreal y = 0.5; qreal offset=7.0; //the offset is so we get a nice little border that allows selecting extreme colors better. qreal yOffset = (cos(kisDegreesToRadians(30))*offset)*2; qreal xOffset = qFloor(sin(kisDegreesToRadians(30))*offset); y = qMin(qMax((qreal)coordinate.y()-yOffset, 0.0)/(height()-yOffset-offset), 1.0); qreal triWidth = width(); qreal horizontalLineLength = ((qreal)coordinate.y()-yOffset)*(2./sqrt(3.)); qreal horizontalLineStart = (triWidth*0.5)-(horizontalLineLength*0.5); qreal relativeX = qMax((qreal)coordinate.x()-xOffset-horizontalLineStart,0.0); x = qMin(relativeX/horizontalLineLength, 1.0); if (coordinate.y()<=yOffset){ x = 0.5; } return QPointF(x, y); } QRegion KisVisualTriangleSelectorShape::getMaskMap() { QRegion mask = QRegion(m_triangle); //QRegion mask = QRegion(); //if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { // mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2))); //} return mask; } void KisVisualTriangleSelectorShape::resizeEvent(QResizeEvent *) { //qDebug() << this << "KisVisualTriangleSelectorShape::resizeEvent(QResizeEvent *)"; setTriangle(); forceImageUpdate(); } void KisVisualTriangleSelectorShape::drawCursor() { //qDebug() << this << "KisVisualTriangleSelectorShape::drawCursor: image needs update" << imagesNeedUpdate(); QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); QImage fullSelector = getImageMap(); QColor col = getColorFromConverter(getCurrentColor()); QPainter painter; painter.begin(&fullSelector); painter.setRenderHint(QPainter::Antialiasing); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(10); painter.setPen(pen); painter.drawPolygon(m_triangle); painter.restore(); //QPainterPath path; QBrush fill; fill.setStyle(Qt::SolidPattern); int cursorwidth = 5; //QRect innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); /*if(m_type==KisVisualTriangleSelectorShape::borderMirrored){ painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y()); painter.drawEllipse(mirror, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); } else {*/ painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); //} painter.end(); setFullImage(fullSelector); } diff --git a/libs/widgets/KisVisualTriangleSelectorShape.h b/libs/widgets/KisVisualTriangleSelectorShape.h index fc4b68e82e..4220107c67 100644 --- a/libs/widgets/KisVisualTriangleSelectorShape.h +++ b/libs/widgets/KisVisualTriangleSelectorShape.h @@ -1,77 +1,77 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_VISUAL_TRIANGLE_SELECTOR_SHAPE_H #define KIS_VISUAL_TRIANGLE_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" class KisVisualTriangleSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{border, borderMirrored}; explicit KisVisualTriangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int barwidth=20 ); ~KisVisualTriangleSelectorShape() override; void setBorderWidth(int width) override; void setTriangle(); /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: - QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; - QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; + QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const override; + QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) const override; singelDTypes m_type; int m_barWidth; QPolygon m_triangle; QPointF m_center; qreal m_radius; QRegion getMaskMap() override; void drawCursor() override; }; #endif