diff --git a/libs/pigment/resources/KoAbstractGradient.h b/libs/pigment/resources/KoAbstractGradient.h index 435ce2b64d..ab055ccc27 100644 --- a/libs/pigment/resources/KoAbstractGradient.h +++ b/libs/pigment/resources/KoAbstractGradient.h @@ -1,93 +1,103 @@ /* Copyright (c) 2007 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOABSTRACTGRADIENT_H #define KOABSTRACTGRADIENT_H #include #include #include "KoColorSpace.h" #include #include class KoAbstractGradient; typedef QSharedPointer KoAbstractGradientSP; class KoColor; /** * KoAbstractGradient is the base class of all gradient resources */ class KRITAPIGMENT_EXPORT KoAbstractGradient : public KoResource { public: explicit KoAbstractGradient(const QString &filename); ~KoAbstractGradient() override; virtual KoAbstractGradient* clone() const = 0; bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice*) const override { return false; } /** * Creates a QGradient from the gradient. * The resulting QGradient might differ from original gradient */ virtual QGradient* toQGradient() const { return new QGradient(); } /// gets the color at position 0 <= t <= 1 virtual void colorAt(KoColor&, qreal t) const; void setColorSpace(KoColorSpace* colorSpace); const KoColorSpace * colorSpace() const; void setSpread(QGradient::Spread spreadMethod); QGradient::Spread spread() const; void setType(QGradient::Type repeatType); QGradient::Type type() const; + ///tell whether there are any foreground or background color stops + virtual bool hasVariableColors() const { + return false; + } + ///Set the colors for stops that use the foreground or background color. + virtual void setVariableColors(const KoColor& foreground, const KoColor& background) { + //Do nothing... Override if gradient type supports variable colors. + Q_UNUSED(foreground); Q_UNUSED(background); + } + void updatePreview(); QImage generatePreview(int width, int height) const; KoAbstractGradient(const KoAbstractGradient &rhs); private: struct Private; Private* const d; }; Q_DECLARE_METATYPE(KoAbstractGradient*) #endif // KOABSTRACTGRADIENT_H diff --git a/libs/pigment/resources/KoSegmentGradient.cpp b/libs/pigment/resources/KoSegmentGradient.cpp index a72da66bc8..c50e675f00 100644 --- a/libs/pigment/resources/KoSegmentGradient.cpp +++ b/libs/pigment/resources/KoSegmentGradient.cpp @@ -1,982 +1,1092 @@ /* Copyright (c) 2000 Matthias Elter 2001 John Califf 2004 Boudewijn Rempt 2004 Adrian Page 2004, 2007 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoColorSpace.h" #include "KoMixColorsOp.h" #include #include #include KoGradientSegment::RGBColorInterpolationStrategy *KoGradientSegment::RGBColorInterpolationStrategy::m_instance = 0; KoGradientSegment::HSVCWColorInterpolationStrategy *KoGradientSegment::HSVCWColorInterpolationStrategy::m_instance = 0; KoGradientSegment::HSVCCWColorInterpolationStrategy *KoGradientSegment::HSVCCWColorInterpolationStrategy::m_instance = 0; KoGradientSegment::LinearInterpolationStrategy *KoGradientSegment::LinearInterpolationStrategy::m_instance = 0; KoGradientSegment::CurvedInterpolationStrategy *KoGradientSegment::CurvedInterpolationStrategy::m_instance = 0; KoGradientSegment::SineInterpolationStrategy *KoGradientSegment::SineInterpolationStrategy::m_instance = 0; KoGradientSegment::SphereIncreasingInterpolationStrategy *KoGradientSegment::SphereIncreasingInterpolationStrategy::m_instance = 0; KoGradientSegment::SphereDecreasingInterpolationStrategy *KoGradientSegment::SphereDecreasingInterpolationStrategy::m_instance = 0; KoSegmentGradient::KoSegmentGradient(const QString& file) : KoAbstractGradient(file) { } KoSegmentGradient::~KoSegmentGradient() { for (int i = 0; i < m_segments.count(); i++) { delete m_segments[i]; m_segments[i] = 0; } } KoSegmentGradient::KoSegmentGradient(const KoSegmentGradient &rhs) : KoAbstractGradient(rhs) { Q_FOREACH (KoGradientSegment *segment, rhs.m_segments) { pushSegment(new KoGradientSegment(*segment)); } } KoAbstractGradient* KoSegmentGradient::clone() const { return new KoSegmentGradient(*this); } bool KoSegmentGradient::load() { QFile file(filename()); if (!file.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); return res; } bool KoSegmentGradient::loadFromDevice(QIODevice *dev) { QByteArray data = dev->readAll(); QTextStream fileContent(data, QIODevice::ReadOnly); fileContent.setAutoDetectUnicode(true); QString header = fileContent.readLine(); if (header != "GIMP Gradient") { return false; } QString nameDefinition = fileContent.readLine(); QString numSegmentsText; if (nameDefinition.startsWith("Name: ")) { QString nameText = nameDefinition.right(nameDefinition.length() - 6); setName(nameText); numSegmentsText = fileContent.readLine(); } else { // Older format without name. numSegmentsText = nameDefinition; } dbgPigment << "Loading gradient: " << name(); int numSegments; bool ok; numSegments = numSegmentsText.toInt(&ok); if (!ok || numSegments < 1) { return false; } dbgPigment << "Number of segments = " << numSegments; const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); for (int i = 0; i < numSegments; i++) { QString segmentText = fileContent.readLine(); QTextStream segmentFields(&segmentText); QStringList values = segmentText.split(' '); qreal leftOffset = values[0].toDouble(); qreal middleOffset = values[1].toDouble(); qreal rightOffset = values[2].toDouble(); qreal leftRed = values[3].toDouble(); qreal leftGreen = values[4].toDouble(); qreal leftBlue = values[5].toDouble(); qreal leftAlpha = values[6].toDouble(); qreal rightRed = values[7].toDouble(); qreal rightGreen = values[8].toDouble(); qreal rightBlue = values[9].toDouble(); qreal rightAlpha = values[10].toDouble(); int interpolationType = values[11].toInt(); int colorInterpolationType = values[12].toInt(); + KoGradientSegmentEndpointType startType, endType; + if (values.count() >= 15) { //file supports FG/BG colors + startType = static_cast(values[13].toInt()); + endType = static_cast(values[14].toInt()); + } + else { + startType = endType = COLOR_ENDPOINT; + } quint8 data[4]; data[2] = static_cast(leftRed * 255 + 0.5); data[1] = static_cast(leftGreen * 255 + 0.5); data[0] = static_cast(leftBlue * 255 + 0.5); data[3] = static_cast(leftAlpha * OPACITY_OPAQUE_U8 + 0.5); KoColor leftColor(data, rgbColorSpace); data[2] = static_cast(rightRed * 255 + 0.5); data[1] = static_cast(rightGreen * 255 + 0.5); data[0] = static_cast(rightBlue * 255 + 0.5); data[3] = static_cast(rightAlpha * OPACITY_OPAQUE_U8 + 0.5); KoColor rightColor(data, rgbColorSpace); + KoGradientSegmentEndpoint left(leftOffset, leftColor, startType); + KoGradientSegmentEndpoint right(rightOffset, rightColor, endType); - KoGradientSegment *segment = new KoGradientSegment(interpolationType, colorInterpolationType, leftOffset, middleOffset, rightOffset, leftColor, rightColor); + KoGradientSegment *segment = new KoGradientSegment(interpolationType, colorInterpolationType, left, right, middleOffset); Q_CHECK_PTR(segment); if (!segment -> isValid()) { delete segment; return false; } m_segments.push_back(segment); } if (!m_segments.isEmpty()) { updatePreview(); setValid(true); return true; } else { return false; } } bool KoSegmentGradient::save() { QFile file(filename()); if (!file.open(QIODevice::WriteOnly)) { return false; } saveToDevice(&file); file.close(); return true; } bool KoSegmentGradient::saveToDevice(QIODevice *dev) const { QTextStream fileContent(dev); fileContent << "GIMP Gradient\n"; fileContent << "Name: " << name() << "\n"; fileContent << m_segments.count() << "\n"; Q_FOREACH (KoGradientSegment* segment, m_segments) { fileContent << QString::number(segment->startOffset(), 'f') << " " << QString::number(segment->middleOffset(), 'f') << " " << QString::number(segment->endOffset(), 'f') << " "; QColor startColor = segment->startColor().toQColor(); QColor endColor = segment->endColor().toQColor(); fileContent << QString::number(startColor.redF(), 'f') << " " << QString::number(startColor.greenF(), 'f') << " " << QString::number(startColor.blueF(), 'f') << " " << QString::number(startColor.alphaF(), 'f') << " "; fileContent << QString::number(endColor.redF(), 'f') << " " << QString::number(endColor.greenF(), 'f') << " " << QString::number(endColor.blueF(), 'f') << " " << QString::number(endColor.alphaF(), 'f') << " "; - fileContent << (int)segment->interpolation() << " " << (int)segment->colorInterpolation() << "\n"; + fileContent << (int)segment->interpolation() << " " << (int)segment->colorInterpolation() << " "; + + fileContent << (int)segment->startType() << " " << (int)segment->endType() << "\n"; + } KoResource::saveToDevice(dev); return true; } KoGradientSegment *KoSegmentGradient::segmentAt(qreal t) const { if (t < 0.0) return 0; if (t > 1.0) return 0; if (m_segments.isEmpty()) return 0; for (QList::const_iterator it = m_segments.begin(); it != m_segments.end(); ++it) { if (t > (*it)->startOffset() - DBL_EPSILON && t < (*it)->endOffset() + DBL_EPSILON) { return *it; } } return 0; } void KoSegmentGradient::colorAt(KoColor& dst, qreal t) const { const KoGradientSegment *segment = segmentAt(t); if (segment) { segment->colorAt(dst, t); } } QGradient* KoSegmentGradient::toQGradient() const { QGradient* gradient = new QLinearGradient(); QColor color; Q_FOREACH (KoGradientSegment* segment, m_segments) { segment->startColor().toQColor(&color); gradient->setColorAt(segment->startOffset() , color); segment->endColor().toQColor(&color); gradient->setColorAt(segment->endOffset() , color); } return gradient; } QString KoSegmentGradient::defaultFileExtension() const { return QString(".ggr"); } void KoSegmentGradient::toXML(QDomDocument &doc, QDomElement &gradientElt) const { gradientElt.setAttribute("type", "segment"); Q_FOREACH(KoGradientSegment *segment, this->segments()) { QDomElement segmentElt = doc.createElement("segment"); QDomElement start = doc.createElement("start"); QDomElement end = doc.createElement("end"); segmentElt.setAttribute("start-offset", KisDomUtils::toString(segment->startOffset())); const KoColor startColor = segment->startColor(); segmentElt.setAttribute("start-bitdepth", startColor.colorSpace()->colorDepthId().id()); segmentElt.setAttribute("start-alpha", KisDomUtils::toString(startColor.opacityF())); + segmentElt.setAttribute("start-type", KisDomUtils::toString(segment->startType())); startColor.toXML(doc, start); segmentElt.setAttribute("middle-offset", KisDomUtils::toString(segment->middleOffset())); segmentElt.setAttribute("end-offset", KisDomUtils::toString(segment->endOffset())); const KoColor endColor = segment->endColor(); segmentElt.setAttribute("end-bitdepth", endColor.colorSpace()->colorDepthId().id()); segmentElt.setAttribute("end-alpha", KisDomUtils::toString(endColor.opacityF())); + segmentElt.setAttribute("end-type", KisDomUtils::toString(segment->endType())); endColor.toXML(doc, end); segmentElt.setAttribute("interpolation", KisDomUtils::toString(segment->interpolation())); segmentElt.setAttribute("color-interpolation", KisDomUtils::toString(segment->colorInterpolation())); segmentElt.appendChild(start); segmentElt.appendChild(end); gradientElt.appendChild(segmentElt); } } KoSegmentGradient KoSegmentGradient::fromXML(const QDomElement &elt) { KoSegmentGradient gradient; QDomElement segmentElt = elt.firstChildElement("segment"); while (!segmentElt.isNull()) { int interpolation = KisDomUtils::toInt(segmentElt.attribute("interpolation", "0.0")); int colorInterpolation = KisDomUtils::toInt(segmentElt.attribute("color-interpolation", "0.0")); double startOffset = KisDomUtils::toDouble(segmentElt.attribute("start-offset", "0.0")); qreal middleOffset = KisDomUtils::toDouble(segmentElt.attribute("middle-offset", "0.0")); qreal endOffset = KisDomUtils::toDouble(segmentElt.attribute("end-offset", "0.0")); QDomElement start = segmentElt.firstChildElement("start"); QString startBitdepth = segmentElt.attribute("start-bitdepth", Integer8BitsColorDepthID.id()); QColor left = KoColor::fromXML(start.firstChildElement(), startBitdepth).toQColor(); left.setAlphaF(KisDomUtils::toDouble(segmentElt.attribute("start-alpha", "1.0"))); QString endBitdepth = segmentElt.attribute("end-bitdepth", Integer8BitsColorDepthID.id()); QDomElement end = segmentElt.firstChildElement("end"); QColor right = KoColor::fromXML(end.firstChildElement(), endBitdepth).toQColor(); right.setAlphaF(KisDomUtils::toDouble(segmentElt.attribute("end-alpha", "1.0"))); - gradient.createSegment(interpolation, colorInterpolation, startOffset, endOffset, middleOffset, left, right); + KoGradientSegmentEndpointType leftType = static_cast(KisDomUtils::toInt(segmentElt.attribute("start-type", "0"))); + KoGradientSegmentEndpointType rightType = static_cast(KisDomUtils::toInt(segmentElt.attribute("end-type", "0"))); + gradient.createSegment(interpolation, colorInterpolation, startOffset, endOffset, middleOffset, left, right, leftType, rightType); segmentElt = segmentElt.nextSiblingElement("segment"); } return gradient; } -KoGradientSegment::KoGradientSegment(int interpolationType, int colorInterpolationType, qreal startOffset, qreal middleOffset, qreal endOffset, const KoColor& startColor, const KoColor& endColor) +KoGradientSegment::KoGradientSegment(int interpolationType, int colorInterpolationType, KoGradientSegmentEndpoint start, KoGradientSegmentEndpoint end, qreal middleOffset) + : m_start(start), m_end(end) { m_interpolator = 0; switch (interpolationType) { case INTERP_LINEAR: m_interpolator = LinearInterpolationStrategy::instance(); break; case INTERP_CURVED: m_interpolator = CurvedInterpolationStrategy::instance(); break; case INTERP_SINE: m_interpolator = SineInterpolationStrategy::instance(); break; case INTERP_SPHERE_INCREASING: m_interpolator = SphereIncreasingInterpolationStrategy::instance(); break; case INTERP_SPHERE_DECREASING: m_interpolator = SphereDecreasingInterpolationStrategy::instance(); break; } m_colorInterpolator = 0; switch (colorInterpolationType) { case COLOR_INTERP_RGB: m_colorInterpolator = RGBColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CCW: m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CW: m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); break; } - if (startOffset < DBL_EPSILON) { - m_startOffset = 0; - } else if (startOffset > 1 - DBL_EPSILON) { - m_startOffset = 1; - } else { - m_startOffset = startOffset; - } - if (middleOffset < m_startOffset + DBL_EPSILON) { - m_middleOffset = m_startOffset; + + if (m_start.offset < DBL_EPSILON) { + m_start.offset = 0; + } else if (m_start.offset > 1 - DBL_EPSILON) { + m_start.offset = 1; + } + + if (middleOffset < m_start.offset + DBL_EPSILON) { + m_middleOffset = m_start.offset; } else if (middleOffset > 1 - DBL_EPSILON) { m_middleOffset = 1; } else { m_middleOffset = middleOffset; } - if (endOffset < m_middleOffset + DBL_EPSILON) { - m_endOffset = m_middleOffset; - } else if (endOffset > 1 - DBL_EPSILON) { - m_endOffset = 1; - } else { - m_endOffset = endOffset; + if (m_end.offset < m_middleOffset + DBL_EPSILON) { + m_end.offset = m_middleOffset; + } else if (m_end.offset > 1 - DBL_EPSILON) { + m_end.offset = 1; } - m_length = m_endOffset - m_startOffset; + m_length = m_end.offset - m_start.offset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { - m_middleT = (m_middleOffset - m_startOffset) / m_length; + m_middleT = (m_middleOffset - m_start.offset) / m_length; } - m_startColor = startColor; - m_endColor = endColor; + m_hasVariableColors = m_start.type != COLOR_ENDPOINT || m_end.type != COLOR_ENDPOINT; + } const KoColor& KoGradientSegment::startColor() const { - return m_startColor; + return m_start.color; } const KoColor& KoGradientSegment::endColor() const { - return m_endColor; + return m_end.color; } qreal KoGradientSegment::startOffset() const { - return m_startOffset; + return m_start.offset; } qreal KoGradientSegment::middleOffset() const { return m_middleOffset; } qreal KoGradientSegment::endOffset() const { - return m_endOffset; + return m_end.offset; +} + +const KoGradientSegmentEndpointType KoGradientSegment::startType() const +{ + return m_start.type; +} + +const KoGradientSegmentEndpointType KoGradientSegment::endType() const +{ + return m_end.type; +} + +void KoGradientSegment::setStartType(KoGradientSegmentEndpointType type) { + m_start.type = type; + if (type == FOREGROUND_ENDPOINT || type == BACKGROUND_ENDPOINT) { + m_hasVariableColors = true; + } + else if (m_end.type == COLOR_ENDPOINT) { + m_hasVariableColors = false; + } +} + +void KoGradientSegment::setEndType(KoGradientSegmentEndpointType type) { + m_end.type = type; + if (type == FOREGROUND_ENDPOINT || type == BACKGROUND_ENDPOINT) { + m_hasVariableColors = true; + } + else if (m_start.type == COLOR_ENDPOINT) { + m_hasVariableColors = false; + } } void KoGradientSegment::setStartOffset(qreal t) { - m_startOffset = t; - m_length = m_endOffset - m_startOffset; + m_start.offset = t; + m_length = m_end.offset - m_start.offset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { - m_middleT = (m_middleOffset - m_startOffset) / m_length; + m_middleT = (m_middleOffset - m_start.offset) / m_length; } } void KoGradientSegment::setMiddleOffset(qreal t) { m_middleOffset = t; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { - m_middleT = (m_middleOffset - m_startOffset) / m_length; + m_middleT = (m_middleOffset - m_start.offset) / m_length; } } void KoGradientSegment::setEndOffset(qreal t) { - m_endOffset = t; - m_length = m_endOffset - m_startOffset; + m_end.offset = t; + m_length = m_end.offset - m_start.offset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { - m_middleT = (m_middleOffset - m_startOffset) / m_length; + m_middleT = (m_middleOffset - m_start.offset) / m_length; } } +void KoGradientSegment::setVariableColors(const KoColor& foreground, const KoColor& background) { + if (m_start.type == FOREGROUND_ENDPOINT) { + m_start.color = foreground; + } + if (m_end.type == FOREGROUND_ENDPOINT) { + m_end.color = foreground; + } + if (m_start.type == BACKGROUND_ENDPOINT) { + m_start.color = background; + } + if (m_end.type == BACKGROUND_ENDPOINT) { + m_end.color = background; + } +} + +bool KoGradientSegment::hasVariableColors() { + return m_hasVariableColors; +} + int KoGradientSegment::interpolation() const { return m_interpolator->type(); } void KoGradientSegment::setInterpolation(int interpolationType) { switch (interpolationType) { case INTERP_LINEAR: m_interpolator = LinearInterpolationStrategy::instance(); break; case INTERP_CURVED: m_interpolator = CurvedInterpolationStrategy::instance(); break; case INTERP_SINE: m_interpolator = SineInterpolationStrategy::instance(); break; case INTERP_SPHERE_INCREASING: m_interpolator = SphereIncreasingInterpolationStrategy::instance(); break; case INTERP_SPHERE_DECREASING: m_interpolator = SphereDecreasingInterpolationStrategy::instance(); break; } } int KoGradientSegment::colorInterpolation() const { return m_colorInterpolator->type(); } void KoGradientSegment::setColorInterpolation(int colorInterpolationType) { switch (colorInterpolationType) { case COLOR_INTERP_RGB: m_colorInterpolator = RGBColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CCW: m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CW: m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); break; } } void KoGradientSegment::colorAt(KoColor& dst, qreal t) const { - Q_ASSERT(t > m_startOffset - DBL_EPSILON && t < m_endOffset + DBL_EPSILON); + Q_ASSERT(t > m_start.offset - DBL_EPSILON && t < m_end.offset + DBL_EPSILON); qreal segmentT; if (m_length < DBL_EPSILON) { segmentT = 0.5; } else { - segmentT = (t - m_startOffset) / m_length; + segmentT = (t - m_start.offset) / m_length; } qreal colorT = m_interpolator->valueAt(segmentT, m_middleT); - m_colorInterpolator->colorAt(dst, colorT, m_startColor, m_endColor); + m_colorInterpolator->colorAt(dst, colorT, m_start.color, m_end.color); + +} +void KoGradientSegment::mirrorSegment() +{ + KoColor tmpColor = startColor(); + setStartColor(endColor()); + setEndColor(tmpColor); + KoGradientSegmentEndpointType tmpType = startType(); + setStartType(endType()); + setEndType(tmpType); + + setMiddleOffset(endOffset() - (middleOffset() - startOffset())); + + if (interpolation() == INTERP_SPHERE_INCREASING) + setInterpolation(INTERP_SPHERE_DECREASING); + else if (interpolation() == INTERP_SPHERE_DECREASING) + setInterpolation(INTERP_SPHERE_INCREASING); + + if (colorInterpolation() == COLOR_INTERP_HSV_CW) + setColorInterpolation(COLOR_INTERP_HSV_CCW); + else if (colorInterpolation() == COLOR_INTERP_HSV_CCW) + setColorInterpolation(COLOR_INTERP_HSV_CW); } bool KoGradientSegment::isValid() const { if (m_interpolator == 0 || m_colorInterpolator == 0) return false; return true; } KoGradientSegment::RGBColorInterpolationStrategy::RGBColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::RGBColorInterpolationStrategy *KoGradientSegment::RGBColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new RGBColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::RGBColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& _start, const KoColor& _end) const { KoColor buffer(m_colorSpace); KoColor start(m_colorSpace); KoColor end(m_colorSpace); KoColor startDummy, endDummy; //hack to get a color space with the bitdepth of the gradients(8bit), but with the colour profile of the image// const KoColorSpace* mixSpace = KoColorSpaceRegistry::instance()->rgb8(dst.colorSpace()->profile()); //convert to the right colorspace for the start and end if we have our mixSpace. if (mixSpace){ startDummy = KoColor(_start, mixSpace); endDummy = KoColor(_end, mixSpace); } else { startDummy = _start; endDummy = _end; } start.fromKoColor(_start); end.fromKoColor(_end); const quint8 *colors[2]; colors[0] = startDummy.data(); colors[1] = endDummy.data(); qint16 colorWeights[2]; colorWeights[0] = static_cast((1.0 - t) * 255 + 0.5); colorWeights[1] = 255 - colorWeights[0]; //check if our mixspace exists, it doesn't at startup. if (mixSpace){ if (*buffer.colorSpace() != *mixSpace) { buffer = KoColor(mixSpace); } mixSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } else { buffer = KoColor(m_colorSpace); m_colorSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } dst.fromKoColor(buffer); } KoGradientSegment::HSVCWColorInterpolationStrategy::HSVCWColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::HSVCWColorInterpolationStrategy *KoGradientSegment::HSVCWColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new HSVCWColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::HSVCWColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const { QColor sc; QColor ec; start.toQColor(&sc); end.toQColor(&ec); int s = static_cast(sc.saturation() + t * (ec.saturation() - sc.saturation()) + 0.5); int v = static_cast(sc.value() + t * (ec.value() - sc.value()) + 0.5); int h; if (ec.hue() < sc.hue()) { h = static_cast(ec.hue() + (1 - t) * (sc.hue() - ec.hue()) + 0.5); } else { h = static_cast(ec.hue() + (1 - t) * (360 - ec.hue() + sc.hue()) + 0.5); if (h > 359) { h -= 360; } } // XXX: added an explicit cast. Is this correct? quint8 opacity = static_cast(sc.alpha() + t * (ec.alpha() - sc.alpha())); QColor result; result.setHsv(h, s, v); result.setAlpha(opacity); dst.fromQColor(result); } KoGradientSegment::HSVCCWColorInterpolationStrategy::HSVCCWColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::HSVCCWColorInterpolationStrategy *KoGradientSegment::HSVCCWColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new HSVCCWColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::HSVCCWColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const { QColor sc; QColor se; start.toQColor(&sc); end.toQColor(&se); int s = static_cast(sc.saturation() + t * (se.saturation() - sc.saturation()) + 0.5); int v = static_cast(sc.value() + t * (se.value() - sc.value()) + 0.5); int h; if (sc.hue() < se.hue()) { h = static_cast(sc.hue() + t * (se.hue() - sc.hue()) + 0.5); } else { h = static_cast(sc.hue() + t * (360 - sc.hue() + se.hue()) + 0.5); if (h > 359) { h -= 360; } } // XXX: Added an explicit static cast quint8 opacity = static_cast(sc.alpha() + t * (se.alpha() - sc.alpha())); QColor result; result.setHsv(h, s, v); result.setAlpha(opacity); dst.fromQColor(result); } KoGradientSegment::LinearInterpolationStrategy *KoGradientSegment::LinearInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new LinearInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::LinearInterpolationStrategy::calcValueAt(qreal t, qreal middle) { Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); qreal value = 0; if (t <= middle) { if (middle < DBL_EPSILON) { value = 0; } else { value = (t / middle) * 0.5; } } else { if (middle > 1 - DBL_EPSILON) { value = 1; } else { value = ((t - middle) / (1 - middle)) * 0.5 + 0.5; } } return value; } qreal KoGradientSegment::LinearInterpolationStrategy::valueAt(qreal t, qreal middle) const { return calcValueAt(t, middle); } KoGradientSegment::CurvedInterpolationStrategy::CurvedInterpolationStrategy() { m_logHalf = log(0.5); } KoGradientSegment::CurvedInterpolationStrategy *KoGradientSegment::CurvedInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new CurvedInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::CurvedInterpolationStrategy::valueAt(qreal t, qreal middle) const { Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); qreal value = 0; if (middle < DBL_EPSILON) { middle = DBL_EPSILON; } value = pow(t, m_logHalf / log(middle)); return value; } KoGradientSegment::SineInterpolationStrategy *KoGradientSegment::SineInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SineInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SineInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle); qreal value = (sin(-M_PI_2 + M_PI * lt) + 1.0) / 2.0; return value; } KoGradientSegment::SphereIncreasingInterpolationStrategy *KoGradientSegment::SphereIncreasingInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SphereIncreasingInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SphereIncreasingInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle) - 1; qreal value = sqrt(1 - lt * lt); return value; } KoGradientSegment::SphereDecreasingInterpolationStrategy *KoGradientSegment::SphereDecreasingInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SphereDecreasingInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SphereDecreasingInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle); qreal value = 1 - sqrt(1 - lt * lt); return value; } -void KoSegmentGradient::createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor & left, const QColor & right) +void KoSegmentGradient::createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor & leftColor, const QColor & rightColor, + KoGradientSegmentEndpointType leftType, KoGradientSegmentEndpointType rightType) { - pushSegment(new KoGradientSegment(interpolation, colorInterpolation, startOffset, middleOffset, endOffset, KoColor(left, colorSpace()), KoColor(right, colorSpace()))); + KoGradientSegmentEndpoint left(startOffset, KoColor(leftColor, colorSpace()), leftType); + KoGradientSegmentEndpoint right(endOffset, KoColor(rightColor, colorSpace()), rightType); + pushSegment(new KoGradientSegment(interpolation, colorInterpolation, left, right, middleOffset)); } const QList KoSegmentGradient::getHandlePositions() const { QList handlePositions; handlePositions.push_back(m_segments[0]->startOffset()); for (int i = 0; i < m_segments.count(); i++) { handlePositions.push_back(m_segments[i]->endOffset()); } return handlePositions; } const QList KoSegmentGradient::getMiddleHandlePositions() const { QList middleHandlePositions; for (int i = 0; i < m_segments.count(); i++) { middleHandlePositions.push_back(m_segments[i]->middleOffset()); } return middleHandlePositions; } void KoSegmentGradient::moveSegmentStartOffset(KoGradientSegment* segment, double t) { QList::iterator it = std::find(m_segments.begin(), m_segments.end(), segment); if (it != m_segments.end()) { if (it == m_segments.begin()) { segment->setStartOffset(0.0); return; } KoGradientSegment* previousSegment = (*(it - 1)); if (t > segment->startOffset()) { if (t > segment->middleOffset()) t = segment->middleOffset(); } else { if (t < previousSegment->middleOffset()) t = previousSegment->middleOffset(); } previousSegment->setEndOffset(t); segment->setStartOffset(t); } } void KoSegmentGradient::moveSegmentEndOffset(KoGradientSegment* segment, double t) { QList::iterator it = std::find(m_segments.begin(), m_segments.end(), segment); if (it != m_segments.end()) { if (it + 1 == m_segments.end()) { segment->setEndOffset(1.0); return; } KoGradientSegment* followingSegment = (*(it + 1)); if (t < segment->endOffset()) { if (t < segment->middleOffset()) t = segment->middleOffset(); } else { if (t > followingSegment->middleOffset()) t = followingSegment->middleOffset(); } followingSegment->setStartOffset(t); segment->setEndOffset(t); } } void KoSegmentGradient::moveSegmentMiddleOffset(KoGradientSegment* segment, double t) { if (segment) { if (t > segment->endOffset()) segment->setMiddleOffset(segment->endOffset()); else if (t < segment->startOffset()) segment->setMiddleOffset(segment->startOffset()); else segment->setMiddleOffset(t); } } void KoSegmentGradient::splitSegment(KoGradientSegment* segment) { Q_ASSERT(segment != 0); QList::iterator it = std::find(m_segments.begin(), m_segments.end(), segment); if (it != m_segments.end()) { KoColor midleoffsetColor(segment->endColor().colorSpace()); segment->colorAt(midleoffsetColor, segment->middleOffset()); + KoGradientSegmentEndpoint left(segment->startOffset(), segment->startColor(), segment->startType()); + KoGradientSegmentEndpoint right(segment->middleOffset(), midleoffsetColor, COLOR_ENDPOINT); KoGradientSegment* newSegment = new KoGradientSegment( segment->interpolation(), segment->colorInterpolation(), - segment ->startOffset(), - (segment->middleOffset() - segment->startOffset()) / 2 + segment->startOffset(), - segment->middleOffset(), - segment->startColor(), - midleoffsetColor); + left, right, + (segment->middleOffset() - segment->startOffset()) / 2 + segment->startOffset()); m_segments.insert(it, newSegment); segment->setStartColor(midleoffsetColor); segment->setStartOffset(segment->middleOffset()); segment->setMiddleOffset((segment->endOffset() - segment->startOffset()) / 2 + segment->startOffset()); } } void KoSegmentGradient::duplicateSegment(KoGradientSegment* segment) { Q_ASSERT(segment != 0); QList::iterator it = std::find(m_segments.begin(), m_segments.end(), segment); if (it != m_segments.end()) { double middlePostionPercentage = (segment->middleOffset() - segment->startOffset()) / segment->length(); double center = segment->startOffset() + segment->length() / 2; + KoGradientSegmentEndpoint left(segment->startOffset(), segment->startColor(), segment->startType()); + KoGradientSegmentEndpoint right(center, segment->endColor(), segment->endType()); KoGradientSegment* newSegment = new KoGradientSegment( segment->interpolation(), segment->colorInterpolation(), - segment ->startOffset(), - segment->length() / 2 * middlePostionPercentage + segment->startOffset(), - center, segment->startColor(), - segment->endColor()); + left, right, + segment->length() / 2 * middlePostionPercentage + segment->startOffset()); m_segments.insert(it, newSegment); segment->setStartOffset(center); segment->setMiddleOffset(segment->length() * middlePostionPercentage + segment->startOffset()); } } void KoSegmentGradient::mirrorSegment(KoGradientSegment* segment) { Q_ASSERT(segment != 0); - KoColor tmpColor = segment->startColor(); - segment->setStartColor(segment->endColor()); - segment->setEndColor(tmpColor); - segment->setMiddleOffset(segment->endOffset() - (segment->middleOffset() - segment->startOffset())); - if (segment->interpolation() == INTERP_SPHERE_INCREASING) - segment->setInterpolation(INTERP_SPHERE_DECREASING); - else if (segment->interpolation() == INTERP_SPHERE_DECREASING) - segment->setInterpolation(INTERP_SPHERE_INCREASING); + segment->mirrorSegment(); + + //KoColor tmpColor = segment->startColor(); + //segment->setStartColor(segment->endColor()); + //segment->setEndColor(tmpColor); + // + //segment->setMiddleOffset(segment->endOffset() - (segment->middleOffset() - segment->startOffset())); + + //if (segment->interpolation() == INTERP_SPHERE_INCREASING) + // segment->setInterpolation(INTERP_SPHERE_DECREASING); + //else if (segment->interpolation() == INTERP_SPHERE_DECREASING) + // segment->setInterpolation(INTERP_SPHERE_INCREASING); - if (segment->colorInterpolation() == COLOR_INTERP_HSV_CW) - segment->setColorInterpolation(COLOR_INTERP_HSV_CCW); - else if (segment->colorInterpolation() == COLOR_INTERP_HSV_CCW) - segment->setColorInterpolation(COLOR_INTERP_HSV_CW); + //if (segment->colorInterpolation() == COLOR_INTERP_HSV_CW) + // segment->setColorInterpolation(COLOR_INTERP_HSV_CCW); + //else if (segment->colorInterpolation() == COLOR_INTERP_HSV_CCW) + // segment->setColorInterpolation(COLOR_INTERP_HSV_CW); } KoGradientSegment* KoSegmentGradient::removeSegment(KoGradientSegment* segment) { Q_ASSERT(segment != 0); if (m_segments.count() < 2) return 0; QList::iterator it = std::find(m_segments.begin(), m_segments.end(), segment); if (it != m_segments.end()) { double middlePostionPercentage; KoGradientSegment* nextSegment; if (it == m_segments.begin()) { nextSegment = (*(it + 1)); middlePostionPercentage = (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length(); nextSegment->setStartOffset(segment->startOffset()); nextSegment->setMiddleOffset(middlePostionPercentage * nextSegment->length() + nextSegment->startOffset()); } else { nextSegment = (*(it - 1)); middlePostionPercentage = (nextSegment->middleOffset() - nextSegment->startOffset()) / nextSegment->length(); nextSegment->setEndOffset(segment->endOffset()); nextSegment->setMiddleOffset(middlePostionPercentage * nextSegment->length() + nextSegment->startOffset()); } delete segment; m_segments.erase(it); return nextSegment; } return 0; } bool KoSegmentGradient::removeSegmentPossible() const { if (m_segments.count() < 2) return false; return true; } const QList& KoSegmentGradient::segments() const { return m_segments; } + +bool KoSegmentGradient::hasVariableColors() const +{ + for (int i = 0; i < m_segments.count(); i++) { + if (m_segments[i]->hasVariableColors()) { + return true; + } + } + return false; +} + +void KoSegmentGradient::setVariableColors(const KoColor& foreground, const KoColor& background) +{ + for (int i = 0; i < m_segments.count(); i++) { + m_segments[i]->setVariableColors(foreground, background); + } +} diff --git a/libs/pigment/resources/KoSegmentGradient.h b/libs/pigment/resources/KoSegmentGradient.h index 3bd9bb5019..70decf6c3d 100644 --- a/libs/pigment/resources/KoSegmentGradient.h +++ b/libs/pigment/resources/KoSegmentGradient.h @@ -1,431 +1,476 @@ /* Copyright (c) 2000 Matthias Elter 2004 Boudewijn Rempt 2004 Adrian Page 2004, 2007 Sven Langkamp 2017 Wolthera van Hövell tot Westerflier This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOSEGMENTGRADIENT_H #define KOSEGMENTGRADIENT_H #include #include #include #include #include "KoColor.h" #include enum { INTERP_LINEAR = 0, INTERP_CURVED, INTERP_SINE, INTERP_SPHERE_INCREASING, INTERP_SPHERE_DECREASING }; enum { COLOR_INTERP_RGB, COLOR_INTERP_HSV_CCW, COLOR_INTERP_HSV_CW }; +//For saving to .ggr to match GIMP format, we also have Foreground (transparent) and Background (transparent) modes, currently unused... +enum KoGradientSegmentEndpointType { + COLOR_ENDPOINT, + FOREGROUND_ENDPOINT, + FOREGROUND_TRANSPARENT_ENDPOINT, + BACKGROUND_ENDPOINT, + BACKGROUND_TRANSPARENT_ENDPOINT +}; + +struct KoGradientSegmentEndpoint { + KoGradientSegmentEndpoint(qreal _off, KoColor _color, KoGradientSegmentEndpointType _type) : + offset(_off), color(_color), type(_type) + { + + } + + qreal offset; + KoColor color; + KoGradientSegmentEndpointType type; + + +}; + /// Write API docs here class KRITAPIGMENT_EXPORT KoGradientSegment { public: - KoGradientSegment(int interpolationType, int colorInterpolationType, qreal startOffset, qreal middleOffset, qreal endOffset, const KoColor& startColor, const KoColor& endColor); + KoGradientSegment(int interpolationType, int colorInterpolationType, KoGradientSegmentEndpoint start, KoGradientSegmentEndpoint end, qreal middleOffset); // startOffset <= t <= endOffset void colorAt(KoColor&, qreal t) const; const KoColor& startColor() const; const KoColor& endColor() const; + const KoGradientSegmentEndpointType startType() const; + const KoGradientSegmentEndpointType endType() const; void setStartColor(const KoColor& color) { - m_startColor = color; + m_start.color = color; } void setEndColor(const KoColor& color) { - m_endColor = color; + m_end.color = color; } + void setStartType(KoGradientSegmentEndpointType type); + void setEndType(KoGradientSegmentEndpointType type); + qreal startOffset() const; qreal middleOffset() const; qreal endOffset() const; void setStartOffset(qreal t); void setMiddleOffset(qreal t); void setEndOffset(qreal t); + void setVariableColors(const KoColor& foreground, const KoColor& background); + bool hasVariableColors(); + qreal length() { return m_length; } int interpolation() const; int colorInterpolation() const; void setInterpolation(int interpolationType); void setColorInterpolation(int colorInterpolationType); + void mirrorSegment(); + bool isValid() const; protected: class ColorInterpolationStrategy { public: ColorInterpolationStrategy() {} virtual ~ColorInterpolationStrategy() {} virtual void colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const = 0; virtual int type() const = 0; }; class RGBColorInterpolationStrategy : public ColorInterpolationStrategy { public: static RGBColorInterpolationStrategy *instance(); void colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const override; int type() const override { return COLOR_INTERP_RGB; } private: RGBColorInterpolationStrategy(); static RGBColorInterpolationStrategy *m_instance; const KoColorSpace * const m_colorSpace; }; class HSVCWColorInterpolationStrategy : public ColorInterpolationStrategy { public: static HSVCWColorInterpolationStrategy *instance(); void colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const override; int type() const override { return COLOR_INTERP_HSV_CW; } private: HSVCWColorInterpolationStrategy(); static HSVCWColorInterpolationStrategy *m_instance; const KoColorSpace * const m_colorSpace; }; class HSVCCWColorInterpolationStrategy : public ColorInterpolationStrategy { public: static HSVCCWColorInterpolationStrategy *instance(); void colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const override; int type() const override { return COLOR_INTERP_HSV_CCW; } private: HSVCCWColorInterpolationStrategy(); static HSVCCWColorInterpolationStrategy *m_instance; const KoColorSpace * const m_colorSpace; }; class InterpolationStrategy { public: InterpolationStrategy() {} virtual ~InterpolationStrategy() {} virtual qreal valueAt(qreal t, qreal middle) const = 0; virtual int type() const = 0; }; class LinearInterpolationStrategy : public InterpolationStrategy { public: static LinearInterpolationStrategy *instance(); qreal valueAt(qreal t, qreal middle) const override; int type() const override { return INTERP_LINEAR; } // This does the actual calculation and is made // static as an optimization for the other // strategies that need this for their own calculation. static qreal calcValueAt(qreal t, qreal middle); private: LinearInterpolationStrategy() {} static LinearInterpolationStrategy *m_instance; }; class CurvedInterpolationStrategy : public InterpolationStrategy { public: static CurvedInterpolationStrategy *instance(); qreal valueAt(qreal t, qreal middle) const override; int type() const override { return INTERP_CURVED; } private: CurvedInterpolationStrategy(); static CurvedInterpolationStrategy *m_instance; qreal m_logHalf; }; class SphereIncreasingInterpolationStrategy : public InterpolationStrategy { public: static SphereIncreasingInterpolationStrategy *instance(); qreal valueAt(qreal t, qreal middle) const override; int type() const override { return INTERP_SPHERE_INCREASING; } private: SphereIncreasingInterpolationStrategy() {} static SphereIncreasingInterpolationStrategy *m_instance; }; class SphereDecreasingInterpolationStrategy : public InterpolationStrategy { public: static SphereDecreasingInterpolationStrategy *instance(); qreal valueAt(qreal t, qreal middle) const override; int type() const override { return INTERP_SPHERE_DECREASING; } private: SphereDecreasingInterpolationStrategy() {} static SphereDecreasingInterpolationStrategy *m_instance; }; class SineInterpolationStrategy : public InterpolationStrategy { public: static SineInterpolationStrategy *instance(); qreal valueAt(qreal t, qreal middle) const override; int type() const override { return INTERP_SINE; } private: SineInterpolationStrategy() {} static SineInterpolationStrategy *m_instance; }; private: InterpolationStrategy *m_interpolator; ColorInterpolationStrategy *m_colorInterpolator; - qreal m_startOffset; + //qreal m_startOffset; qreal m_middleOffset; - qreal m_endOffset; + //qreal m_endOffset; qreal m_length; qreal m_middleT; - KoColor m_startColor; - KoColor m_endColor; + //KoColor m_startColor; + //KoColor m_endColor; + KoGradientSegmentEndpoint m_start, m_end; + bool m_hasVariableColors = false; + }; /** * KoSegmentGradient stores a segment based gradients like Gimp gradients */ class KRITAPIGMENT_EXPORT KoSegmentGradient : public KoAbstractGradient { public: explicit KoSegmentGradient(const QString &file = QString()); ~KoSegmentGradient() override; KoAbstractGradient* clone() const override; /// reimplemented bool load() override; bool loadFromDevice(QIODevice *dev) override; /// not implemented bool save() override; bool saveToDevice(QIODevice* dev) const override; /// reimplemented void colorAt(KoColor& dst, qreal t) const override; + /// reimplemented + bool hasVariableColors() const override; + /// reimplemented + void setVariableColors(const KoColor& foreground, const KoColor& background) override; + /** * Returns the segment at a given position * @param t position inside the gradient, with 0 <= t <= 1 * @return the segment the position, 0 if no segment is found */ KoGradientSegment *segmentAt(qreal t) const; /// reimplemented QGradient* toQGradient() const override; /// reimplemented QString defaultFileExtension() const override; /** * @brief toXML * convert the gradient to xml. */ void toXML(QDomDocument& doc, QDomElement& gradientElt) const; /** * @brief fromXML * get a segment gradient from xml. * @return gradient */ static KoSegmentGradient fromXML(const QDomElement& elt); /** * a gradient colour picker can consist of one or more segments. * A segment has two end points - each colour in the gradient * colour picker represents a segment end point. * @param interpolation * @param colorInterpolation * @param startOffset * @param endOffset * @param middleOffset * @param left * @param right + * @param leftType + * @param rightType * @return void */ - void createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor & left, const QColor & right); + void createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, + const QColor & leftColor, const QColor & rightColor, + KoGradientSegmentEndpointType leftType = COLOR_ENDPOINT, KoGradientSegmentEndpointType rightType = COLOR_ENDPOINT); /** * gets a list of end points of the segments in the gradient * colour picker. If two colours, one segment then two end * points, and if three colours, then two segments with four * endpoints. * @return a list of double values */ const QList getHandlePositions() const; /** * gets a list of middle points of the segments in the gradient * colour picker. * @return a list of double values */ const QList getMiddleHandlePositions() const; /** * Moves the StartOffset of the specified segment to the * specified value and corrects the endoffset of the previous * segment. If the segment is the first Segment the startoffset * will be set to 0.0 . The offset will maximally be moved till * the middle of the current or the previous segment. This is * useful if someone clicks to move the handler for a segment, * to set the half the segment to the right and half the segment * to the left of the handler. * @param segment the segment for which to move the relative * offset within the gradient colour picker. * @param t the new startoff position for the segment * @return void */ void moveSegmentStartOffset(KoGradientSegment* segment, double t); /** * Moves the endoffset of the specified segment to the specified * value and corrects the startoffset of the following segment. * If the segment is the last segment the endoffset will be set * to 1.0 . The offset will maximally be moved till the middle * of the current or the following segment. This is useful if * someone moves the segment handler in the gradient colour * picker, and needs the segment to move with it. Sets the end * position of the segment to the correct new position. * @param segment the segment for which to move the relative * end position within the gradient colour picker. * @param t the new end position for the segment * @return void */ void moveSegmentEndOffset(KoGradientSegment* segment, double t); /** * moves the Middle of the specified segment to the specified * value. The offset will maximally be moved till the endoffset * or startoffset of the segment. This sets the middle of the * segment to the same position as the handler of the gradient * colour picker. * @param segment the segment for which to move the relative * middle position within the gradient colour picker. * @param t the new middle position for the segment * @return void */ void moveSegmentMiddleOffset(KoGradientSegment* segment, double t); /** * splits the specified segment into two equal parts * @param segment the segment to split * @return void */ void splitSegment(KoGradientSegment* segment); /** * duplicate the specified segment * @param segment the segment to duplicate * @return void */ void duplicateSegment(KoGradientSegment* segment); /** * create a segment horizontally reversed to the specified one. * @param segment the segment to reverse * @return void */ void mirrorSegment(KoGradientSegment* segment); /** * removes the specific segment from the gradient colour picker. * @param segment the segment to remove * @return the segment which will be at the place of the old * segment. 0 if the segment is not in the gradient or it is * not possible to remove the segment. */ KoGradientSegment* removeSegment(KoGradientSegment* segment); /** * checks if it's possible to remove a segment (at least two * segments in the gradient) * @return true if it's possible to remove an segment */ bool removeSegmentPossible() const; const QList& segments() const; protected: KoSegmentGradient(const KoSegmentGradient &rhs); inline void pushSegment(KoGradientSegment* segment) { m_segments.push_back(segment); } QList m_segments; private: bool init(); }; #endif // KOSEGMENTGRADIENT_H diff --git a/libs/pigment/resources/KoStopGradient.cpp b/libs/pigment/resources/KoStopGradient.cpp index ac583e733e..5695b12b74 100644 --- a/libs/pigment/resources/KoStopGradient.cpp +++ b/libs/pigment/resources/KoStopGradient.cpp @@ -1,604 +1,647 @@ /* Copyright (C) 2005 Tim Beaulen Copyright (C) 2007 Jan Hambrecht Copyright (c) 2007 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoMixColorsOp.h" #include "kis_dom_utils.h" #include #include KoStopGradient::KoStopGradient(const QString& filename) : KoAbstractGradient(filename) { } KoStopGradient::~KoStopGradient() { } -bool KoStopGradient::operator==(const KoStopGradient &rhs) const +bool KoStopGradient::operator==(const KoStopGradient& rhs) const { return *colorSpace() == *rhs.colorSpace() && spread() == rhs.spread() && type() == rhs.type() && m_start == rhs.m_start && m_stop == rhs.m_stop && m_focalPoint == rhs.m_focalPoint && m_stops == rhs.m_stops; } KoAbstractGradient* KoStopGradient::clone() const { return new KoStopGradient(*this); } bool KoStopGradient::load() { QFile f(filename()); if (!f.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&f); f.close(); return res; } -bool KoStopGradient::loadFromDevice(QIODevice *dev) +bool KoStopGradient::loadFromDevice(QIODevice* dev) { QString strExt; const int result = filename().lastIndexOf('.'); if (result >= 0) { strExt = filename().mid(result).toLower(); } QByteArray ba = dev->readAll(); QBuffer buf(&ba); loadSvgGradient(&buf); if (m_stops.count() >= 2) { setValid(true); } updatePreview(); return true; } bool KoStopGradient::save() { QFile fileOut(filename()); - if (! fileOut.open(QIODevice::WriteOnly)) + if (!fileOut.open(QIODevice::WriteOnly)) return false; bool retval = saveToDevice(&fileOut); fileOut.close(); return retval; } QGradient* KoStopGradient::toQGradient() const { QGradient* gradient; switch (type()) { case QGradient::LinearGradient: { gradient = new QLinearGradient(m_start, m_stop); break; } case QGradient::RadialGradient: { QPointF diff = m_stop - m_start; qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); gradient = new QRadialGradient(m_start, radius, m_focalPoint); break; } case QGradient::ConicalGradient: { qreal angle = atan2(m_start.y(), m_start.x()) * 180.0 / M_PI; if (angle < 0.0) angle += 360.0; gradient = new QConicalGradient(m_start, angle); break; } default: return 0; } QColor color; for (QList::const_iterator i = m_stops.begin(); i != m_stops.end(); ++i) { - i->second.toQColor(&color); - gradient->setColorAt(i->first , color); + i->second.first.toQColor(&color); + gradient->setColorAt(i->first, color); } gradient->setCoordinateMode(QGradient::ObjectBoundingMode); gradient->setSpread(this->spread()); return gradient; } -bool KoStopGradient::stopsAt(KoGradientStop &leftStop, KoGradientStop &rightStop, qreal t) const +bool KoStopGradient::stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop, qreal t) const { - if (! m_stops.count()) + if (!m_stops.count()) return false; if (t <= m_stops.first().first || m_stops.count() == 1) { // we have only one stop or t is before the first stop leftStop = m_stops.first(); rightStop = KoGradientStop(-std::numeric_limits::infinity(), leftStop.second); return true; - } else if (t >= m_stops.last().first) { + } + else if (t >= m_stops.last().first) { // t is after the last stop rightStop = m_stops.last(); leftStop = KoGradientStop(std::numeric_limits::infinity(), rightStop.second); return true; - } else { + } + else { // we have at least two color stops // -> find the two stops which frame our t - auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor()), [](const KoGradientStop &a, const KoGradientStop &b){ + auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoGradientStopInfo(KoColor(), COLORSTOP)), [](const KoGradientStop& a, const KoGradientStop& b) { return a.first < b.first; - }); + }); leftStop = *(it - 1); rightStop = *(it); return true; } } void KoStopGradient::colorAt(KoColor& dst, qreal t) const { KoColor buffer; KoGradientStop leftStop, rightStop; if (!stopsAt(leftStop, rightStop, t)) return; const KoColorSpace* mixSpace = KoColorSpaceRegistry::instance()->rgb8(dst.colorSpace()->profile()); KoColor startDummy, endDummy; - if (mixSpace){ - startDummy = KoColor(leftStop.second, mixSpace); - endDummy = KoColor(rightStop.second, mixSpace); - } else { - startDummy = leftStop.second; - endDummy = rightStop.second; - } - const quint8 *colors[2]; + if (mixSpace) { + startDummy = KoColor(leftStop.second.first, mixSpace); + endDummy = KoColor(rightStop.second.first, mixSpace); + } + else { + startDummy = leftStop.second.first; + endDummy = rightStop.second.first; + } + const quint8* colors[2]; colors[0] = startDummy.data(); colors[1] = endDummy.data(); qreal localT; qreal stopDistance = rightStop.first - leftStop.first; if (stopDistance < DBL_EPSILON) { localT = 0.5; - } else { + } + else { localT = (t - leftStop.first) / stopDistance; } qint16 colorWeights[2]; colorWeights[0] = static_cast((1.0 - localT) * 255 + 0.5); colorWeights[1] = 255 - colorWeights[0]; //check if our mixspace exists, it doesn't at startup. - if (mixSpace){ + if (mixSpace) { if (*buffer.colorSpace() != *mixSpace) { buffer = KoColor(mixSpace); } mixSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } else { buffer = KoColor(colorSpace()); colorSpace()->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } dst.fromKoColor(buffer); } -KoStopGradient * KoStopGradient::fromQGradient(const QGradient * gradient) +KoStopGradient* KoStopGradient::fromQGradient(const QGradient* gradient) { - if (! gradient) + if (!gradient) return 0; - KoStopGradient * newGradient = new KoStopGradient(QString()); + KoStopGradient* newGradient = new KoStopGradient(QString()); newGradient->setType(gradient->type()); newGradient->setSpread(gradient->spread()); switch (gradient->type()) { case QGradient::LinearGradient: { - const QLinearGradient * g = static_cast(gradient); + const QLinearGradient* g = static_cast(gradient); newGradient->m_start = g->start(); newGradient->m_stop = g->finalStop(); newGradient->m_focalPoint = g->start(); break; } case QGradient::RadialGradient: { - const QRadialGradient * g = static_cast(gradient); + const QRadialGradient* g = static_cast(gradient); newGradient->m_start = g->center(); newGradient->m_stop = g->center() + QPointF(g->radius(), 0); newGradient->m_focalPoint = g->focalPoint(); break; } case QGradient::ConicalGradient: { - const QConicalGradient * g = static_cast(gradient); + const QConicalGradient* g = static_cast(gradient); qreal radian = g->angle() * M_PI / 180.0; newGradient->m_start = g->center(); newGradient->m_stop = QPointF(100.0 * cos(radian), 100.0 * sin(radian)); newGradient->m_focalPoint = g->center(); break; } default: delete newGradient; return 0; } - Q_FOREACH (const QGradientStop & stop, gradient->stops()) { + Q_FOREACH(const QGradientStop & stop, gradient->stops()) { KoColor color(newGradient->colorSpace()); color.fromQColor(stop.second); - newGradient->m_stops.append(KoGradientStop(stop.first, color)); + newGradient->m_stops.append(KoGradientStop(stop.first, KoGradientStopInfo(color, COLORSTOP))); } newGradient->setValid(true); return newGradient; } void KoStopGradient::setStops(QList< KoGradientStop > stops) { m_stops.clear(); + m_hasVariableStops = false; KoColor color; - Q_FOREACH (const KoGradientStop & stop, stops) { - color = stop.second; + Q_FOREACH(const KoGradientStop & stop, stops) { + color = stop.second.first; color.convertTo(colorSpace()); - m_stops.append(KoGradientStop(stop.first, color)); + m_stops.append(KoGradientStop(stop.first, KoGradientStopInfo(color, stop.second.second))); + qDebug() << "KoStopGradient::setStops, stoptype: " << stop.second.second; + if (stop.second.second != COLORSTOP) { + m_hasVariableStops = true; + } } updatePreview(); } QList KoStopGradient::stops() const { return m_stops; } -void KoStopGradient::loadSvgGradient(QIODevice *file) +bool KoStopGradient::hasVariableColors() const { + return m_hasVariableStops; +} + +void KoStopGradient::setVariableColors(const KoColor& foreground, const KoColor& background) { + KoColor color; + for (int i = 0; i < m_stops.count(); i++){ + if (m_stops[i].second.second == FOREGROUNDSTOP) { + color = foreground; + } + else if (m_stops[i].second.second == BACKGROUNDSTOP) { + color = background; + } + else continue; + color.convertTo(colorSpace()); + m_stops[i].second.first = color; + } + updatePreview(); +} + +void KoStopGradient::loadSvgGradient(QIODevice* file) { QDomDocument doc; if (!(doc.setContent(file))) file->close(); else { for (QDomNode n = doc.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (e.isNull()) continue; if (e.tagName() == "linearGradient" || e.tagName() == "radialGradient") { parseSvgGradient(e); return; } // Inkscape gradients are in another defs if (e.tagName() == "defs") { for (QDomNode defnode = e.firstChild(); !defnode.isNull(); defnode = defnode.nextSibling()) { QDomElement defelement = defnode.toElement(); if (defelement.isNull()) continue; if (defelement.tagName() == "linearGradient" || defelement.tagName() == "radialGradient") { parseSvgGradient(defelement); return; } } } } } } void KoStopGradient::parseSvgGradient(const QDomElement& element) { m_stops.clear(); setSpread(QGradient::PadSpread); /*QString href = e.attribute( "xlink:href" ).mid( 1 ); if( !href.isEmpty() ) { }*/ setName(element.attribute("id", i18n("SVG Gradient"))); const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); bool bbox = element.attribute("gradientUnits") != "userSpaceOnUse"; if (element.tagName() == "linearGradient") { if (bbox) { QString s; s = element.attribute("x1", "0%"); qreal xOrigin; if (s.endsWith('%')) xOrigin = s.remove('%').toDouble(); else xOrigin = s.toDouble() * 100.0; s = element.attribute("y1", "0%"); qreal yOrigin; if (s.endsWith('%')) yOrigin = s.remove('%').toDouble(); else yOrigin = s.toDouble() * 100.0; s = element.attribute("x2", "100%"); qreal xVector; if (s.endsWith('%')) xVector = s.remove('%').toDouble(); else xVector = s.toDouble() * 100.0; s = element.attribute("y2", "0%"); qreal yVector; if (s.endsWith('%')) yVector = s.remove('%').toDouble(); else yVector = s.toDouble() * 100.0; m_start = QPointF(xOrigin, yOrigin); m_stop = QPointF(xVector, yVector); - } else { + } + else { m_start = QPointF(element.attribute("x1").toDouble(), element.attribute("y1").toDouble()); m_stop = QPointF(element.attribute("x2").toDouble(), element.attribute("y2").toDouble()); } setType(QGradient::LinearGradient); - } else { + } + else { if (bbox) { QString s; s = element.attribute("cx", "50%"); qreal xOrigin; if (s.endsWith('%')) xOrigin = s.remove('%').toDouble(); else xOrigin = s.toDouble() * 100.0; s = element.attribute("cy", "50%"); qreal yOrigin; if (s.endsWith('%')) yOrigin = s.remove('%').toDouble(); else yOrigin = s.toDouble() * 100.0; s = element.attribute("cx", "50%"); qreal xVector; if (s.endsWith('%')) xVector = s.remove('%').toDouble(); else xVector = s.toDouble() * 100.0; s = element.attribute("r", "50%"); if (s.endsWith('%')) xVector += s.remove('%').toDouble(); else xVector += s.toDouble() * 100.0; s = element.attribute("cy", "50%"); qreal yVector; if (s.endsWith('%')) yVector = s.remove('%').toDouble(); else yVector = s.toDouble() * 100.0; s = element.attribute("fx", "50%"); qreal xFocal; if (s.endsWith('%')) xFocal = s.remove('%').toDouble(); else xFocal = s.toDouble() * 100.0; s = element.attribute("fy", "50%"); qreal yFocal; if (s.endsWith('%')) yFocal = s.remove('%').toDouble(); else yFocal = s.toDouble() * 100.0; m_start = QPointF(xOrigin, yOrigin); m_stop = QPointF(xVector, yVector); m_focalPoint = QPointF(xFocal, yFocal); - } else { + } + else { m_start = QPointF(element.attribute("cx").toDouble(), element.attribute("cy").toDouble()); m_stop = QPointF(element.attribute("cx").toDouble() + element.attribute("r").toDouble(), - element.attribute("cy").toDouble()); + element.attribute("cy").toDouble()); m_focalPoint = QPointF(element.attribute("fx").toDouble(), element.attribute("fy").toDouble()); } setType(QGradient::RadialGradient); } // handle spread method QString spreadMethod = element.attribute("spreadMethod"); if (!spreadMethod.isEmpty()) { if (spreadMethod == "reflect") setSpread(QGradient::ReflectSpread); else if (spreadMethod == "repeat") setSpread(QGradient::RepeatSpread); } for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement colorstop = n.toElement(); if (colorstop.tagName() == "stop") { qreal opacity = 0.0; QColor c; float off; QString temp = colorstop.attribute("offset"); if (temp.contains('%')) { temp = temp.left(temp.length() - 1); off = temp.toFloat() / 100.0; - } else + } + else off = temp.toFloat(); if (!colorstop.attribute("stop-color").isEmpty()) parseSvgColor(c, colorstop.attribute("stop-color")); else { // try style attr QString style = colorstop.attribute("style").simplified(); QStringList substyles = style.split(';', QString::SkipEmptyParts); - Q_FOREACH (const QString & s, substyles) { + Q_FOREACH(const QString & s, substyles) { QStringList substyle = s.split(':'); QString command = substyle[0].trimmed(); QString params = substyle[1].trimmed(); if (command == "stop-color") parseSvgColor(c, params); if (command == "stop-opacity") opacity = params.toDouble(); } } if (!colorstop.attribute("stop-opacity").isEmpty()) opacity = colorstop.attribute("stop-opacity").toDouble(); KoColor color(rgbColorSpace); color.fromQColor(c); color.setOpacity(static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5)); - + QString stopTypeStr = colorstop.attribute("krita-stop-type", "0"); + KoGradientStopType stopType = static_cast(stopTypeStr.toInt()); + if (stopType != COLORSTOP) { + m_hasVariableStops = true; + } //According to the SVG spec each gradient offset has to be equal to or greater than the previous one //if not it needs to be adjusted to be equal if (m_stops.count() > 0 && m_stops.last().first >= off) { off = m_stops.last().first; } - m_stops.append(KoGradientStop(off, color)); + m_stops.append(KoGradientStop(off, KoGradientStopInfo(color, stopType))); } } } -void KoStopGradient::parseSvgColor(QColor &color, const QString &s) +void KoStopGradient::parseSvgColor(QColor& color, const QString& s) { if (s.startsWith("rgb(")) { QString parse = s.trimmed(); QStringList colors = parse.split(','); QString r = colors[0].right((colors[0].length() - 4)); QString g = colors[1]; QString b = colors[2].left((colors[2].length() - 1)); if (r.contains('%')) { r = r.left(r.length() - 1); r = QString::number(int((qreal(255 * r.toDouble()) / 100.0))); } if (g.contains('%')) { g = g.left(g.length() - 1); g = QString::number(int((qreal(255 * g.toDouble()) / 100.0))); } if (b.contains('%')) { b = b.left(b.length() - 1); b = QString::number(int((qreal(255 * b.toDouble()) / 100.0))); } color = QColor(r.toInt(), g.toInt(), b.toInt()); - } else { + } + else { QString rgbColor = s.trimmed(); QColor c; if (rgbColor.startsWith('#')) c.setNamedColor(rgbColor); else { c = QColor(rgbColor); } color = c; } } QString KoStopGradient::defaultFileExtension() const { return QString(".svg"); } -void KoStopGradient::toXML(QDomDocument &doc, QDomElement &gradientElt) const +void KoStopGradient::toXML(QDomDocument& doc, QDomElement& gradientElt) const { gradientElt.setAttribute("type", "stop"); for (int s = 0; s < m_stops.size(); s++) { KoGradientStop stop = m_stops.at(s); QDomElement stopElt = doc.createElement("stop"); stopElt.setAttribute("offset", KisDomUtils::toString(stop.first)); - stopElt.setAttribute("bitdepth", stop.second.colorSpace()->colorDepthId().id()); - stopElt.setAttribute("alpha", KisDomUtils::toString(stop.second.opacityF())); - stop.second.toXML(doc, stopElt); + stopElt.setAttribute("bitdepth", stop.second.first.colorSpace()->colorDepthId().id()); + stopElt.setAttribute("alpha", KisDomUtils::toString(stop.second.first.opacityF())); + stopElt.setAttribute("stoptype", KisDomUtils::toString(stop.second.second)); + stop.second.first.toXML(doc, stopElt); gradientElt.appendChild(stopElt); } } -KoStopGradient KoStopGradient::fromXML(const QDomElement &elt) +KoStopGradient KoStopGradient::fromXML(const QDomElement& elt) { KoStopGradient gradient; QList stops; QDomElement stopElt = elt.firstChildElement("stop"); while (!stopElt.isNull()) { qreal offset = KisDomUtils::toDouble(stopElt.attribute("offset", "0.0")); QString bitDepth = stopElt.attribute("bitdepth", Integer8BitsColorDepthID.id()); KoColor color = KoColor::fromXML(stopElt.firstChildElement(), bitDepth); color.setOpacity(KisDomUtils::toDouble(stopElt.attribute("alpha", "1.0"))); - stops.append(KoGradientStop(offset, color)); + KoGradientStopType stoptype = static_cast(KisDomUtils::toInt(stopElt.attribute("stoptype", "0"))); + stops.append(KoGradientStop(offset, KoGradientStopInfo(color, stoptype))); stopElt = stopElt.nextSiblingElement("stop"); } gradient.setStops(stops); return gradient; } -bool KoStopGradient::saveToDevice(QIODevice *dev) const +bool KoStopGradient::saveToDevice(QIODevice* dev) const { QTextStream stream(dev); const QString spreadMethod[3] = { QString("spreadMethod=\"pad\" "), QString("spreadMethod=\"reflect\" "), QString("spreadMethod=\"repeat\" ") }; const QString indent = " "; stream << "" << endl; stream << indent; stream << "" << endl; QColor color; // color stops - Q_FOREACH (const KoGradientStop & stop, m_stops) { - stop.second.toQColor(&color); + Q_FOREACH(const KoGradientStop & stop, m_stops) { + stop.second.first.toQColor(&color); stream << indent << indent; stream << "(color.alpha()) / 255.0f << "\"" << " />" << endl; + stream << "\" stop-opacity=\"" << static_cast(color.alpha()) / 255.0f; + stream << "\" krita-stop-type=\"" << QString().setNum(stop.second.second) << "\""; + + stream << " />" << endl; } stream << indent; stream << "" << endl; stream << "" << endl; KoResource::saveToDevice(dev); return true; -} +} \ No newline at end of file diff --git a/libs/pigment/resources/KoStopGradient.h b/libs/pigment/resources/KoStopGradient.h index 4c4d653809..cdd97454fa 100644 --- a/libs/pigment/resources/KoStopGradient.h +++ b/libs/pigment/resources/KoStopGradient.h @@ -1,104 +1,121 @@ /* Copyright (c) 2007 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOSTOPGRADIENT_H #define KOSTOPGRADIENT_H #include #include +#include #include "KoColor.h" #include #include #include #include -typedef QPair KoGradientStop; +enum KoGradientStopType +{ + COLORSTOP, + FOREGROUNDSTOP, + BACKGROUNDSTOP +}; + +typedef QPair KoGradientStopInfo; + +typedef QPair KoGradientStop; struct KoGradientStopValueSort { inline bool operator() (const KoGradientStop& a, const KoGradientStop& b) { - return (a.second.toQColor().valueF() < b.second.toQColor().valueF()); + return (a.second.first.toQColor().valueF() < b.second.first.toQColor().valueF()); } }; /** * Resource for colorstop based gradients like SVG gradients */ class KRITAPIGMENT_EXPORT KoStopGradient : public KoAbstractGradient, public boost::equality_comparable { public: + explicit KoStopGradient(const QString &filename = QString()); ~KoStopGradient() override; bool operator==(const KoStopGradient &rhs) const; KoAbstractGradient* clone() const override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /// reimplemented QGradient* toQGradient() const override; /// Find stops surrounding position, returns false if position outside gradient bool stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop, qreal t) const; /// reimplemented void colorAt(KoColor&, qreal t) const override; /// Creates KoStopGradient from a QGradient static KoStopGradient * fromQGradient(const QGradient * gradient); /// Sets the gradient stops void setStops(QList stops); - QList stops() const; + QList stops() const; + + /// reimplemented + bool hasVariableColors() const override; + /// reimplemented + void setVariableColors(const KoColor& foreground, const KoColor& background) override; /// reimplemented QString defaultFileExtension() const override; /** * @brief toXML * Convert the gradient to an XML string. */ void toXML(QDomDocument& doc, QDomElement& gradientElt) const; /** * @brief fromXML * convert a gradient from xml. * @return a gradient. */ static KoStopGradient fromXML(const QDomElement& elt); protected: QList m_stops; + bool m_hasVariableStops = false; QPointF m_start; QPointF m_stop; QPointF m_focalPoint; private: void loadSvgGradient(QIODevice *file); void parseSvgGradient(const QDomElement& element); void parseSvgColor(QColor &color, const QString &s); }; #endif // KOSTOPGRADIENT_H diff --git a/libs/psd/asl/kis_asl_xml_writer.cpp b/libs/psd/asl/kis_asl_xml_writer.cpp index a902e76769..d19cbd3f16 100644 --- a/libs/psd/asl/kis_asl_xml_writer.cpp +++ b/libs/psd/asl/kis_asl_xml_writer.cpp @@ -1,399 +1,399 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 "kis_asl_xml_writer.h" #include #include #include #include #include #include #include #include #include #include "kis_dom_utils.h" #include "kis_asl_writer_utils.h" struct KisAslXmlWriter::Private { QDomDocument document; QDomElement currentElement; }; KisAslXmlWriter::KisAslXmlWriter() : m_d(new Private) { QDomElement el = m_d->document.createElement("asl"); m_d->document.appendChild(el); m_d->currentElement = el; } KisAslXmlWriter::~KisAslXmlWriter() { } QDomDocument KisAslXmlWriter::document() const { if (m_d->document.documentElement() != m_d->currentElement) { warnKrita << "KisAslXmlWriter::document(): unbalanced enter/leave descriptor/array"; } return m_d->document; } void KisAslXmlWriter::enterDescriptor(const QString &key, const QString &name, const QString &classId) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Descriptor"); el.setAttribute("name", name); el.setAttribute("classId", classId); m_d->currentElement.appendChild(el); m_d->currentElement = el; } void KisAslXmlWriter::leaveDescriptor() { if (!m_d->currentElement.parentNode().toElement().isNull()) { m_d->currentElement = m_d->currentElement.parentNode().toElement(); } else { warnKrita << "KisAslXmlWriter::leaveDescriptor(): unbalanced enter/leave descriptor"; } } void KisAslXmlWriter::enterList(const QString &key) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "List"); m_d->currentElement.appendChild(el); m_d->currentElement = el; } void KisAslXmlWriter::leaveList() { if (!m_d->currentElement.parentNode().toElement().isNull()) { m_d->currentElement = m_d->currentElement.parentNode().toElement(); } else { warnKrita << "KisAslXmlWriter::leaveList(): unbalanced enter/leave list"; } } void KisAslXmlWriter::writeDouble(const QString &key, double value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Double"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeInteger(const QString &key, int value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Integer"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeEnum(const QString &key, const QString &typeId, const QString &value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Enum"); el.setAttribute("typeId", typeId); el.setAttribute("value", value); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeUnitFloat(const QString &key, const QString &unit, double value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "UnitFloat"); el.setAttribute("unit", unit); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeText(const QString &key, const QString &value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Text"); el.setAttribute("value", value); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeBoolean(const QString &key, bool value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Boolean"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeColor(const QString &key, const QColor &value) { enterDescriptor(key, "", "RGBC"); writeDouble("Rd ", value.red()); writeDouble("Grn ", value.green()); writeDouble("Bl ", value.blue()); leaveDescriptor(); } void KisAslXmlWriter::writePoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "CrPt"); writeDouble("Hrzn", value.x()); writeDouble("Vrtc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writePhasePoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "Pnt "); writeDouble("Hrzn", value.x()); writeDouble("Vrtc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writeOffsetPoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "Pnt "); writeUnitFloat("Hrzn", "#Prc", value.x()); writeUnitFloat("Vrtc", "#Prc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writeCurve(const QString &key, const QString &name, const QVector &points) { enterDescriptor(key, "", "ShpC"); writeText("Nm ", name); enterList("Crv "); Q_FOREACH (const QPointF &pt, points) { writePoint("", pt); } leaveList(); leaveDescriptor(); } QString KisAslXmlWriter::writePattern(const QString &key, const KoPattern *pattern) { enterDescriptor(key, "", "KisPattern"); writeText("Nm ", pattern->name()); QString uuid = KisAslWriterUtils::getPatternUuidLazy(pattern); writeText("Idnt", uuid); // Write pattern data QBuffer buffer; buffer.open(QIODevice::WriteOnly); pattern->savePatToDevice(&buffer); QDomCDATASection dataSection = m_d->document.createCDATASection(qCompress(buffer.buffer()).toBase64()); QDomElement dataElement = m_d->document.createElement("node"); dataElement.setAttribute("type", "KisPatternData"); dataElement.setAttribute("key", "Data"); dataElement.appendChild(dataSection); m_d->currentElement.appendChild(dataElement); leaveDescriptor(); return uuid; } void KisAslXmlWriter::writePatternRef(const QString &key, const KoPattern *pattern, const QString &uuid) { enterDescriptor(key, "", "Ptrn"); writeText("Nm ", pattern->name()); writeText("Idnt", uuid); leaveDescriptor(); } void KisAslXmlWriter::writeGradientImpl(const QString &key, const QString &name, QVector colors, QVector transparencies, QVector positions, QVector middleOffsets) { enterDescriptor(key, "Gradient", "Grdn"); writeText("Nm ", name); writeEnum("GrdF", "GrdF", "CstS"); writeDouble("Intr", 4096); enterList("Clrs"); for (int i = 0; i < colors.size(); i++) { enterDescriptor("", "", "Clrt"); writeColor("Clr ", colors[i]); writeEnum("Type", "Clry", "UsrS"); // NOTE: we do not support BG/FG color tags writeInteger("Lctn", positions[i] * 4096.0); writeInteger("Mdpn", middleOffsets[i] * 100.0); leaveDescriptor(); }; leaveList(); enterList("Trns"); for (int i = 0; i < colors.size(); i++) { enterDescriptor("", "", "TrnS"); writeUnitFloat("Opct", "#Prc", transparencies[i] * 100.0); writeInteger("Lctn", positions[i] * 4096.0); writeInteger("Mdpn", middleOffsets[i] * 100.0); leaveDescriptor(); }; leaveList(); leaveDescriptor(); } void KisAslXmlWriter::writeSegmentGradient(const QString &key, const KoSegmentGradient *gradient) { const QList&segments = gradient->segments(); KIS_SAFE_ASSERT_RECOVER_RETURN(!segments.isEmpty()); QVector colors; QVector transparencies; QVector positions; QVector middleOffsets; Q_FOREACH (const KoGradientSegment *seg, segments) { const qreal start = seg->startOffset(); const qreal end = seg->endOffset(); const qreal mid = (end - start) > DBL_EPSILON ? (seg->middleOffset() - start) / (end - start) : 0.5; QColor color = seg->startColor().toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; positions << start; middleOffsets << mid; } // last segment if (!segments.isEmpty()) { const KoGradientSegment *lastSeg = segments.last(); QColor color = lastSeg->endColor().toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; positions << lastSeg->endOffset(); middleOffsets << 0.5; } writeGradientImpl(key, gradient->name(), colors, transparencies, positions, middleOffsets); } void KisAslXmlWriter::writeStopGradient(const QString &key, const KoStopGradient *gradient) { QVector colors; QVector transparencies; QVector positions; QVector middleOffsets; Q_FOREACH (const KoGradientStop &stop, gradient->stops()) { - QColor color = stop.second.toQColor(); + QColor color = stop.second.first.toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; positions << stop.first; middleOffsets << 0.5; } writeGradientImpl(key, gradient->name(), colors, transparencies, positions, middleOffsets); } diff --git a/libs/ui/forms/wdgautogradient.ui b/libs/ui/forms/wdgautogradient.ui index f8478b930a..491c8a9d17 100644 --- a/libs/ui/forms/wdgautogradient.ui +++ b/libs/ui/forms/wdgautogradient.ui @@ -1,375 +1,445 @@ KisWdgAutogradient 0 0 500 250 500 250 Name: 0 1 Qt::ClickFocus - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Segment Color - - - - - - - - Sans Serif - 9 - 50 - false - false - false - false - - - - Opacity: - - - - - + + Sans Serif 9 50 false false false false - Left: + Right: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + 0 0 0 30 Sans Serif 9 50 false false false false Qt::ClickFocus - + 0 0 Sans Serif 9 50 false false false false Qt::ClickFocus 100 100 - - + + Sans Serif 9 50 false false false false - Right: + Opacity: + + + + + + + + Sans Serif + 9 + 50 + false + false + false + false + + + + Left: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + + + Foreground + + + leftBtnGroup + + + + + + + Foreground + + + rightBtnGroup + + + + + 0 0 0 30 Sans Serif 9 50 false false false false Qt::ClickFocus - + + + + + Sans Serif + 9 + 50 + false + false + false + false + + + + Segment Color + + + + + + + Background + + + leftBtnGroup + + + + + + + Color + + + true + + + leftBtnGroup + + + + + + + Color + + + true + + + rightBtnGroup + + + + 0 0 Sans Serif 9 50 false false false false Qt::ClickFocus 100 100 + + + + Background + + + rightBtnGroup + + + 0 0 0 0 Qt::Horizontal 40 20 Sans Serif 9 50 false false false false Qt::ClickFocus Linear Curved Sine Sphere Inc. Sphere Dec. Sans Serif 9 50 false false false false Qt::ClickFocus RGB HSV CW HSV CCW - - KisIntParseSpinBox - QSpinBox -
kis_int_parse_spin_box.h
-
KisColorButton QPushButton
kis_color_button.h
+ + KisIntParseSpinBox + QSpinBox +
kis_int_parse_spin_box.h
+
KisGradientSliderWidget
KisGradientSliderWidget.h
+ + + +
diff --git a/libs/ui/forms/wdgstopgradienteditor.ui b/libs/ui/forms/wdgstopgradienteditor.ui index 32e61154b8..1b61db4d59 100644 --- a/libs/ui/forms/wdgstopgradienteditor.ui +++ b/libs/ui/forms/wdgstopgradienteditor.ui @@ -1,150 +1,171 @@ KisWdgStopGradientEditor 0 0 368 - 167 + 231 Name: 0 1 Qt::ClickFocus Qt::NoFocus true Qt::Vertical 0 0 - - - + + + - Stop: + Foreground - + 0 0 Sans Serif 9 50 false false false false Qt::ClickFocus - + 0 0 + + + + Color + + + + + + + Stop: + + + + + + + Background + + + KisDoubleSliderSpinBox QWidget
kis_slider_spin_box.h
1
KisColorButton QPushButton
kis_color_button.h
KisStopGradientSliderWidget QWidget
kis_stopgradient_slider_widget.h
1
diff --git a/libs/ui/kis_autogradient.cc b/libs/ui/kis_autogradient.cc index 5d33501c5b..260cee7b06 100644 --- a/libs/ui/kis_autogradient.cc +++ b/libs/ui/kis_autogradient.cc @@ -1,172 +1,251 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * 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 "kis_autogradient.h" #include #include #include #include #include #include #include "kis_debug.h" #include "KisGradientSliderWidget.h" /****************************** KisAutogradient ******************************/ -KisAutogradientEditor::KisAutogradientEditor(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption) +KisAutogradientEditor::KisAutogradientEditor(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption, KoColor fgColor, KoColor bgColor) : QWidget(parent) - , m_autogradientResource(gradient) + , m_autogradientResource(gradient), + m_fgColor(fgColor), + m_bgColor(bgColor) { setObjectName(name); setupUi(this); setWindowTitle(caption); gradientSlider->setGradientResource(m_autogradientResource); nameedit->setText(gradient->name()); KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { slotSelectedSegment(segment); } connect(nameedit, SIGNAL(editingFinished()), this, SLOT(slotChangedName())); connect(gradientSlider, SIGNAL(sigSelectedSegment(KoGradientSegment*)), SLOT(slotSelectedSegment(KoGradientSegment*))); connect(gradientSlider, SIGNAL(sigChangedSegment(KoGradientSegment*)), SLOT(slotChangedSegment(KoGradientSegment*))); connect(comboBoxColorInterpolationType, SIGNAL(activated(int)), SLOT(slotChangedColorInterpolation(int))); connect(comboBoxInterpolationType, SIGNAL(activated(int)), SLOT(slotChangedInterpolation(int))); connect(leftColorButton, SIGNAL(changed(KoColor)), SLOT(slotChangedLeftColor(KoColor))); connect(rightColorButton, SIGNAL(changed(KoColor)), SLOT(slotChangedRightColor(KoColor))); connect(intNumInputLeftOpacity, SIGNAL(valueChanged(int)), SLOT(slotChangedLeftOpacity(int))); connect(intNumInputRightOpacity, SIGNAL(valueChanged(int)), SLOT(slotChangedRightOpacity(int))); + connect(leftBtnGroup, SIGNAL(buttonToggled(QAbstractButton*, bool)), this, SLOT(slotChangedLeftType(QAbstractButton*, bool))); + connect(rightBtnGroup, SIGNAL(buttonToggled(QAbstractButton*, bool)), this, SLOT(slotChangedRightType(QAbstractButton*, bool))); } void KisAutogradientEditor::activate() { paramChanged(); } void KisAutogradientEditor::slotSelectedSegment(KoGradientSegment* segment) { leftColorButton->setColor(segment->startColor()); rightColorButton->setColor(segment->endColor()); comboBoxColorInterpolationType->setCurrentIndex(segment->colorInterpolation()); comboBoxInterpolationType->setCurrentIndex(segment->interpolation()); int leftOpacity = segment->startColor().opacityF(); intNumInputLeftOpacity->setValue(leftOpacity * 100); intNumInputLeftOpacity->setSuffix(i18n(" %")); int rightOpacity = segment->endColor().opacityF(); intNumInputRightOpacity->setValue(rightOpacity * 100); intNumInputRightOpacity->setSuffix(i18n(" %")); + KoGradientSegmentEndpointType leftType = segment->startType(); + KoGradientSegmentEndpointType rightType = segment->endType(); + switch (leftType) { + case COLOR_ENDPOINT: + leftColorRadioButton->setChecked(true); break; + case FOREGROUND_ENDPOINT: + leftForegroundRadioButton->setChecked(true); break; + case BACKGROUND_ENDPOINT: + leftBackgroundRadioButton->setChecked(true); break; + } + switch (rightType) { + case COLOR_ENDPOINT: + rightColorRadioButton->setChecked(true); break; + case FOREGROUND_ENDPOINT: + rightForegroundRadioButton->setChecked(true); break; + case BACKGROUND_ENDPOINT: + rightBackgroundRadioButton->setChecked(true); break; + } + + paramChanged(); } void KisAutogradientEditor::slotChangedSegment(KoGradientSegment*) { paramChanged(); } void KisAutogradientEditor::slotChangedInterpolation(int type) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) segment->setInterpolation(type); gradientSlider->update(); paramChanged(); } void KisAutogradientEditor::slotChangedColorInterpolation(int type) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) segment->setColorInterpolation(type); gradientSlider->update(); paramChanged(); } void KisAutogradientEditor::slotChangedLeftColor(const KoColor& color) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(color, segment->startColor().colorSpace()); c.setOpacity(segment->startColor().opacityU8()); segment->setStartColor(c); } gradientSlider->update(); paramChanged(); } void KisAutogradientEditor::slotChangedRightColor(const KoColor& color) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(color, segment->endColor().colorSpace()); c.setOpacity(segment->endColor().opacityU8()); segment->setEndColor(c); } gradientSlider->repaint(); paramChanged(); } void KisAutogradientEditor::slotChangedLeftOpacity(int value) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(segment->startColor(), segment->startColor().colorSpace()); c.setOpacity(qreal(value) / qreal(100.0)); segment->setStartColor(c); } gradientSlider->repaint(); paramChanged(); } void KisAutogradientEditor::slotChangedRightOpacity(int value) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(segment->endColor(), segment->endColor().colorSpace()); c.setOpacity(quint8((value *OPACITY_OPAQUE_U8) / 100)); segment->setEndColor(c); } gradientSlider->repaint(); paramChanged(); } +void KisAutogradientEditor::slotChangedLeftType(QAbstractButton* button, bool checked) +{ + if (!checked) { //Radio buttons, so we only care about the one that was checked, not the one unchecked + return; + } + KoGradientSegmentEndpointType type; + KoColor color; + const KoColorSpace* colorSpace = m_autogradientResource->colorSpace(); + if (button == leftForegroundRadioButton) { + type = FOREGROUND_ENDPOINT; + color = KoColor(m_fgColor, colorSpace); + } + else if (button == leftBackgroundRadioButton) { + type = BACKGROUND_ENDPOINT; + color = KoColor(m_bgColor, colorSpace); + } + else { + type = COLOR_ENDPOINT; + color = KoColor(leftColorButton->color(), colorSpace); + } + KoGradientSegment* segment = gradientSlider->selectedSegment(); + if (segment) { + segment->setStartType(type); + } + slotChangedLeftColor(color); + +} + +void KisAutogradientEditor::slotChangedRightType(QAbstractButton* button, bool checked) +{ + if (!checked) { //Radio buttons, so we only care about the one that was checked, not the one unchecked + return; + } + KoGradientSegmentEndpointType type; + KoColor color; + const KoColorSpace* colorSpace = m_autogradientResource->colorSpace(); + if (button == rightForegroundRadioButton) { + type = FOREGROUND_ENDPOINT; + color = KoColor(m_fgColor, colorSpace); + } + else if (button == rightBackgroundRadioButton) { + type = BACKGROUND_ENDPOINT; + color = KoColor(m_bgColor, colorSpace); + } + else { + type = COLOR_ENDPOINT; + color = KoColor(rightColorButton->color(), colorSpace); + } + KoGradientSegment* segment = gradientSlider->selectedSegment(); + if (segment) { + segment->setEndType(type); + } + slotChangedRightColor(color); +} + void KisAutogradientEditor::slotChangedName() { m_autogradientResource->setName(nameedit->text()); } void KisAutogradientEditor::paramChanged() { m_autogradientResource->updatePreview(); } diff --git a/libs/ui/kis_autogradient.h b/libs/ui/kis_autogradient.h index 7ba6b680a4..0c48db457f 100644 --- a/libs/ui/kis_autogradient.h +++ b/libs/ui/kis_autogradient.h @@ -1,50 +1,54 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * 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_AUTOGRADIENT_H_ #define _KIS_AUTOGRADIENT_H_ #include "ui_wdgautogradient.h" class KoGradientSegment; class KoSegmentGradient; class KisAutogradientEditor : public QWidget, public Ui::KisWdgAutogradient { Q_OBJECT public: - KisAutogradientEditor(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption); + KisAutogradientEditor(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption, KoColor fgColor, KoColor bgColor); void activate(); private: KoSegmentGradient* m_autogradientResource; + KoColor m_fgColor, m_bgColor; private Q_SLOTS: void slotSelectedSegment(KoGradientSegment* segment); void slotChangedSegment(KoGradientSegment* segment); void slotChangedInterpolation(int type); void slotChangedColorInterpolation(int type); void slotChangedLeftColor(const KoColor& color); void slotChangedRightColor(const KoColor& color); void slotChangedLeftOpacity(int value); void slotChangedRightOpacity(int value); + void slotChangedLeftType(QAbstractButton* button, bool checked); + void slotChangedRightType(QAbstractButton* button, bool checked); + void slotChangedName(); void paramChanged(); }; #endif diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp index df5f283528..5e6b5f9d23 100644 --- a/libs/ui/kis_canvas_resource_provider.cpp +++ b/libs/ui/kis_canvas_resource_provider.cpp @@ -1,567 +1,571 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * 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 "kis_canvas_resource_provider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "KisViewManager.h" #include "canvas/kis_canvas2.h" KisCanvasResourceProvider::KisCanvasResourceProvider(KisViewManager * view) : m_view(view) { m_fGChanged = true; } KisCanvasResourceProvider::~KisCanvasResourceProvider() { disconnect(); // in case Qt gets confused } KoCanvasResourceProvider* KisCanvasResourceProvider::resourceManager() { return m_resourceManager; } void KisCanvasResourceProvider::setResourceManager(KoCanvasResourceProvider *resourceManager) { m_resourceManager = resourceManager; QVariant v; v.setValue(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); m_resourceManager->setResource(KoCanvasResourceProvider::ForegroundColor, v); v.setValue(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); m_resourceManager->setResource(KoCanvasResourceProvider::BackgroundColor, v); setCurrentCompositeOp(COMPOSITE_OVER); setMirrorHorizontal(false); setMirrorVertical(false); m_resourceManager->setResource(HdrExposure, 0.0); m_resourceManager->setResource(HdrGamma, 1.0); m_resourceManager->setResource(EffectiveZoom, 1.0); connect(m_resourceManager, SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(slotCanvasResourceChanged(int,QVariant))); m_resourceManager->setResource(KoCanvasResourceProvider::ApplicationSpeciality, KoCanvasResourceProvider::NoAdvancedText); m_resourceManager->setResource(GamutMaskActive, false); } KoCanvasBase * KisCanvasResourceProvider::canvas() const { return m_view->canvasBase(); } KoColor KisCanvasResourceProvider::bgColor() const { return m_resourceManager->resource(KoCanvasResourceProvider::BackgroundColor).value(); } KoColor KisCanvasResourceProvider::fgColor() const { return m_resourceManager->resource(KoCanvasResourceProvider::ForegroundColor).value(); } float KisCanvasResourceProvider::HDRExposure() const { return static_cast(m_resourceManager->resource(HdrExposure).toDouble()); } void KisCanvasResourceProvider::setHDRExposure(float exposure) { m_resourceManager->setResource(HdrExposure, static_cast(exposure)); } float KisCanvasResourceProvider::HDRGamma() const { return static_cast(m_resourceManager->resource(HdrGamma).toDouble()); } void KisCanvasResourceProvider::setHDRGamma(float gamma) { m_resourceManager->setResource(HdrGamma, static_cast(gamma)); } KoPattern * KisCanvasResourceProvider::currentPattern() const { if (m_resourceManager->hasResource(CurrentPattern)) { return m_resourceManager->resource(CurrentPattern).value(); } else { return 0; } } KoAbstractGradient* KisCanvasResourceProvider::currentGradient() const { if (m_resourceManager->hasResource(CurrentGradient)) { return m_resourceManager->resource(CurrentGradient).value(); } else { return 0; } } KisImageWSP KisCanvasResourceProvider::currentImage() const { return m_view->image(); } KisNodeSP KisCanvasResourceProvider::currentNode() const { return m_view->activeNode(); } KoGamutMask *KisCanvasResourceProvider::currentGamutMask() const { if (m_resourceManager->hasResource(CurrentGamutMask)) { return m_resourceManager->resource(CurrentGamutMask).value(); } else { return nullptr; } } bool KisCanvasResourceProvider::gamutMaskActive() const { return m_resourceManager->resource(GamutMaskActive).toBool(); } KisPaintOpPresetSP KisCanvasResourceProvider::currentPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(CurrentPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(CurrentPaintOpPreset, v); } KisPaintOpPresetSP KisCanvasResourceProvider::previousPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(PreviousPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPreviousPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPreviousPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(PreviousPaintOpPreset, v); } void KisCanvasResourceProvider::slotPatternActivated(KoResource * res) { KoPattern *pattern = dynamic_cast(res); QVariant v; v.setValue(pattern); m_resourceManager->setResource(CurrentPattern, v); emit sigPatternChanged(pattern); } void KisCanvasResourceProvider::slotGradientActivated(KoResource *res) { KoAbstractGradient * gradient = dynamic_cast(res); QVariant v; v.setValue(gradient); m_resourceManager->setResource(CurrentGradient, v); emit sigGradientChanged(gradient); } void KisCanvasResourceProvider::setBGColor(const KoColor& c) { QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceProvider::BackgroundColor, v); emit sigBGColorChanged(c); } void KisCanvasResourceProvider::setFGColor(const KoColor& c) { m_fGChanged = true; QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceProvider::ForegroundColor, v); emit sigFGColorChanged(c); } void KisCanvasResourceProvider::slotSetFGColor(const KoColor& c) { setFGColor(c); } void KisCanvasResourceProvider::slotSetBGColor(const KoColor& c) { setBGColor(c); } void KisCanvasResourceProvider::slotNodeActivated(const KisNodeSP node) { QVariant v; v.setValue(KisNodeWSP(node)); m_resourceManager->setResource(CurrentKritaNode, v); emit sigNodeChanged(currentNode()); } void KisCanvasResourceProvider::slotImageSizeChanged() { if (KisImageWSP image = m_view->image()) { float fw = image->width() / image->xRes(); float fh = image->height() / image->yRes(); QSizeF postscriptSize(fw, fh); m_resourceManager->setResource(KoCanvasResourceProvider::PageSize, postscriptSize); } } void KisCanvasResourceProvider::slotOnScreenResolutionChanged() { KisImageWSP image = m_view->image(); KisCanvas2 *canvas = m_view->canvasBase(); if(!image || !canvas) return; qreal zoomX, zoomY; canvas->coordinatesConverter()->zoom(&zoomX, &zoomY); qreal scaleX = zoomX / image->xRes(); qreal scaleY = zoomY / image->yRes(); emit sigOnScreenResolutionChanged(scaleX, scaleY); } void KisCanvasResourceProvider::slotCanvasResourceChanged(int key, const QVariant & res) { if(key == KoCanvasResourceProvider::ForegroundColor || key == KoCanvasResourceProvider::BackgroundColor) { - KoAbstractGradient* resource = KoResourceServerProvider::instance()->gradientServer()->resources()[0]; - KoStopGradient* stopGradient = dynamic_cast(resource); - if(stopGradient) { - QList stops; - stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), fgColor().colorSpace())); - stopGradient->setStops(stops); - KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); - } - resource = KoResourceServerProvider::instance()->gradientServer()->resources()[1]; - stopGradient = dynamic_cast(resource); - if(stopGradient) { - QList stops; - stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, bgColor()); - stopGradient->setStops(stops); - KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); + QList resources = KoResourceServerProvider::instance()->gradientServer()->resources(); + for (int i = 0; i < resources.count(); i++) { + KoAbstractGradient* gradient = resources[i]; + //KoStopGradient* stopGradient = dynamic_cast(resource); + //if (stopGradient && stopGradient->hasVariableStops()) { + //convert all foreground and background stops to the new colors + //stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), fgColor().colorSpace())); + if(gradient->hasVariableColors()){ + gradient->setVariableColors(fgColor(), bgColor()); + KoResourceServerProvider::instance()->gradientServer()->updateResource(gradient); + } } + //resource = KoResourceServerProvider::instance()->gradientServer()->resources()[1]; + //stopGradient = dynamic_cast(resource); + //if(stopGradient) { + // QList stops; + // stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, bgColor()); + // stopGradient->setStops(stops); + // KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); + //} } switch (key) { case(KoCanvasResourceProvider::ForegroundColor): m_fGChanged = true; emit sigFGColorChanged(res.value()); break; case(KoCanvasResourceProvider::BackgroundColor): emit sigBGColorChanged(res.value()); break; case(CurrentPattern): emit sigPatternChanged(static_cast(res.value())); break; case(CurrentGradient): emit sigGradientChanged(static_cast(res.value())); break; case(CurrentKritaNode) : emit sigNodeChanged(currentNode()); break; case (Opacity): { emit sigOpacityChanged(res.toDouble()); } default: ; // Do nothing }; } void KisCanvasResourceProvider::setCurrentCompositeOp(const QString& compositeOp) { m_resourceManager->setResource(CurrentCompositeOp, QVariant::fromValue(compositeOp)); } QString KisCanvasResourceProvider::currentCompositeOp() const { return m_resourceManager->resource(CurrentCompositeOp).value(); } bool KisCanvasResourceProvider::eraserMode() const { return m_resourceManager->resource(EraserMode).toBool(); } void KisCanvasResourceProvider::setEraserMode(bool value) { m_resourceManager->setResource(EraserMode, QVariant::fromValue(value)); } void KisCanvasResourceProvider::slotPainting() { if (m_fGChanged) { emit sigFGColorUsed(fgColor()); m_fGChanged = false; } } void KisCanvasResourceProvider::slotGamutMaskActivated(KoGamutMask *mask) { QVariant v; v.setValue(mask); m_resourceManager->setResource(CurrentGamutMask, v); m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(true)); emit sigGamutMaskChanged(mask); } void KisCanvasResourceProvider::slotGamutMaskUnset() { m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(false)); m_resourceManager->clearResource(CurrentGamutMask); emit sigGamutMaskUnset(); } void KisCanvasResourceProvider::slotGamutMaskPreviewUpdate() { emit sigGamutMaskPreviewUpdate(); } void KisCanvasResourceProvider::slotGamutMaskDeactivate() { m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(false)); emit sigGamutMaskDeactivated(); } QList > KisCanvasResourceProvider::perspectiveGrids() const { return m_perspectiveGrids; } void KisCanvasResourceProvider::addPerspectiveGrid(KisAbstractPerspectiveGrid* grid) { m_perspectiveGrids.append(grid); } void KisCanvasResourceProvider::removePerspectiveGrid(KisAbstractPerspectiveGrid* grid) { m_perspectiveGrids.removeOne(grid); } void KisCanvasResourceProvider::clearPerspectiveGrids() { m_perspectiveGrids.clear(); } void KisCanvasResourceProvider::setMirrorHorizontal(bool mirrorHorizontal) { m_resourceManager->setResource(MirrorHorizontal, mirrorHorizontal); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontal() const { return m_resourceManager->resource(MirrorHorizontal).toBool(); } void KisCanvasResourceProvider::setMirrorVertical(bool mirrorVertical) { m_resourceManager->setResource(MirrorVertical, mirrorVertical); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVertical() const { return m_resourceManager->resource(MirrorVertical).toBool(); } void KisCanvasResourceProvider::setMirrorHorizontalLock(bool isLocked) { m_resourceManager->setResource(MirrorHorizontalLock, isLocked); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontalLock() { return m_resourceManager->resource(MirrorHorizontalLock).toBool(); } void KisCanvasResourceProvider::setMirrorVerticalLock(bool isLocked) { m_resourceManager->setResource(MirrorVerticalLock, isLocked); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVerticalHideDecorations() { return m_resourceManager->resource(MirrorVerticalHideDecorations).toBool(); } void KisCanvasResourceProvider::setMirrorVerticalHideDecorations(bool hide) { m_resourceManager->setResource(MirrorVerticalHideDecorations, hide); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontalHideDecorations() { return m_resourceManager->resource(MirrorHorizontalHideDecorations).toBool(); } void KisCanvasResourceProvider::setMirrorHorizontalHideDecorations(bool hide) { m_resourceManager->setResource(MirrorHorizontalHideDecorations, hide); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVerticalLock() { return m_resourceManager->resource(MirrorVerticalLock).toBool(); } void KisCanvasResourceProvider::mirrorVerticalMoveCanvasToCenter() { emit moveMirrorVerticalCenter(); } void KisCanvasResourceProvider::mirrorHorizontalMoveCanvasToCenter() { emit moveMirrorHorizontalCenter(); } void KisCanvasResourceProvider::setOpacity(qreal opacity) { m_resourceManager->setResource(Opacity, opacity); } qreal KisCanvasResourceProvider::opacity() const { return m_resourceManager->resource(Opacity).toReal(); } void KisCanvasResourceProvider::setFlow(qreal flow) { m_resourceManager->setResource(Flow, flow); } qreal KisCanvasResourceProvider::flow() const { return m_resourceManager->resource(Flow).toReal(); } void KisCanvasResourceProvider::setSize(qreal size) { m_resourceManager->setResource(Size, size); } qreal KisCanvasResourceProvider::size() const { return m_resourceManager->resource(Size).toReal(); } void KisCanvasResourceProvider::setPatternSize(qreal size) { m_resourceManager->setResource(PatternSize, size); } qreal KisCanvasResourceProvider::patternSize() const { return m_resourceManager->resource(PatternSize).toReal(); } void KisCanvasResourceProvider::setGlobalAlphaLock(bool lock) { m_resourceManager->setResource(GlobalAlphaLock, lock); } bool KisCanvasResourceProvider::globalAlphaLock() const { return m_resourceManager->resource(GlobalAlphaLock).toBool(); } void KisCanvasResourceProvider::setDisablePressure(bool value) { m_resourceManager->setResource(DisablePressure, value); } bool KisCanvasResourceProvider::disablePressure() const { return m_resourceManager->resource(DisablePressure).toBool(); } void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResource* workspace) { emit sigLoadingWorkspace(workspace); } void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResource* workspace) { emit sigSavingWorkspace(workspace); } diff --git a/libs/ui/kis_control_frame.cpp b/libs/ui/kis_control_frame.cpp index 765bc074fa..7e27eea62d 100644 --- a/libs/ui/kis_control_frame.cpp +++ b/libs/ui/kis_control_frame.cpp @@ -1,239 +1,243 @@ /* * kis_control_frame.cc - part of Krita * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Sven Langkamp * Copyright (c) 2006 Boudewijn Rempt * * 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.g * * 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 "kis_control_frame.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "kis_canvas_resource_provider.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_gradient_chooser.h" #include "KisViewManager.h" #include "kis_config.h" #include "kis_paintop_box.h" #include "kis_custom_pattern.h" #include "widgets/kis_pattern_chooser.h" #include "kis_favorite_resource_manager.h" #include "kis_display_color_converter.h" #include KisControlFrame::KisControlFrame(KisViewManager *view, QWidget *parent, const char* name) : QObject(view) , m_viewManager(view) , m_patternWidget(0) , m_gradientWidget(0) , m_patternChooserPopup(0) , m_gradientChooserPopup(0) , m_paintopBox(0) { setObjectName(name); m_font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); m_patternWidget = new KisIconWidget(parent, "patterns"); m_patternWidget->setToolTip(i18n("Fill Patterns")); m_patternWidget->setFixedSize(32, 32); m_gradientWidget = new KisIconWidget(parent, "gradients"); m_gradientWidget->setToolTip(i18n("Gradients")); m_gradientWidget->setFixedSize(32, 32); } void KisControlFrame::setup(QWidget *parent) { createPatternsChooser(m_viewManager); createGradientsChooser(m_viewManager); QWidgetAction *action = new QWidgetAction(this); action->setText(i18n("&Patterns")); m_viewManager->actionCollection()->addAction("patterns", action); action->setDefaultWidget(m_patternWidget); action = new QWidgetAction(this); action->setText(i18n("&Gradients")); m_viewManager->actionCollection()->addAction("gradients", action); action->setDefaultWidget(m_gradientWidget); // XXX: KOMVC we don't have a canvas here yet, needs a setImageView const KoColorDisplayRendererInterface *displayRenderer = \ KisDisplayColorConverter::dumbConverterInstance()->displayRendererInterface(); m_dual = new KoDualColorButton(m_viewManager->canvasResourceProvider()->fgColor(), m_viewManager->canvasResourceProvider()->bgColor(), displayRenderer, m_viewManager->mainWindow(), m_viewManager->mainWindow()); m_dual->setPopDialog(true); action = new QWidgetAction(this); action->setText(i18n("&Color")); m_viewManager->actionCollection()->addAction("dual", action); action->setDefaultWidget(m_dual); connect(m_dual, SIGNAL(foregroundColorChanged(KoColor)), m_viewManager->canvasResourceProvider(), SLOT(slotSetFGColor(KoColor))); connect(m_dual, SIGNAL(backgroundColorChanged(KoColor)), m_viewManager->canvasResourceProvider(), SLOT(slotSetBGColor(KoColor))); connect(m_viewManager->canvasResourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), m_dual, SLOT(setForegroundColor(KoColor))); connect(m_viewManager->canvasResourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), m_dual, SLOT(setBackgroundColor(KoColor))); connect(m_viewManager->canvasResourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), m_gradientWidget, SLOT(update())); connect(m_viewManager->canvasResourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), m_gradientWidget, SLOT(update())); m_dual->setFixedSize(28, 28); connect(m_viewManager, SIGNAL(viewChanged()), SLOT(slotUpdateDisplayRenderer())); m_paintopBox = new KisPaintopBox(m_viewManager, parent, "paintopbox"); action = new QWidgetAction(this); action->setText(i18n("&Painter's Tools")); m_viewManager->actionCollection()->addAction("paintops", action); action->setDefaultWidget(m_paintopBox); } void KisControlFrame::slotUpdateDisplayRenderer() { if (m_viewManager->canvasBase()){ m_dual->setDisplayRenderer(m_viewManager->canvasBase()->displayColorConverter()->displayRendererInterface()); m_dual->setColorSpace(m_viewManager->canvasBase()->image()->colorSpace()); m_viewManager->canvasBase()->image()->disconnect(m_dual); connect(m_viewManager->canvasBase()->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), m_dual, SLOT(setColorSpace(const KoColorSpace*)), Qt::UniqueConnection); } else if (m_viewManager->viewCount()==0) { m_dual->setDisplayRenderer(); } } void KisControlFrame::slotSetPattern(KoPattern * pattern) { m_patternWidget->setResource(pattern); m_patternChooser->setCurrentPattern(pattern); } void KisControlFrame::slotSetGradient(KoAbstractGradient * gradient) { m_gradientWidget->setResource(gradient); } void KisControlFrame::createPatternsChooser(KisViewManager * view) { if (m_patternChooserPopup) delete m_patternChooserPopup; m_patternChooserPopup = new QWidget(m_patternWidget); m_patternChooserPopup->setObjectName("pattern_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_patternChooserPopup); l2->setObjectName("patternpopuplayout"); m_patternsTab = new QTabWidget(m_patternChooserPopup); m_patternsTab->setObjectName("patternstab"); m_patternsTab->setFocusPolicy(Qt::NoFocus); m_patternsTab->setFont(m_font); l2->addWidget(m_patternsTab); m_patternChooser = new KisPatternChooser(m_patternChooserPopup); m_patternChooser->setFont(m_font); QWidget *patternChooserPage = new QWidget(m_patternChooserPopup); QHBoxLayout *patternChooserPageLayout = new QHBoxLayout(patternChooserPage); patternChooserPageLayout->addWidget(m_patternChooser); m_patternsTab->addTab(patternChooserPage, i18n("Patterns")); KisCustomPattern* customPatterns = new KisCustomPattern(0, "custompatterns", i18n("Custom Pattern"), m_viewManager); customPatterns->setFont(m_font); m_patternsTab->addTab(customPatterns, i18n("Custom Pattern")); connect(m_patternChooser, SIGNAL(resourceSelected(KoResource*)), view->canvasResourceProvider(), SLOT(slotPatternActivated(KoResource*))); connect(customPatterns, SIGNAL(activatedResource(KoResource*)), view->canvasResourceProvider(), SLOT(slotPatternActivated(KoResource*))); connect(view->canvasResourceProvider(), SIGNAL(sigPatternChanged(KoPattern*)), this, SLOT(slotSetPattern(KoPattern*))); m_patternChooser->setCurrentItem(0, 0); if (m_patternChooser->currentResource() && view->canvasResourceProvider()) { view->canvasResourceProvider()->slotPatternActivated(m_patternChooser->currentResource()); } m_patternWidget->setPopupWidget(m_patternChooserPopup); } void KisControlFrame::createGradientsChooser(KisViewManager * view) { if (m_gradientChooserPopup) { delete m_gradientChooserPopup; m_gradientChooserPopup = 0; } m_gradientChooserPopup = new QWidget(m_gradientWidget); m_gradientChooserPopup->setObjectName("gradient_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_gradientChooserPopup); l2->setObjectName("gradientpopuplayout"); m_gradientTab = new QTabWidget(m_gradientChooserPopup); m_gradientTab->setObjectName("gradientstab"); m_gradientTab->setFocusPolicy(Qt::NoFocus); m_gradientTab->setFont(m_font); l2->addWidget(m_gradientTab); m_gradientChooser = new KisGradientChooser(m_gradientChooserPopup); m_gradientChooser->setFont(m_font); m_gradientTab->addTab(m_gradientChooser, i18n("Gradients")); connect(m_gradientChooser, SIGNAL(resourceSelected(KoResource*)), view->canvasResourceProvider(), SLOT(slotGradientActivated(KoResource*))); connect (view->mainWindow(), SIGNAL(themeChanged()), m_gradientChooser, SLOT(slotUpdateIcons())); connect(view->canvasResourceProvider(), SIGNAL(sigGradientChanged(KoAbstractGradient*)), this, SLOT(slotSetGradient(KoAbstractGradient*))); + connect(view->canvasResourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), m_gradientChooser, SLOT(setForegroundColor(KoColor))); + connect(view->canvasResourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), m_gradientChooser, SLOT(setBackgroundColor(KoColor))); + + m_gradientChooser->setCurrentItem(0, 0); if (m_gradientChooser->currentResource() && view->canvasResourceProvider()) view->canvasResourceProvider()->slotGradientActivated(m_gradientChooser->currentResource()); m_gradientWidget->setPopupWidget(m_gradientChooserPopup); } diff --git a/libs/ui/kis_stopgradient_editor.cpp b/libs/ui/kis_stopgradient_editor.cpp index 51867bd096..07da6d8b5d 100644 --- a/libs/ui/kis_stopgradient_editor.cpp +++ b/libs/ui/kis_stopgradient_editor.cpp @@ -1,257 +1,315 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * 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 "kis_stopgradient_editor.h" #include #include #include #include #include #include #include #include "kis_debug.h" #include /****************************** KisStopGradientEditor ******************************/ KisStopGradientEditor::KisStopGradientEditor(QWidget *parent) : QWidget(parent), - m_gradient(0) + m_gradient(0), + m_fgColor(KoColor()), + m_bgColor(KoColor()) { setupUi(this); connect(gradientSlider, SIGNAL(sigSelectedStop(int)), this, SLOT(stopChanged(int))); connect(nameedit, SIGNAL(editingFinished()), this, SLOT(nameChanged())); connect(colorButton, SIGNAL(changed(KoColor)), SLOT(colorChanged(KoColor))); + + connect(colorRadioButton, SIGNAL(toggled(bool)), this, SLOT(stopTypeChanged())); + connect(foregroundRadioButton, SIGNAL(toggled(bool)), this, SLOT(stopTypeChanged())); + connect(backgroundRadioButton, SIGNAL(toggled(bool)), this, SLOT(stopTypeChanged())); + opacitySlider->setPrefix(i18n("Opacity: ")); opacitySlider->setRange(0.0, 1.0, 2); connect(opacitySlider, SIGNAL(valueChanged(qreal)), this, SLOT(opacityChanged(qreal))); buttonReverse->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); buttonReverse->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverse); connect(buttonReverse, SIGNAL(pressed()), SLOT(reverse())); buttonReverseSecond->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); buttonReverseSecond->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverseSecond); connect(buttonReverseSecond, SIGNAL(clicked()), SLOT(reverse())); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); setCompactMode(false); setGradient(0); stopChanged(-1); } -KisStopGradientEditor::KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption) +KisStopGradientEditor::KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption, + KoColor fgColor, KoColor bgColor) : KisStopGradientEditor(parent) { + m_fgColor = fgColor; + m_bgColor = bgColor; setObjectName(name); setWindowTitle(caption); setGradient(gradient); } void KisStopGradientEditor::setCompactMode(bool value) { lblName->setVisible(!value); buttonReverse->setVisible(!value); nameedit->setVisible(!value); buttonReverseSecond->setVisible(value); } void KisStopGradientEditor::setGradient(KoStopGradient *gradient) { m_gradient = gradient; setEnabled(m_gradient); if (m_gradient) { gradientSlider->setGradientResource(m_gradient); nameedit->setText(gradient->name()); stopChanged(gradientSlider->selectedStop()); } emit sigGradientChanged(); } void KisStopGradientEditor::notifyGlobalColorChanged(const KoColor &color) { if (colorButton->isEnabled() && color != colorButton->color()) { colorButton->setColor(color); } } boost::optional KisStopGradientEditor::currentActiveStopColor() const { if (!colorButton->isEnabled()) return boost::none; return colorButton->color(); } void KisStopGradientEditor::stopChanged(int stop) { if (!m_gradient) return; const bool hasStopSelected = stop >= 0; opacitySlider->setEnabled(hasStopSelected); colorButton->setEnabled(hasStopSelected); stopLabel->setEnabled(hasStopSelected); + foregroundRadioButton->setEnabled(hasStopSelected); + backgroundRadioButton->setEnabled(hasStopSelected); + colorRadioButton->setEnabled(hasStopSelected); if (hasStopSelected) { - KoColor color = m_gradient->stops()[stop].second; + KoColor color; + KoGradientStopType type = m_gradient->stops()[stop].second.second; + qDebug() << "GradientEditor::stopChanged: stop " << stop << " type: " << type; + if (type == FOREGROUNDSTOP) { + foregroundRadioButton->setChecked(true); + color = m_fgColor;// KoColor(m_fgColor, m_gradient->stops()[stop].second.first.colorSpace()); + } + else if (type == BACKGROUNDSTOP) { + backgroundRadioButton->setChecked(true); + color = m_bgColor; // KoColor(m_bgColor, m_gradient->stops()[stop].second.first.colorSpace()); + } + else { + colorRadioButton->setChecked(true); + color = m_gradient->stops()[stop].second.first; + } + opacitySlider->setValue(color.opacityF()); - + color.setOpacity(1.0); colorButton->setColor(color); + } emit sigGradientChanged(); } +void KisStopGradientEditor::stopTypeChanged() { + QList stops = m_gradient->stops(); + int currentStop = gradientSlider->selectedStop(); + double t = stops[currentStop].first; + KoColor color = stops[currentStop].second.first; + + KoGradientStopType type; + if (foregroundRadioButton->isChecked()) { + type = FOREGROUNDSTOP; + color = KoColor(m_fgColor, color.colorSpace()); + } else if (backgroundRadioButton->isChecked()) { + type = BACKGROUNDSTOP; + color = KoColor(m_bgColor, color.colorSpace()); + } + else { + type = COLORSTOP; + } + + stops.removeAt(currentStop); + stops.insert(currentStop, KoGradientStop(t, KoGradientStopInfo(color, type))); + m_gradient->setStops(stops); + gradientSlider->update(); //setSelectedStopType(type); + emit sigGradientChanged(); +} + void KisStopGradientEditor::colorChanged(const KoColor& color) { if (!m_gradient) return; QList stops = m_gradient->stops(); int currentStop = gradientSlider->selectedStop(); double t = stops[currentStop].first; - KoColor c(color, stops[currentStop].second.colorSpace()); - c.setOpacity(stops[currentStop].second.opacityU8()); + KoColor c(color, stops[currentStop].second.first.colorSpace()); + c.setOpacity(stops[currentStop].second.first.opacityU8()); + + KoGradientStopType type = stops[currentStop].second.second; stops.removeAt(currentStop); - stops.insert(currentStop, KoGradientStop(t, c)); - + stops.insert(currentStop, KoGradientStop(t, KoGradientStopInfo(c, type))); + qDebug() << "GradientEditor::colorChanged: stop " << currentStop << " type: " << stops[currentStop].second.second; m_gradient->setStops(stops); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::opacityChanged(qreal value) { if (!m_gradient) return; QList stops = m_gradient->stops(); int currentStop = gradientSlider->selectedStop(); double t = stops[currentStop].first; - KoColor c = stops[currentStop].second; + KoColor c = stops[currentStop].second.first; c.setOpacity(value); + KoGradientStopType type = stops[currentStop].second.second; + stops.removeAt(currentStop); - stops.insert(currentStop, KoGradientStop(t, c)); - + stops.insert(currentStop, KoGradientStop(t, KoGradientStopInfo(c, type))); + qDebug() << "GradientEditor::opacityChanged: stop " << currentStop << " type: " << stops[currentStop].second.second; m_gradient->setStops(stops); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::nameChanged() { if (!m_gradient) return; m_gradient->setName(nameedit->text()); emit sigGradientChanged(); } void KisStopGradientEditor::reverse() { if (!m_gradient) return; QList stops = m_gradient->stops(); QList reversedStops; for(const KoGradientStop& stop : stops) { reversedStops.push_front(KoGradientStop(1 - stop.first, stop.second)); } m_gradient->setStops(reversedStops); gradientSlider->setSelectedStop(stops.size() - 1 - gradientSlider->selectedStop()); emit sigGradientChanged(); } void KisStopGradientEditor::sortByValue( SortFlags flags = SORT_ASCENDING ) { if (!m_gradient) return; bool ascending = (flags & SORT_ASCENDING) > 0; bool evenDistribution = (flags & EVEN_DISTRIBUTION) > 0; QList stops = m_gradient->stops(); const int stopCount = stops.size(); QList sortedStops; std::sort(stops.begin(), stops.end(), KoGradientStopValueSort()); int stopIndex = 0; for (const KoGradientStop& stop : stops) { - const float value = evenDistribution ? (float)stopIndex / (float)(stopCount - 1) : stop.second.toQColor().valueF(); + const float value = evenDistribution ? (float)stopIndex / (float)(stopCount - 1) : stop.second.first.toQColor().valueF(); const float position = ascending ? value : 1.f - value; if (ascending) { sortedStops.push_back(KoGradientStop(position, stop.second)); } else { sortedStops.push_front(KoGradientStop(position, stop.second)); } stopIndex++; } m_gradient->setStops(sortedStops); gradientSlider->setSelectedStop(stopCount - 1); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::showContextMenu(const QPoint &origin) { QMenu contextMenu(i18n("Options"), this); QAction reverseValues(i18n("Reverse Values"), this); connect(&reverseValues, &QAction::triggered, this, &KisStopGradientEditor::reverse); QAction sortAscendingValues(i18n("Sort by Value"), this); connect(&sortAscendingValues, &QAction::triggered, this, [this]{ this->sortByValue(SORT_ASCENDING); } ); QAction sortAscendingDistributed(i18n("Sort by Value (Even Distribution)"), this); connect(&sortAscendingDistributed, &QAction::triggered, this, [this]{ this->sortByValue(SORT_ASCENDING | EVEN_DISTRIBUTION);} ); contextMenu.addAction(&reverseValues); contextMenu.addSeparator(); contextMenu.addAction(&sortAscendingValues); contextMenu.addAction(&sortAscendingDistributed); contextMenu.exec(mapToGlobal(origin)); } diff --git a/libs/ui/kis_stopgradient_editor.h b/libs/ui/kis_stopgradient_editor.h index 7560e5feda..141a458e7e 100644 --- a/libs/ui/kis_stopgradient_editor.h +++ b/libs/ui/kis_stopgradient_editor.h @@ -1,68 +1,71 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * 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_STOPGRADIENT_EDITOR_H_ #define _KIS_STOPGRADIENT_EDITOR_H_ #include "kritaui_export.h" #include "ui_wdgstopgradienteditor.h" #include class KoStopGradient; class KRITAUI_EXPORT KisStopGradientEditor : public QWidget, public Ui::KisWdgStopGradientEditor { Q_OBJECT public: enum SortFlag { SORT_ASCENDING = 1 << 0, EVEN_DISTRIBUTION = 1 << 1 }; Q_DECLARE_FLAGS( SortFlags, SortFlag); KisStopGradientEditor(QWidget *parent); - KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption); + KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption, KoColor fgColor, KoColor bgColor); void setCompactMode(bool value); void setGradient(KoStopGradient* gradient); void notifyGlobalColorChanged(const KoColor &color); boost::optional currentActiveStopColor() const; Q_SIGNALS: void sigGradientChanged(); private: KoStopGradient* m_gradient; + KoColor m_fgColor, m_bgColor; + private Q_SLOTS: void stopChanged(int stop); + void stopTypeChanged(); void colorChanged(const KoColor& color); void opacityChanged(qreal value); void nameChanged(); void reverse(); void sortByValue(SortFlags flags); void showContextMenu( const class QPoint& origin ); }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisStopGradientEditor::SortFlags); #endif diff --git a/libs/ui/widgets/kis_gradient_chooser.cc b/libs/ui/widgets/kis_gradient_chooser.cc index ebfa522d34..22a9fd6a14 100644 --- a/libs/ui/widgets/kis_gradient_chooser.cc +++ b/libs/ui/widgets/kis_gradient_chooser.cc @@ -1,210 +1,220 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (C) 2011 Srikanth Tiyyagura * * 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 "widgets/kis_gradient_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisViewManager.h" #include "kis_global.h" #include "kis_autogradient.h" #include "kis_canvas_resource_provider.h" #include "kis_stopgradient_editor.h" -KisCustomGradientDialog::KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget *parent, const char *name) +KisCustomGradientDialog::KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget *parent, const char *name, + KoColor fgColor, KoColor bgColor) : KoDialog(parent, Qt::Dialog) { setButtons(Close); setDefaultButton(Close); setObjectName(name); setModal(false); KoStopGradient* stopGradient = dynamic_cast(gradient); if (stopGradient) { - m_page = new KisStopGradientEditor(stopGradient, this, "autogradient", i18n("Custom Stop Gradient")); + m_page = new KisStopGradientEditor(stopGradient, this, "autogradient", i18n("Custom Stop Gradient"), fgColor, bgColor); } else { KoSegmentGradient* segmentedGradient = dynamic_cast(gradient); if (segmentedGradient) { - m_page = new KisAutogradientEditor(segmentedGradient, this, "autogradient", i18n("Custom Segmented Gradient")); + m_page = new KisAutogradientEditor(segmentedGradient, this, "autogradient", i18n("Custom Segmented Gradient"), fgColor, bgColor); } } setCaption(m_page->windowTitle()); setMainWidget(m_page); } KisGradientChooser::KisGradientChooser(QWidget *parent, const char *name) : QFrame(parent) { setObjectName(name); m_lbName = new QLabel(); KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QSharedPointer adapter (new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->showTaggingBar(true); m_itemChooser->setFixedSize(250, 250); m_itemChooser->setColumnCount(1); m_itemChooser->itemView()->keepAspectRatio(false); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(update(KoResource*))); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SIGNAL(resourceSelected(KoResource*))); QWidget* buttonWidget = new QWidget(this); QHBoxLayout* buttonLayout = new QHBoxLayout(buttonWidget); m_addGradient = new QToolButton(this); m_addGradient->setText(i18n("Add...")); m_addGradient->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); connect(m_addGradient, SIGNAL(clicked()), this, SLOT(addStopGradient())); buttonLayout->addWidget(m_addGradient); QMenu *menuAddGradient = new QMenu(m_addGradient); QAction* addStopGradient = new QAction(i18n("Stop gradient"), this); connect(addStopGradient, SIGNAL(triggered(bool)), this, SLOT(addStopGradient())); menuAddGradient->addAction(addStopGradient); QAction* addSegmentedGradient = new QAction(i18n("Segmented gradient"), this); connect(addSegmentedGradient, SIGNAL(triggered(bool)), this, SLOT(addSegmentedGradient())); menuAddGradient->addAction(addSegmentedGradient); m_addGradient->setMenu(menuAddGradient); m_addGradient->setPopupMode(QToolButton::MenuButtonPopup); m_editGradient = new QPushButton(); m_editGradient->setText(i18n("Edit...")); m_editGradient->setEnabled(false); connect(m_editGradient, SIGNAL(clicked()), this, SLOT(editGradient())); buttonLayout->addWidget(m_editGradient); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setObjectName("main layout"); mainLayout->setMargin(2); mainLayout->addWidget(m_lbName); mainLayout->addWidget(m_itemChooser, 10); mainLayout->addWidget(buttonWidget); slotUpdateIcons(); setLayout(mainLayout); } KisGradientChooser::~KisGradientChooser() { } KoResource *KisGradientChooser::currentResource() { return m_itemChooser->currentResource(); } void KisGradientChooser::setCurrentResource(KoResource *resource) { m_itemChooser->setCurrentResource(resource); } void KisGradientChooser::setCurrentItem(int row, int column) { m_itemChooser->setCurrentItem(row, column); if (currentResource()) update(currentResource()); } void KisGradientChooser::slotUpdateIcons() { if (m_addGradient && m_editGradient) { m_addGradient->setIcon(KisIconUtils::loadIcon("list-add")); m_editGradient->setIcon(KisIconUtils::loadIcon("configure")); } } +void KisGradientChooser::setForegroundColor(KoColor color) { + m_foregroundColor = color; +} + +void KisGradientChooser::setBackgroundColor(KoColor color) { + m_backgroundColor = color; +} + void KisGradientChooser::update(KoResource * resource) { KoAbstractGradient *gradient = static_cast(resource); m_lbName->setText(gradient ? i18n(gradient->name().toUtf8().data()) : ""); m_editGradient->setEnabled(gradient && gradient->removable()); } void KisGradientChooser::addStopGradient() { KoStopGradient* gradient = new KoStopGradient(""); QList stops; - stops << KoGradientStop(0.0, KoColor(QColor(250, 250, 0), KoColorSpaceRegistry::instance()->rgb8())) << KoGradientStop(1.0, KoColor(QColor(255, 0, 0, 255), KoColorSpaceRegistry::instance()->rgb8())); + stops << KoGradientStop(0.0, KoGradientStopInfo(KoColor(QColor(250, 250, 0), KoColorSpaceRegistry::instance()->rgb8()), COLORSTOP)) + << KoGradientStop(1.0, KoGradientStopInfo(KoColor(QColor(255, 0, 0, 255), KoColorSpaceRegistry::instance()->rgb8()), COLORSTOP)); gradient->setType(QGradient::LinearGradient); gradient->setStops(stops); addGradient(gradient); } void KisGradientChooser::addSegmentedGradient() { KoSegmentGradient* gradient = new KoSegmentGradient(""); gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, 0.0, 1.0, 0.5, Qt::black, Qt::white); gradient->setName(i18n("unnamed")); addGradient(gradient); } void KisGradientChooser::addGradient(KoAbstractGradient* gradient) { KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QString saveLocation = rserver->saveLocation(); - KisCustomGradientDialog dialog(gradient, this, "KisCustomGradientDialog"); + KisCustomGradientDialog dialog(gradient, this, "KisCustomGradientDialog", m_foregroundColor, m_backgroundColor); dialog.exec(); gradient->setFilename(saveLocation + gradient->name() + gradient->defaultFileExtension()); gradient->setValid(true); rserver->addResource(gradient); m_itemChooser->setCurrentResource(gradient); } void KisGradientChooser::editGradient() { - KisCustomGradientDialog dialog(static_cast(currentResource()), this, "KisCustomGradientDialog"); + KisCustomGradientDialog dialog(static_cast(currentResource()), this, "KisCustomGradientDialog", m_foregroundColor, m_backgroundColor); dialog.exec(); } diff --git a/libs/ui/widgets/kis_gradient_chooser.h b/libs/ui/widgets/kis_gradient_chooser.h index abfbdb16fc..6c3f85d1d6 100644 --- a/libs/ui/widgets/kis_gradient_chooser.h +++ b/libs/ui/widgets/kis_gradient_chooser.h @@ -1,91 +1,96 @@ /* * Copyright (c) 2004 Adrian Page * * 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_GRADIENT_CHOOSER_H_ #define KIS_GRADIENT_CHOOSER_H_ #include +#include #include #include #include class KoAbstractGradient; class KoStopGradient; class KisViewManager; class QLabel; class QPushButton; class KisAutogradientEditor; class KoResource; class KoResourceItemChooser; class KisCustomGradientDialog : public KoDialog { Q_OBJECT public: - KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget *parent, const char *name); + KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget *parent, const char *name, KoColor fgColor, KoColor bgColor); private: QWidget * m_page; }; class KRITAUI_EXPORT KisGradientChooser : public QFrame { Q_OBJECT public: KisGradientChooser(QWidget *parent = 0, const char *name = 0); ~KisGradientChooser() override; /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected KoResource *currentResource(); void setCurrentResource(KoResource *resource); void setCurrentItem(int row, int column); Q_SIGNALS: /// Emitted when a resource was selected void resourceSelected(KoResource * resource); public Q_SLOTS: void slotUpdateIcons(); + void setForegroundColor(KoColor); + void setBackgroundColor(KoColor); private Q_SLOTS: virtual void update(KoResource * resource); void addStopGradient(); void addSegmentedGradient(); void editGradient(); private: void addGradient(KoAbstractGradient* gradient); private: QLabel *m_lbName; KoResourceItemChooser * m_itemChooser; + KoColor m_foregroundColor, m_backgroundColor; + QToolButton* m_addGradient; QPushButton* m_editGradient; }; #endif // KIS_GRADIENT_CHOOSER_H_ diff --git a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp index 210486ab72..89c02ab5f6 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp @@ -1,367 +1,386 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * 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 "widgets/kis_stopgradient_slider_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_global.h" #include "kis_debug.h" #include "krita_utils.h" KisStopGradientSliderWidget::KisStopGradientSliderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , m_selectedStop(0) , m_drag(0) { QLinearGradient defaultGradient; m_defaultGradient.reset(KoStopGradient::fromQGradient(&defaultGradient)); setGradientResource(0); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); setMouseTracking(true); QWindow *window = this->window()->windowHandle(); if (window) { connect(window, SIGNAL(screenChanged(QScreen*)), SLOT(updateHandleSize())); } updateHandleSize(); } void KisStopGradientSliderWidget::updateHandleSize() { QFontMetrics fm(font()); const int h = fm.height(); m_handleSize = QSize(0.34 * h, h); } int KisStopGradientSliderWidget::handleClickTolerance() const { // the size of the default text! return m_handleSize.width(); } void KisStopGradientSliderWidget::setGradientResource(KoStopGradient* gradient) { m_gradient = gradient ? gradient : m_defaultGradient.data(); if (m_gradient && m_selectedStop >= 0) { m_selectedStop = qBound(0, m_selectedStop, m_gradient->stops().size() - 1); emit sigSelectedStop(m_selectedStop); } else { m_selectedStop = -1; } } -void KisStopGradientSliderWidget::paintHandle(qreal position, const QColor &color, bool isSelected, QPainter *painter) +void KisStopGradientSliderWidget::setSelectedStopType(KoGradientStopType type) { + if (m_gradient && m_selectedStop >= 0) { + //QList stops = m_gradient->stops(); + //stops[m_selectedStop].second.second = type; + //m_gradient->setStops(stops); + //qDebug() << "GradientSliderWidget: selected stop set to: " << type; + //update(); + } +} + +void KisStopGradientSliderWidget::paintHandle(qreal position, const QColor &color, bool isSelected, QString text, QPainter *painter) { - const QRect handlesRect = this->handlesStipeRect(); + const QRect handlesRect = this->handlesStripeRect(); const int handleCenter = handlesRect.left() + position * handlesRect.width(); const int handlesHalfWidth = handlesRect.height() * 0.26; // = 1.0 / 0.66 * 0.34 / 2.0 <-- golden ratio QPolygon triangle(3); triangle[0] = QPoint(handleCenter, handlesRect.top()); triangle[1] = QPoint(handleCenter - handlesHalfWidth, handlesRect.bottom()); triangle[2] = QPoint(handleCenter + handlesHalfWidth, handlesRect.bottom()); + QPoint textPos(handleCenter - handlesHalfWidth, handlesRect.top() - handlesRect.height() / 2); + const qreal lineWidth = 1.0; if (!isSelected) { painter->setPen(QPen(palette().text(), lineWidth)); painter->setBrush(QBrush(color)); painter->setRenderHint(QPainter::Antialiasing); painter->drawPolygon(triangle); } else { painter->setPen(QPen(palette().highlight(), 1.5 * lineWidth)); painter->setBrush(QBrush(color)); painter->setRenderHint(QPainter::Antialiasing); painter->drawPolygon(triangle); } + painter->drawText(textPos, text); } void KisStopGradientSliderWidget::paintEvent(QPaintEvent* pe) { QWidget::paintEvent(pe); QPainter painter(this); painter.setPen(Qt::black); const QRect previewRect = gradientStripeRect(); KritaUtils::renderExactRect(&painter, kisGrowRect(previewRect, 1)); painter.drawRect(previewRect); if (m_gradient) { QImage image = m_gradient->generatePreview(previewRect.width(), previewRect.height()); if (!image.isNull()) { painter.drawImage(previewRect.topLeft(), image); } QList handlePositions = m_gradient->stops(); for (int i = 0; i < handlePositions.count(); i++) { - if (i == m_selectedStop) continue; + //if (i == m_selectedStop) continue; + QString text = ""; + if (handlePositions[i].second.second == FOREGROUNDSTOP) { + text = "FG"; + } else if (handlePositions[i].second.second == BACKGROUNDSTOP) { + text = "BG"; + } paintHandle(handlePositions[i].first, - handlePositions[i].second.toQColor(), - false, &painter); + handlePositions[i].second.first.toQColor(), + i == m_selectedStop, text, &painter); } - if (m_selectedStop >= 0) { - paintHandle(handlePositions[m_selectedStop].first, - handlePositions[m_selectedStop].second.toQColor(), - true, &painter); - } + //if (m_selectedStop >= 0) { + // paintHandle(handlePositions[m_selectedStop].first, + // handlePositions[m_selectedStop].second.first.toQColor(), + // true, &painter); + //} } } int findNearestHandle(qreal t, const qreal tolerance, const QList &stops) { int result = -1; qreal minDistance = tolerance; for (int i = 0; i < stops.size(); i++) { const KoGradientStop &stop = stops[i]; const qreal distance = qAbs(t - stop.first); if (distance < minDistance) { minDistance = distance; result = i; } } return result; } void KisStopGradientSliderWidget::mousePressEvent(QMouseEvent * e) { if (!allowedClickRegion(handleClickTolerance()).contains(e->pos())) { QWidget::mousePressEvent(e); return; } if (e->buttons() != Qt::LeftButton ) { QWidget::mousePressEvent(e); return; } - const QRect handlesRect = this->handlesStipeRect(); + const QRect handlesRect = this->handlesStripeRect(); const qreal t = (qreal(e->x()) - handlesRect.x()) / handlesRect.width(); const QList stops = m_gradient->stops(); const int clickedStop = findNearestHandle(t, qreal(handleClickTolerance()) / handlesRect.width(), stops); if (clickedStop >= 0) { if (m_selectedStop != clickedStop) { m_selectedStop = clickedStop; emit sigSelectedStop(m_selectedStop); } m_drag = true; } else { insertStop(qBound(0.0, t, 1.0)); m_drag = true; } update(); updateCursor(e->pos()); } void KisStopGradientSliderWidget::mouseReleaseEvent(QMouseEvent * e) { Q_UNUSED(e); m_drag = false; updateCursor(e->pos()); } int getNewInsertPosition(const KoGradientStop &stop, const QList &stops) { int result = 0; for (int i = 0; i < stops.size(); i++) { if (stop.first <= stops[i].first) break; result = i + 1; } return result; } void KisStopGradientSliderWidget::mouseMoveEvent(QMouseEvent * e) { updateCursor(e->pos()); if (m_drag) { - const QRect handlesRect = this->handlesStipeRect(); + const QRect handlesRect = this->handlesStripeRect(); double t = (qreal(e->x()) - handlesRect.x()) / handlesRect.width(); QList stops = m_gradient->stops(); if (t < -0.1 || t > 1.1) { if (stops.size() > 2 && m_selectedStop >= 0) { m_removedStop = stops[m_selectedStop]; stops.removeAt(m_selectedStop); m_selectedStop = -1; } } else { if (m_selectedStop < 0) { m_removedStop.first = qBound(0.0, t, 1.0); const int newPos = getNewInsertPosition(m_removedStop, stops); stops.insert(newPos, m_removedStop); m_selectedStop = newPos; } else { KoGradientStop draggedStop = stops[m_selectedStop]; draggedStop.first = qBound(0.0, t, 1.0); stops.removeAt(m_selectedStop); const int newPos = getNewInsertPosition(draggedStop, stops); stops.insert(newPos, draggedStop); m_selectedStop = newPos; } } m_gradient->setStops(stops); emit sigSelectedStop(m_selectedStop); update(); } else { QWidget::mouseMoveEvent(e); } } void KisStopGradientSliderWidget::updateCursor(const QPoint &pos) { const bool isInAllowedRegion = allowedClickRegion(handleClickTolerance()).contains(pos); QCursor currentCursor; if (isInAllowedRegion) { - const QRect handlesRect = this->handlesStipeRect(); + const QRect handlesRect = this->handlesStripeRect(); const qreal t = (qreal(pos.x()) - handlesRect.x()) / handlesRect.width(); const QList stops = m_gradient->stops(); const int clickedStop = findNearestHandle(t, qreal(handleClickTolerance()) / handlesRect.width(), stops); if (clickedStop >= 0) { currentCursor = m_drag ? Qt::ClosedHandCursor : Qt::OpenHandCursor; } } if (currentCursor.shape() != Qt::ArrowCursor) { setCursor(currentCursor); } else { unsetCursor(); } } void KisStopGradientSliderWidget::insertStop(double t) { KIS_ASSERT_RECOVER(t >= 0 && t <= 1.0 ) { t = qBound(0.0, t, 1.0); } QList stops = m_gradient->stops(); KoColor color; m_gradient->colorAt(color, t); - const KoGradientStop stop(t, color); + const KoGradientStop stop(t, KoGradientStopInfo(color, COLORSTOP)); const int newPos = getNewInsertPosition(stop, stops); stops.insert(newPos, stop); m_gradient->setStops(stops); m_selectedStop = newPos; emit sigSelectedStop(m_selectedStop); } QRect KisStopGradientSliderWidget::sliderRect() const { return QRect(QPoint(), size()).adjusted(m_handleSize.width(), 1, -m_handleSize.width(), -1); } QRect KisStopGradientSliderWidget::gradientStripeRect() const { const QRect rc = sliderRect(); return rc.adjusted(0, 0, 0, -m_handleSize.height()); } -QRect KisStopGradientSliderWidget::handlesStipeRect() const +QRect KisStopGradientSliderWidget::handlesStripeRect() const { const QRect rc = sliderRect(); return rc.adjusted(0, rc.height() - m_handleSize.height(), 0, 0); } QRegion KisStopGradientSliderWidget::allowedClickRegion(int tolerance) const { QRegion result; result += sliderRect(); - result += handlesStipeRect().adjusted(-tolerance, 0, tolerance, 0); + result += handlesStripeRect().adjusted(-tolerance, 0, tolerance, 0); return result; } int KisStopGradientSliderWidget::selectedStop() { return m_selectedStop; } void KisStopGradientSliderWidget::setSelectedStop(int selected) { m_selectedStop = selected; emit sigSelectedStop(m_selectedStop); update(); } int KisStopGradientSliderWidget::minimalHeight() const { QFontMetrics fm(font()); const int h = fm.height(); QStyleOptionToolButton opt; QSize sz = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(h, h), this); return sz.height() + m_handleSize.height(); } QSize KisStopGradientSliderWidget::sizeHint() const { const int h = minimalHeight(); return QSize(2 * h, h); } QSize KisStopGradientSliderWidget::minimumSizeHint() const { const int h = minimalHeight(); return QSize(h, h); } diff --git a/libs/ui/widgets/kis_stopgradient_slider_widget.h b/libs/ui/widgets/kis_stopgradient_slider_widget.h index f00d7f83c4..53bb2efe44 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.h +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.h @@ -1,82 +1,83 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * 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_STOP_GRADIENT_SLIDER_WIDGET_H_ #define _KIS_STOP_GRADIENT_SLIDER_WIDGET_H_ #include #include #include #include #include class KisStopGradientSliderWidget : public QWidget { Q_OBJECT public: KisStopGradientSliderWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); public: void paintEvent(QPaintEvent *) override; void setGradientResource(KoStopGradient* gradient); int selectedStop(); void setSelectedStop(int selected); QSize sizeHint() const override; QSize minimumSizeHint() const override; + void setSelectedStopType(KoGradientStopType type); Q_SIGNALS: void sigSelectedStop(int stop); protected: void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; private Q_SLOTS: void updateHandleSize(); private: void insertStop(double t); QRect sliderRect() const; QRect gradientStripeRect() const; - QRect handlesStipeRect() const; + QRect handlesStripeRect() const; QRegion allowedClickRegion(int tolerance) const; void updateCursor(const QPoint &pos); - void paintHandle(qreal position, const QColor &color, bool isSelected, QPainter *painter); + void paintHandle(qreal position, const QColor &color, bool isSelected, QString text, QPainter *painter); int handleClickTolerance() const; int minimalHeight() const; private: QScopedPointer m_defaultGradient; KoStopGradient* m_gradient; int m_selectedStop; KoGradientStop m_removedStop; bool m_drag; QSize m_handleSize; }; #endif diff --git a/libs/widgets/KisGradientSliderWidget.cpp b/libs/widgets/KisGradientSliderWidget.cpp index 924cb57533..027721ed59 100644 --- a/libs/widgets/KisGradientSliderWidget.cpp +++ b/libs/widgets/KisGradientSliderWidget.cpp @@ -1,225 +1,258 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * 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 "KisGradientSliderWidget.h" #include #include #include #include #include #include #include #include #include #include #include #define MARGIN 5 #define HANDLE_SIZE 10 +#define MIN_HEIGHT 60 KisGradientSliderWidget::KisGradientSliderWidget(QWidget *parent, const char* name, Qt::WindowFlags f) : QWidget(parent, f), m_currentSegment(0), m_selectedSegment(0), m_drag(0) { setObjectName(name); - setMinimumHeight(30); + setMinimumHeight(MIN_HEIGHT); m_segmentMenu = new QMenu(); m_segmentMenu->addAction(i18n("Split Segment"), this, SLOT(slotSplitSegment())); m_segmentMenu->addAction(i18n("Duplicate Segment"), this, SLOT(slotDuplicateSegment())); m_segmentMenu->addAction(i18n("Mirror Segment"), this, SLOT(slotMirrorSegment())); m_removeSegmentAction = new QAction(i18n("Remove Segment"), this); connect(m_removeSegmentAction, SIGNAL(triggered()), this, SLOT(slotRemoveSegment())); m_segmentMenu->addAction(m_removeSegmentAction); } void KisGradientSliderWidget::setGradientResource(KoSegmentGradient* agr) { m_autogradientResource = agr; m_selectedSegment = m_autogradientResource->segmentAt(0.0); emit sigSelectedSegment(m_selectedSegment); } + + +void KisGradientSliderWidget::paintSegmentHandle(int position, const QString text, const QPoint& textPos, QPainter& painter) +{ + QPolygon triangle(3); + triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); + triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN); + triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN); + painter.drawPolygon(triangle); + painter.drawText(textPos, text); +} + void KisGradientSliderWidget::paintEvent(QPaintEvent* pe) { QWidget::paintEvent(pe); QPainter painter(this); painter.fillRect(rect(), palette().window()); painter.setPen(Qt::black); painter.drawRect(MARGIN, MARGIN, width() - 2 * MARGIN, height() - 2 * MARGIN - HANDLE_SIZE); if (m_autogradientResource) { QImage image = m_autogradientResource->generatePreview(width() - 2 * MARGIN - 2, height() - 2 * MARGIN - HANDLE_SIZE - 2); QPixmap pixmap(image.width(), image.height()); if (!image.isNull()) { painter.drawImage(MARGIN + 1, MARGIN + 1, image); } painter.fillRect(MARGIN + 1, height() - MARGIN - HANDLE_SIZE, width() - 2 * MARGIN, HANDLE_SIZE, QBrush(Qt::white)); if (m_selectedSegment) { QRect selection(qRound(m_selectedSegment->startOffset()*(double)(width() - 2 * MARGIN - 2)) + 6, height() - HANDLE_SIZE - MARGIN, qRound((m_selectedSegment->endOffset() - m_selectedSegment->startOffset())*(double)(width() - 12)), HANDLE_SIZE); painter.fillRect(selection, QBrush(palette().highlight())); } - QPolygon triangle(3); - QList handlePositions = m_autogradientResource->getHandlePositions(); - int position; - painter.setBrush(QBrush(Qt::black)); - for (int i = 0; i < handlePositions.count(); i++) { - position = qRound(handlePositions[i] * (double)(width() - 12)) + 6; - triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); - triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN); - triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN); - painter.drawPolygon(triangle); - } - painter.setBrush(QBrush(Qt::white)); - QList middleHandlePositions = m_autogradientResource->getMiddleHandlePositions(); - for (int i = 0; i < middleHandlePositions.count(); i++) { - position = qRound(middleHandlePositions[i] * (double)(width() - 12)) + 6; - triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); - triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 2), height() - MARGIN); - triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 2), height() - MARGIN); - painter.drawPolygon(triangle); + QList segments = m_autogradientResource->segments(); + for (int i = 0; i < segments.count(); i++) { + KoGradientSegment* segment = segments[i]; + + //paint segment start + int position = qRound(segment->startOffset() * (double)(width() - 12)) + 6; + QPoint textPos(position, height() - 2 * (HANDLE_SIZE + MARGIN)); + QString text = segment->startType() == FOREGROUND_ENDPOINT ? "FG" : (segment->startType() == BACKGROUND_ENDPOINT ? "BG" : ""); + paintSegmentHandle(position, text, textPos, painter); + + //paint segment end + position = qRound(segment->endOffset() * (double)(width() - 12)) + 6; + textPos.setX(position - HANDLE_SIZE); + text = segment->endType() == FOREGROUND_ENDPOINT ? "FG" : (segment->endType() == BACKGROUND_ENDPOINT ? "BG" : ""); + paintSegmentHandle(position, text, textPos, painter); + + //paint midpoint + position = qRound(segment->middleOffset() * (double)(width() - 12)) + 6; + painter.setBrush(QBrush(Qt::white)); + paintSegmentHandle(position, "", textPos, painter); } + //QList handlePositions = m_autogradientResource->getHandlePositions(); + //int position; + //painter.setBrush(QBrush(Qt::black)); + //for (int i = 0; i < handlePositions.count(); i++) { + // position = qRound(handlePositions[i] * (double)(width() - 12)) + 6; + // triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); + // triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN); + // triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN); + // painter.drawPolygon(triangle); + //} + //painter.setBrush(QBrush(Qt::white)); + //QList middleHandlePositions = m_autogradientResource->getMiddleHandlePositions(); + //for (int i = 0; i < middleHandlePositions.count(); i++) { + // position = qRound(middleHandlePositions[i] * (double)(width() - 12)) + 6; + // triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); + // triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 2), height() - MARGIN); + // triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 2), height() - MARGIN); + // painter.drawPolygon(triangle); + //} } } void KisGradientSliderWidget::mousePressEvent(QMouseEvent * e) { if ((e->y() < MARGIN || e->y() > height() - MARGIN) || (e->x() < MARGIN || e->x() > width() - MARGIN) || e-> button() != Qt::LeftButton) { QWidget::mousePressEvent(e); return; } double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); KoGradientSegment* segment = 0; segment = m_autogradientResource->segmentAt(t); if (segment != 0) { m_currentSegment = segment; QRect leftHandle(qRound(m_currentSegment->startOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 1)), height() - HANDLE_SIZE, HANDLE_SIZE - 1, HANDLE_SIZE); QRect middleHandle(qRound(m_currentSegment->middleOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 2)), height() - HANDLE_SIZE - MARGIN, HANDLE_SIZE - 1, HANDLE_SIZE); QRect rightHandle(qRound(m_currentSegment->endOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 1)), height() - HANDLE_SIZE, HANDLE_SIZE - 1, HANDLE_SIZE); // Change the activation order of the handles to avoid deadlocks if (t > 0.5) { if (leftHandle.contains(e->pos())) m_drag = LEFT_DRAG; else if (middleHandle.contains(e->pos())) m_drag = MIDDLE_DRAG; else if (rightHandle.contains(e->pos())) m_drag = RIGHT_DRAG; } else { if (rightHandle.contains(e->pos())) m_drag = RIGHT_DRAG; else if (middleHandle.contains(e->pos())) m_drag = MIDDLE_DRAG; else if (leftHandle.contains(e->pos())) m_drag = LEFT_DRAG; } if (m_drag == NO_DRAG) { m_selectedSegment = m_currentSegment; emit sigSelectedSegment(m_selectedSegment); } } repaint(); } void KisGradientSliderWidget::mouseReleaseEvent(QMouseEvent * e) { Q_UNUSED(e); m_drag = NO_DRAG; } void KisGradientSliderWidget::mouseMoveEvent(QMouseEvent * e) { if ((e->y() < MARGIN || e->y() > height() - MARGIN) || (e->x() < MARGIN || e->x() > width() - MARGIN)) { QWidget::mouseMoveEvent(e); return; } double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); switch (m_drag) { case RIGHT_DRAG: m_autogradientResource->moveSegmentEndOffset(m_currentSegment, t); break; case LEFT_DRAG: m_autogradientResource->moveSegmentStartOffset(m_currentSegment, t); break; case MIDDLE_DRAG: m_autogradientResource->moveSegmentMiddleOffset(m_currentSegment, t); break; } if (m_drag != NO_DRAG) emit sigChangedSegment(m_currentSegment); repaint(); } void KisGradientSliderWidget::contextMenuEvent(QContextMenuEvent * e) { m_removeSegmentAction->setEnabled(m_autogradientResource->removeSegmentPossible()); m_segmentMenu->popup(e->globalPos()); } void KisGradientSliderWidget::slotSplitSegment() { m_autogradientResource->splitSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotDuplicateSegment() { m_autogradientResource->duplicateSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotMirrorSegment() { m_autogradientResource->mirrorSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotRemoveSegment() { m_selectedSegment = m_autogradientResource->removeSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } diff --git a/libs/widgets/KisGradientSliderWidget.h b/libs/widgets/KisGradientSliderWidget.h index d48866ead0..3c40b67915 100644 --- a/libs/widgets/KisGradientSliderWidget.h +++ b/libs/widgets/KisGradientSliderWidget.h @@ -1,91 +1,93 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * 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_GRADIENT_SLIDER_WIDGET_H_ #define _KIS_GRADIENT_SLIDER_WIDGET_H_ #include #include #include class QAction; class QMenu; class KoGradientSegment; class KoSegmentGradient; #include "kritawidgets_export.h" /** * @brief The KisGradientSliderWidget class makes it possible to edit gradients. */ class KRITAWIDGETS_EXPORT KisGradientSliderWidget : public QWidget { Q_OBJECT public: KisGradientSliderWidget(QWidget *parent = 0, const char* name = 0, Qt::WindowFlags f = 0); public: void paintEvent(QPaintEvent *) override; void setGradientResource(KoSegmentGradient* agr); KoGradientSegment* selectedSegment() { return m_selectedSegment; } Q_SIGNALS: void sigSelectedSegment(KoGradientSegment*); void sigChangedSegment(KoGradientSegment*); protected: void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; void contextMenuEvent(QContextMenuEvent * e) override; + void paintSegmentHandle(int position, const QString text, const QPoint& textPos, QPainter& painter); + private Q_SLOTS: void slotSplitSegment(); void slotDuplicateSegment(); void slotMirrorSegment(); void slotRemoveSegment(); private: enum { NO_DRAG, LEFT_DRAG, RIGHT_DRAG, MIDDLE_DRAG }; enum { SPLIT_SEGMENT, DUPLICATE_SEGMENT, MIRROR_SEGMENT, REMOVE_SEGMENT }; KoSegmentGradient* m_autogradientResource; KoGradientSegment* m_currentSegment; KoGradientSegment* m_selectedSegment; QMenu* m_segmentMenu; int m_drag; QAction *m_removeSegmentAction; }; #endif diff --git a/libs/widgets/KoResourceServerProvider.cpp b/libs/widgets/KoResourceServerProvider.cpp index 1370a357a9..0808ed09e4 100644 --- a/libs/widgets/KoResourceServerProvider.cpp +++ b/libs/widgets/KoResourceServerProvider.cpp @@ -1,199 +1,201 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourceServerProvider.h" #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoResourcePaths.h" #include "klocalizedstring.h" #include using namespace std; class GradientResourceServer : public KoResourceServer { public: GradientResourceServer(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) , m_foregroundToTransparent(0) , m_foregroundToBackground(0) { insertSpecialGradients(); } void insertSpecialGradients() { const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; KoStopGradient* gradient = new KoStopGradient(); gradient->setType(QGradient::LinearGradient); gradient->setName(i18n("Foreground to Transparent")); - stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), cs)); + stops << KoGradientStop(0.0, KoGradientStopInfo(KoColor(Qt::black, cs), FOREGROUNDSTOP)); + stops << KoGradientStop(1.0, KoGradientStopInfo(KoColor(QColor(0, 0, 0, 0), cs), COLORSTOP)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToTransparent = gradient; gradient = new KoStopGradient(); gradient->setType(QGradient::LinearGradient); gradient->setName(i18n("Foreground to Background")); stops.clear(); - stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(Qt::white, cs)); + stops << KoGradientStop(0.0, KoGradientStopInfo(KoColor(Qt::black, cs), FOREGROUNDSTOP)); + stops << KoGradientStop(1.0, KoGradientStopInfo(KoColor(Qt::white, cs), BACKGROUNDSTOP)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToBackground = gradient; } private: friend class KoResourceBundle; KoAbstractGradient* createResource( const QString & filename ) override { QString fileExtension; int index = filename.lastIndexOf('.'); if (index != -1) fileExtension = filename.mid(index).toLower(); KoAbstractGradient* grad = 0; if(fileExtension == ".svg" || fileExtension == ".kgr") grad = new KoStopGradient(filename); else if(fileExtension == ".ggr" ) grad = new KoSegmentGradient(filename); return grad; } QList< KoAbstractGradient* > sortedResources() override { QList< KoAbstractGradient* > resources = KoResourceServer::sortedResources(); QList< KoAbstractGradient* > sorted; if (m_foregroundToTransparent && resources.contains(m_foregroundToTransparent)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToTransparent))); } if (m_foregroundToBackground && resources.contains(m_foregroundToBackground)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToBackground))); } return sorted + resources; } KoAbstractGradient* m_foregroundToTransparent; KoAbstractGradient* m_foregroundToBackground; }; struct Q_DECL_HIDDEN KoResourceServerProvider::Private { KoResourceServer* patternServer; KoResourceServer* gradientServer; KoResourceServer* paletteServer; KoResourceServer *svgSymbolCollectionServer; KoResourceServer* gamutMaskServer; }; KoResourceServerProvider::KoResourceServerProvider() : d(new Private) { d->patternServer = new KoResourceServerSimpleConstruction("ko_patterns", "*.pat:*.jpg:*.gif:*.png:*.tif:*.xpm:*.bmp" ); d->patternServer->loadResources(blacklistFileNames(d->patternServer->fileNames(), d->patternServer->blackListedFiles())); d->gradientServer = new GradientResourceServer("ko_gradients", "*.svg:*.ggr"); d->gradientServer->loadResources(blacklistFileNames(d->gradientServer->fileNames(), d->gradientServer->blackListedFiles())); d->paletteServer = new KoResourceServerSimpleConstruction("ko_palettes", "*.kpl:*.gpl:*.pal:*.act:*.aco:*.css:*.colors:*.xml:*.sbz"); d->paletteServer->loadResources(blacklistFileNames(d->paletteServer->fileNames(), d->paletteServer->blackListedFiles())); d->svgSymbolCollectionServer = new KoResourceServerSimpleConstruction("symbols", "*.svg"); d->svgSymbolCollectionServer->loadResources(blacklistFileNames(d->svgSymbolCollectionServer->fileNames(), d->svgSymbolCollectionServer->blackListedFiles())); d->gamutMaskServer = new KoResourceServerSimpleConstruction("ko_gamutmasks", "*.kgm"); d->gamutMaskServer->loadResources(blacklistFileNames(d->gamutMaskServer->fileNames(), d->gamutMaskServer->blackListedFiles())); } KoResourceServerProvider::~KoResourceServerProvider() { delete d->patternServer; delete d->gradientServer; delete d->paletteServer; delete d->svgSymbolCollectionServer; delete d->gamutMaskServer; delete d; } Q_GLOBAL_STATIC(KoResourceServerProvider, s_instance) KoResourceServerProvider* KoResourceServerProvider::instance() { return s_instance; } QStringList KoResourceServerProvider::blacklistFileNames(QStringList fileNames, const QStringList &blacklistedFileNames) { if (!blacklistedFileNames.isEmpty()) { foreach (const QString &s, blacklistedFileNames) { fileNames.removeAll(s); } } return fileNames; } KoResourceServer* KoResourceServerProvider::patternServer() { return d->patternServer; } KoResourceServer* KoResourceServerProvider::gradientServer() { return d->gradientServer; } KoResourceServer* KoResourceServerProvider::paletteServer() { return d->paletteServer; } KoResourceServer *KoResourceServerProvider::svgSymbolCollectionServer() { return d->svgSymbolCollectionServer; } KoResourceServer* KoResourceServerProvider::gamutMaskServer() { return d->gamutMaskServer; } diff --git a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp index 17e647b826..93caeb47ed 100644 --- a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp @@ -1,143 +1,143 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Spencer Brown * 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 "krita_filter_gradient_map.h" #include #include #include #include #include #include #include "kis_config_widget.h" #include #include #include #include #include #include "gradientmap.h" #include #include KritaFilterGradientMap::KritaFilterGradientMap() : KisFilter(id(), FiltersCategoryMapId, i18n("&Gradient Map...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(true); setSupportsLevelOfDetail(true); setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsThreading(true); } void KritaFilterGradientMap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const { Q_ASSERT(!device.isNull()); QDomDocument doc; if (config->version()==1) { QDomElement elt = doc.createElement("gradient"); KoAbstractGradient *gradientAb = KoResourceServerProvider::instance()->gradientServer()->resourceByName(config->getString("gradientName")); if (!gradientAb) { qWarning() << "Could not find gradient" << config->getString("gradientName"); } gradientAb = KoResourceServerProvider::instance()->gradientServer()->resources().first(); QScopedPointer qGradient(gradientAb->toQGradient()); KoStopGradient::fromQGradient(qGradient.data())->toXML(doc, elt); doc.appendChild(elt); } else { doc.setContent(config->getString("gradientXML", "")); } KoStopGradient gradient = KoStopGradient::fromXML(doc.firstChildElement()); const ColorMode colorMode = ColorMode(config->getInt("colorMode")); KisDitherUtil ditherUtil; if (colorMode == ColorMode::Dither) ditherUtil.setConfiguration(*config, "dither/"); KoColor outColor(Qt::white, device->colorSpace()); KisSequentialIteratorProgress it(device, applyRect, progressUpdater); qreal grey; const int pixelSize = device->colorSpace()->pixelSize(); while (it.nextPixel()) { grey = qreal(device->colorSpace()->intensity8(it.oldRawData())) / 255; if (colorMode == ColorMode::Nearest) { KoGradientStop leftStop, rightStop; if (!gradient.stopsAt(leftStop, rightStop, grey)) continue; if (std::abs(grey - leftStop.first) < std::abs(grey - rightStop.first)) { - outColor = leftStop.second; + outColor = leftStop.second.first; } else { - outColor = rightStop.second; + outColor = rightStop.second.first; } } else if (colorMode == ColorMode::Dither) { KoGradientStop leftStop, rightStop; if (!gradient.stopsAt(leftStop, rightStop, grey)) continue; qreal localT = (grey - leftStop.first) / (rightStop.first - leftStop.first); if (localT < ditherUtil.threshold(QPoint(it.x(), it.y()))) { - outColor = leftStop.second; + outColor = leftStop.second.first; } else { - outColor = rightStop.second; + outColor = rightStop.second.first; } } else { gradient.colorAt(outColor, grey); } outColor.setOpacity(qMin(KoColor(it.oldRawData(), device->colorSpace()).opacityF(), outColor.opacityF())); outColor.convertTo(device->colorSpace()); memcpy(it.rawData(), outColor.data(), pixelSize); } } KisFilterConfigurationSP KritaFilterGradientMap::factoryConfiguration() const { return new KisFilterConfiguration(id().id(), 2); } KisFilterConfigurationSP KritaFilterGradientMap::defaultConfiguration() const { KisFilterConfigurationSP config = factoryConfiguration(); KoAbstractGradient *gradient = KoResourceServerProvider::instance()->gradientServer()->resources().first(); KoStopGradient stopGradient; QScopedPointer qGradient(gradient->toQGradient()); stopGradient.fromQGradient(qGradient.data()); QDomDocument doc; QDomElement elt = doc.createElement("gradient"); stopGradient.toXML(doc, elt); doc.appendChild(elt); config->setProperty("gradientXML", doc.toString()); config->setProperty("colorMode", false); KisDitherWidget::factoryConfiguration(*config, "dither/"); return config; } KisConfigWidget * KritaFilterGradientMap::createConfigurationWidget(QWidget * parent, const KisPaintDeviceSP dev, bool) const { return new KritaGradientMapConfigWidget(parent, dev); }