diff --git a/libs/image/tests/kis_asl_layer_style_serializer_test.cpp b/libs/image/tests/kis_asl_layer_style_serializer_test.cpp index 80984fa7f5..0538fb5552 100644 --- a/libs/image/tests/kis_asl_layer_style_serializer_test.cpp +++ b/libs/image/tests/kis_asl_layer_style_serializer_test.cpp @@ -1,423 +1,423 @@ /* * 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_layer_style_serializer_test.h" #include #include #include #include #include #include #include "kis_global.h" #include "testutil.h" #include "kis_psd_layer_style.h" #include "kis_asl_layer_style_serializer.h" #include #define CMP(object, method, value) QCOMPARE(style->object()->method(), value) void KisAslLayerStyleSerializerTest::testReading() { KisAslLayerStyleSerializer s; // QString srcFileName(TestUtil::fetchDataFileLazy("asl/test_all_style.asl")); QString srcFileName(TestUtil::fetchDataFileLazy("asl/test_all_and_pattern.asl")); QFile aslFile(srcFileName); aslFile.open(QIODevice::ReadOnly); s.readFromDevice(&aslFile); QVector styles = s.styles(); QVERIFY(styles.size() == 1); KisPSDLayerStyleSP style = styles.first(); CMP(dropShadow, effectEnabled, true); CMP(dropShadow, blendMode, COMPOSITE_MULT); CMP(dropShadow, color, QColor(Qt::black)); CMP(dropShadow, opacity, 15); CMP(dropShadow, angle, -120); CMP(dropShadow, useGlobalLight, false); CMP(dropShadow, distance, 2); CMP(dropShadow, spread, 1); CMP(dropShadow, size, 7); CMP(dropShadow, antiAliased, true); CMP(dropShadow, noise, 3); // CMP(dropShadow, contourLookupTable,); CMP(innerShadow, effectEnabled, true); CMP(innerShadow, blendMode, COMPOSITE_DARKEN); CMP(innerShadow, color, QColor(Qt::black)); CMP(innerShadow, opacity, 28); CMP(innerShadow, angle, 120); CMP(innerShadow, useGlobalLight, true); CMP(innerShadow, distance, 8); CMP(innerShadow, spread, 15); CMP(innerShadow, size, 27); CMP(innerShadow, antiAliased, false); CMP(innerShadow, noise, 10); // CMP(innerShadow, contourLookupTable,); CMP(outerGlow, effectEnabled, true); CMP(outerGlow, blendMode, COMPOSITE_SCREEN); CMP(outerGlow, color, QColor(255, 255, 189)); CMP(outerGlow, opacity, 43); CMP(outerGlow, spread, 23); CMP(outerGlow, size, 109); CMP(outerGlow, antiAliased, true); CMP(outerGlow, noise, 29); // CMP(outerGlow, contourLookupTable,); // CMP(outerGlow, gradient,); CMP(outerGlow, fillType, psd_fill_solid_color); CMP(outerGlow, technique, psd_technique_precise); CMP(outerGlow, range, 69); CMP(outerGlow, jitter, 18); CMP(innerGlow, effectEnabled, true); CMP(innerGlow, blendMode, COMPOSITE_SCREEN); CMP(innerGlow, color, QColor(255, 255, 189)); CMP(innerGlow, opacity, 55); CMP(innerGlow, spread, 21); CMP(innerGlow, size, 128); CMP(innerGlow, antiAliased, true); CMP(innerGlow, noise, 33); // CMP(innerGlow, contourLookupTable,); // CMP(innerGlow, gradient,); CMP(innerGlow, fillType, psd_fill_solid_color); CMP(innerGlow, technique, psd_technique_softer); CMP(innerGlow, range, 32); CMP(innerGlow, jitter, 22); CMP(innerGlow, source, psd_glow_edge); CMP(satin, effectEnabled, true); CMP(satin, blendMode, COMPOSITE_MULT); CMP(satin, color, QColor(Qt::black)); CMP(satin, opacity, 68); CMP(satin, angle, 19); CMP(satin, distance, 11); CMP(satin, size, 14); CMP(satin, antiAliased, false); CMP(satin, invert, true); // CMP(satin, contourLookupTable,); CMP(colorOverlay, effectEnabled, true); CMP(colorOverlay, blendMode, COMPOSITE_OVER); CMP(colorOverlay, color, QColor(Qt::red)); CMP(colorOverlay, opacity, 63); CMP(gradientOverlay, effectEnabled, true); CMP(gradientOverlay, blendMode, COMPOSITE_OVER); CMP(gradientOverlay, opacity, 100); CMP(gradientOverlay, angle, 90); CMP(gradientOverlay, style, psd_gradient_style_linear); CMP(gradientOverlay, reverse, false); CMP(gradientOverlay, alignWithLayer, true); CMP(gradientOverlay, scale, 100); CMP(gradientOverlay, gradientXOffset, 0); CMP(gradientOverlay, gradientYOffset, 0); //CMP(gradientOverlay, dither, ); CMP(gradientOverlay, gradient()->name, QString("Two Color")); CMP(stroke, effectEnabled, true); CMP(stroke, blendMode, COMPOSITE_OVER); CMP(stroke, opacity, 67); CMP(stroke, size, 13); CMP(stroke, fillType, psd_fill_solid_color); CMP(stroke, position, psd_stroke_outside); CMP(stroke, color, QColor(210, 33, 87)); CMP(bevelAndEmboss, effectEnabled, true); CMP(bevelAndEmboss, highlightBlendMode, COMPOSITE_SCREEN); CMP(bevelAndEmboss, highlightOpacity, 75); CMP(bevelAndEmboss, highlightColor, QColor(255, 255, 255)); CMP(bevelAndEmboss, shadowBlendMode, COMPOSITE_MULT); CMP(bevelAndEmboss, shadowOpacity, 75); CMP(bevelAndEmboss, shadowColor, QColor(Qt::black)); CMP(bevelAndEmboss, technique, psd_technique_softer); CMP(bevelAndEmboss, style, psd_bevel_inner_bevel); CMP(bevelAndEmboss, useGlobalLight, true); CMP(bevelAndEmboss, angle, 120); CMP(bevelAndEmboss, altitude, 30); CMP(bevelAndEmboss, depth, 83); CMP(bevelAndEmboss, size, 49); CMP(bevelAndEmboss, direction, psd_direction_up); // FIXME: contour CMP(bevelAndEmboss, glossAntiAliased, false); CMP(bevelAndEmboss, soften, 2); CMP(bevelAndEmboss, contourEnabled, true); // FIXME: contour curve CMP(bevelAndEmboss, antiAliased, true); CMP(bevelAndEmboss, contourRange, 60); CMP(bevelAndEmboss, textureEnabled, false); CMP(patternOverlay, effectEnabled, true); CMP(patternOverlay, blendMode, COMPOSITE_OVER); CMP(patternOverlay, opacity, 100); CMP(patternOverlay, alignWithLayer, true); CMP(patternOverlay, scale, 100); CMP(patternOverlay, horizontalPhase, 201); CMP(patternOverlay, verticalPhase, 162); CMP(patternOverlay, pattern()->name, QString("$$$/Presets/Patterns/Patterns_pat/Bubbles=Bubbles")); CMP(patternOverlay, pattern()->filename, QString("b7334da0-122f-11d4-8bb5-e27e45023b5f.pat")); } void KisAslLayerStyleSerializerTest::testWriting() { QVector styles; QByteArray refXMLDoc; { KisAslLayerStyleSerializer s; QString srcFileName(TestUtil::fetchDataFileLazy("asl/test_all_and_pattern.asl")); QFile aslFile(srcFileName); aslFile.open(QIODevice::ReadOnly); s.readFromDevice(&aslFile); styles = s.styles(); { aslFile.seek(0); KisAslReader reader; QDomDocument doc = reader.readFile(&aslFile); refXMLDoc = doc.toByteArray(); } } // now we have an initialized KisPSDLayerStyle object { KisAslLayerStyleSerializer s; s.setStyles(styles); QFile dstFile("test_written.asl"); dstFile.open(QIODevice::WriteOnly); s.saveToDevice(&dstFile); dstFile.close(); } QByteArray resultXMLDoc; { QFile resultFile("test_written.asl"); resultFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&resultFile); resultXMLDoc = doc.toByteArray(); } QFile refXMLFile("save_round_trip_src.xml"); refXMLFile.open(QIODevice::WriteOnly); refXMLFile.write(refXMLDoc); refXMLFile.close(); QFile resultXMLFile("save_round_trip_dst.xml"); resultXMLFile.open(QIODevice::WriteOnly); resultXMLFile.write(resultXMLDoc); resultXMLFile.close(); QEXPECT_FAIL("", "Tried to compare two xml files, which are not the same. The order of attributes when serializing is undefined", Continue); QCOMPARE(resultXMLDoc, refXMLDoc); } #include void KisAslLayerStyleSerializerTest::testWritingGlobalPatterns() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); KoPatternSP pattern = server->firstResource(); Q_ASSERT(pattern); dbgKrita << ppVar(pattern->name()); dbgKrita << ppVar(pattern->filename()); style->patternOverlay()->setEffectEnabled(true); style->patternOverlay()->setPattern(pattern); { KisAslLayerStyleSerializer s; s.setStyles(QVector() << style); QFile dstFile("test_written_pattern_only.asl"); dstFile.open(QIODevice::WriteOnly); s.saveToDevice(&dstFile); dstFile.close(); } /* QByteArray resultXMLDoc; { QFile resultFile("test_written.asl"); resultFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&resultFile); resultXMLDoc = doc.toByteArray(); } */ } void KisAslLayerStyleSerializerTest::testReadMultipleStyles() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); QVector styles; { KisAslLayerStyleSerializer s; QString srcFileName(TestUtil::fetchDataFileLazy("asl/multiple_styles.asl")); QFile aslFile(srcFileName); aslFile.open(QIODevice::ReadOnly); s.readFromDevice(&aslFile); styles = s.styles(); } { KisAslLayerStyleSerializer s; QString dstFileName("multiple_styles_out.asl"); QFile aslFile(dstFileName); aslFile.open(QIODevice::WriteOnly); s.setStyles(styles); s.saveToDevice(&aslFile); } { KisAslLayerStyleSerializer s; QString srcFileName("multiple_styles_out.asl"); QFile aslFile(srcFileName); aslFile.open(QIODevice::ReadOnly); s.readFromDevice(&aslFile); styles = s.styles(); dbgKrita << ppVar(styles.size()); } } void KisAslLayerStyleSerializerTest::testWritingGradients() { KoStopGradient stopGradient(""); { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; - stops << KoGradientStop(0.0, KoColor(Qt::black, cs)); - stops << KoGradientStop(0.3, KoColor(Qt::red, cs)); - stops << KoGradientStop(0.6, KoColor(Qt::green, cs)); - stops << KoGradientStop(1.0, KoColor(Qt::white, cs)); + stops << KoGradientStop(0.0, KoColor(Qt::black, cs), COLORSTOP); + stops << KoGradientStop(0.3, KoColor(Qt::red, cs), COLORSTOP); + stops << KoGradientStop(0.6, KoColor(Qt::green, cs), COLORSTOP); + stops << KoGradientStop(1.0, KoColor(Qt::white, cs), COLORSTOP); stopGradient.setStops(stops); } KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->outerGlow()->setEffectEnabled(true); style->outerGlow()->setFillType(psd_fill_gradient); style->outerGlow()->setGradient(toQShared(new KoStopGradient(stopGradient))); style->innerGlow()->setEffectEnabled(true); style->innerGlow()->setFillType(psd_fill_gradient); style->innerGlow()->setGradient(toQShared(new KoStopGradient(stopGradient))); style->gradientOverlay()->setEffectEnabled(true); style->gradientOverlay()->setGradient(toQShared(new KoStopGradient(stopGradient))); style->stroke()->setEffectEnabled(true); style->stroke()->setFillType(psd_fill_gradient); style->stroke()->setGradient(toQShared(new KoStopGradient(stopGradient))); { KisAslLayerStyleSerializer s; s.setStyles(QVector() << style); QFile dstFile("test_written_stop_gradient.asl"); dstFile.open(QIODevice::WriteOnly); s.saveToDevice(&dstFile); dstFile.close(); } QString xmlDoc; { QFile resultFile("test_written_stop_gradient.asl"); resultFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&resultFile); xmlDoc = doc.toString(); } { // the reference document has stripped "Idnt" field which is random QRegExp rx(""); rx.setMinimal(true); int pos = 0; while ((pos = rx.indexIn(xmlDoc, pos)) != -1) { xmlDoc.remove(pos, rx.matchedLength()); } { //QFile xmlFile("reference_gradients.asl.xml"); //xmlFile.open(QIODevice::WriteOnly); //xmlFile.write(xmlDoc.toLatin1()); //xmlFile.close(); } QString refFileName(TestUtil::fetchDataFileLazy("reference_gradients.asl.xml")); QFile refFile(refFileName); refFile.open(QIODevice::ReadOnly); QString refDoc = QString(refFile.readAll()); QEXPECT_FAIL("", "Tried to compare two gradient files, which are not the same. The order of attributes when serializing is undefined.", Continue); QCOMPARE(xmlDoc, refDoc); } } QTEST_MAIN(KisAslLayerStyleSerializerTest) diff --git a/libs/image/tests/kis_asl_parser_test.cpp b/libs/image/tests/kis_asl_parser_test.cpp index 05824f24ae..0ea606e934 100644 --- a/libs/image/tests/kis_asl_parser_test.cpp +++ b/libs/image/tests/kis_asl_parser_test.cpp @@ -1,332 +1,332 @@ /* * 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_parser_test.h" #include #include "testutil.h" #include #include #include #include #include #include #include void KisAslParserTest::test() { QString fileName(TestUtil::fetchDataFileLazy("asl/freebie.asl")); QFile aslFile(fileName); aslFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&aslFile); dbgKrita << ppVar(doc.toString()); KisAslObjectCatcher trivialCatcher; KisAslXmlParser parser; parser.parseXML(doc, trivialCatcher); } struct CallbackVerifier { CallbackVerifier() : m_numCallsHappened(0) {} void setColor(const QColor &color) { QVERIFY(color == QColor(Qt::white)); m_numCallsHappened++; } void setOpacity(double opacity) { QVERIFY(qFuzzyCompare(opacity, 75)); m_numCallsHappened++; } void setBlendingMode(const QString &mode) { QVERIFY(mode == "Scrn"); m_numCallsHappened++; } void setEnabled(bool value) { QVERIFY(value); m_numCallsHappened++; } void setCurve(const QString &name, const QVector &points) { QCOMPARE(name, QString("Linear")); QCOMPARE(points[0], QPointF()); QCOMPARE(points[1], QPointF(255.0, 255.0)); m_numCallsHappened++; } void setText(const QString &text) { QCOMPARE(text, QString("11adf7a2-a120-11e1-957c-d1ee226781a4")); m_numCallsHappened++; } void setPattern(const KoPatternSP pattern) { dbgKrita << ppVar(pattern->name()); dbgKrita << ppVar(pattern->filename()); //QCOMPARE(text, QString("11adf7a2-a120-11e1-957c-d1ee226781a4")); m_numCallsHappened++; } int m_numCallsHappened; }; void KisAslParserTest::testWithCallbacks() { using namespace std::placeholders; QString fileName(TestUtil::fetchDataFileLazy("asl/freebie.asl")); QFile aslFile(fileName); aslFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&aslFile); KisAslCallbackObjectCatcher c; CallbackVerifier verifier; c.subscribeColor("/Styl/Lefx/IrGl/Clr ", std::bind(&CallbackVerifier::setColor, &verifier, _1)); c.subscribeUnitFloat("/Styl/Lefx/IrGl/Opct", "#Prc", std::bind(&CallbackVerifier::setOpacity, &verifier, _1)); c.subscribeEnum("/Styl/Lefx/IrGl/Md ", "BlnM", std::bind(&CallbackVerifier::setBlendingMode, &verifier, _1)); c.subscribeBoolean("/Styl/Lefx/IrGl/enab", std::bind(&CallbackVerifier::setEnabled, &verifier, _1)); c.subscribeCurve("/Styl/Lefx/OrGl/TrnS", std::bind(&CallbackVerifier::setCurve, &verifier, _1, _2)); c.subscribeText("/null/Idnt", std::bind(&CallbackVerifier::setText, &verifier, _1)); KisAslXmlParser parser; parser.parseXML(doc, c); QCOMPARE(verifier.m_numCallsHappened, 6); } #include void KisAslParserTest::testASLXMLWriter() { KisAslXmlWriter w; QImage testImage(QSize(16, 16), QImage::Format_ARGB32); KoPatternSP testPattern1(new KoPattern(testImage, "Some very nice name ;)", "")); KoPatternSP testPattern2(new KoPattern(testImage, "Another very nice name ;P", "")); w.enterList(ResourceType::Patterns); w.writePattern("", testPattern1); w.writePattern("", testPattern2); w.leaveList(); w.enterDescriptor("", "", "null"); w.writeText("Nm ", "www.designpanoply.com - Freebie 5"); w.writeText("Idnt", "11adf7a2-a120-11e1-957c-d1ee226781a4"); w.leaveDescriptor(); w.enterDescriptor("", "", "Styl"); w.enterDescriptor("documentMode", "", "documentMode"); w.leaveDescriptor(); w.enterDescriptor("Lefx", "", "Lefx"); w.writeUnitFloat("Scl ", "#Prc", 100); w.writeBoolean("masterFxSwitch", true); w.enterDescriptor("DrSh", "", "DrSh"); w.writeBoolean("enab", true); w.writeEnum("Md ", "BlnM", "Mltp"); w.writeColor("Clr ", Qt::green); w.writeUnitFloat("Opct", "#Prc", 16); w.writeBoolean("uglg", false); w.writeUnitFloat("lagl", "#Prc", 100); w.writeUnitFloat("Dstn", "#Pxl", 100); w.writeUnitFloat("Ckmt", "#Pxl", 100); w.writeUnitFloat("blur", "#Pxl", 100); w.writeUnitFloat("Nose", "#Prc", 100); w.writeBoolean("anta", true); w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeBoolean("layerConceals", true); w.leaveDescriptor(); w.leaveDescriptor(); w.leaveDescriptor(); dbgKrita << ppVar(w.document().toString()); } #include #include void KisAslParserTest::testWritingGradients() { KisAslXmlWriter w1; KoSegmentGradient segmentGradient; segmentGradient.createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, 0.0, 0.3, 0.15, Qt::black, Qt::red); segmentGradient.createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, 0.3, 0.6, 0.45, Qt::red, Qt::green); segmentGradient.createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, 0.6, 1.0, 0.8, Qt::green, Qt::white); w1.writeSegmentGradient("tstG", &segmentGradient); //dbgKrita << "==="; //dbgKrita << ppVar(w1.document().toString()); KisAslXmlWriter w2; const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; - stops << KoGradientStop(0.0, KoColor(Qt::black, cs)); - stops << KoGradientStop(0.3, KoColor(Qt::red, cs)); - stops << KoGradientStop(0.6, KoColor(Qt::green, cs)); - stops << KoGradientStop(1.0, KoColor(Qt::white, cs)); + stops << KoGradientStop(0.0, KoColor(Qt::black, cs), COLORSTOP); + stops << KoGradientStop(0.3, KoColor(Qt::red, cs), COLORSTOP); + stops << KoGradientStop(0.6, KoColor(Qt::green, cs), COLORSTOP); + stops << KoGradientStop(1.0, KoColor(Qt::white, cs), COLORSTOP); KoStopGradient stopGradient; stopGradient.setStops(stops); w2.writeStopGradient("tstG", &stopGradient); //dbgKrita << "==="; //dbgKrita << ppVar(w2.document().toString()); QCOMPARE(w1.document().toString(), w2.document().toString()); } #include void KisAslParserTest::testASLWriter() { //QString srcFileName(TestUtil::fetchDataFileLazy("asl/testset/freebie_with_pattern.asl")); QString srcFileName(TestUtil::fetchDataFileLazy("asl/freebie.asl")); QDomDocument srcDoc; { QFile srcAslFile(srcFileName); srcAslFile.open(QIODevice::ReadOnly); KisAslReader reader; srcDoc = reader.readFile(&srcAslFile); QFile tfile("src_parsed.xml"); tfile.open(QIODevice::WriteOnly); tfile.write(srcDoc.toByteArray()); tfile.close(); } QString dstFileName("test.asl"); { QFile dstAslFile(dstFileName); dstAslFile.open(QIODevice::WriteOnly); KisAslWriter writer; writer.writeFile(&dstAslFile, srcDoc); dstAslFile.flush(); dstAslFile.close(); } QDomDocument dstDoc; { QFile roundTripAslFile(dstFileName); roundTripAslFile.open(QIODevice::ReadOnly); KisAslReader reader; dstDoc = reader.readFile(&roundTripAslFile); QFile tfile("dst_parsed.xml"); tfile.open(QIODevice::WriteOnly); tfile.write(dstDoc.toByteArray()); tfile.close(); } QCOMPARE(srcDoc.toByteArray(), dstDoc.toByteArray()); } void KisAslParserTest::testParserWithPatterns() { QDir dir(QString(FILES_DATA_DIR) + '/' + "testset"); QFileInfoList files = dir.entryInfoList(QStringList() << "*.asl", QDir::Files); int index = 0; Q_FOREACH (const QFileInfo &fileInfo, files) { //if (index != 12) {index++; continue;} dbgKrita << "===" << index << "==="; dbgKrita << ppVar(fileInfo.fileName()); QFile aslFile(fileInfo.absoluteFilePath()); aslFile.open(QIODevice::ReadOnly); KisAslReader reader; QDomDocument doc = reader.readFile(&aslFile); QFile xmlFile("mydata.xml"); xmlFile.open(QIODevice::WriteOnly); xmlFile.write(doc.toByteArray()); //dbgKrita << ppVar(doc.toString()); CallbackVerifier verifier; KisAslCallbackObjectCatcher c; c.subscribePattern("/Patterns/KisPattern", std::bind(&CallbackVerifier::setPattern, &verifier, std::placeholders::_1)); c.subscribePattern("/patterns/KisPattern", std::bind(&CallbackVerifier::setPattern, &verifier, std::placeholders::_1)); KisAslXmlParser parser; parser.parseXML(doc, c); //QCOMPARE(verifier.m_numCallsHappened, 7); index++; //break; } } QTEST_MAIN(KisAslParserTest) diff --git a/libs/pigment/resources/KoSegmentGradient.cpp b/libs/pigment/resources/KoSegmentGradient.cpp index 07421282c2..fcf386b5a0 100644 --- a/libs/pigment/resources/KoSegmentGradient.cpp +++ b/libs/pigment/resources/KoSegmentGradient.cpp @@ -1,1068 +1,1052 @@ /* 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)); } } KoResourceSP KoSegmentGradient::clone() const { return KoResourceSP(new KoSegmentGradient(*this)); } bool KoSegmentGradient::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) { Q_UNUSED(resourcesInterface); 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, 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::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() << " "; 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"))); 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, 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 (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 (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_end.offset - m_start.offset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { m_middleT = (m_middleOffset - m_start.offset) / m_length; } m_hasVariableColors = m_start.type != COLOR_ENDPOINT || m_end.type != COLOR_ENDPOINT; } const KoColor& KoGradientSegment::startColor() const { return m_start.color; } const KoColor& KoGradientSegment::endColor() const { return m_end.color; } qreal KoGradientSegment::startOffset() const { return m_start.offset; } qreal KoGradientSegment::middleOffset() const { return m_middleOffset; } qreal KoGradientSegment::endOffset() const { 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_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_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_start.offset) / m_length; } } void KoGradientSegment::setEndOffset(qreal t) { 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_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_start.offset - DBL_EPSILON && t < m_end.offset + DBL_EPSILON); qreal segmentT; if (m_length < DBL_EPSILON) { segmentT = 0.5; } else { segmentT = (t - m_start.offset) / m_length; } qreal colorT = m_interpolator->valueAt(segmentT, m_middleT); 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 & leftColor, const QColor & rightColor, KoGradientSegmentEndpointType leftType, KoGradientSegmentEndpointType rightType) { 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(), 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(), 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); 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); } 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 644f2ebcdc..873d206f00 100644 --- a/libs/pigment/resources/KoSegmentGradient.h +++ b/libs/pigment/resources/KoSegmentGradient.h @@ -1,478 +1,474 @@ /* 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, 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_start.color = color; } void setEndColor(const KoColor& 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_middleOffset; - //qreal m_endOffset; qreal m_length; qreal m_middleT; - //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; KoSegmentGradient(const KoSegmentGradient &rhs); KoSegmentGradient &operator=(const KoSegmentGradient &rhs) = delete; KoResourceSP clone() const override; bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override; bool saveToDevice(QIODevice* dev) const override; QPair resourceType() const override { return QPair(ResourceType::Gradients, ResourceSubType::SegmentedGradients); } /// 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 & 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: inline void pushSegment(KoGradientSegment* segment) { m_segments.push_back(segment); } QList m_segments; private: bool init(); }; typedef QSharedPointer KoSegmentGradientSP; #endif // KOSEGMENTGRADIENT_H diff --git a/libs/pigment/resources/KoStopGradient.cpp b/libs/pigment/resources/KoStopGradient.cpp index 86dcad180d..a6b3803a6c 100644 --- a/libs/pigment/resources/KoStopGradient.cpp +++ b/libs/pigment/resources/KoStopGradient.cpp @@ -1,633 +1,633 @@ /* 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() { } KoStopGradient::KoStopGradient(const KoStopGradient &rhs) : KoAbstractGradient(rhs), m_stops(rhs.m_stops), m_start(rhs.m_start), m_stop(rhs.m_stop), m_focalPoint(rhs.m_focalPoint) { } 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; } KoResourceSP KoStopGradient::clone() const { return KoResourceSP(new KoStopGradient(*this)); } bool KoStopGradient::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) { Q_UNUSED(resourcesInterface); 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; } 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.first.toQColor(&color); - gradient->setColorAt(i->first, color); + i->color.toQColor(&color); + gradient->setColorAt(i->position, color); } gradient->setCoordinateMode(QGradient::ObjectBoundingMode); gradient->setSpread(this->spread()); return gradient; } bool KoStopGradient::stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop, qreal t) const { if (!m_stops.count()) return false; - if (t <= m_stops.first().first || m_stops.count() == 1) { + if (t <= m_stops.first().position || 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); + rightStop = KoGradientStop(-std::numeric_limits::infinity(), leftStop.color, leftStop.type); return true; } - else if (t >= m_stops.last().first) { + else if (t >= m_stops.last().position) { // t is after the last stop rightStop = m_stops.last(); - leftStop = KoGradientStop(std::numeric_limits::infinity(), rightStop.second); + leftStop = KoGradientStop(std::numeric_limits::infinity(), rightStop.color, rightStop.type); return true; } 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, KoGradientStopInfo(KoColor(), COLORSTOP)), [](const KoGradientStop& a, const KoGradientStop& b) { - return a.first < b.first; + auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor(), COLORSTOP), [](const KoGradientStop& a, const KoGradientStop& b) { + return a.position < b.position; }); 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.first, mixSpace); - endDummy = KoColor(rightStop.second.first, mixSpace); + startDummy = KoColor(leftStop.color, mixSpace); + endDummy = KoColor(rightStop.color, mixSpace); } else { - startDummy = leftStop.second.first; - endDummy = rightStop.second.first; + startDummy = leftStop.color; + endDummy = rightStop.color; } const quint8* colors[2]; colors[0] = startDummy.data(); colors[1] = endDummy.data(); qreal localT; - qreal stopDistance = rightStop.first - leftStop.first; + qreal stopDistance = rightStop.position - leftStop.position; if (stopDistance < DBL_EPSILON) { localT = 0.5; } else { - localT = (t - leftStop.first) / stopDistance; + localT = (t - leftStop.position) / 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 (*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); } QSharedPointer KoStopGradient::fromQGradient(const QGradient *gradient) { if (!gradient) return QSharedPointer(0); QSharedPointer newGradient(new KoStopGradient(QString())); newGradient->setType(gradient->type()); newGradient->setSpread(gradient->spread()); switch (gradient->type()) { case QGradient::LinearGradient: { 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); 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); 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: return QSharedPointer(0);; } Q_FOREACH(const QGradientStop & stop, gradient->stops()) { KoColor color(newGradient->colorSpace()); color.fromQColor(stop.second); - newGradient->m_stops.append(KoGradientStop(stop.first, KoGradientStopInfo(color, COLORSTOP))); + newGradient->m_stops.append(KoGradientStop(stop.first, 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.first; + color = stop.color; color.convertTo(colorSpace()); - m_stops.append(KoGradientStop(stop.first, KoGradientStopInfo(color, stop.second.second))); - qDebug() << "KoStopGradient::setStops, stoptype: " << stop.second.second; - if (stop.second.second != COLORSTOP) { + m_stops.append(KoGradientStop(stop.position, color, stop.type)); + qDebug() << "KoStopGradient::setStops, stoptype: " << stop.type; + if (stop.type != COLORSTOP) { m_hasVariableStops = true; } } updatePreview(); } QList KoStopGradient::stops() const { return m_stops; } 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) { + if (m_stops[i].type == FOREGROUNDSTOP) { color = foreground; } - else if (m_stops[i].second.second == BACKGROUNDSTOP) { + else if (m_stops[i].type == BACKGROUNDSTOP) { color = background; } else continue; color.convertTo(colorSpace()); - m_stops[i].second.first = color; + m_stops[i].color = 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 { 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 { 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 { 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()); 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 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) { 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; + if (m_stops.count() > 0 && m_stops.last().position >= off) { + off = m_stops.last().position; } - m_stops.append(KoGradientStop(off, KoGradientStopInfo(color, stopType))); + m_stops.append(KoGradientStop(off, color, stopType)); } } } 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 { 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 { 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.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); + stopElt.setAttribute("offset", KisDomUtils::toString(stop.position)); + stopElt.setAttribute("bitdepth", stop.color.colorSpace()->colorDepthId().id()); + stopElt.setAttribute("alpha", KisDomUtils::toString(stop.color.opacityF())); + stopElt.setAttribute("stoptype", KisDomUtils::toString(stop.type)); + stop.color.toXML(doc, stopElt); gradientElt.appendChild(stopElt); } } 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"))); KoGradientStopType stoptype = static_cast(KisDomUtils::toInt(stopElt.attribute("stoptype", "0"))); - stops.append(KoGradientStop(offset, KoGradientStopInfo(color, stoptype))); + stops.append(KoGradientStop(offset, color, stoptype)); stopElt = stopElt.nextSiblingElement("stop"); } gradient.setStops(stops); return gradient; } 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.first.toQColor(&color); + stop.color.toQColor(&color); stream << indent << indent; stream << "(color.alpha()) / 255.0f; - stream << "\" krita-stop-type=\"" << QString().setNum(stop.second.second) << "\""; + stream << "\" krita-stop-type=\"" << QString().setNum(stop.type) << "\""; stream << " />" << endl; } stream << indent; stream << "" << endl; stream << "" << endl; KoResource::saveToDevice(dev); return true; } diff --git a/libs/pigment/resources/KoStopGradient.h b/libs/pigment/resources/KoStopGradient.h index f552e2517c..fa1346e741 100644 --- a/libs/pigment/resources/KoStopGradient.h +++ b/libs/pigment/resources/KoStopGradient.h @@ -1,125 +1,138 @@ /* 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 enum KoGradientStopType { COLORSTOP, FOREGROUNDSTOP, BACKGROUNDSTOP }; -typedef QPair KoGradientStopInfo; +struct KoGradientStop { + KoGradientStopType type; + KoColor color; + qreal position; + + KoGradientStop(qreal _position = 0.0, KoColor _color = KoColor(), KoGradientStopType _type = COLORSTOP) { + type = _type; + color = _color; + position = _position; + } + + bool operator == (const KoGradientStop& other) { + return this->type == other.type && this->color == other.color && this->position == other.position; + } +}; -typedef QPair KoGradientStop; struct KoGradientStopValueSort { inline bool operator() (const KoGradientStop& a, const KoGradientStop& b) { - return (a.second.first.toQColor().valueF() < b.second.first.toQColor().valueF()); + return (a.color.toQColor().valueF() < b.color.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; KoStopGradient(const KoStopGradient &rhs); bool operator==(const KoStopGradient &rhs) const; KoStopGradient &operator=(const KoStopGradient &rhs) = delete; KoResourceSP clone() const override; bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override; bool saveToDevice(QIODevice* dev) const override; QPair resourceType() const override { return QPair(ResourceType::Gradients, ResourceSubType::StopGradients); } /// 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 QSharedPointer fromQGradient(const QGradient *gradient); /// Sets the gradient stops void setStops(QList stops); 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); }; typedef QSharedPointer KoStopGradientSP; #endif // KOSTOPGRADIENT_H diff --git a/libs/psd/asl/kis_asl_xml_writer.cpp b/libs/psd/asl/kis_asl_xml_writer.cpp index 9f30e9fe49..34ee163aac 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 KoPatternSP 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 KoPatternSP 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.first.toQColor(); + QColor color = stop.color.toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; - positions << stop.first; + positions << stop.position; middleOffsets << 0.5; } writeGradientImpl(key, gradient->name(), colors, transparencies, positions, middleOffsets); } diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp index e66df68bab..9aeea54cc4 100644 --- a/libs/ui/kis_canvas_resource_provider.cpp +++ b/libs/ui/kis_canvas_resource_provider.cpp @@ -1,602 +1,590 @@ /* * 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)); } KoPatternSP KisCanvasResourceProvider::currentPattern() const { if (m_resourceManager->hasResource(CurrentPattern)) { return m_resourceManager->resource(CurrentPattern).value(); } else { return 0; } } KoAbstractGradientSP 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(); } KoGamutMaskSP 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(KoResourceSP res) { KoPatternSP pattern = res.dynamicCast(); QVariant v; v.setValue(pattern); m_resourceManager->setResource(CurrentPattern, v); emit sigPatternChanged(pattern); } void KisCanvasResourceProvider::slotGradientActivated(KoResourceSP res) { KoAbstractGradientSP gradient = res.dynamicCast(); 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) { KoAbstractGradientSP resource = KoResourceServerProvider::instance()->gradientServer()->resourceByFilename("Foreground to Background"); if (resource) { KoStopGradientSP stopGradient = resource.dynamicCast(); if (stopGradient) { QList stops; - stops << KoGradientStop(0.0, KoGradientStopInfo(fgColor(), FOREGROUNDSTOP)) << KoGradientStop(1.0, KoGradientStopInfo(bgColor(), BACKGROUNDSTOP)); + stops << KoGradientStop(0.0, fgColor(), FOREGROUNDSTOP) << KoGradientStop(1.0, bgColor(), BACKGROUNDSTOP); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } } resource = KoResourceServerProvider::instance()->gradientServer()->resourceByFilename("Foreground to Transparent"); if (resource){ KoStopGradientSP stopGradient = resource.dynamicCast(); if (stopGradient) { QList stops; - stops << KoGradientStop(0.0, KoGradientStopInfo(fgColor(), FOREGROUNDSTOP)) << KoGradientStop(1.0, KoGradientStopInfo(KoColor(Qt::transparent, fgColor().colorSpace()), COLORSTOP)); + stops << KoGradientStop(0.0, fgColor(), FOREGROUNDSTOP) << KoGradientStop(1.0, KoColor(Qt::transparent, fgColor().colorSpace()), COLORSTOP); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } } // TODO: fix updating dynamic gradients that have FG/BG colors inside #if 0 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); - //} #endif } 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(res.value()); break; case(CurrentGradient): emit sigGradientChanged(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(KoGamutMaskSP 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(KisWorkspaceResourceSP workspace) { emit sigLoadingWorkspace(workspace); } void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResourceSP workspace) { emit sigSavingWorkspace(workspace); } diff --git a/libs/ui/kis_stopgradient_editor.cpp b/libs/ui/kis_stopgradient_editor.cpp index 161110b924..96938a1b3b 100644 --- a/libs/ui/kis_stopgradient_editor.cpp +++ b/libs/ui/kis_stopgradient_editor.cpp @@ -1,315 +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_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(KoStopGradientSP 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(KoStopGradientSP 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; - KoGradientStopType type = m_gradient->stops()[stop].second.second; + KoGradientStopType type = m_gradient->stops()[stop].type; 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()); + color = m_fgColor; } else if (type == BACKGROUNDSTOP) { backgroundRadioButton->setChecked(true); - color = m_bgColor; // KoColor(m_bgColor, m_gradient->stops()[stop].second.first.colorSpace()); + color = m_bgColor; } else { colorRadioButton->setChecked(true); - color = m_gradient->stops()[stop].second.first; + color = m_gradient->stops()[stop].color; } 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; + double t = stops[currentStop].position; + KoColor color = stops[currentStop].color; 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))); + stops.insert(currentStop, KoGradientStop(t, 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; + double t = stops[currentStop].position; - KoColor c(color, stops[currentStop].second.first.colorSpace()); - c.setOpacity(stops[currentStop].second.first.opacityU8()); + KoColor c(color, stops[currentStop].color.colorSpace()); + c.setOpacity(stops[currentStop].color.opacityU8()); - KoGradientStopType type = stops[currentStop].second.second; + KoGradientStopType type = stops[currentStop].type; stops.removeAt(currentStop); - stops.insert(currentStop, KoGradientStop(t, KoGradientStopInfo(c, type))); - qDebug() << "GradientEditor::colorChanged: stop " << currentStop << " type: " << stops[currentStop].second.second; + stops.insert(currentStop, KoGradientStop(t, c, type)); + qDebug() << "GradientEditor::colorChanged: stop " << currentStop << " type: " << stops[currentStop].type; 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; + double t = stops[currentStop].position; - KoColor c = stops[currentStop].second.first; + KoColor c = stops[currentStop].color; c.setOpacity(value); - KoGradientStopType type = stops[currentStop].second.second; + KoGradientStopType type = stops[currentStop].type; stops.removeAt(currentStop); - stops.insert(currentStop, KoGradientStop(t, KoGradientStopInfo(c, type))); - qDebug() << "GradientEditor::opacityChanged: stop " << currentStop << " type: " << stops[currentStop].second.second; + stops.insert(currentStop, KoGradientStop(t, c, type)); + qDebug() << "GradientEditor::opacityChanged: stop " << currentStop << " type: " << stops[currentStop].type; 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)); + reversedStops.push_front(KoGradientStop(1 - stop.position, stop.color, stop.type)); } 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.first.toQColor().valueF(); + const float value = evenDistribution ? (float)stopIndex / (float)(stopCount - 1) : stop.color.toQColor().valueF(); const float position = ascending ? value : 1.f - value; if (ascending) { - sortedStops.push_back(KoGradientStop(position, stop.second)); + sortedStops.push_back(KoGradientStop(position, stop.color, stop.type)); } else { - sortedStops.push_front(KoGradientStop(position, stop.second)); + sortedStops.push_front(KoGradientStop(position, stop.color, stop.type)); } 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/widgets/kis_gradient_chooser.cc b/libs/ui/widgets/kis_gradient_chooser.cc index 9a1bd75d93..f3c0974b9f 100644 --- a/libs/ui/widgets/kis_gradient_chooser.cc +++ b/libs/ui/widgets/kis_gradient_chooser.cc @@ -1,256 +1,256 @@ /* * 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(KoAbstractGradientSP gradient, QWidget *parent, const char *name, KoColor fgColor, KoColor bgColor) : KoDialog(parent, Qt::Dialog) { setButtons(Ok|Cancel); setDefaultButton(Ok); setObjectName(name); setModal(false); connect(this, SIGNAL(okClicked()), this, SLOT(accept())); connect(this, SIGNAL(cancelClicked()), this, SLOT(reject())); KoStopGradientSP stopGradient = gradient.dynamicCast(); if (stopGradient) { m_page = new KisStopGradientEditor(stopGradient, this, "autogradient", i18n("Custom Stop Gradient"), fgColor, bgColor); } else { KoSegmentGradientSP segmentedGradient = gradient.dynamicCast(); if (segmentedGradient) { 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(); m_itemChooser = new KisResourceItemChooser(ResourceType::Gradients, false, this); m_itemChooser->showTaggingBar(true); m_itemChooser->setFixedSize(250, 250); m_itemChooser->itemView()->setViewMode(QListView::ListMode); connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(update(KoResourceSP ))); connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SIGNAL(resourceSelected(KoResourceSP ))); 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() { } KoResourceSP KisGradientChooser::currentResource() { return m_itemChooser->currentResource(); } void KisGradientChooser::setCurrentResource(KoResourceSP resource) { m_itemChooser->setCurrentResource(resource); } void KisGradientChooser::setCurrentItem(int row) { m_itemChooser->setCurrentItem(row); 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(KoResourceSP resource) { KoAbstractGradientSP gradient = resource.staticCast(); m_lbName->setText(gradient ? i18n(gradient->name().toUtf8().data()) : ""); m_editGradient->setEnabled(true); } void KisGradientChooser::addStopGradient() { KoStopGradientSP gradient(new KoStopGradient("")); QList stops; - 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)); + stops << KoGradientStop(0.0, KoColor(QColor(250, 250, 0), KoColorSpaceRegistry::instance()->rgb8()), COLORSTOP) + << KoGradientStop(1.0, KoColor(QColor(255, 0, 0, 255), KoColorSpaceRegistry::instance()->rgb8()), COLORSTOP); gradient->setType(QGradient::LinearGradient); gradient->setName(i18n("unnamed")); gradient->setStops(stops); addGradient(gradient); } void KisGradientChooser::addSegmentedGradient() { KoSegmentGradientSP 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(KoAbstractGradientSP gradient, bool editGradient) { KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QString saveLocation = rserver->saveLocation(); KisCustomGradientDialog dialog(gradient, this, "KisCustomGradientDialog", m_foregroundColor, m_backgroundColor); dialog.exec(); QFileInfo fileInfo(saveLocation + gradient->name().split(" ").join("_") + gradient->defaultFileExtension()); bool fileOverwriteAccepted = false; QString oldname = gradient->name(); while(!fileOverwriteAccepted) { if (dialog.exec() == KoDialog::Accepted) { if (gradient->name().isEmpty()) { return; } if (editGradient && oldname == gradient->name()) { fileOverwriteAccepted = true; continue; } fileInfo = QFileInfo(saveLocation + gradient->name().split(" ").join("_") + gradient->defaultFileExtension()); if (fileInfo.exists()) { int res = QMessageBox::warning(this, i18nc("@title:window", "Name Already Exists") , i18n("The name '%1' already exists, do you wish to overwrite it?", gradient->name()) , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (res == QMessageBox::Yes) fileOverwriteAccepted = true; } else { fileOverwriteAccepted = true; } } else { return; } } gradient->setFilename(gradient->name() + gradient->defaultFileExtension()); gradient->setValid(true); rserver->addResource(gradient); //TODO: select the right gradient from the resource server. Right now this is not possible :( m_itemChooser->setCurrentItem(0); } void KisGradientChooser::editGradient() { // FIXME: restore actual editing! // KisCustomGradientDialog dialog(static_cast(currentResource()), this, "KisCustomGradientDialog", m_foregroundColor, m_backgroundColor); // dialog.exec(); addGradient(currentResource().staticCast(), true); } diff --git a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp index b309e78e90..a15359704c 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp @@ -1,386 +1,369 @@ /* * 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 = 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(KoStopGradientSP gradient) { m_gradient = gradient ? gradient : m_defaultGradient; 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::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->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; QString text = ""; - if (handlePositions[i].second.second == FOREGROUNDSTOP) { + if (handlePositions[i].type == FOREGROUNDSTOP) { text = "FG"; - } else if (handlePositions[i].second.second == BACKGROUNDSTOP) { + } else if (handlePositions[i].type == BACKGROUNDSTOP) { text = "BG"; } - paintHandle(handlePositions[i].first, - handlePositions[i].second.first.toQColor(), + paintHandle(handlePositions[i].position, + handlePositions[i].color.toQColor(), i == m_selectedStop, text, &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); + const qreal distance = qAbs(t - stop.position); 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->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; + if (stop.position <= stops[i].position) break; result = i + 1; } return result; } void KisStopGradientSliderWidget::mouseMoveEvent(QMouseEvent * e) { updateCursor(e->pos()); if (m_drag) { 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); + m_removedStop.position = 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); + draggedStop.position = 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->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, KoGradientStopInfo(color, COLORSTOP)); + const KoGradientStop stop(t, 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::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 += 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 26c2c9a106..465e9ae99d 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.h +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.h @@ -1,83 +1,82 @@ /* * 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 #include class KisStopGradientSliderWidget : public QWidget { Q_OBJECT public: KisStopGradientSliderWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); public: void paintEvent(QPaintEvent *) override; void setGradientResource(KoStopGradientSP 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 handlesStripeRect() const; QRegion allowedClickRegion(int tolerance) const; void updateCursor(const QPoint &pos); void paintHandle(qreal position, const QColor &color, bool isSelected, QString text, QPainter *painter); int handleClickTolerance() const; int minimalHeight() const; private: KoStopGradientSP m_defaultGradient; KoStopGradientSP m_gradient; int m_selectedStop; KoGradientStop m_removedStop; bool m_drag; QSize m_handleSize; }; #endif diff --git a/libs/widgets/KoResourceServerProvider.cpp b/libs/widgets/KoResourceServerProvider.cpp index 37c60dfed6..b9a0710e25 100644 --- a/libs/widgets/KoResourceServerProvider.cpp +++ b/libs/widgets/KoResourceServerProvider.cpp @@ -1,185 +1,185 @@ /* 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) : KoResourceServer(type) { insertSpecialGradients(); } void insertSpecialGradients() { qDebug() << "insertSpecialGradients broken because we don't have a list we can insert in front of anymore"; const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; KoStopGradientSP gradient(new KoStopGradient()); gradient->setType(QGradient::LinearGradient); gradient->setName(i18n("Foreground to Transparent")); - stops << KoGradientStop(0.0, KoGradientStopInfo(KoColor(Qt::black, cs), FOREGROUNDSTOP)); - stops << KoGradientStop(1.0, KoGradientStopInfo(KoColor(QColor(0, 0, 0, 0), cs), COLORSTOP)); + stops << KoGradientStop(0.0, KoColor(Qt::black, cs), FOREGROUNDSTOP); + stops << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), cs), COLORSTOP); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false); m_foregroundToTransparent = gradient; gradient.reset(new KoStopGradient()); gradient->setType(QGradient::LinearGradient); gradient->setName(i18n("Foreground to Background")); stops.clear(); - stops << KoGradientStop(0.0, KoGradientStopInfo(KoColor(Qt::black, cs), FOREGROUNDSTOP)); - stops << KoGradientStop(1.0, KoGradientStopInfo(KoColor(Qt::white, cs), BACKGROUNDSTOP)); + stops << KoGradientStop(0.0, KoColor(Qt::black, cs), FOREGROUNDSTOP); + stops << KoGradientStop(1.0, KoColor(Qt::white, cs), BACKGROUNDSTOP); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false); m_foregroundToBackground = gradient; } private: friend class KoResourceBundle; KoAbstractGradientSP createResource( const QString & filename ) { QString fileExtension; int index = filename.lastIndexOf('.'); if (index != -1) fileExtension = filename.mid(index).toLower(); KoAbstractGradientSP grad; if(fileExtension == ".svg" || fileExtension == ".kgr") { grad.reset(new KoStopGradient(filename)); } else if(fileExtension == ".ggr" ) { grad.reset(new KoSegmentGradient(filename)); } return grad; } KoAbstractGradientSP m_foregroundToTransparent; KoAbstractGradientSP 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 KoResourceServer(ResourceType::Patterns); d->gradientServer = new GradientResourceServer(ResourceType::Gradients); d->paletteServer = new KoResourceServer(ResourceType::Palettes); d->svgSymbolCollectionServer = new KoResourceServer(ResourceType::Symbols); d->gamutMaskServer = new KoResourceServer(ResourceType::GamutMasks); } 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 cb3aa4ba27..4f80e9f6ce 100644 --- a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp @@ -1,231 +1,231 @@ /* * 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 "gradientmap.h" #include #include #include #include class KritaFilterGradientMapConfiguration : public KisFilterConfiguration { public: KritaFilterGradientMapConfiguration(const QString & name, qint32 version, KisResourcesInterfaceSP resourcesInterface) : KisFilterConfiguration(name, version, resourcesInterface) { } KritaFilterGradientMapConfiguration(const KritaFilterGradientMapConfiguration &rhs) : KisFilterConfiguration(rhs) { } virtual KisFilterConfigurationSP clone() const override { return new KritaFilterGradientMapConfiguration(*this); } KoStopGradientSP gradientImpl(KisResourcesInterfaceSP resourcesInterface) const { KoStopGradientSP gradient; if (this->version() == 1) { auto source = resourcesInterface->source(ResourceType::Gradients); KoAbstractGradientSP gradientAb = source.resourceForName(this->getString("gradientName")); if (!gradientAb) { qWarning() << "Could not find gradient" << this->getString("gradientName"); gradientAb = source.fallbackResource(); } gradient = gradientAb.dynamicCast(); if (!gradient) { QScopedPointer qGradient(gradientAb->toQGradient()); QDomDocument doc; QDomElement elt = doc.createElement("gradient"); KoStopGradient::fromQGradient(qGradient.data())->toXML(doc, elt); doc.appendChild(elt); gradient = KoStopGradient::fromXML(doc.firstChildElement()) .clone() .dynamicCast(); } } else { QDomDocument doc; doc.setContent(this->getString("gradientXML", "")); gradient = KoStopGradient::fromXML(doc.firstChildElement()) .clone() .dynamicCast(); } return gradient; } KoStopGradientSP gradient() const { return gradientImpl(resourcesInterface()); } QList linkedResources(KisResourcesInterfaceSP globalResourcesInterface) const override { QList resources; // only the first version of the filter loaded the gradient by name if (this->version() == 1) { KoStopGradientSP gradient = gradientImpl(globalResourcesInterface); if (gradient) { resources << gradient; } } resources << KisDitherWidget::prepareLinkedResources(*this, "dither/", globalResourcesInterface); return resources; } QList embeddedResources(KisResourcesInterfaceSP globalResourcesInterface) const override { QList resources; // the second version of the filter embeds the gradient if (this->version() > 1) { KoStopGradientSP gradient = gradientImpl(globalResourcesInterface); if (gradient) { resources << gradient; } } return resources; } }; using KritaFilterGradientMapConfigurationSP = KisPinnedSharedPtr; 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()); const KritaFilterGradientMapConfiguration* config = dynamic_cast(_config.data()); KIS_SAFE_ASSERT_RECOVER_RETURN(config); KoStopGradientSP gradient = config->gradient(); 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.first; + if (std::abs(grey - leftStop.position) < std::abs(grey - rightStop.position)) { + outColor = leftStop.color; } else { - outColor = rightStop.second.first; + outColor = rightStop.color; } } else if (colorMode == ColorMode::Dither) { KoGradientStop leftStop, rightStop; if (!gradient->stopsAt(leftStop, rightStop, grey)) continue; - qreal localT = (grey - leftStop.first) / (rightStop.first - leftStop.first); + qreal localT = (grey - leftStop.position) / (rightStop.position - leftStop.position); if (localT < ditherUtil.threshold(QPoint(it.x(), it.y()))) { - outColor = leftStop.second.first; + outColor = leftStop.color; } else { - outColor = rightStop.second.first; + outColor = rightStop.color; } } 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(KisResourcesInterfaceSP resourcesInterface) const { return new KritaFilterGradientMapConfiguration(id().id(), 2, resourcesInterface); } KisFilterConfigurationSP KritaFilterGradientMap::defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const { KisFilterConfigurationSP config = factoryConfiguration(resourcesInterface); auto source = resourcesInterface->source(ResourceType::Gradients); KoAbstractGradientSP gradient = source.fallbackResource(); 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); }